【问题标题】:Unidirectional One to One relationship entity framework, cascade delete doesn't work单向一对一关系实体框架,级联删除不起作用
【发布时间】:2016-03-30 15:36:50
【问题描述】:

我想实现一个单向的一对一关系;但是级联删除不起作用。

我有以下课程:

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:名称:类型中的每个属性名称必须是唯一的。属性名称“Address_Id”已定义。

我相信我把事情搞混了(MapKey 和 AddressId 的属性)。但是,我不知道如何解决这个问题。


我经历了this SO question和this article;但是,到目前为止还没有运气。

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

【问题讨论】:

    标签: c# entity-framework-6


    【解决方案1】:

    由于某种原因,当student 对象被删除时,它并没有删除address。

    这是您定义的关系的正常行为。这不是数据注释或流畅配置的问题。如果你有不同的期望,你最好重新审视你的模型。

    每个关系都有一个称为principal的一侧和另一侧称为dependent。 principal 方(又名 master,primary)是被引用的一方。 从属一侧(也称为细节,次要)是引用主体的一侧。外键放在 从属 端,并且当关系为 optional 时,必须始终指向现有的 principal 或 null。当 principal 记录被删除时,cascade delete 的工作原理是删除所有 从属 记录。

    正如您提到的article 的代码如何确定关联中的主体和从属端?部分中所述,EF 始终使用required 端作为主体 并且仅当两者都是required 时才允许您选择一个。

    说了这么多,让我们看看你有什么。

    Address 是 required,Student 是 optional。您还想将 FK 放入 Student,即 Student 引用 Address。

    这意味着在你们的关系中,Address 是委托人,Student 是从属。这意味着 Address 可能存在而没有 Student 引用它。如果cascade delete 已打开(如您所做的那样),删除Address 将删除Student,而不是相反。

    我认为所有这些都应该解释为什么它会以现在的方式工作,并且没有任何属性或配置可以帮助实现您的要求。如果您希望不同,同一篇文章(以及同一系列相关文章)解释了如何将关系配置为使用共享主键关联或外键关联 地址端。无论是单向还是双向都绝对与问题没有任何共同点——请参阅文章中的Should We Make the Associations Bidirectional? 部分。

    【讨论】:

    • 感谢您的解释。
    【解决方案2】:

    你的外键应该是这样的:

    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 关键字是否有助于延迟加载?
    • 对不起,我刚刚查看了我的数据库。级联删除也不起作用。
    • 虚拟关键字延迟加载相关实体,以便在加载父对象时加载实体。急切加载是当您将 Include() 添加到 linq 到实体查询时,因此有 2 个选择。
    • 谢谢詹姆斯。希望我将使用Required 注释。目前,我可以看到学生表的cascadeDelete 设置为true(在迁移文件中);但是,localdb 出于某种原因表现得很有趣。不过我还有一个问题。 Required 注释也会使外键不可为空。有什么办法可以制作外键nullable?
    • 您可以通过将属性设为可为空的 int 来使外键可为空吗?但这不会使实体成为[必需],因为这意味着该实体始终需要该关系。但是你为什么要这样做呢?
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2023-03-12
    • 1970-01-01
    • 2012-01-10
    • 2015-02-14
    • 1970-01-01
    • 2013-07-03
    • 2012-05-15
    相关资源
    最近更新 更多