实体框架一对一关系

Posted

技术标签:

【中文标题】实体框架一对一关系【英文标题】:Entity Framework one-to-one relationships 【发布时间】:2017-10-03 15:09:38 【问题描述】:

我在理解如何使用 Entity Framework Core 为 Web API 设置一对一关系时遇到了一些问题。

考虑以下对象:

public class Car
  
    [JsonIgnore]
    public Int32 CarId  get; set; 

    public virtual Horn Horn  get; set; 
    public virtual ICollection<Wheel> Wheels  get; set; 


public class Horn

    [JsonIgnore]
    public Int32 HornId  get; set; 
    public Sound Sound  get; set; 


public class Sound

    // some other props

当我在我的存储库中执行查询时,默认情况下会排除一对多,除非我使用 .Include(),但是,对于一对一属性,默认情况下会在我序列化时包含它们。

例如它变得非常混乱,因为我查询了一辆车,它在 JSON 响应中返回了它的所有子组件。

我可以设置car.Horn = null 等,但对于复杂的对象,这似乎很难维护。我希望它像.Include() 一样工作,但默认情况下被排除在外(如果我确实想查询完整对象)。

编辑:注意,这个问题是递归的,汽车拉响喇叭从而拉响声音。在像用户表这样的真实示例中,除非专门取消子属性,否则序列化时自动拉入的数据非常巨大。

编辑2:

这是一个存储库调用示例,默认情况下会返回所有一对一属性:

var group = _context.Car.Include(c => c.Wheels).SingleOrDefault(u => u.CarId == id);

请注意,对于多对一,包含按预期工作,但即使删除了包含,此查询也会递归返回所有一对一的子对象。

似乎在 EF CORE 2.1 中引入了某种类型的延迟加载

【问题讨论】:

显示您的实体配置 - 您是否使用复杂类型、表格拆分? 你使用的是 EF Core 还是? 我正在使用 EF Core,简单的实体与主键上的关系。 最新的 EFC 2.0 中不会发生这种情况。你用的是什么EFC版本?您还需要提供minimal reproducible example。 我正在使用 EF CORE 2.0: 【参考方案1】:

这篇文章应该给你一个提示。 https://msdn.microsoft.com/en-us/library/jj574232(v=vs.113).aspx 主要是:

关闭延迟加载以进行序列化

延迟加载和序列化不能很好地混合,如果你不是 小心,您最终可能会查询整个数据库,因为 延迟加载已启用。大多数序列化程序通过访问每个 类型实例的属性。属性访问触发惰性 加载,因此更多的实体被序列化。在那些实体属性上 被访问,甚至更多的实体被加载。这是一个很好的做法 在序列化实体之前关闭延迟加载。以下 部分展示了如何做到这一点。

编辑: 这是为所有实体禁用延迟加载的方法。但请注意,您必须通过多种方式实现此目的,因此请查看文章中的其他选项...

public class YourContext : DbContext 
 
    public YourContext() 
     
        this.Configuration.LazyLoadingEnabled = false; 
     

【讨论】:

这不是真正的答案。展示你如何关闭它,然后它可能是一个有效的答案。 EF Core 不支持延迟加载 是的,这仅对经典 EF 有效 太糟糕了,这在 EF Core 中不起作用 - 这与我正在寻找的类似。当它是一个包含许多一对一表的较大表(例如“用户”表)时,这个问题会变得更糟。除非无效,否则即使子表也会从这些表中引入一对一的子关系,因此它是递归的!【参考方案2】:

上下文映射

   modelBuilder.Entity<SessionFeedbackModel>(entity =>
        
            entity.HasOne(s => s.Session).WithOne(p => p.Feedback)
                .HasForeignKey<SessionFeedbackModel>(s => s.SessionId).OnDelete(DeleteBehavior.Restrict);
        );

        modelBuilder.Entity<SessionQuestionModel>(entity =>
        
            entity.HasOne(e => e.SessionResult).WithOne(e => e.SessionQuestion)
                .HasForeignKey<SessionQuestionResultModel>(e => e.SessionQuestionId)
                .OnDelete(DeleteBehavior.Restrict);

        );

型号

   public class SessionQuestionResultModel
    
        public int Id  get; set; 

        public int SessionQuestionId  get; set; 

        public SessionQuestionModel SessionQuestion  get; set; 
    


    public class SessionFeedbackModel
    
        public int Id  get; set; 
        public int SessionId  get; set; 

        public SessionModel Session  get; set; 

    

EF Core 1.x 或 2.x 不太支持或根本不支持 1 对 1,但可以通过这种方式完成,这对于 EF 6.x.x 将完全不同

【讨论】:

以上是关于实体框架一对一关系的主要内容,如果未能解决你的问题,请参考以下文章

在实体框架 6 中不起作用的实体之间的一对一关系

实体框架代码优先关系 - 如何定义两个对象之间的关系:两个实体之间的可选一对一

使用实体框架 4.1 代码优先方法将一对一的表关系映射到单个实体

实体框架可选的一对一关系不起作用

用于一对一识别关系的实体框架代码优先流利 API 配置

实体框架使用流畅的API继承了一对一到一个关系配置