一对一或零对一实体框架代码优先 Fluent Api
Posted
技术标签:
【中文标题】一对一或零对一实体框架代码优先 Fluent Api【英文标题】:One or Zero to One Entity Framework Code First FluentApi 【发布时间】:2015-04-14 11:12:30 【问题描述】:-
我需要创建 fluentapi 一对一或零对一引用,并在两个实体上都具有导航属性。
EntityTwo 应该包含简单的属性来存储外键 (EntityOneId)
public class EntityOne
public int Id get; set;
public EntityTwo EntityTwo get; set;
public class EntityTwo
public int Id get; set;
public int EntityOneId get; set;
public EntityOne EntityOne get; set;
public class MyDbContext : DbContext
protected override void OnModelCreating(DbModelBuilder modelBuilder)
base.OnModelCreating(modelBuilder);
//some code trimmed
modelBuilder.Entity<EntityOne>()
.HasOptional(entity => entity.EntityTwo)
.WithRequired();
modelBuilder.Entity<EntityTwo>()
.HasRequired(entity => entity.EntityOne)
.WithMany()
.HasForeignKey(entity => entity.EntityOneId)
.WillCascadeOnDelete(false);
更复杂的场景:
public class EntityOne
public int Id get; set;
public EntityTwo EntityTwo get; set;
public class EntityThree
public int Id get; set;
public EntityTwo EntityTwo get; set;
public class EntityTwo
public int Id get; set;
public int EntityOneId get; set;
public EntityOne EntityOne get; set;
public int EntityThreeId get; set;
public EntityThree EntityThree get; set;
public class MyDbContext : DbContext
protected override void OnModelCreating(DbModelBuilder modelBuilder)
base.OnModelCreating(modelBuilder);
//some code trimmed
modelBuilder.Entity<EntityOne>()
.HasOptional(entity => entity.EntityTwo)
.WithRequired();
modelBuilder.Entity<EntityThree>()
.HasOptional(entity => entity.EntityTwo)
.WithRequired();
modelBuilder.Entity<EntityTwo>()
.HasRequired(entity => entity.EntityOne)
.WithMany()
.HasForeignKey(entity => entity.EntityOneId)
.WillCascadeOnDelete(false);
modelBuilder.Entity<EntityTwo>()
.HasRequired(entity => entity.EntityThree)
.WithMany()
.HasForeignKey(entity => entity.EntityThreeId)
.WillCascadeOnDelete(false);
【问题讨论】:
可能与this 重复。还是我错了? 为清楚起见,您可以使用***.com/a/45182785/1941942 【参考方案1】:在一对一关系中,一端必须是主要的,而另一端必须是从属的。主端是最先插入的端,它可以在没有依赖端的情况下存在。依赖端是必须插入主体之后的端,因为它具有主体的外键。配置一对一关系时,Entity Framework 要求依赖的主键也是外键。实现您想要的正确方法可能是这样,但使用数据注释:
public class EntityOne
public int Id get; set;
public virtual EntityTwo EntityTwo get; set;
public class EntityTwo
[Key, ForeignKey("EntityOne")]
public int EntityOneId get; set;
public virtual EntityOne EntityOne get; set;
我建议您查看此link,您可以在此处找到有关如何在 EF Code First 中工作的更多信息。
更新:
恐怕您想要的东西是不可能的。您不能与未声明为 PK 的 FK 创建一对一的关系。如果您想让每个实体都有自己的Id
并配置这两个实体之间的一对一关系,请删除EntityTwo
中的 FK 属性。
我的建议是使用 Fluent Api 映射该关系,如下所示:
protected override void OnModelCreating(DbModelBuilder modelBuilder)
modelBuilder.Entity<EntityTwo>()
.HasRequired(et => et.EntityOne)
.WithOptional(eo=>eo.EntityTwo);
或者您可以在主要的导航属性上添加Required
属性,例如:
public class EntityTwo
public int Id get; set;
// public int EntityOneId get; set;
[Required]
public EntityOne EntityOne get; set;
【讨论】:
这个例子是有效的,但是它不符合我的期望。我希望 EntityTwo 有自己的 Id,并带有指向其他实体的链接(每个链接都是唯一的) 你好@OlegGochachko。我前段时间更新了我的答案。您是否尝试过该配置? “您不能与未声明为 PK 的 FK 创建一对一关系。”通过 SQL,FK 是候选键之一就足够了。【参考方案2】:我想出的唯一方法是创建一个集合和一个辅助属性来表示一/零侧,这确实有点难看。为了清楚起见,包括数据注释。
public class EntityOne
[Key]
public int EntityOneId get; set;
public EntityTwo EntityTwo => EntityTwoNavigation?.FirstOrDefault();
public ICollection<EntityTwo> EntityTwoNavigation get; set;
public class EntityTwo
[Key]
public int EntityTwoId get; set;
public int EntityOneId get; set;
[ForeignKey("EntityOneId")]
public EntityOne EntityOne get; set;
【讨论】:
以上是关于一对一或零对一实体框架代码优先 Fluent Api的主要内容,如果未能解决你的问题,请参考以下文章
使用实体框架 4.1 代码优先方法将一对一的表关系映射到单个实体
实体框架代码优先关系 - 如何定义两个对象之间的关系:两个实体之间的可选一对一