我有如下表结构,如图所示。 (参见:Table structure)。两个表(“批处理”和“方法”)都引用“项目”表。
当我现在创建一个新项目时,我也希望创建所有子项。
这样做我做了以下操作:
_dbContext.Projects.Where(x => x.Id == prjId)
.Include(x => x.Batches)
.Include(x => x.Batches.Select(y => y.Measurements))
.Include(x => x.Methods).AsNoTracking().FirstOrDefault();
现在的问题是:
创建了新的 Batch 和 Method 实例 - 因此它们获得了新的 ID(PK)。引用的 Project_Id (FK) 设置正确。但是在我的新 Measurement 实例中,只有 Batch_Id(FK) 设置正确并且 Method_Id 保持不变(具有旧值)(参见:result)。
我需要的是从 Methods 表中设置 Measurements.Mehtod_Id。
有没有合适的解决方案?
我的实体如下所示
public class Project
{
[Key]
public long Id { get; set; }
public string Name { get; set; }
public bool IsActive { get; set; }
public virtual List<Batch> Batches { get; set; }
public virtual List<Method> Methods { get; set; }
}
public class Batch : BaseObject
{
public Batch()
{
BatchFiles = new List<FileAttachment>();
Measurements = new List<Measurement>();
}
public long Id { get; protected set; }
public long Project_Id { get; set; }
public virtual Project Project { get; set; }
public virtual List<Measurement> Measurements { get; set; }
}
public class Method : BaseObject
{
public Method()
{
Parameters = new List<Parameter>();
}
public long Id { get; protected set; }
public long Project_Id { get; set; }
public virtual Project Project { get; set; }
public virtual List<Measurement> Measurements { get; set; }
}
public class Measurement
{
public int Id { get; protected set; }
[ForeignKey("Batch")]
public long? Batch_Id { get; set; }
[Required]
public virtual Batch Batch { get; set; }
[ForeignKey("Method")]
public long? Method_Id { get; set; }
public virtual Method Method { get; set; }
}
// creation code (just a copy with new IDs for all childs)
Project newProjectVersion = _dbContext.Projects.Where(x => x.Id == prjId)
.Include(x => x.Batches)
.Include(x => x.Batches.Select(y => y.Measurements))
.Include(x => x.Methods)
.AsNoTracking().FirstOrDefault();
_dbContext.Projects.Add(newProjectVersion);
_dbContext.SaveChanges();
感谢您的帮助!
最佳答案
第一个问题是您的 Select
语句没有将 Measurement
连接到 Method
因为 AsNoTracking()
添加。只有 Project
和 Method
是连接的,因为它们明确地 Included
Project
实体。 Measurement
有一个 Method_id
,但是这个值在它们的 Method
属性中没有伴随一个 Method
。如果您遍历对象图(虽然禁用了延迟加载!),您可以在调试器中检查它。因此,当所有实体都被添加
添加到上下文中时,EF 不会注意到测量接收到新方法。
您可能也想通过Include
-ing Measurement.Method
来解决这个问题:
...
.Include(x => x.Batches.Select(y => y.Measurements.Select(m => m.Method)))
...
现在您会看到 Measurement.Method
将填充对象图中的所有位置。
但是,这里有一个陷阱。使用 AsNoTracking
时,EF6 不会跟踪它具体化的实体 (duh)。这意味着对于每个 Measurement
它都会创建一个新的 Method
实例,即使之前为另一个 实现了相同的
。 (在这种情况下,它总是会具体化重复项,因为您已经包含了 Method
(通过 id) >测量Project.Methods
。)
这就是为什么您不能使用一个上下文实例通过 AsNoTracking
和 Add
快速完成此操作的原因。您会收到一条错误消息,提示 EF 尝试附加重复的实体。
您必须使用一个上下文构建对象图,并进行跟踪,这样 EF 就不会具体化重复项。然后,您必须将此对象图添加
到一个新的上下文中。看起来像这样:
Project project;
using(var db = new MyContext())
{
db.Configuration.ProxyCreationEnabled = false;
project = db.Projects.Where(x => x.Id == prjId)
.Include(x => x.Batches)
.Include(x => x.Batches.Select(y => y.Measurements))
.Include(x => x.Methods).FirstOrDefault();
}
using(var db = new MyContext())
{
db.Projects.Add(project);
db.SaveChages();
}
三点说明:
- 代理创建被禁用,因为如果不首先显式分离代理,则无法将代理附加到另一个上下文。
- 不,我没有忘记包含
Measurement.Method
。所有方法都是通过将它们包含在Project
中来加载的,现在(由于跟踪,并假设测量将只有它们所属项目的方法),EF 将它们与Measurement
关系修正。 - EF-core 在这方面更聪明:当添加
AsNoTracking
时,它不会跟踪物化实体,但它仍然不会创建重复项。它似乎在对象图的构建过程中有一些临时跟踪。
关于mysql - EntityFramework 包含并可能加入?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/44966277/