首页 > 解决方案 > EF 手动将实体列表附加到父实体中

问题描述

class Student{
public string Name {get; set;}

public EntityCollection<Info> Infos {get; set;}
}

class Info{
public string Title {get; set;}
public Student Student {get; set;}
}

我有两个这样的实体。首先我将查询一个学生实体

var student = db.Students.FirstOrDefault(s => s.StudentId = 1);

然后我在单独的查询中查询该学生的信息列表

var infos = from c in db.Info where c.StudentId = 1 and ....

如果我遍历 infos 并将其手动添加到 student.Infos 中,它将导致插入新行

foreach(info in infos){
student.Infos.Add(info);
}

如何在 db.SaveChanges() 时将信息列表附加到学生实体而不将新行插入到信息表中。喜欢

student.Infos = infos 

标签: asp.netentity-framework

解决方案


当您使用导航属性时,EF 会在幕后为您完成工作。它不仅仅是一个单独加载数据的数据层,而是建立了数据之间的关系,并且能够一次性加载相关数据的整个对象图(急切加载)或按需加载(延迟加载)

首先:您可以将 Info 集合更新为ICollection<Info>List<Info>。我选择是List<Info>因为我经常使用.AddRange(). 此外,将其标记为虚拟以启用 EF 代理和延迟加载。

从那里,要访问学生的信息,您可以使用:

var student = db.Students.Include(s => s.Infos).SingleOrDefault(s => s.StudentId = 1);

这将为所选学生预先加载信息。无需单独加载它们。

如果您不使用 .Include(..),那么您仍然可以访问 Infos(前提是 DbContext 仍在范围内),尽管这会触发额外的 SQL 调用来加载 Infos。(懒加载)

当加载数据以在 DbContext 范围之外发送时,例如从 API 调用返回或发送到视图,建议仅使用来自各种实体所需的字段组成 DTO 或 ViewModel,然后执行.Select()填充它们,并返回 DTO 而不是实体。这避免了在处理 DbContext 后延迟加载调用的问题以及由于序列化等触发延迟加载时出现的意外性能问题。


推荐阅读