在HasOptional()中映射外键。实体框架6中的WithOptionalDependent()关系

时间:2015-08-31 14:38:07

标签: c# entity-framework fluent-entity-framework

我在Entity Framework 6.1.3中有以下数据模型:

using System.Data.Entity;

public class Student
{
    public int Id { get; set; }
    public virtual Contact Contact { get; set; }
}

public class Contact
{
    public int Id { get; set; }
    public virtual Student Student { get; set; }
}

public class MyContext : DbContext
{
    protected override void OnModelCreating(DbModelBuilder builder)
    {
        builder.Entity<Contact>()
            .HasOptional(x => x.Student)
            .WithOptionalDependent(x => x.Contact)
            .WillCascadeOnDelete(true);
    }
}

public static class Program
{
    private static void Main()
    {
        Database.SetInitializer(new DropCreateDatabaseAlways<MyContext>());

        using (var context = new MyContext())
            context.Database.Initialize(force: true);
    }
}

当我启动此代码时,我得到了正确的表格结构:

dbo.Contacts
    Id (PK)
    Student_Id (FK, NULL, CASCADE ON DELETE)

dbo.Students
    Id (PK)

但是,现在我想在Student_Id实体中添加Contact属性。因此,我可以阅读Student_Id而无需通过.Student.Id导航加入其他表格。

如果我将该属性添加到Contact实体,我最终会有两列Student_IdStudent_Id1,或者最终会收到一条错误消息Each property name in a type must be unique.

该列已经在数据库中了,我所需要的只是将它放在实体中,为什么这么麻烦?有解决方案吗?

2 个答案:

答案 0 :(得分:12)

我设法在asking on GitHub之后得到了实体框架计划经理的回复。

  

不幸的是,这是EF6的限制。您不能以一对一的关系拥有外键属性,除非它也是主键属性。这主要是因为EF6不支持备用键/唯一索引,因此您无法强制非主键属性是唯一的。当外键属性不在实体中时你可以这样做的事实有点怪癖......但显然不是我们要删除的东西。

     

EF Core支持BTW备用密钥(因此这种情况)。

- 罗文米勒@  https://github.com/aspnet/EntityFramework6/issues/159#issuecomment-274889438

答案 1 :(得分:8)

如果你想以一对一的关系在依赖实体中声明FK属性,我恐怕你也必须把它当作PK。 EF Code First requires,依赖实体的PK也必须是关系的FK:

Contact

但我认为这不是你想要的。所以,我认为你有三个选择:

根据我的经验,最后一个是你想要实现的最多调整(但这是我的意见)。在这种情况下,您可以根据需要使用Fk属性,唯一需要通过集合更改Student上的public class Student { public int Id { get; set; } public virtual ICollection<Contact> Contacts { get; set; } } 导航属性(或省略此nav。属性并创建单向关系) ):

 builder.Entity<Contact>()
        .HasOptional(x => x.Student)
        .WithMany(x => x.Contacts)
        .HasForeignKey(x => x.StudentId)
        .WillCascadeOnDelete(true);

配置就是这样:

 builder.Entity<Contact>()
        .HasOptional(x => x.Student)
        .WithMany()
        .HasForeignKey(x => x.StudentId)
        .WillCascadeOnDelete(true);

 builder.Entity<Student>()
        .HasOptional(x => x.Contact)
        .WithMany()
        .HasForeignKey(x => x.ContactId)
        .WillCascadeOnDelete(true);

更新

第四个选项可以创建两个单向关系:

{{1}}

但是这个选项打破了两个表之间的真实关系。