实体框架中的 ICollection<T> 与 List<T>

Posted

技术标签:

【中文标题】实体框架中的 ICollection<T> 与 List<T>【英文标题】:ICollection<T> Vs List<T> in Entity Framework 【发布时间】:2011-12-01 03:13:37 【问题描述】:

在开始设计一些实体框架应用程序之前,我只看了一些网络广播。我真的没有阅读那么多文档,我觉得我现在正在为此受苦。

我在课堂上一直使用List&lt;T&gt;,效果很好。

现在我已经阅读了一些文档,它指出我应该使用ICollection&lt;T&gt;。我改成了这个,它甚至没有引起模型上下文的改变。这是因为List&lt;T&gt;ICollection&lt;T&gt; 都继承了IEnumerable&lt;T&gt;,而这正是EF 真正需要的吗?

但是,如果是这种情况,为什么 EF 文档没有说明它需要 IEnumerable&lt;T&gt; 而不是 ICollection&lt;T&gt;

无论如何,我所做的有什么缺点,还是应该改变它?

【问题讨论】:

【参考方案1】:

尽管该问题已在几年前发布,但当有人正在寻找相同的场景时,它仍然有效。

最近有一篇 [2015] CodeProject 文章用示例代码解释了许多细节和图形表示的差异。它不直接针对 EF,但仍然希望它能提供更大的帮助:

List vs IEnumerable vs IQueryable vs ICollection vs IDictionary

【讨论】:

【参考方案2】:

实体框架将使用ICollection&lt;T&gt;,因为它需要支持Add 操作,这些操作不是IEnumerable&lt;T&gt; 接口的一部分。

还请注意,您使用了ICollection&lt;T&gt;,您只是将其公开为List&lt;T&gt; 实现。 List&lt;T&gt; 带来了 IList&lt;T&gt;ICollection&lt;T&gt;IEnumerable&lt;T&gt;

至于您的更改,尽管List&lt;T&gt; 有效,但通过界面公开是一个不错的选择。接口定义了合约,但没有定义实现。实现可能会改变。例如,在某些情况下,实现可能是HashSet&lt;T&gt;。 (顺便说一下,这种思维方式不仅可以用于实体框架。一个好的面向对象实践是针对接口而不是实现进行编程。实现可以并且将会改变。)

【讨论】:

所以....只是为了让我进一步理解-List继承IList,继承ICollection,继承IEnumerable? 是的,这就是链条。由于继承层次结构,List&lt;T&gt; 必须实现每个接口(@98​​7654333@、ICollection&lt;T&gt;IEnumerable&lt;T&gt;)。为了补全,IList&lt;T&gt; 还选择了非泛型的IListICollectionIEnumerable 接口。 谢谢... Ixxx 的某些功能仍然无法理解!但是,您说得有道理,最后一件让我烦恼的事情是,如果另一个 Ixx 继承了 IEnumerable,如果 Ienumerable 是只读的,它如何添加到 IEnumerable 中? ...如果太复杂,别担心,等我有时间,我会尝试启动反射器! 正常的 Linq 操作不会添加或改变事物,它们只是过滤、分组、项目等。仅向前、只读序列是支持这些操作所必需的。当您拥有处理数据持久性的 Entity Framework 之类的 Linq 提供程序时,添加的能力是一个巨大的好处,它需要一个更强大的界面,这就是邀请 ICollection&lt;T&gt; 参加聚会的原因(这个界面也带来了 @987654341 @,所以“正常”的 Linq 操作仍然有效)。 @AnthonyPegram:我认为说三个接口都必须实现是完全不正确的。由于 IList 继承了 ICollection,而 ICollection 又继承了 IEnumerable,因此 List 只需实现 IList 就足够了。【参考方案3】:

他们选择了他们所做的接口,因为它对您使用 Linq 时 Entity Framework 执行的魔术查询提供了可理解的抽象。

接口之间的区别如下:

IEnumerable&lt;T&gt; 是只读的 您可以向ICollection&lt;T&gt; 添加和删除项目 您可以随机访问(按索引)List&lt;T&gt;

其中,ICollectionIEnumerable 很好地映射到数据库操作,因为查询和添加/删除实体是您可能在数据库中执行的操作。

按索引的随机访问也不会映射,因为您必须有一个现有的查询结果才能迭代,否则每次随机访问都会再次查询数据库。另外,索引映射到什么?行号?您想做的行号查询并不多,而且在构建更大的查询时根本没有用。所以他们根本不支持它。

支持ICollection&lt;T&gt;,并允许您查询和更改数据,所以使用它。

List&lt;T&gt; 开始工作的原因是因为 EF 实现最终返回一个。但那是在查询链的末尾,而不是开头。因此,将您的属性设置为ICollection&lt;T&gt; 将使 EF 创建一堆 SQL 并在最后只返回一个 List&lt;T&gt; 更加明显,而不是对您使用的每一级 Linq 进行查询。

【讨论】:

【参考方案4】:

ICollection 与 IEnumerable 的不同之处在于,您实际上可以将项目添加到集合中,而使用 IEnumerable 则不能。因此,例如,在您的 POCO 类中,如果您打算允许将集合添加到,您希望使用 ICollection。将 ICollection 设为虚拟也可以从延迟加载中受益。

【讨论】:

我想了解 - 您可以使用 List 执行相同的操作(甚至更多!)。为什么选择 ICollection?为什么不列出?看起来更简单、更强大。 List 实现 ICollection 和 IEnumerable。更多的操作,但随之而来的是更多的开销。

以上是关于实体框架中的 ICollection<T> 与 List<T>的主要内容,如果未能解决你的问题,请参考以下文章

为啥 HashSet<T> 没有实现 ICollection?

将关系映射到实体框架中的抽象集合

ICollection<T>.Contains 自定义类型

在 linq to entity 中查询实体的 ICollection

从xml继承/实现List/ICollection/e.t.c反序列化类型

IEnumerable,ICollection,IList接口问题