17

我在 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..

该列已经在数据库中,我只需要在实体中也有它,为什么这么麻烦?有解决办法吗?

4

2 回答 2

16

在 GitHub 上询问后,我设法得到了 Entity Framework Program Manager 的回复。

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

顺便说一句,EF Core 支持备用键(因此也是这种情况)。

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

于 2017-01-25T09:00:10.967 回答
9

如果要在依赖实体中以一对一的关系声明 FK 属性,恐怕您也必须将其用作 PK。EF Code First要求依赖实体的 PK 也必须是关系的 FK:

public class Contact
{
    [Key,ForeignKey("Student")]
    public int StudentId { get; set; }
    public virtual Student Student { get; set; }
}

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

  • 您保留当前的关系配置。
  • 建立真实的一对一关系
  • 创建一对多关系

根据我的经验,最后一个最适合您想要实现的目标(但这是我的观点)。在这种情况下,您可以根据需要使用 Fk 属性,唯一需要通过集合更改Contact导航属性Student(或省略此 nav. 属性并创建单向关系):

public class Student
{
    public int Id { get; set; }
    public virtual ICollection<Contact> Contacts { get; set; }
}

配置将是这样的:

 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);

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

于 2015-08-31T15:13:41.460 回答