如何使用 Fluent api 为基表指定级联删除?
问题:如何让 EF 4.1 使用基表的 Fluent API 在外键约束上指定 ON DELETE CASCADE
选项?我知道如何处理与其他表的关系,但如何让它为 TPT(每种类型的表)表生成此关系?
描述: 让我指出,我指的不是外键关系。对于我的 DbContext,我总是为我的实体使用映射对象,只是因为在大多数情况下我更喜欢明确而不是接受约定方法。话虽这么说,我的 TPT 表的所有配置都在 EntityTypeConfiguration
当我通过创建派生自另一个类的新类来定义 TPT 关系时,ON DELETE CASCADE
不会在 SQL 约束中生成,这就是问题所在。
看看下面的代码...
public class Person
{
public int PersonId { get; set; }
public string Name { get; set; }
}
public class OtherPerson : Person
{
public string SomeOtherProperty { get; set; }
}
public class PersonMap : System.Data.Entity.ModelConfiguration.EntityTypeConfiguration<Person>
{
public PersonMap()
{
this.HasKey(t => t.PersonId); // Primary Key
this.Property(t => t.PersonId)
.HasColumnName("PersonId") // Explicitly set column name
.IsRequired() // Field is required / NOT NULL
.HasDatabaseGeneratedOption(DatabaseGeneratedOption.Identity); // Specify as Identity (Not necessary, but I'm explicit)
this.Property(t => t.Name)
.HasColumnName("Name") // Explicitly set column name
.IsRequired() // Field is required / NOT NULL
.HasMaxLength(50); // Max Length
this.ToTable("People"); // Map to table name People
}
}
public class OtherPersonMap : System.Data.Entity.ModelConfiguration.EntityTypeConfiguration<OtherPerson>
{
public OtherPersonMap()
{
this.Property(t => t.SomeOtherProperty)
.HasColumnName("SomeOtherProperty") // Explicitly set column name
.IsRequired() // Field is required / NOT NULL
.HasMaxLength(10); // Max Length
this.ToTable("OtherPeople"); /* Map to table name OtherPeople
* This also causes TPT to create a shared primary key from the base table
* and double serving as a foreign key to base table.
*/
}
上面的代码非常简单。我有两种类型,它们在数据库中正确创建。如果我创建一个新的 OtherPerson
并保存到数据库,它会正确创建 2 条记录,第一条记录位于 People
表中,另一条记录位于 OtherPeople
中具有共享主键的表,该主键也是从 OtherPeople 到 People 的外键。 现在,如果我在代码中删除 OtherPerson,则 DbContext 或 EF 会正确删除两条记录。但是,如果我直接从数据库中删除该记录,People
表中就会留下一条孤立记录。
那么,如何使用 Fluent API 为基表生成的外键约束指定 ON DELETE CASCADE
?
抱歉,问题太长了,但我只是我想尽可能地描述我的问题。 提前致谢。
Question: How do I get EF 4.1 to specify the ON DELETE CASCADE
option on the foreign key constraint using the fluent api for base tables? I know how to do it with relationships to other tables, but how do I have it generate this for TPT (Table Per Type) tables?
Description:
Let me point out, I am not referring to foreign key relationships. With my DbContext I always use Mapping objects for my entities, only because in most cases I prefer to be explicit as opposed to accepting the convention approach. That being said, all the configuration for my TPT tables are being handled in the EntityTypeConfiguration<SomeEntityClass>
classes.
When I define a TPT relationship by creating a new class which derives from another, the ON DELETE CASCADE
does not get generated in the SQL constraint, which is the problem.
Have a look at the following code...
public class Person
{
public int PersonId { get; set; }
public string Name { get; set; }
}
public class OtherPerson : Person
{
public string SomeOtherProperty { get; set; }
}
public class PersonMap : System.Data.Entity.ModelConfiguration.EntityTypeConfiguration<Person>
{
public PersonMap()
{
this.HasKey(t => t.PersonId); // Primary Key
this.Property(t => t.PersonId)
.HasColumnName("PersonId") // Explicitly set column name
.IsRequired() // Field is required / NOT NULL
.HasDatabaseGeneratedOption(DatabaseGeneratedOption.Identity); // Specify as Identity (Not necessary, but I'm explicit)
this.Property(t => t.Name)
.HasColumnName("Name") // Explicitly set column name
.IsRequired() // Field is required / NOT NULL
.HasMaxLength(50); // Max Length
this.ToTable("People"); // Map to table name People
}
}
public class OtherPersonMap : System.Data.Entity.ModelConfiguration.EntityTypeConfiguration<OtherPerson>
{
public OtherPersonMap()
{
this.Property(t => t.SomeOtherProperty)
.HasColumnName("SomeOtherProperty") // Explicitly set column name
.IsRequired() // Field is required / NOT NULL
.HasMaxLength(10); // Max Length
this.ToTable("OtherPeople"); /* Map to table name OtherPeople
* This also causes TPT to create a shared primary key from the base table
* and double serving as a foreign key to base table.
*/
}
The above code is really simple. I have 2 types and they are correctly create in the database. If I create a new OtherPerson
and save to the database it correctly creates 2 records, 1st a record in the People
table and another in the OtherPeople
table with a shared primary key which is also the foreign key from OtherPeople to People.
Now, the DbContext or EF rather, correctly deletes both records if I delete the OtherPerson within my code. However, should I delete the record directly from the database, an orphan record is left behind in the People
table.
So, how do I get the ON DELETE CASCADE
to be specified for the foreign key constraints generated for base tables using the fluent api?
Sorry the question is so long but I just wanted to describe the best I could my problem.
Thanks in advance.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
您似乎是说要从
OtherPeople
表(派生实体)中删除一条记录,级联删除应确保People
表(基础实体)中对应的记录也将被删除。但这是错误的方向。 EF 创建从基本实体表到派生实体表的关系和外键约束,因此: PK 表是
People
,FK 表是OtherPeople
。通过对此关系进行级联删除,您只能确保在删除相应的People
记录时删除OtherPeople
记录,而不是相反。仅此关系(也没有级联删除)可确保您无法在
OtherPeople
表中获取孤立记录,因为这会违反 FK 约束。 (如果没有相关的OtherPerson
,则无法删除Person
。)出于您的特殊目的,您实际上需要在数据库中使用第二个 FK 约束,其中 PK 表为
OtherPeople< /code> ,
FK
表是People
。这种关系根本不是由 EF TPT 映射创建的,并且仅当People
上的 PK 不是身份时(至少在 SQL Server 中),它才会起作用。但它是你模型中的一个恒等式。所以你连数据库中的级联删除都无法创建这种关系,更不用说用EF了。回到 EF 在数据库中实际创建的关系(这不是您想要级联删除的关系),我认为 EF Code-First 中没有映射选项可以让您控制 TPT 所需的关系映射。唯一的方法是直接在数据库中执行此操作,或者 - 如果您想从 Code-First 模型生成数据库 - 在自定义初始化程序中编写原始 SQL 语句(设置级联删除)并将其发送到数据库创建所有表和关系后。
不知何故,在数据库中
People
就像Order
而OtherPeople
就像OrderItem
- 只是不是1 - to-*
而是1-to-0..1
关系。您想要的是,如果子OrderItem
被删除,则父Order
也会被删除,这意味着依赖项将删除主体。You seem to say that you want to delete a record from the
OtherPeople
table (derived entity) and cascading delete should ensure that the corresponding record in thePeople
table (base entity) will be deleted as well.But this is the wrong direction. EF creates a relationship and foreign key constraint which goes from the base entity table to the derived entity table, so: The PK table is
People
and the FK table isOtherPeople
. With a cascading delete on this relationship you could only ensure that anOtherPeople
record is deleted when the correspondingPeople
record will be deleted, not the other way around.This relationship alone - also without cascading delete - makes sure that you cannot get orphan records in the
OtherPeople
table because it would violate the FK constraint. (You cannot delete aPerson
without the relatedOtherPerson
.)For your special purpose you would actually need a second FK constraint in the database where PK table is
OtherPeople
and theFK
table isPeople
. This relationship isn't created by EF TPT mapping at all and it also would only work if the PK onPeople
is not an identity (at least in SQL Server). But it is an identity in your model. So you can't even create this relationship with cascading delete in the database, not to mention with EF.Back to the relationship which EF actually creates in the database (which is not the one you want with cascading delete) I don't think that there is a mapping option in EF Code-First which would allow you to control the relationship needed for TPT mapping. The only way is to do it directly in the database or - if you want to generate the database from your Code-First model - write a raw SQL statement (which sets up the cascading delete) in a custom initializer and send this to the database after all tables and relationships have been created.
Somehow in the database
People
is likeOrder
andOtherPeople
is likeOrderItem
- just not a1-to-*
but a1-to-0..1
relationship. What you want is that the parentOrder
is deleted if the childOrderItem
is deleted which means that the dependent will delete the principal.