【问题标题】:Entity Framework: Get parent record with filtered child records实体框架:使用过滤的子记录获取父记录
【发布时间】:2013-02-28 14:04:57
【问题描述】:

我对 EF 了解不多,但必须做一些错误修复。其中一个错误发生如下:

  • 使用ObjectContext 获取父记录(EF LINQ 查询)
  • 更改一些属性
  • 保存更改

问题在于Get parent record,更具体地说只获取父级的活动子级

这是当前的hack

var data =
    (from q in Context.Questions.Include("Status").Include("Category")
     where q.Id == id
     select q).SingleOrDefault();

var atts = Context.Answers.Where(a => a.qId == id && a.active); // 1
data.Answers.Clear(); // 2
foreach (var att in atts)
{
    data.Answers.Add(att); // 3
}

会发生什么:

  1. 从数据库中获取活动子记录
  2. 由于延迟加载,所有附件都是从数据库中获取的。然后立即清除该集合。 (EF 跟踪将这些记录标记为“删除”?)
  3. 循环所有活动记录并将它们再次添加到集合中(EF 跟踪将这些记录标记为“插入”?)

更新时出现以下异常:The operation failed: The relationship could not be changed because one or more of the foreign-key properties is non-nullable. When a change is made to a relationship, the related foreign-key property is set to a null value. If the foreign-key does not support null values, a new relationship must be defined, the foreign-key property must be assigned another non-null value, or the unrelated object must be deleted.

我认为这是一个非常普遍的错误,因为 EF 对清除集合然后再次添加一些相同的记录感到困惑。

我的问题:如何仅获取活动的子记录并将它们置于“未更改”状态,以便 EF 在任何时候都无法决定删除并重新插入我的记录。显然我也不想在更新时丢失非活动记录。

不是答案(或者是吗?):经常在 SO 和 Google 上找到,但无法让它发挥作用:

Context.ContextOptions.LazyLoadingEnabled = false;

var data =
    (from q in Context.Questions.Include("Status").Include("Category")
     where q.qId == id
     select new
     {
         Question = q,
         Answers = q.Answer.Where(a => a.active)
     }).ToArray().Select(q => q.Question).FirstOrDefault();

return data; // Does not contain the answers... :(

【问题讨论】:

    标签: .net entity-framework


    【解决方案1】:

    您可以显式加载该属性,而不是先加载它,然后再清除它。这将防止在对象图中加载不需要的对象,因此在断开非活动实体时不会出现错误。

    var data =
        (from q in Context.Questions.Include("Status").Include("Category")
         where q.Id == id
         select q).SingleOrDefault();
    
    Context.Entry(data).Collection(b => b.Answers).Query()
        .Where(a => a.active)
        .Load();
    

    【讨论】:

    • 不幸的是,Entry 是在 DbContext 中定义的,它派生自项目中使用的 ObjectContext
    • 尝试将您的 ObjectContext 转换为 DbContext。见objectcontext-does-not-contain-a-definition-for-entry
    • 你想同时使用 Include() 和 Load() 吗?我认为如果你使用 Load() 那么你就不需要 Include()。也许我错了。
    • 他的包含是不同的导航属性(状态),然后是正在加载的(答案)。我只是把它留在了那里,因为它在原始代码示例中..
    【解决方案2】:

    调用data.Answers.Clear() 是不够的,因为它只会删除您的问题和答案之间的关联。如果您还想删除这些答案,您也需要从上下文中删除它们。

    foreach(var answer in data.Answers) {
      Context.DeleteObject(answer);
    }
    
    data.Answers.Clear();
    

    【讨论】:

    • 我不想删除任何东西。我想get 一个问题及其所有有效答案。
    • 您正在清除您的问题的答案,以便您的答案的 ForeignKey 设置为 NULL,除非该属性可以为空,否则这是不允许的
    • 清除答案是造成错误的丑陋黑客。 I don't want to delete anything。如果我可以在没有任何删除/清除的情况下仅使用有效答案来解决问题,那就太好了。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-10-13
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-03-06
    相关资源
    最近更新 更多