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).
Related
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
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).
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.
This question already has answers here:
Entity Framework: Ignore Columns
(7 answers)
Closed 9 years ago.
I have auto generated model from a database in Entity Framework version 4.1.10331.0.
I want to ignore a column from an entity without using the Fluent Api and without changing the ObjectContext into DbContext (and of course without deleting the column from the SQL table) and without marking the property generated in the model with the attribute NotMapped, because whenever I update my context in the model that column will reappear.
Can someone please help me in this case?
Thanks and best regards Ben
I don't see the problem updating your EF each time you regenerate the model, but I can propose 2 solutions:
Create a View that contains the columns you need, then generated it in EF.
Create another class derived from you entity that will show the data you want. This class will be your "application Entity" (As you know additional management should be considered here)
EF database-first is very under-tooled in many places. Similarily to your problem, if you generate a model from DB and rename a column in CodeSpace (so column users.col_chr_UsrName is just User.Name), you also would lose it when regenerating the model.
If I remember well, in EF3, EF4 and even in EF5 there is no way to preserve them. If you just "update" the model, they have a chance of surviving, but regenerating never preserves anything.
You can try to create a script or set of scripts that you will run after regenerating, and those scripts may seek and apply fixes to the generated model. But thats, well, "workaround" (literally, work and around), not a real solution.
Another thing, with more work, is to define Views or StoredProcedures (or custom table mappings) that will handle the projection, but they sometimes also may get hairy after regenerating (especially custom table maping which will always evaporate).
You can actually ignore the unwanted columns and prepare a set of light LINQ wrappers/accessors that will perform the projection, and put them in some static MyTables class and use that class instead of RawTable. That will work and may be usable, but is not again pretty.
IMHO, the best approach is to use either a script that will fix the model afterwards, or live with the unwanted columns, or .. not use the autogeneration from within the designer. Try to find another, more smart, generator.
Im making .net application as a project on my Univeristy and I have a problem with Self-Tracking Entity Sets. I'm selecting an record, passing it through a wcf service, make some changes and pass it to the server again. There I want to compare what was changed, so Im selecting the same record from context once a again (this is the record with old values) and comparing. Then, after comparing I want to call ApplyChanges on context with entity passed via the service, and Im getting an error:
AcceptChanges cannot continue because the object's key values conflict with another object in the ObjectStateManager. Make sure that the key values are unique before calling AcceptChanges.
I suppose it's because loading the same entity twice (before changes and after changes to compare). Is there any better way to compare changes(I need to make change history in another db table)? And wouldnt this error also apear if two clients gets the same record, and the first one changes it and wants to store into db? Im using .net 4.0.
This is not supposed way to use STEs. STEs wrap a lot of logic but they are not able to handle duplicate keys attached to context.
So I can imagine two solutions:
Do not load entity for comparing changes. Instead apply changes from your STE and handle SavingChanges event (or override SaveChanges on context) to get applied changes from ObjectStateManager.
Try to detach loaded entity before you apply changes from STE.