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
|
I read the forums and I don't think there is an answer for this one yet. I was wondering with the best practice and the expected behavour of calling our.SaveChanges(true) twice is in one unit of work. This is related to my original request I made a month ago about the item not saving correctly if I use Aggregates. I am finding that if I call SaveChanges and pass in true, that the second time, no updates are pushed to the database. I am looking for a recommendation as to how I should handle this condition and what happens when I pass in true. If I do not pass in true, will it still allow me to make more changes to the in memory objects and save the changes? Should I allow for calling save more than once? I ask this because I originally was just backing out of a commit by not calling save the second time if a condition was true, but I always wanted to save for this other condition. Insight would be greatly appreciated. Joe Feser |
|
|
Yes, you can call SaveChanges(false) -- or, equivalently, SaveChanges() -- many times during the course of a unit of work. By contrast, although it is possible to call SaveChanges(true) more than once in a UOW, a great deal care is required and it's usually clearer to use a new UOW. To see why, I need to briefly explain what role the UOW plays in entity saving. One of the jobs of the UOW is to track the list of entities that are managed by the UOW (and, among other things, therefore may need to be saved). When you load an entity from the database or add an entity to the UOW, it gets put on this list (known as the identity map). When you call SaveChanges, LightSpeed walks down the identity map looking for entities that need saving (inserting, updating or deleting) and does the business. So far so good. Now for that "true" parameter. The meaning of "reset=true" is "I want to clear my existing entity cache and start reloading fresh versions of entities from the database." Therefore, if the reset parameter to SaveChanges is true, after walking the identity map, LightSpeed clears the identity map. That means that the entities which were in the identity map are no longer in the identity map. So if you call SaveChanges again, then when LightSpeed walks the identity map, it doesn't encounter those entities, so they don't get checked for pending saves. So you should consider that after calling SaveChanges(true) all existing entity references are obsolete -- or at least that LightSpeed has forgotten about them. You can still refer to them, for example to get the ID under which a new entity was saved in order to reload it: but you must reload any entities that you want to carry on modifying. (Actually, I think you can just Attach the old entity back to the unit of work: but this kinda defeats the "I want to start reloading from the database" aspect of reset=true.) Therefore, in a situation where you want to carry on working with the entities you have, you should call SaveChanges (or, equivalently, SaveChanges(false)). If you pass in false (or omit the reset argument), then yes, it will still allow you to make more changes to the in-memory objects and save the changes, because the existing entity instances are still in the identity map. And you can call SaveChanges(false) as many times as you like without any problems. You should pass true to SaveChanges only if you are planning to start reloading fresh entity instances after you do so (specifically, if you want to be able to reload fresh entity instances but don't want to create a new UOW). Thinking about this we should probably improve the diagnostics in this situation, e.g. detaching the obsolete entities from the UOW. In the meantime, hopefully this gives you an idea of what is going on and why you are seeing the behaviour you see. |
|
|
This explains why I was never able to create a stripped down version of the "bug" that I thought a had a few weeks ago that I posted. The issue was I was saving many times with SaveChanges(true) because that is what I was calling with EFwithout an issue. By reading the docs, I thought that "resetting" meant that you mark the objects as unchanged so that if I did make additional changes, they would be detected. So is it safe to never use the true parameter? From your post, it appears that true should only be used if you want to "start over". I will go fix my code since I may have additional bugs out there. Thanks for explaining this. Joe |
|
|
Ah, what a mess, now I have two accounts. :) Thanks Ivan. Joe |
|
|
Absolutely, it is completely safe to never pass reset = true: in fact it is absolutely normal to do so. Your entities will be automatically marked as unmodified during the save, so that further changes will be detected. So it is usually best to call SaveChanges with no argument (which is equivalent to SaveChanges(false)). As you say, reset = true is required only if you want to "start over." We're sorry for the confusing nature of the documentation here, and will have a go at improving it. |
|
|
My saving issues have gone away. They were caused by double saving and passing in true. Thanks for everything. Joe |
|
|
Would be nice if, rather than a bool flag, you had specific methods for each option. i.e.
vs
|
|
|
Hi Jason, We don't normally like to add to our API where you have two things do the same thing, and we're unlikely to make a breaking API change for this. I'd recommend creating an extension method if you prefer your approach :-) I hope that helps, John-Daniel Trask |
|