4

In entity framework 6 there are multiple way of adding / removing entities, for example for adding entities, we can use:-

b.Students.Add(student);
db.SaveChanges();

OR

db.Entry(student).State = EntityState.Added;
db.SaveChanges();

and similarly when Deleting object:-

db.Entry(studentToDelete).State = EntityState.Deleted;
db.SaveChanges();

OR

db.Remove(StudentToDelete)
db.SaveChanges();

I did not find much resources that talks about the differences , and most of the online tutorials mention both approaches as if they are the same. but i have read a reply on an article link is that using dbset.Add set the status for the entity and all its related entities/collections to added, while using EntityState.Added will adds also all the related entities/collections to the context but leaves them as unmodified, and same thing applies for dbset.Remove & EntityState.Deleted

so are these differences correct ?

Edit

As i understand that graph operation means that both the parent and child got deleted/added , if the parent is marked for deletion or for addition. so i did these two tests :-

using (var db = new TestContext())
{
    var a = new Department { DepartmentName = "Shipping" };
    var b = new Employee { FirstName = "Bob", LastName = "Dodds", Department = a };
    db.Entry(b).State = EntityState.Added;
    db.SaveChanges();
}



using (var db = new TestContext())
{
    var a2 = new Department { DepartmentName = "Production" };
    var b2 = new Employee { FirstName = "Sarah", LastName = "Gomez", Department = a2 };
    db.Employees.Add(b2);
    db.SaveChanges();
}

where both have added the dept & the employee. so can you adivce on this please?

Community
  • 1
  • 1
John John
  • 1
  • 72
  • 238
  • 501

1 Answers1

1

From Lerman & Miller's DbContext book (p. 80):

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

Which is:

If the entity is not tracked by the context, it will start being tracked by the context in the Added state. Both DbSet.Add and setting the State to Added are graph operations— meaning that any other entities that are not being tracked by the context and are reachable from the root entity will also be marked as Added. If the entity (the root entity - my addiditon) is already tracked by the context, it will be moved to the Added state.

Note that this is incorrectly answered in the question you refer to. The book was written with EF 4.3 in mind, and it doesn't mention any breaking change since EF 4.1 when DbContext was introduced.

Setting an entity's state to deleted (either through DbSet.Remove() or by setting Entry(entity).State to Deleted) is not a graph operation. It only affects the entity's state, not the entities in its object graph.

The latter is true for any entity state except Added.

An exception to this rule is when cascaded delete is configured, both in the database and in the EF model. In a many-to-many association with a hidden junction table, cascaded delete is the default, so junction records are always deleted when a root entity is marked for delete (either by setting its state to Deleted or by removing it from its DbSet).

For instance, let A and B have a many-to-many association. The junction table AB is only in the database, not in the class model. If you fetch an A from the database (without Include()-ing its Bs) and delete it, the A is deleted and al of its AB records, but no Bs are deleted.

When in a one-to-many association cascaded delete is configured the 'many' entities will be deleted when a '1' entity is deleted. If A and B have a one-to-many association, deleting an A will also delete its Bs.

Gert Arnold
  • 105,341
  • 31
  • 202
  • 291
  • I think both "DbSet.Remove()" & "Entry(entity).State to Deleted" are graph operations. because let say i retrieve an object from the database using .Include as follow "var test = context.Users.Include(a=>a.Account).SingleOrDefault(a=>a.ID = 123); ", then i delete the test var by either using DbSet.Remove() or Entry(ntiity).Sate . then both will remove the Users object and also the many to many table rows (assuming that the relation between User & Account is many to many) ,, – John John Jul 25 '15 at 00:35
  • 1
    I added a bit to my answer according to your correct comment. I'm not sure how your last edit changes your question. – Gert Arnold Jul 25 '15 at 19:30
  • now i am not using Cascade on delete ,, so seems to me both approaches are the same. your last reply is saying that the exception is when using Cascade delete .. but in my case i did not use cascade on delete.. so according to my above 2 tests both .ADD & setting the entity state as Added were able to add the Department & the Employee objects .. so they achieve the same outcome and both are graph operation ? can you adivce ? – John John Jul 25 '15 at 21:04
  • 1
    Cascaded delete is not about adding, it's about marking an entity as `Deleted` by any of the two methods available. I'm afraid I can't quite follow you. – Gert Arnold Jul 25 '15 at 21:17
  • yes i know this , but my original question was about ADD() & Remove() so that why i refer to deleting object.now you mentioned that both the Add() & "setting the entity as Added" are not a graph operations. But from my 2 tests i was able to add the related Department when i explicitly add the Employee ,, so in this case seems they are similar ... and both methods will add the related entities/collections , and if this is not true then the Department object in my test should not have been added when i add the Employee ? is this correct ? – John John Jul 25 '15 at 21:22
  • 1
    But I'm saying (quoting) that both `Add` operations *are* graph operations... (?) – Gert Arnold Jul 25 '15 at 21:27
  • so you mean that .ADD() & setting the model as Added are grpah operations? while .Remove() and setting an object as Deleted are not graph operations ? second question so in this case .ADD & setting an entity as added are the same ? – John John Jul 25 '15 at 21:30
  • Yes, three times. And not only in this case. – Gert Arnold Jul 25 '15 at 21:33
  • so now when using .Remove() and setting the object as Deleted, will do these; let say i have a m-to-m relation between Account & Users , and i wrote the following "context.Account.Remove(account)" then this operation will remove the Account and its related Users if i am loading the Users to the context using .Include()?. while it will raise an exception if i try to "context.Account.Remove(account)" while i am not loading the related Users and the account i am trying to remove have Users object related to it ? is this correct ? – John John Jul 25 '15 at 21:47
  • i think my original question was not clear from the begging (i apology). i was asking is if there are any differences between .ADD & setting the entity as Added. and another quesuion on the differences between .Remove and setting the object as Deleted. i was not asking about the differecnes between .Remove and .ADD. so using .ADD and setting the entity state as Added are similar . on the same line using .Remove is similar to setting the entity as Deleted .. – John John Jul 25 '15 at 21:52
  • from my own test your A,B,AB examples are not 100% accurate. because if you write the following "var test = context.A.Include(r=>r.B).FirstOrdefault()" and you remove test variable then this will delete A and AB records,, but B will never got deleted. while and if i do not use .Include() as follow var test = context.A.FirstOrdefault()" and there are AB entities that are referencing A then my delete operation will raise an exception ... – John John Jul 25 '15 at 22:00
  • also i one to many relation if i remove the parent and i am loading the child navigation property the FK will be set to null , but loading the child navigation property such as "var test = context.A.Include(r=>r.B).firstof defualt()" will never delete B it will only set its FK to null, and if the FK is required then an exception will be raised.. – John John Jul 25 '15 at 22:02
  • Last addition. We're drifting away from your original question which I answered the way you intended to ask it. – Gert Arnold Jul 25 '15 at 22:06
  • yes this is true but your last edit is not accurate 100% based on my tests . so i can not set it as answered , so other will not get confused.. as B will never get deleted even if you .Include()ing it. so either the AB will be removed (m-to-m) situation or the B.AID FK will set to null (one-to-many) ,, but B never gor removed if i remove A.. – John John Jul 25 '15 at 22:10