As far as I understand, if I change a state of an entry in context like that:
context.Entry(doc).State = EntityState.Added;
the whole object graph behind doc will be set to EntityState.Added. That is how this mechanism described here:
Note that for all of these examples if the entity being added has
references to other entities that are not yet tracked then these new
entities will also be added to the context and will be inserted into
the database the next time that SaveChanges is called.
In my situation this behaviour is undesirable. When I receive doc entity, it's relations are already in database (were added in different context) and adding them again will cause an error. I need to add doc to a database with all references, but don't try to add other objects in graph.
Of course, I can iterate through all graph and set state explicitly, but does an easier way exist?
In Entity Framework Core, the behavior changed, calling:
context.Entry(asset).State = EntityState.Added;
will affect only the entity and not the related ones.
👉 I know the question is for Entity Framework classic (not Core), but surely will be more people using EF Core reaching here (like me) 😉
You may have a look at GraphDiff
According to this dedicated blog entry, it seems to fit your needs :
Say you have a Company which has many Contacts. A contact is not
defined on its own and is a One-To-Many (with required parent) record
of a Company. i.e. The company is the Aggregate Root. Assume you have
a detached Company graph with its Contacts attached and want to
reflect the state of this graph in the database.
At present using the Entity Framework you will need to perform the
updates of the contacts manually, check if each contact is new and
add, check if updated and edit, check if removed then delete it from
the database. Once you have to do this for a few different aggregates
in a large system you start to realize there must be a better, more
generic way.
Well good news is that after a few refactorings I've found a nice solution to this problem.
Related
We are leading into some issues with ef-core on sql databases in a web-api when trying to update complexe objects on the database provided by a client.
A detailed example: When receiving an object "Blog" with 1-n "Posts" from an client and trying to update this existing object on database, should we:
Make sure the primary keys are set and just use
dbContext.Update(blogFromClient)
Load and track the blog while
including the posts from database, then patch the changes from
client onto this object and use SaveChanges()
When using approach (1) we got issues with:
Existing posts for the existing blog on database are not deleted
when the client does not post them any more, needing to manually
figure them out and delete them
Getting tracking issues ("is already been tracked") if
dependencies of the blog (for example an "User" as "Creator") are
already in ChangeTracker
Cannot unit test our business logic without using a real DbContext
while using a repository pattern (tracking errors do just not exist)
While using a real DbContext with InMemoryDatabase for tests cannot rely on things like foreign-key exceptions or computed
columns
when using approach (2):
we can easily manage updated relations and keep an easy track of
the object
lead into performance penalty because of loading the
object which we do not really need
need to map many manual things
as tools like AutoMapper cannot be used to automaticlly map
objects with n-n relations while keeping a correct track by ef core (getting some primary key errors, as some objects are deleted from lists and are added again with the same primary
key, which is not allowed as the primary key cannot be set on insert)
n-n relations can be easily damaged by this as on database
there could be n-n blog to post, while the post in blog does hold
the same relation to its posts. if only one relation is (blog to
post, but not post to blog - which is the same in sql) is posted and
the other part is deleted from list, ef core will track this entry
as "deleted".
in vanilla SQL we would manage this by
deleting all existing relations for the blog to posts
updating the post itself
creating all new relations
in ef core we cannot write such statements like deleting of bulk relations without loading them before and then keeping detailed track on each relation.
Is there any best practice, how to handle an update of complexe objects with deep relations while getting the "new" data from a client?
The correct approach is #2: "Load and track the blog while including the posts from database, then patch the changes from client onto this object and use SaveChanges()".
As to your concerns:
lead into performance penalty because of loading the object which we do not really need
You are incorrect in assuming you don't need this. You do in fact need this because you absolutely shouldn't be posting every single property on every single entity and related entity, including things that should not be be changed like audit props and such. If you don't post every property, then you will end up nulling stuff out when you save. As such, the only correct path is to always load the full dataset from the database and then modify that via what was posted. Doing it any other way will cause problems and is totally and completely 100% wrong.
need to map many manual things as tools like AutoMapper cannot be used to automaticlly map objects with n-n relations while keeping a correct track by ef core
What you're describing here is a limitation of any automatic mapping. In order to map entity to entity in collections, the tool would have to somehow know what identifies each entity uniquely. That's usually going to be a PK, of course, but AutoMapper doesn't (and shouldn't) make assumptions about that. Instead, the default and naive behavior is to simply replace the collection on the destination with the collection on the source. To EF, though, that looks like you're deleting everything in the collection and then adding new items to the collection, which is the source of your issue.
There's two paths forward. First, you can simply ignore the collection props on the source, and then manually map these. You can still use AutoMapper for the mapping, but you'd simply need to iterate over each item in the collection individually matching it with the appropriate item that should map to it, based on your knowledge of what identifies the entity (i.e. the part AutoMapper doesn't know).
Second, there's actually an additional library for AutoMapper to make this easier: AutoMapper.Collection. The entire point of this library is to provide the ability to tell AutoMapper how to identify your entities, so that it can then map collections correctly. If you utilize this library and add the additional necessary configuration, then you can map your entities as normal without worrying about collections getting messed up.
We are using entity framework code first to save reports to SQL database, many of the objects have many to many relations so the data is split into different tables.
In order to prevent duplication of data we first check if a certain object is already saved and later on we add the relation to the database.
For example have object Person that can have many countries, and object Country that can hold multiple Person object.
During the beginning of the save flow we query the database for existing countries and update them in the Person object if they exist, or create them if they don't.
This flow worked fine while we have only one saving process at the same time but now we got requirement to support it many times simultaneously and my worry is that one thread will add a new country right after other thread will check existing countries.
I was wondering what good practices are there to solve this problem with minimal impact on performance.
Thanks!
It doesn't sound like your fully leveraging the capabilities of your chosen ORM. Relationships are represented in your returned entities if you are using the library according to it's documentation. So updating a single entity's many-to-many relationship would update for all other related entities so long as the EntityID remains the same.
If you still are having trouble trusting the integrity of this relationship, I would suggest using the bulk-update feature of entity framework
I am using Entity Framework 6 where, for performance reasons, I load my entities into my DbContext up front and then use them locally. Up to now, all changes to the database have gone through the DbContext so my local entities and the database have been in sync. However, I now have to call a Stored Procedure on the database, which has the side effects of making changes to tables (outside of the DbContext) that need to be reflected in my entities. By changes, I mean it is adding new records and deleting / updating existing records.
I do not want to dispose of my DbContext and create a new one, as some of the entity instances are wrapped within ViewModel classes. So, deleting the DbContext in this way would lead to major problems in the UI.
It is my understanding that simply calling Load() on all my DbSets of the DbContext will just replace the existing instances. So, any objects using the old entities instances won't work.
So, I thought I could use the Reload method like:
context.Entry(entity).Reload();
which would update my local entities, but I can only do this for the entities that the DbContext already knows about. It doesn't cover any NEW entities or DELETED entities that were created / deleted as a result of the Stored Procedure executing.
So, I am looking for a way to:
Load, from the database, entities that are NEW to my DbContext
Reload existing entities in my DbContext
Remove any deleted entities from my DbContext
Here is the official documentation for Entity Framework.
Starting from the analysis of your database situation, it suggests smart and quick ways to obtain what you want, detailing when necessary data-read strategies (like eager or lazy loading) or providing tutorials to correctly use code generation and the Wizard GUI.
http://www.entityframeworktutorial.net/choosing-development-approach-with-entity-framework.aspx
Here some more detailed info and tutorial on data-read strategies:
https://www.c-sharpcorner.com/article/eager-loading-lazy-loading-and-explicit-loading-in-entity-framework/
As I already told you in comments, I would suggest a database-first approach and with lazy loading to avoid uncontrolled data behaviours (or reloading the whole db when running a stored procedure).
Talking about the SP, it can simply be mapped through the Wizard that comes with Entity Framework and wrapped by a method.
Hope you will find these resources helpful!
In general EntityFramework can not aware on change in database and update dbcontext .there is no optimized or EntityFramework built-in solution for it.
I think you can use CDC in SqlServer, push change to your application and update your dbcontext. But it not acceptable solution for all business and senario
i am reading this topic on MSDN
can any one please explain me that what is difference between these two as mention
DetectChanges is use to detect the changes in DBContext and related Entities
and
ChangeTracking is also use to detect changes in Entity as mentioned in this link
please explain me the actual difference betweeen theese two.
So EF needs to detect changes you make to the context, like adding\modifying\removing entities. Entities might be plain POCO entities and so have no embedded behaviour to track changes to their properties. So EF should make a snapshot of the entities it receives from database and then compare this database snapshot with actual state of the context. Even more - EF should track relationships between objects in the context and keep them synchronized. All this is done by method called DetectChanges(). It is being called at various moments, most importantly when you call SaveChanges, but also when you add\remove\attach entities to the context and so on.
If you design your entity classes in a special way (all properties virtual, collections represented by ICollection etc) - you can use automatic change tracking. EF will create special proxy classes inherited from your entity classes and will use that to immediatly detect changes to your entity properties. Note that DetectChanges is still used in this case, exactly as described above. But it performs less work, since most of the changes are already detected right when they happened.
Summary: DetectChanges is a method to perform snapshot-based change detection (and more) and is a part of the group of ways used by Entity Framework to track (detect) changes to the context. Read more about DetectChanges here: http://blog.oneunicorn.com/2012/03/10/secrets-of-detectchanges-part-1-what-does-detectchanges-do/
I have an application which uses Entity Framework Code First. I am attempting to write my resource access layer. I have several objects which all have separate database tables and a lot of object relationships. Can someone point me to an up-to-date example of CRUD methods with related objects? Everything I have found uses an older version (I use DbContext, not ObjectContext, etc.) and I am having problems writing it myself.
For example, I am currently working on an object with a parent-child relationship with itself. I am attempting to write the Create method. If I use context.Objects.Add(newObject) then all the children objects also have their state changed to Added, which means that duplicate children are added. So I tried looping through all the children and attaching them to the context, but then any children that did not previously exist do not get added to the database and a DbUpdateException is thrown.
Is there a generic way I can attach all related entities and have their states be correct? Any help you can give me would be appreciated. Thanks!
Edit:
I tried explicitly loading the children using Load() and then adding the initial object. Unfortunately, it caused an exception because the parent comment had the child in its list of children but the parentID of the existing child had not yet been updated.
No there is no way to attach whole graph and let EF automatically set correct state - these problems didn't changed since ObjectContext API. You must always set state manually for each entity and relation or you must build the graph from attached entities. The only exception are Self tracking entities but they are not supported with DbContext API.