c# - 实体框架以相反的顺序记录一个集合
问题描述
我尝试将包含对象集合的对象保存到我的数据库中。
实体在模型类中定义的方式应该是 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();
但是,当然,我讨厌让这条线出现在解决方案中。
解决方案
+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
。
一般的代码规则是任何使用ElementAt
、First
/FirstOrDefault
或类似的顺序相关方法的代码都应该始终有OrderBy
/OrderByDescending
子句。
推荐阅读
- angular - 如何动态创建验证器并绑定到表单组?
- php - Laravel groupBy 违规
- python - 如何将字典与相同的键合并?
- javascript - 代码在小提琴和浏览器中工作,但在 sharepoint 2013 中不工作
- python - Python 使用 scipy.integrate.quad 优化计算(需要很长时间)
- jdbc - Talend - 为什么连接找不到 com.microsoft.sqlserver.jdbc.SQLServerDriver
- php - php curl 空 certinfo 并将 certinfo 设置为 1
- c++ - 如何从头开始创建 avi 文件?
- ios - Xcode 在模拟器上工作,而不是在移动设备上工作;得到错误代码 1
- javascript - 单击以根据地理位置重定向用户