What is the difference between SaveOptions.AcceptAllChangesAfterSave and SaveOptions.DetectChangesBeforeSave in Entity Framework? When to use SaveOptions.None?
These options are provided in objectContext.SaveChanges(SaveOptions options).
Can any of these option, in any way, be used to reverse the changes made by objectContext.SaveChanges()?
They're two entirely different things. Note how SaveOptions has the Flags attribute: this indicates you can combine multiple flags, in this case to make SaveOptions.AcceptAllChangesAfterSave | SaveOptions.DetectChangesBeforeSave.
And if you're wondering about something like SaveOptions.None | SaveOptions.AcceptAllChangesAfterSave, then keep in mind that SaveOptions.None is the zero value, so this is just a long-winded way of writing SaveOptions.AcceptAllChangesAfterSave.
So you use SaveOptions.None when you want neither SaveOptions.AcceptAllChangesAfterSave nor SaveOptions.DetectChangesBeforeSave.
Can any of these option, in any way, be used to reverse the changes made by objectContext.SaveChanges()?
In the context? If you don't include SaveOptions.AcceptAllChangesAfterSave, then all changes will be preserved locally as unsaved. All added entities will remain in "added" state, all modified entities will remain in "modified" state, all deleted entities will still be available by explicitly requesting your context's deleted entities. Attempting to save again will likely fail, as the database has already been updated. You can then use the regular methods for reverting unsaved changes, but it requires a lot of manual work on your part, it requires manually looking up the original values of all properties and restoring that value. A detailed example of how to do this is, I think, beyond the scope of this question, but see Undo changes in entity framework entities.
In the database? This requires even more work on your part, and may not even be possible at all: once an entity with a server-generated column (e.g. auto-increment key, or row version field), it is generally impossible to restore it with those exact same values it originally had.
Related
I want to add or update entities in EFCore 5.
Currently I am using Context.Find to determine whether to update or to add. I want this logic to be very performant and I see that much of cpu time is spent on the Find method (database call). I would like to move the logic of determining add or update to be evaluated by the database once SaveChanges is called. I would like to be able to specify which properties have changed and which should be used by the possibly already existing entity (or initialized with default values). I guess this can be done with Context.Entry(...).Property(...).IsModified.
I still want to be able to use the DbContext change tracking, multiple add or update calls should be combined, custom queries are not possible.
Primary keys are defined and not auto generated.
Is there any way to achieve this with EntityFrameworkCore?
There is/was IDbSetExtensions.AddOrUpdate but I think it is not available in current release? Also I think it is not recommended to use outside of migrations/seeding. Moreover I think it does not work as I guess it would overwrite existing values with default values of the changed entity (unchanged values should not be overwritten to default values, I am not recreating the complete entity on upsert, thats why I would like to specify which properties have changed).
Im running a process that will affect a lot of records within a database for a user. I only want to apply all of the changes or none of them depending on the result of all of the changes. (e.g if one of the sub processes fail then no changes overall should take place). I also want to save notifications to the database to alert users of the outcome of the processes (e.g if a sub process fails then a notification is raised to let the user know that no changes were made due to reason x).
The best way I can think to do this is to detach all of the entries within the change tracker as they are added, then create notifications if something has succeeded or failed and save changes, then when it comes to applying all the changes I can iterate though the change tracker and reset the Entity State and save changes once more.
The issue i'm facing with this approach is that when it comes to reset the Entity State, I don't know whether the entity is Added or Modified. I could implement my own change tracker to store the previous state of the entity but it would make EF's change tracker redundant.
I could also only add all of the entity's right when I come to save them but that would require passing many objects down a chain link of nested methods right until the end.
Does anyone have any better suggestions or is it standard practice to use one of the mentioned hacks for this problem?
It sounds like you are trying to implement the Unit of Work pattern. The DbContext of EntityFramework makes this fairly easy to use, as the DbContext its self is the unit of work.
Just instantiate a new context and make the changes you need to it. You can pass the context around to any functions that make their changes. Once the "logical unit" operations are complete, call SaveChanges. As long as the individual methods do not call SaveChanges, you can compose them together in to a single unit, committed once the entire logical operation as finished. Everything will be committed atomically, within a single transaction. The data won't be left in an inconsistent state.
You told about transactions. Using Transactions or SaveChanges(false) and AcceptAllChanges()?
also you can implement versions of data in DB. as for me it will be more ease and correct way (you must always only insert data and never update. 1-to-many). in this case you can simply delete last records or mark them as unactive
To improve performance of Entity Framework application there is suggestion to set AutoDetectChangesEnabled = false.
Following tutorial on MSDN states :
An alternative to disabling and re-enabling is to leave automatic detection of changes turned off at all times and either call context.ChangeTracker.DetectChanges explicitly or use change tracking proxies diligently. Both of these options are advanced and can easily introduce subtle bugs into your application so use them with care.
https://msdn.microsoft.com/en-us/data/jj556205.aspx
The last part is what concerns me.
Can you give some most common problems that could happen with this optimization approach?
What are good measures to prevent from unintended consequences?
My experience with ChangeTracking is: You should leave it on, if possible at all.
For me, I had two subtle problems with ChangeTracking (For us ChangeTracking was disabled globally).
Firstly, when adding/removing entities, you WILL have to set the entity state manually, because usually ChangeTracking sets the entity state to modified/added (you have to set deleted manually anyways), and this for every single entity (also those in navigation properties). Also, you have to set FK's manually in many cases.
Secondly, when EDITING related entities, you will have to call ChangeTracking or set the related entities manually - which in my experience, is quite complicated. This is because EF keeps an snapshot of related entities in its context graph, and checks this for referential integrity, not the actual related entry in your DbSet entries.
For further reference, I found an interesting article on ChangeTracking by one EF developer, Arthur Vickers.
Part 1
Part 2
Part 3 - possibly most interesting to you
Part 4
Part 5
Always make sure that you haven't accidentally disabled the EntityFramework Proxy Types. I had such problem and spent a plenty of time fixing it. EF's changes tracking is somehow related to this and when I disabled the changes tracking it also disabled proxy types.
EF uses it's own proxy types that mimic your types to apply it's own Lazy Loading to them. When proxy types and hence lazy loading are disabled, EF just stops loading inner entities. So if you will have a MyClass with a property myClass.MyAnotherClass it will be always null.
Personally I would recommend to leave the changes tracking enabled if you're not proficient with it. I tried to work with it being disabled, spent a few days trying to make it working and then turned it back to enabled state. It definitely affects the performance, but it's pretty intelligent and gives you a lot of advantages in exchange of that.
I have a method that will Remove a set of entities.
I have a method that will AddOrUpdate a set of entities.
These methods are independently useful, but they have issues working together in entity framework.
The problem is that after removing a set of entities, for example (A,B,C,D), subsequent queries that resolve to one or more of those records always return cached garbage copies whose property values were nulled during the removal process. An intermediate DbContext.SaveChanges solves the issue, but introduces additional overhead and leaves the operation in a half-complete state, so it would also have to be wrapped in another transaction.
What's the best way to handle this.
Should I avoid an API that has Remove and Add/Update operations altogether, instead opting for an up-front hybrid operation that determines which ones are actually being removed and which ones are sticking around to be updated? or
Should I keep the two useful methods and just wrap the two steps in a transaction scope, so that I can save changes to the context immediately after the remove, allowing subsequent adds/updates to properly reflect their removal, while still have the ability to commit or rollback at the end (e.g. if the new permissions can/cannot be set)?
I don't want use lower-level operations such as turning off tracking or attaching/detaching entities.
Suppose the entities are permissions. Business logic dictates that I should use a logical two-step process to reset a user's permissions by first deleting any that I have permission to delete, followed immediately by trying to add/update any new permissions that I am allowed to assign.
When approaching this with two separate steps, I run into the problem as follows. The first problem I encounter is that immediately after removing a set of permission entities like (A,B,C,D), entity framework mangles the object properties, setting many of them to null (presumably to sever foreign key relationships). The problem is that because the entities still exist in the database, when trying to "add or update" a permission which still has a record in the database but has been removed in the context, EF always returns the cached/garbage copy of it. So although I've removed the entity... I can't actually determine, within that same context, whether I need to re-attach/update it or add a new entity outright. In other words, the framework returns an entity as though it exists (because it does still exist in the database) in spite of it being flagged as removed, but that entity object has garbage/null data, so that I can't even tell at that point whether it's safe to add a new one or I should try to "un-remove" the existing one.
It seems to me that such a remove/add-or-update pattern is simply not good for this kind of entity framework (or even ORMs in general). Instead, I'd have to determine, in a single up-front operation, whether any of the new permissions already exist, so I can selectively delete the ones that are going away, while updating the ones that are just being reassigned (a new access level, for example).
Sorry about the title - hopefully the question will make clear what I want to know, then maybe someone can suggest a better title and I'll edit it!
We have a domain model. Part of this model is a collection of "Assets" that the user currently has. The user can then create "Actions" that are possible future changes to the state of these "Assets". At present, these actions have an "Apply" method and a reference to their associated "Asset". This "Apply" method makes a modification to the "Asset" and returns it.
At various points in the code, we need to pull back a list of assets with any future dated actions applied. However, we often need to do this within the scope of an NHibernate transaction and therefore when the transaction is committed the changes to the "Asset" will be saved as well - but we don't want them to be.
We've been through various ways of doing this
Cloning a version of the "Asset" (so that it is disconnected from Nhibernate) and then applying the "Action" and returning this cloned copy.
Actually using Nhibernate to disconnect the object before returning it
Obviously these each have various (massive!) downsides.
Any ideas? Let me know if this question requires further explanation and what on earth I should change the title to!
It's been a while since I had any NHibernate fun, but could you retrieve the Assets using a second NHibernate session? Changes made to the Asset will then not be saved when the transaction on the first session commits.
You could manage this with NHibernate using ISession.Evict(obj) or similar techniques, but honestly it sounds like you're missing a domain concept. I would model this as:
var asset = FetchAsset();
var proposedAsset = asset.ApplyActionsToClone();
The proposedAsset would be a clone of the original asset with the actions applied to it. This cloned object would be disconnected from NHibernate and therefore not persisted when the Unit of Work commits. If applying the actions is expensive, you could even do the following:
asset.ApplyProposedChanges(proposedAsset);
I have been working around a similar problem where performance was also an issue, thus it was not possible to re-load the aggregate using a secondary (perhaps stateless) session. And because the entities that needed to be changed "temporarily" where very complex, I could not easily clone them.
What I ended up with was "manually" rolling back the changes to what would be the assets in your case. It turned out to work well. We stored each action applied to the entity as a list of events (in memory that is). After use the events could be re-read and each change could be rolled back by a counter-action.
If it's only a small variety of actions that can be applied, I would say it's easily manageable to create a counter-action for each, or else it might be possible to create a more generic mechanism.
We had only four actions, so we went for the manual edition.
Sounds like you want to use a Unit of Work wrapper, so you can commit or revert changes as needed.