mysql - EntityFramework 包含并可能加入?

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

现在的问题是:
创建了新的 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() 添加。只有 ProjectMethod 是连接的,因为它们明确地 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。)

这就是为什么您不能使用一个上下文实例通过 AsNoTrackingAdd 快速完成此操作的原因。您会收到一条错误消息,提示 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/

相关文章:

c# - 从 LINQ to Entities 存储数据的最有效集合?

c# - Entity Framework 4.1 - 使用过滤器覆盖实体 (DBSet)

mysql - MySQL可以通过比较函数排序吗?

php - 将 MySQL 输出解析为 JSON 提取字段名称

java - 没有合适的驱动程序

entity-framework - Linq to Entities 返回所有行

c# - 如何在 Entity Framework 项目中将表数据转换为Excel格式?

php - 在没有 cron-job 的情况下使用 php 和 mysql 发送提醒邮件?

mysql - 在 laravel 5.1 中将 float 更改为更精确的 float

c# - 如何在asp.net mvc中使用 Entity Framework 在父表中创建外键并将其分配给子表