Entity Framework中的ICollection<T>和List<T>有什么区别?

168

在我涉足设计几个Entity Framework应用之前,我只观看了一些网络讲座。实际上我并没有阅读很多文档,现在感觉正在为此付出代价。

我在我的类中使用了List<T>,效果很好。

现在我已经阅读了一些文档,文档指出我应该使用ICollection<T>。我进行了更改,甚至没有导致模型上下文的变化。这是因为List<T>ICollection<T>都继承了IEnumerable<T>,EF所需的实际上是IEnumerable<T>吗?

然而,如果是这样的话,为什么EF文档没有说明它要求IEnumerable<T>而不是ICollection<T>呢?


有一篇最近的[2015年]CodeProject文章,详细解释了示例代码以及图形化表示法上[List vs IEnumerable vs IQueryable vs ICollection vs IDictionary]的区别。虽然它并非直接针对EF,但仍希望能够提供更大的帮助。 - BiLaL
3个回答

169

Entity Framework会使用ICollection<T>,因为它需要支持Add操作,而这不是IEnumerable<T>接口的一部分。

此外请注意,你曾经使用了ICollection<T>,你只是将其暴露为List<T>实现。 List<T>带有IList<T>ICollection<T>IEnumerable<T>

至于你的更改,通过接口进行公开是一个好选择,即使List<T>可以工作。接口定义了契约但不定义具体实现,实现可能会发生变化。在某些情况下,实现可能会是HashSet<T>,例如。(顺便说一句,这是一个可以应用于Entity Framework之外的思维方式。良好的面向对象编程实践是基于接口而非实现进行编程。因为实现可能会发生变化。)


9
为了让我更好地理解一下——List继承自IList,而IList又继承自ICollection,ICollection 又继承自IEnumerable,是吗? - wil
6
是的,这就是链。由于继承层次结构的原因,List<T>必须实现这些接口(IList<T>, ICollection<T>, IEnumerable<T>)。为了完整性,IList<T>还会获取非泛型的IListICollectionIEnumerable接口。 - Anthony Pegram
10
普通的 Linq 操作不会添加或改变任何东西,它们只是过滤、分组、投影等等。前向只读序列就足以支持这些操作。当你有一个像 Entity Framework 这样处理数据持久性的 Linq 提供程序时,添加功能是一个重要的优势,需要更强大的接口,这就引入了 ICollection<T> 接口(该接口也带来了 IEnumerable<T>,因此“普通”的 Linq 操作仍然有效)。 - Anthony Pegram
1
@CraigJ,这取决于您对实现的理解。List<T>必须实现每个接口的方法和属性。List<T>不必声明它正在实现那些接口(除了IList<T>之外),因为这个事实已经是传递声明的。 - Anthony Pegram
我有点晚加入这个对话,但是使用List<T>的继承,每个需要更多时间吗?如果明白我的意思的话,使用ICollection定义会更快吗? - Christian4423
显示剩余2条评论

80
他们选择了这个接口,是因为它可以在使用Linq时,对Entity Framework执行的魔法查询进行可理解的抽象。以下是这些接口之间的区别:
- `IEnumerable` 是只读的。 - 您可以向 `ICollection` 添加和删除项目。 - 您可以通过索引随机访问 `List`。
在这些接口中,`ICollection` 和 `IEnumerable` 映射到数据库操作非常好,因为查询和添加/删除实体是您可能在数据库中要做的事情。
通过索引进行随机访问映射得不太好,因为您必须有现有的查询结果来迭代,或者每次随机访问都会再次查询数据库。此外,索引映射到什么?行号?您可能不想要太多行号查询,而且在构建更大的查询时根本没有用处。所以他们干脆不支持它。
`ICollection` 得到了支持,并允许您查询和更改数据,所以请使用它。
`List` 起作用的原因是因为 EF 实现最终返回了一个 `List`。但那是在查询链的末尾,而不是在开始时。因此,将属性设置为 `ICollection` 将使EF创建一堆 SQL,并仅在最后返回一个 `List`,而不是对您使用的每个 Linq 级别执行查询。

10

ICollection与IEnumerable不同的是,你可以向集合中添加项,而IEnumerable则不能。因此,在你的POCO类中,如果你想允许集合被添加,那么应该使用ICollection。为了受益于延迟加载,请将ICollection设置为虚拟的。


1
我想了解 - 你可以使用List<T>执行相同的操作(甚至更多!)。为什么要使用ICollection<T>?为什么不使用List<T>?看起来更简单和更强大。 - monstro
1
List<T> 实现了 ICollection 和 IEnumerable 接口。虽然带来了更多的操作,但也伴随着更多的开销。 - IronAces

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接