EntityFramework包含并可能加入?

时间:2017-07-07 08:38:21

标签: mysql entity-framework

我有如下表结构,如图所示。 (见: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();

现在问题如下:
创建新的批处理和方法实例 - 因此它们获得新的ID(PK)。引用的Project_Id(FK)设置正确。但在我的新Measurement实例中,只有Batch_Id(FK)设置正确且Method_Id保持不变(具有旧值)(参见:result)。

我需要的是Measurements.Mehtod_Id是从Methods表中设置的。
有没有合适的解决方案呢?

我的实体如下所示

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();

感谢您的帮助!

2 个答案:

答案 0 :(得分:1)

第一个问题是,由于Select添加,您的Measurement语句未将MethodAsNoTracking()连接起来。只有ProjectMethod已连接,因为它们明确Included实体ProjectMeasurement有一个Method_id,但这个值在Method属性中没有Method。您可以在调试器中检查是否遍历对象图(尽管延迟加载已禁用!)。因此,当所有实体都Add - 上下文时,EF不会注意到测量结果会接收新方法。

Include

现在您将看到Measurement.Method将在对象图中的任何位置填充。

然而,这里有一个问题。使用... .Include(x => x.Batches.Select(y => y.Measurements.Select(m => m.Method))) ... 时,EF6不会跟踪它实现的实体(duh)。这意味着,对于每个Measurement.Method,它会创建一个新的AsNoTracking实例,即使之前为另一个Measurement实现了相同的Method(按id)。 (在这种情况下,它将始终具有重复项,因为您已经包含Method。)

这就是为什么您无法使用{1}}和Measurement使用一个上下文实例快速执行此操作的原因。您将收到EF尝试附加重复实体的错误。

您必须使用一个上下文构建对象图,并进行跟踪,因此EF不会实现重复项。然后,您必须Project.Methods此对象图表到新的上下文。看起来像这样:

AsNoTracking

三条评论:

  • 代理创建已禁用,因为您无法将代理附加到其他上下文,而无需先将其明确分离。
  • 不,我没有忘记加入Add。通过将它们包含在Add和现在(因为跟踪,并假设测量只包含它们所属的项目的方法)来加载所有方法,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(); } s连接起来< em> relationship fixup 。
  • EF-core在这里更聪明:添加Measurement.Method时,它不会跟踪物化实体,但仍然不会创建重复项。在构建对象图时,似乎有一些临时跟踪。

答案 1 :(得分:0)

到目前为止,谢谢你的回答。现在这很好用。不幸的是,我注意到Measurements实体与名为&#39; MeasurementTypes&#39;的表格有另一个必需的关系:

[Required]
public virtual MeasurementType MeasurementType { get; set; }
[ForeignKey("MeasurementType")]
public long MeasurementType_Id { get; set; }

与批次和方法相比,不得复制这些条目,并且条目已存在于MeasrementTypes表中。 将所需的参考文献放入测量值的好方法是什么?