在HasOptional()中映射外键。entity framework6中的WithOptionalDependent()关系
我在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() .HasOptional(x => x.Student) .WithOptionalDependent(x => x.Contact) .WillCascadeOnDelete(true); } } public static class Program { private static void Main() { Database.SetInitializer(new DropCreateDatabaseAlways()); 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_Id
两列Student_Id
和Student_Id1
,或者我最后会收到一条错误消息,指出Each property name in a type must be unique.
。
该列已经在数据库中了,我所需要的只是将它放在实体中,为什么这么麻烦呢? 有解决方案吗?
在向GitHub询问后,我设法得到了entity framework项目经理的回复。
不幸的是,这是EF6的限制。 您不能以一对一的关系拥有外键属性,除非它也是主键属性。 这主要是因为EF6不支持备用键/唯一索引,因此您无法强制非主键属性是唯一的。 当外键属性不在实体中时,你可以这样做的事实有点怪癖……但显然不是我们要删除的东西😄。
EF Core支持BTW备用密钥(因此也支持此方案)。
– Rowan Miller @ https://github.com/aspnet/EntityFramework6/issues/159#issuecomment-274889438
如果你想以一对一的关系在依赖实体中声明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属性,唯一需要通过集合更改Student
上的Contact
导航属性(或省略此nav。属性并创建单向关系):
public class Student { public int Id { get; set; } public virtual ICollection Contacts { get; set; } }
配置将是这样的:
builder.Entity() .HasOptional(x => x.Student) .WithMany(x => x.Contacts) .HasForeignKey(x => x.StudentId) .WillCascadeOnDelete(true);
更新
第四个选项可以创建两个单向关系:
builder.Entity() .HasOptional(x => x.Student) .WithMany() .HasForeignKey(x => x.StudentId) .WillCascadeOnDelete(true); builder.Entity() .HasOptional(x => x.Contact) .WithMany() .HasForeignKey(x => x.ContactId) .WillCascadeOnDelete(true);
但是这个选项打破了两个表之间的真实关系。