单向一对一关系实体框架,级联删除不起作用。

8

我希望实现一对一的单向关系,但是级联删除不起作用。

我有以下类:

public class Student
{
    public int Id { get; set; }
    public string Name { get; set; }
    public Address Address { get; set; }
}

public class Address
{
    public int Id { get; set; }
    public string Street { get; set; }
    //I don't want the StudentId foreign key or the property of Student class here 
}

在我的Context类中,我将关系映射如下:
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
    modelBuilder.Entity<Student>()
        .HasRequired(s => s.Address)
        .WithOptional()
        .Map(m => m.MapKey("Address_Id"))
        .WillCascadeOnDelete();
}

由于某些原因,当删除student对象时,它没有删除address

此外,我还想在Student类中添加外键属性(即AddressId):

[ForeignKey("Address")]
[Column("Address_Id")]
public string AddressId { get; set; }

然而,当我尝试添加新的迁移时,出现以下错误:

Address_Id: Name: Each property name in a type must be unique. Property name 'Address_Id' is already defined.

我相信我正在混淆(使用MapKeyAddressId属性)。然而,我不知道该如何解决这个问题。


我查看了这个SO问题这篇文章,但是到目前为止还没有成功。

链接到DotNetFiddle。它不会工作,因为没有数据库。

2个回答

3
由于某些原因,当删除student对象时,它不会删除address。这是您定义的关系的正常行为。这不是数据注释或流畅配置的问题。如果您有不同的期望,最好重新审视您的模型。
每个关系都有一个称为principal的一侧和另一侧称为dependentprincipal(也称为主控方)是被引用的对象。dependent(也称为详细信息或次要信息)是引用principal的对象。外键放在dependent一端,并且必须始终指向现有的principal或在关系是optional时指向nullcascade delete通过在删除principal记录时删除所有dependent记录来工作。
正如您提到的文章中的“Code First 如何确定关联中的主要和从属端”一节所解释的那样,EF总是使用“required”端作为“主要”端,并且只有在两者都是“required”时才允许您选择其中一个。
综上所述,让我们看看您的需求。 “Address”是“必需”的,“Student”是“可选的”。此外,您希望将FK放在“Student”中,即“Student”引用“Address”。
所有这些意味着,在您的关系中,Address主要的,而 Student从属的。这意味着 Address 可能存在,而没有 Student 引用它。如果打开了 级联删除(就像你所做的那样),删除 Address 将删除 Student,而不是相反。我认为所有这些都应该解释清楚为什么现在它是按照这种方式工作的,没有属性或配置可以帮助实现您所要求的内容。如果您想要不同的方式,同一篇文章(以及同一系列相关的文章)解释了如何在 Address 侧配置关系以使用 共享主键关联外键关联。无论是单向还是双向,绝对与问题无关 - 请参见文章中的 我们是否应该使关联双向? 部分。

感谢您的解释。 - Dumbledore

3
你的外键应该是这样的:
public class Student
{
    public int Id { get; set; }
    public string Name { get; set; }
    [ForeignKey("AddressId")]
    public Address Address { get; set; }        
    [Column("Address_Id")]
    public int AddressId { get; set; }
}

在您的流畅映射中,您只需要:
modelBuilder.Entity<Student>()
    .HasRequired(s => s.Address)
    .WillCascadeOnDelete(true);

或者您可以使用注释强制级联删除:

[Required]
[ForeignKey("AddressId")]
public Address Address { get; set; }

现在更新你的数据库,你的映射应该是正确的,删除应该会级联。

感谢您的回答。很抱歉,流畅映射似乎无法正常工作。Required 注释是有效的。但是,除非在属性中添加 virtual 关键字,否则 EF 不会加载 Address 对象。它应该是这样的行为吗?当需要检索 ICollection 时,virtual 关键字是否只有在惰性加载时才能帮助呢? - Dumbledore
对不起,我刚才查了一下我的数据库。级联删除也不起作用。 - Dumbledore
1
虚拟关键字会延迟加载相关实体,因此当加载父对象时,该实体被加载。急切加载是在 Linq to Entity 查询中添加 Include() 的方法,因此有两种选择。 - James Dev
谢谢James。希望我能使用“Required”注释。目前,我可以看到学生表(在迁移文件中)的“cascadeDelete”设置为“true”;然而,由于某些原因,“localdb”表现得很奇怪。不过我还有一个问题。“Required”注释也会使外键非空。有没有办法让外键可为空? - Dumbledore
你可以通过将属性设置为可空int? 来使外键可为空,但这并不会使实体[Required],因为这意味着实体上始终需要关联。但是,你为什么要这样做呢? - James Dev
好的,现在我只是想使用 [Required] 来执行级联删除(流畅映射不起作用)。所以,我的情况是“可空外键,并启用级联删除”。 - Dumbledore

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接