Delete orphans support
Entity Framework should support automatic deletion of orphan records, the way "all-delete-orphan" works in NHibernate.
If I have a one-to-many relationship between Orders and OrderLines, and code inside the Order class calls OrderLines.Remove(orderLine), this should cause the order line to be deleted when I save changes. Currently, EF attempts to set the order line's OrderID to NULL. If the OrderID column is non-nullable, the update fails with a constraint violation error.
I found this forum post in which Daniel Simmons from Microsoft says EF doesn't support this: http://social.msdn.microsoft.com/forums/en-us/adodotnetentityframework/thread/CB9C1C4A-DF12-44E4-B00A-417C80BF5453
This is an important feature for an ORM, since it's difficult to cleanly work around it. One workaround is to add a call to context.OrderLines.Delete(orderLine) immediately when an order line is removed in memory. But the Order aggregate should be able to manage its order lines without taking a direct dependency on the ORM.
This feature is currently planned to be included in EF7.
I would go even further. In some cases an exclusive N:1 relation could exists. Since it's not 1:N and there's no meaning of talking about orphans, but if the parent is deleted and it holds such an exclusive N:1, then the N:1 should be also deleted.
The delete orphan was a feature in NHibernate before a decade, so I'm glad it finally makes to EF7!
"How basic ORM functionality gets prioritized above the 40 or so people who seem to want store app or mobile support (which you seem to have started)?"
Because it is basic ORM functionality and it should have been there from day 1.
I find that most of the people using EF actually could have made it with Linq-To-SQL only. However one shouldn't forget that EF is an ORM, it is supposed to really shine in OO programs, and DDD designs.
As such it is very surprising that this feature hasn't been there for so long. It is the basis for anyone creating an aggregate.
I came up with a clean work around a few months ago that keeps the domain model intact and persistence ignorant, I'll post it. But it is positive that the EF team finally pays more attention to DDD scenarios...
Nathan Cooper commented
How basic ORM functionality gets prioritized above the 40 or so people who seem to want store app or mobile support (which you seem to have started)? I would rename this from "Delete orphans support", because that suggests that orphan creation it's self is acceptable default behavior for an ORM.
Raffaele Garofalo commented
This is absolutely a shame, we work with multiple ORMs like NHibernate and they simply handle the Remove children object by deleting the object from the Database. How is possible that we are working with version 6 of EF and we still have this basics ORM issues? Shouldn't be version 0.6?
Jordan M commented
I have already commented on this once, so apologies for the spam - but every time I come back to this it seems worse.
I know there is plenty of code around where people are accessing their DbContext directly in the service or UI layers of their applications where this wouldn't be so much of an issue.
But.... if you have properly wrapped Entity Framework up in your data access layer this gets really annoying. It means you end up having to create a DAO for every entity that you might possibly need to delete. Normally I would only have DAOs for the main entities in my application, and manage their children via the collections hanging off them.
Please fix this.
Jordan M commented
This is a must have feature. I cannot believe that Entity Framework hasn't got this, This gives NHibernate a simple but significant advantage.
This is an ORM - the O stands for "Object" and one of the *main* benefits of using an ORM is that as much as possible it should allow you to do object oriented programming. Automatically syncing trees of objects to the database is a massive part of that.
If a collection of an entities makes up part of its parent, if one of those objects is removed from its parents collection then it should be deleted from the database. You shouldn't have to then go and delete it again using a call to your data access layer.
I agree with Vir, I'll move on NHibernate just because of this. My project uses DDD and I don't want to inject IStuffRepositories in my domain objects just to remove something from the collection. To me the purpose of an ORM if actually to avoid to have to do this kind of things.
Lack of this functionality in Entity Framework makes that whole ORM just useless in real life cases where POCO objects should not be aware of persistence layer. Just simple property-level attribute like [DeleteOnRemove] would do the trick, better yet second method like .Delete for collection that will actualy delete object as oposite to current .Remove method which could be left unchanged.
could be an interesting feature...
Kieron Dye commented
Unfortunately the identifying relationship is not always possible. From my understanding to make the identifying relationship work you have to make the foreign key part of the primary key. We have a scenario where the child has derived types. The derived type tables have the child key but do not have the parent key and so modifying the child to use the parent key in its own primary key breaks the inheritance. Presumably this would also be a problem if the child had children.
Graeme Miller commented
This can be handled by making the OrderLine key an identifying relationship http://msdn.microsoft.com/en-us/library/ee373856.aspx.
If the orderline key is a composite and contains the parent key (OrderId) you can use remove on the collection and it works. However it is far from clear and it should be handled as an option.
Daniel Simmons has an explanation here
(see scenario #1).
I do not see how the current implementation is actually better than deleting the orphaned objects though.
And Thank You Richard for an awesome workaround! Love it.
Jin Huihui commented
I also think this is very important, Linq to Sql can do this, why can't EF do this. I strongly suggest this can be addressed by EF5
Richard Beier commented
I was able to work around this by putting the following in my OrderRepository, before the call to context.SaveChanges():
var orphans = _context.ObjectStateManager.GetObjectStateEntries(EntityState.Modified)
.Select(x => x.Entity)
.Where(x => x.OrderID == null)
foreach ( var orphan in orphans )
But I still think there should be an option for this in the mapping :).