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
|
Hello, in our current application we have a WPF view where the user should be able to add, remove and insert elements from a list. That view holds a ViewModel which contains a LightSpeed entity which has an EntityCollection<T> (which is binded to the View). Add works pretty well: a new element appears at the end of the list and the WPF interface automatically shows the new item. But Insert and Remove are giving me problems: calling Insert(index, element) always inserts the element in the last position and calling RemoveAt gives me an ObjectDisposedException (the UnitOfWork) which I don't really understand (I want to work with the list detached from the database). So I'm a little lost here about why those methods aren't working as I was expecting (I can solve the Remove problem doing the operation inside a UnitOfWork, but I would like to understand why is not working right now :) Regards, Vicente |
|
|
The reason that Remove (and therefore RemoveAt) require a unit of work is that removing an entity from a dependent parent collection (assuming CascadeDeletes is true) actually registers it as a pending delete. However, a disposed unit of work will not accept this registration (because it knows it will never be able to commit it), and throws the ObjectDisposedException that you're seeing. Regarding Insert not respecting the index, I can't reproduce this in our test environment: the inserted element appears at the correct position in the entity collection. However, note that when you later reload the collection from the database, the element will appear at whatever position is appropriate for the load sort order (default to by ID, which would put new elements last); so it's probably best not to rely on the insert position as a permanent thing. However, if this remains an issue, could you provide us with a stripped-down (but complete) project that reproduces the problem? Thanks! |
|
|
Hi Ivan, I have been doing some more tests. The Insert was my mistake, when constructing my child entity I was setting the parent property, which was causing the child to be added to the parent collection, so later the Insert wouldn't add the same entity again (nice :)). That's why it seemed Insert was not respecting the order, because the child was already there, my bad. But the Remove is giving me more headaches. Right now our app is a WPF app using the MVVM pattern, where every ViewModel wraps a LightSpeed entity. In this concrete case it's a Path (Line) that contains a collection of Segments. I'm pretty new to ORMs (I played with nHibernate and then moved to LightSpeed), so the design right now for the ViewModels are that entities are totally detached from the DB: if we want one entity, we create a UoW, get it and the UoW dies. If we want to save, we create the UoW, attach, save and the UoW dies. If we want to cancel changes, we reload the entity. And so on. I have found quite a lot of topics in using ORMs with web apps (specially with ASP.NET MVC) but not so much guidance for Winforms/WPF apps. So far the few things I read are to use "short-lived" unit of works (Sessions in nHibernate), but while the uow-per-request pattern is pretty clear, the "short-lived" uow is not clear at all (at least for me :( ). So I went the route of working disconnected and so far everything was working pretty well (I haven't done heavy testing on it, but it seemed so), except for this Remove case, and right now, I'm at a loss on how to solve it. Any tips? It's the totally disconnected model a mistake? Which is the "good" way of doing this in WPF? Regards, |
|
|
Hi Vicente, Thanks for your feedback. The short lived / disconnected route is the correct path to be taking however there is an issue around removing items from an EntityCollection currently as you have seen. The reason behind this is that cascading deletes can require an active unit of work to discover which entities may subsequently need to be removed with the removal of the entity from the collection. While this makes sense it's also not optimal for short lived / disconnected scenarios and we are committed to improving the situation. Unfortunately this will have to be post LightSpeed 3.0 due to the already huge workload associated with that. My recommendation for working around this is to have the remove event pass back to a controller/presenter method which can attach the currently loaded entities to a live unit of work (similar to what you are doing with your save) and then perform the remove. If everything goes correctly this should update your underlying ViewModel's entity and be reflected via the bindings in your user interface. Suboptimal but likely the best work around available at the moment. There is also the option to use a longer running unit of work with the ConnectionStrategy work that Ivan has added to LightSpeed which provides a mechanism to be partially connected (disconnect from the db and reconnect on demand). I'd recommend my first suggestion first as it will be tidier but if you have any additional issues we can help you look into this option as well. I'm not sure if you have access to LightSpeed 3.0 but last week I added a first cut WinForms sample to look at some of the unique scenarios to client application development. It's an early cut so we can beef it up to demonstrate additional use cases in future but if you have access to LS3 then I'd recommend checking it out and providing feedback on what you would like to see :-) I hope that helps - please let me know if you have any additional questions. John-Daniel Trask |
|
|
Hi John-Daniel, first, thanks a lot for the detailed answer, it has helped a lot. Sorry for my late answer as I have been playing a little with this and testing things around (and found some other mistakes here and there). I have been playing with something like this in our Repository class: </p> <p>public void RemoveSegment(Path path, Segment segment)</p> <p>{</p> <p> using (var uow = this.context.CreateUnitOfWork())</p> <p> {</p> <p> uow.Attach(path);</p> <p> path.Segments.Remove(segment);</p> <p> }</p> <p>}</p> <p> </p> <p> </p> <p> <p> <p><span style="font-size: x-small;"> If I understood you well, that's what you were proposing (so far everything seems to work here but I haven't tried any complex cases like cascading deletes and so on). This method gets called from the ICommand that is binded to the ViewModel (instead of doing path.Segments.Remove directly, I call that). I think we can live with something like this for our collections until there's a better option in the future (it is not so tidy after all :)). Either way, I'll try to look at the ConnectionStrategy and the Winforms sample. I'm pretty new to Lightspeed, so I want to make sure I get things right (and this is the third time I change the data layer, first custom SPs, next nHibernate, now Lightspeed, so I just want to make sure I don't redo it a forth time). Regards, Vicente |
|
|
Sight, code appeared horrible, something like this (no tabs):
public void RemoveSegment(Path path, Segment segment)
{ using (var uow = this .context.CreateUnitOfWork())
{ uow.Attach(path); path.Segments.Remove(segment); } }
|
|