在实体框架中映射HasOptional(). withoptionaldependent()关系中的外键
本文关键字:关系 withoptionaldependent 实体 映射 HasOptional 框架 | 更新日期: 2023-09-27 18:10:37
我在实体框架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_Id
和Student_Id1
两列,或者我最终得到一个错误消息说Each property name in a type must be unique.
。
列已经在数据库中了,我所需要的就是在实体中也有它,为什么这么麻烦?有解决办法吗?
在GitHub上询问后,我设法从实体框架程序管理器获得响应。
不幸的是,这是EF6的限制。在一对一关系中不能有外键属性,除非它也是主键属性。这主要是因为EF6不支持备用键/唯一索引,所以你不能强制非主键属性是唯一的。事实上,当外键属性不在实体中时,你可以这样做,这有点奇怪……但显然我们不会删除 。
BTW备用键(因此这种场景)在EF Core中是支持的。
mdash;罗文·米勒@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
导航属性。属性并创建单向关系):
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);