问题
Apparently Cascade Deleting with Entity Framework is very confusing. I found lot's of questions but I have not found a solution for my problem. If I manually set the "Delete Rule" to cascade it all works. But via Fluent API I haven't found a way to set this property in the database.
In my case I have a base class (with it's own table in the database)
public abstract class PropertyBase
{
public int PropertyID { get; set; }
public string Name { get; set; }
public virtual AspectBase AspectBase { get; set; }
}
And I have derived classes which are stored Table Per Type.
public class TextProperty : PropertyBase
{
public string Value { get; set; }
}
public class IntProperty : PropertyBase
{
public int Value { get; set; }
}
In my database context I have the following:
modelBuilder.Entity<PropertyBase>()
.ToTable("Properties")
.HasKey(p => p.PropertyID);
modelBuilder.Entity<IntProperty>()
.ToTable("IntProperties");
modelBuilder.Entity<TextProperty>()
.ToTable("TextProperties");
Below is a snapshot of the database table for "IntProperties".
I need to set the Delete rule of the selected foreignkey in the image above. If I do this manually in the database, then it all works fine. I really have no idea on how to achieve this. Please help.
I know it has to be something with WillCascadeOnDelete, but to be able to do this with Fluent API I probably need some navigation properties?
This is not a duplicate question: because in my case it's a derived class of the abstract base class. Some have mentioned that it is not possible with an existing database, but luckily I don't have an existing database. I am trying to accomplish this Code First and with Fluent API. Any help is very welcome!
回答1:
This has been reported and discussed more often, for example here: Cascade delete in entity framework ( table per type inheritance ). I would mark this as a duplicate, but since the question and Slauma's answer are about EF version 4, I think it's time for an update.
The discouraging part is that the bug (which I think it is) still occurs. I may be overlooking some edge cases (I probably do), but I think in TPT the relation between base and subtype could default to cascaded delete.
The error as indicated in the referred question still occurs. In your case you would see it if you'd delete a master entity that owns a collection of properties. Let's say you have this class:
class Master
{
public int ID { get; set; }
public virtual ICollection<PropertyBase> Properties { get; set; }
}
And the association Properties
is marked as cascaded delete.
Now if you do ...
var master = context.Find(x);
context.Masters.Remove(master);
context.SaveChanges();
... you'll see that EF only emits one DELETE
statement for Master
. It relies on the database to cascade the delete to the Properties
table. Well, it does, but then the FKs from IntProperty
and TextProperty
are violated, because these do not cascade deletes.
You can fix this by doing:
var master = context.Include(m => m.Properties).Single(m => m.ID == x);
context.Masters.Remove(master);
context.SaveChanges();
Now EF explicitly deletes the properies and the subtypes.1
The funny thing is that EF knows perfectly well that for deleting a property, either by ...
var intProp = context.Properties.OfType<IntProp>().First();
context.Properties.Remove(intProp); // delete from the base table
... or ...
var intProp = context.Properties.OfType<IntProp>().First();
context.IntProperties.Remove(intProp); // delete from the derived table
... it should emit two delete statements.
So that leaves you without tooling to configure the TPT association as cascaded. You'll have to add it to the migration scripts manually. However, that won't stop EF from executing 2 delete statements for each individual property that is to be deleted, because it's not aware of the cascade in the database. This can incur a serious performance hit. But it will enable you to delete a master record (owning properties) by one delete statement.
1 This seems to be an improvement compared to EF 4, where apparently it was necessary to have Remove
statements for each child record too.
回答2:
Cascade deletions can only happens at database level, EF does not do nothing in this regards. The problem here is that you ( and many others :P) are confusing usage of WillCascadeOnDelete. It is useful only when you use Code First development flow, in this case EF will generate migration code to set this property in the database foreign key and nothing more, it is up to the database to delete relationships.
When you work with database first workflow as it seems is your case, this setting is simply ignored.
来源:https://stackoverflow.com/questions/34565764/entity-framework-cascade-delete-for-inherited-class