首页 > 解决方案 > 实体框架以相反的顺序记录一个集合

问题描述

我尝试将包含对象集合的对象保存到我的数据库中。

实体在模型类中定义的方式应该是 AFAIK:

public partial class Item
    {
       ...
       public virtual ICollection<Subitem> Subitems{ get; set; }
    }

大多数时候,收藏是按照我收藏的顺序保存的。我的意思是 item.Subitems[0] 将在 item.Subitems[1] 之前保存,在 item.Subitems[2] 之前...

但是在单个用例中,出于任何原因,它们以相反的方式保存:item.Subitems[N max] 保存在 .... 之前,保存在 item.Subitems[1] 之前保存在 item.Subitems[0] 之前。

奇怪的是,在这个用例中,我像在其他用例中一样设置我的集合并以相同的方式保存它:

public MyMethod (ICollection<Subitem> subitems) // I assert that the collection is in the order I want here
{
  foreach (var item in subitems)  // I assert that the collection is in the order I want here
        {
          Subitem subitem= CreateItem(item);
          item.Subitems.Add(subitem);
        }
}

稍后在代码中通常:

myContext.SaveChanges() // I assert that the collection is in the order I want here

我们使用事务,尽管它不应该改变任何 AFAIK。

我也尝试过:

List<Subitem> subitemsList = new ();
 foreach (var item in subitems)  // I assert that the collection is in the order I want here
        {
          Subitem subitem= CreateItem(item);
          //item.Subitems.Add(subitem);
          subitemsList.Add(subitem);
        }
 item.Subitems =subitemsList ; // I assert that the collection is in the order I want here

为什么 EF 有时会以相反的顺序保存集合元素?

我的补丁是在我将我的集合设置在导致问题的用例中之后执行的:

item.Subitems = item.Subitems.Reverse();

但是,当然,我讨厌让这条线出现在解决方案中。

标签: c#entity-framework

解决方案


+1 Panagiotis,这暴露了一个糟糕的单元测试/代码假设。如果顺序很重要,代码/测试必须提供一个OrderBy子句来确保可预测、可重复的行为。

就 SaveChanges 之后的测试断言而言,问题的根源可能是:

public virtual ICollection<Subitem> Subitems{ get; set; }

这告诉 EF SubItems 是一组简单的引用。EF 与代理一起工作,因此除非它需要符合特定的接口,否则它将根据它被告知它需要符合的内容进行优化。ICollection仅强制 Subitems 是一个可以添加和删除的集合。将其更改为IList 可能会在测试范围内提供您期望的行为,或概述两个相似对象之间的行为差​​异:

public virtual IList<Subitem> Subitems{ get; set; }

IList强制元素可以通过索引访问,因此应该保持隐含的顺序。然而,这并不意味着从 DbContext 等重新加载的数据将保持该顺序,它甚至可能无法保证以该顺序插入数据。如果订单很重要,那么您的代码和测试应该始终提供一个OrderBy子句,无论是定义为ICollection还是IList

一般的代码规则是任何使用ElementAtFirst/FirstOrDefault或类似的顺序相关方法的代码都应该始终有OrderBy/OrderByDescending子句。


推荐阅读