This thread looks to be a little on the old side and therefore may no longer be relevant. Please see if there is a newer thread on the subject and ensure you're using the most recent build of any software if your question regards a particular product.
This thread has been locked and is no longer accepting new posts, if you have a question regarding this topic please email us at support@mindscape.co.nz
|
Hi, Lightspeed uses IQueryable for Db items. IQueryable is not observable by default, therefore adding/removing and items will not automatically update UI control, e.g., ItemsControl (WPF) I tried to wrap-around IQueryable to ObservableCollection, but it didn't work. Is there a way to make ItemsControl to observe the changes? Thanks. -chris |
|
|
You can't do this with IQueryable, but you can do it using the query objects API, specifically the Find(Query, IList) method:
Or of course since an IQueryable is also IEnumerable, you can just initialise an ObservableCollection from your IQueryable:
You can easily wrap this in an extension method so that you can write Note that the ObservableCollection once created from the query is disconnected from the query, i.e. do not expect items to turn up in the ObservableCollection just because they have been added to the database or the unit of work. ObservableCollection means that the collection can be observed by UI elements, not that it observes a data source itself. |
|
|
Hi, Ivan, I guess that whole point of making ObservableCollection is to make UI to observe the changes to the data source. It sounds like it just create ObservableCollection but it doesn't notify the db data changes. However, I find that one-to-many relationship creates EntityCollection and it is both observable and queryable. Why isn't it the same for foreign-key entities? Couldn't we make it the same EntityCollection? I could update the UI manually whenever there are changes but entities can be added/removed from anywhere where it doens't have access to UI and updating UI manually is error-prone and can make the code very ugly. I hope there is a better solution. Thanks. -chris |
|
|
EntityCollection is observable, meaning that the UI can detect when something is added to or removed from the collection. EntityCollection does NOT monitor the database and update itself when something with the appropriate foreign key is added to or removed from the database. If you need to monitor changes within the database, you will need to implement some sort of polling or notification system. SQL Server used to have a notification system but I believe this has now been withdrawn. You might be able to implement something with triggers. However even this will not handle the scenario where something in the database has been updated, because LightSpeed does not update entities that are already part of the unit of work. The best approach is to rethink your unit of work boundaries so as to keep your units of work short-lived. A unit of work should basically be along the lines of:
That is, instead of creating a long-lived unit of work and trying to have it present a live, continually-updating view of a changing database, create many short-lived units of work, re-querying the database each time. |
|
|
Oh.. let me clarify what I meant by updating db data source. I don't meant to say updating db directly but through Uow. When you call uow.Add() or uow.Remove(), EntityCollection for association gets notified, however, foreign-keyed entities (IQueryable) does not, although it correctly adds/removes from the list. Thanks. -chris |
|
|
Ah, I see now. The thing is, an EntityCollection is bound up with an association, and entities know which associations they participate in. So when an entity is added into the UOW that takes part in an association, we can notify the EntityCollection. However, an entity doesn't know what queries it satisfies. So when an entity is added into the UOW, if we were to update query result lists, we would have to rerun every query to see if that entity satisfied it and therefore needed to be added to the result list. This would be complex, and in some cases is not even possible (consider the case where the query involves a stored procedure or a function that is defined in the database rather than in the client). So what you're describing isn't directly possible at the moment, though it would be rather cool. A possible solution would be to encapsulate the unit of work in a repository API. The repository would also maintain ObservableCollections for the queries you're interested in. Then when you added an entity via the repository API, you could check it for relevant properties (such as foreign keys) and add it to the required ObservableCollections. Another possibility is to look at projects such as Bindable LINQ (http://bindablelinq.codeplex.com/) or Obtics (http://obtics.codeplex.com/). These allow you to put an ObservableCollection over a LINQ to Objects query. However, they do depend on the queried set also being observable, so you would still need some sort of encapsulation to maintain an ObservableCollection of 'all currently loaded entities of type X' to be a Bindable LINQ or Obtics data source; but this should be a bit simpler than maintaining individual per-query collections. |
|
|
Glad we are in sync. ^^ I need some time to chew on what you just suggested and I'll give it a try but I have a simple question. Changing IQueryable to EntityCollection just like association would probably the easiest/coolest way to resolve this issues as EntityCollectin is also queryable, therefore it won't affect existing code. I think it is very useful to be able to nofitified for changes to made to foriegn-keyed entity collection. Are there other implication that I don't know of? Thanks. -chris |
|
|
EntityCollection is NOT queryable, so this would have a huge impact on existing code, and of course it would still not handle the general case (because an EntityCollection works via its knowledge of associations, not of queries). However, it sounds like all you are interested in is the foreign-keyed case. Is that right? If so, the easiest solution is to figure out the parent entity and use its children collection:
Now children is an EntityCollection and will track changes to the set of entities with the same parentId. Of course you can encapsulate this in a helper method if you don't want application code to be polluted with the detour via the parent entity. You can also use eager loading or named aggregates to make the collection load efficient if database round-trips are a concern. |
|
|
Thanks but that's not quite what I was looking for. I need UI to display list of all entities (not just children of certain parent) and updates itself by adding/removing new entitities. IQueryable will not trigger the changes by default. As I said earlier, add/remove can be done in low-level where it doesn't have an access to the UI. It can be done through global varialble to expose the UI but can be quite ugly. Is it possible to make it both queryable and observable? Thanks. |
|
|
Okay, so you need an observable collection of ALL entities, not just those that meet a particular query or have a particular foreign key, and you want this collection to observe the UOW? That's not possible, because the unit of work is not observable. But you can do it the other way round:
The idea is that your code adds and removes using the observable collection (so that the UI can observe it) and you use an event handler to propagate these adds and removes to the UOW so that they can be persisted. |
|
|
I see..the workaround is add one more level of indirection.. It can be several level of indirection depends on how you look at it but I guess it's not too bad.. I appreciate for your help, however, I would like to take this opportunity to say something about my experience. The support is pretty good and very helpful but there are times that I think we can solve it better way. When you look at one workaround at a time, it's not big of deal but now, I have many workarounds and it's getting little difficult to keep track of all of them. There are many reasons that we have to resolve with the workarounds but I've heard, the fix will affect exisiting codes and therefore it won't be changed, and sometimes I hear "not many users requested". I fully understand about breaking existing code but I can't find good ground for the second reason. I think it's about lack of resource but hearing "not many users requested" makes me feel invalidated. I'm sure there are many others who are not paying attention to the forum or, find the workaround him/herself. I think Ivan(and his team) is super amazing but it seems he needs some help. Anyway, I think break the existing code is inevitable during the course of development and I really wish that we have a chance to rectify it. Next major update is probably the only chance we have, I wish user will have a chance to participate shaping it. Becasue we miss the next major update, we'll probably have to wait for another round of major update, and it could be quite painful. If you would like, I will prepare my wish list and share it with you. Thank. -chris |
|