【问题标题】: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”已定义。

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


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

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

【问题讨论】:

    标签: c# entity-framework-6


    【解决方案1】:

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

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

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

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

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

    AddressrequiredStudentoptional。您还想将 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
    相关资源
    最近更新 更多