C# 映射实体框架6中HasOptional()与OptionalDependent()关系中的外键
我在实体框架6.1.3中有以下数据模型:C# 映射实体框架6中HasOptional()与OptionalDependent()关系中的外键,c#,entity-framework,fluent-entity-framework,C#,Entity Framework,Fluent 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
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);
}
}
但是,现在我想添加Student\u Id
属性,以便在Contact
实体中可用。因此,我可以阅读Student\u Id
,而无需通过.Student.Id
导航加入其他表
如果我将属性添加到联系人
实体中,则会出现两列Student\u Id
和Student\u Id 1
,或者会出现一条错误消息,提示类型中的每个属性名称必须是唯一的。
这个列已经在数据库中了,我所需要的就是把它也放在实体中,为什么这么麻烦?有解决方案吗?如果要在一对一关系中的从属实体中声明FK属性,恐怕也必须将其用作PK。EF首先编码依赖实体的PK也必须是关系的FK:
public class Contact
{
[Key,ForeignKey("Student")]
public int StudentId { get; set; }
public virtual Student Student { get; set; }
}
但我认为这不是你想要的。所以,我认为你有三个选择:
- 您将保留当前的关系配置
- 创造一个真实的世界李>
- 创建一对多关系
Student
上的Contact
导航属性(或省略此导航属性并创建单向关系):
公共班级学生
{
公共int Id{get;set;}
公共虚拟ICollection联系人{get;set;}
}
配置如下所示:
builder.Entity<Contact>()
.HasOptional(x => x.Student)
.WithMany(x => x.Contacts)
.HasForeignKey(x => x.StudentId)
.WillCascadeOnDelete(true);
builder.Entity()
.has可选(x=>x.Student)
.具有多个(x=>x个联系人)
.HasForeignKey(x=>x.StudentId)
.WillCascadeOnDelete(真);
更新
第四个选项是创建两个单向关系:
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);
builder.Entity()
.has可选(x=>x.Student)
.有很多
.HasForeignKey(x=>x.StudentId)
.WillCascadeOnDelete(真);
builder.Entity()
.has可选(x=>x.Contact)
.有很多
.HasForeignKey(x=>x.ContactId)
.WillCascadeOnDelete(真);
但是这个选项打破了这两个表之间的实际关系。我在之后设法从实体框架程序经理那里得到了一个响应
不幸的是,这是EF6的一个限制。在一对一关系中不能有外键属性,除非它也是主键属性。这本质上是因为EF6不支持备用键/唯一索引,所以不能强制非主键属性是唯一的。当外键属性不在实体中时可以执行此操作,这有点奇怪。。。但是很明显,我们不会删除某些内容。您可以通过将FK字段添加到模型中来阻止EF隐式创建FK字段:public int Student_Id{get;set;}然后用注释或fluent指示这是导航属性的外键。@SteveGreene:不过,正如我在问题中所述,EF不让我这么做。它要么创建两列,要么抱怨属性名称的唯一性。我尝试将字段添加到模型中,甚至尝试使用MapKey函数配置关系,但没有成功。对,您需要告诉EF如何与HasForeignKey或MapKey建立关联@史蒂文·格林:谢谢你的帮助。HasForeignKey的问题在于,它仅在具有许多关系的
中可用。当我尝试使用MapKey时,我要么得到两列,要么得到我提到的错误。这个解决方案的问题是,它迫使我建立一对多关系。我不能在那里集合。我不想改变关于我的模型的任何东西,我不想改变算术,它会给我带来太多的问题,太多的开销。我只想读取数据库表中的列。如果要创建一对一关系,并且每个实体都有自己的PK,恐怕唯一的选择是您已经有了。抱歉,无法使用该配置映射FK列谢谢您的帮助。这有什么原因吗?我的意思是,专栏已经在那里了,我只是想读一下。如果实体框架的这种限制是不合理的,那就太奇怪了。我真的不知道EF在内部是如何管理的,事实上,你想要实现的不是一对一的关系,而是一对一的关系。两个实体必须共享同一PK。也许你可以在这个关系中找到关于这个主题的更多信息。这个关系是0..1到0..1,这意味着甚至不可能共享PK。EF6.1支持外键引用非主唯一键:-自2014年以来就是这样。所以我很好奇为什么链接的github帖子是2017年发布的。我现在很困惑。
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);