Confuse articles and documentation about the differences (if any) between System.Data.EntityState.Add & DbSet.Add

I am working on a C # ASP.NET MVC 5 web application with EF 5. Mapping my database tables using EF generates the DbContext and .edmx . Today I read an excellent article on creating common DAL classes , but I settled on the following sentence:

Note that using the Entry method to change the state of an object will only affect the actual object that you pass to the method. This will not be a cascade through the graph and setting the status of all related objects, unlike the DbSet.Add method.

This contradicts what is mentioned in these questions:

In all of the above questions, answers, all users noted that using System.Data.EntityState.Added exactly matches using DbSet.Add . But in the first article, I argued that using System.Data.EntityState.Added would not cascade through the graph.

Based on my test, I conclude that using System.Data.EntityState.Added will be cascaded through the graph, as is the case with DbSet.Add . Is the article wrong or is it my test and Q&A?

+7
entity-framework-5 entity-framework dbcontext
source share
2 answers

These methods are the same that you can test by regular testing, or, if you want to be absolutely sure, by studying the EF 6 code.

This calls the InternalSet<T>.Add(object) method.

  1. DbEntityEntry<T>.State property ( http://entityframework.codeplex.com/SourceControl/latest#src/EntityFramework/Infrastructure/DbEntityEntry.cs )

     public EntityState State { get { return _internalEntityEntry.State; } set { _internalEntityEntry.State = value; } } 

Where _internalEntityEntry is of type InternalEntityEntry .

InternalEntityEntry.State property ( http://entityframework.codeplex.com/SourceControl/latest#src/EntityFramework/Internal/EntityEntries/InternalEntityEntry.cs )

  public virtual EntityState State { get { return IsDetached ? EntityState.Detached : _stateEntry.State; } set { if (!IsDetached) { if (_stateEntry.State == EntityState.Modified && value == EntityState.Unchanged) { // Special case modified to unchanged to be "reject changes" even // ChangeState will do "accept changes". This keeps the behavior consistent with // setting modified to false at the property level (once that is supported). CurrentValues.SetValues(OriginalValues); } _stateEntry.ChangeState(value); } else { switch (value) { case EntityState.Added: _internalContext.Set(_entityType).InternalSet.Add(_entity); break; case EntityState.Unchanged: _internalContext.Set(_entityType).InternalSet.Attach(_entity); break; case EntityState.Modified: case EntityState.Deleted: _internalContext.Set(_entityType).InternalSet.Attach(_entity); _stateEntry = _internalContext.GetStateEntry(_entity); Debug.Assert(_stateEntry != null, "_stateEntry should not be null after Attach."); _stateEntry.ChangeState(value); break; } } } } 

You see that if the object is disconnected (your case) and the state is added, the same InternalSet<T>.Add(object) called.

Regarding verification by testing:

 using (var ctx = new TestDBEntities()) { // just some entity, details does not matter var code = new Code(); // another entity var error = new Error(); // Code has a collection of Errors code.Errors.Add(error); var codeEntry = ctx.Entry(code); // modify code entry and mark as added codeEntry.State = EntityState.Added; // note we did not do anything with Error var errorEntry = ctx.Entry(error); // but it is marked as Added too, because when marking Code as Added - // navigation properties were also explored and attached, just like when // you do DbSet.Add Debug.Assert(errorEntry.State == EntityState.Added); } 
+5
source share

I do not know the author of this blog. I know the authors of the book DbContext though (although not personally). They know EF inside out. Therefore, when on page 80 they write

Calling DbSet.Add and setting State to Added both achieve exactly the same.

I know what I'm doing. They do the same thing:

If an object is not tracked by context, it will begin to be tracked by the context in the Added state. Both DbSet.Add and the State setting in Added are DbSet.Add operations - which means that any other objects that are not tracked by the context and inaccessible from the root entity will also be marked as Added .

I also know from experience that it works that way. But to eliminate any doubts in the EF source code, both DbSet.Add and DbEntityEntry.State (when installing Added ) arrive at the same point in the ObjectContext , which does the actual work:

 public virtual void AddObject(string entitySetName, object entity) 

This is a feature that continues to mislead developers who start working with EF, as can be seen from the large number of questions in StackOverflow that ask something like "how are my objects duplicated?". Julia Lerman wrote the entire blog , explaining why this could happen.

This ongoing misconception made the EF team decide to change this behavior in EF7.

Perhaps the blog writer you are linking to was one of those misguided developers.

+5
source share

All Articles