Entity Framework Pitfalls: Deleting Detached Entities With Required References
It is common practice in O/RMs to delete an entity without actually loading id, just by knowing its id. This saves one SELECT and is great for performance. For example, using Entity Framework Code First:
1: ctx.Entry(new Project { ProjectId = 1 }).State = EntityState.Deleted;
2: ctx.SaveChanges();
This, however will fail if there is a [Required] reference (might be defined in fluent configuration, it doesn’t matter) to another entity (many-to-one, one-to-one)! For example, if our Product entity would have something like this:
1: public class Project
2: {
3: public Int32 ProjectId { get; set; }
4:
5: [Required]
6: public virtual Customer Customer { get; set; }
7:
8: //...
9: }
In this case, the required constraint is treated like a concurrency check and the above query will fail miserably. From conversations with the EF team, I understood this is related with some EF internals, which apparently are difficult to change.
There are three workarounds, though:
-
Remove the required constraint, which may not be appropriate at all;
-
Load the entity into the context, which, of course, was exactly what we were trying to avoid;
-
Add a foreign key property for the navigation property.
The third option would be to have something like:
1: public class Project
2: {
3: public Int32 ProjectId { get; set; }
4:
5: [Required]
6: public virtual Customer Customer { get; set; }
7:
8: [ForeignKey("Customer")]
9: public Int32 CustomerId { get; set; }
10:
11: //...
12: }
It really shouldn’t be required to have this foreign key – that’s what navigation properties are meant to replace – but it is. Let’s hope that some future version of EF will fix this.