【问题标题】:.net ORM Comparison [closed].net ORM 比较 [关闭]
【发布时间】:2011-07-03 09:14:35
【问题描述】:

我正在和某人谈论实体框架,我还没有真正进入它,但我想学习它。但是,我仍然有点困惑是否应该学习它。我听到很多人说你不应该使用实体框架,但我没有听到任何争论为什么会这样。

所以我的问题是,使用实体框架compared to other products 的优缺点是什么。喜欢

  • NHibernate
  • DataObjects.Net
  • 等等..

在易用性、可测试性、语义方面……

我知道有一些 duplicate questions 关于这个。但是它们都有些过时了(2008,2009),老实说,这些论点也缺乏一些东西。我知道 Entity Framework 4.0 可用,但我还没有找到一个好的(完整的)比较。


答案

这里的一些好人通过解释不同框架的一些细节来回答我的问题。认为在这里展示它们以供将来参考可能会很好。

【问题讨论】:

  • 除了那个是 09 年 9 月的,而且 EF 发生了很大变化
  • 我对该问题的回答于 2010 年 6 月更新,从那时起 EF4 或其他 ORM 并没有太大变化。无论如何,您不应该仅仅因为想要更新鲜的答案而创建重复的问题。
  • 有关基准测试,请查看ormeter.net
  • 天啊,这些基准不会有偏见吧? “你是谁?.​​.....此外,我们公司有一个产品在这个领域竞争(DataObjects.Net),所以我们知道必须测试什么。”

标签: .net orm comparison


【解决方案1】:
【解决方案2】:

我花费了大量时间来调整实体框架以满足我的需求,因此可以说它满足了您对 ORM 的大部分要求。但是有些方面过于复杂,因为其他 ORM 已经表明它可以变得更容易。

例如,开始使用 Entity Framework 相当容易,因为您只需在 Visual Studio 中启动设计器并在几分钟内就拥有一个正常工作的 ORM。但是您最终会得到与设计者创建的 ObjectContext 相关联的实体类(使用自定义 T4 模板可以避免这种情况)。这不一定是一件坏事,但它是那种你不想在实际应用程序中使用的 Microsoft“入门”方法。

但是,如果您更深入地研究实体框架,您会发现如何避免其中的大部分陷阱:Designer 生成一个 EDMX 文件,(如果您在 XML 编辑器中查看它)只不过是一个组合ORM 的三个主要方面,物理存储(您的数据库),概念模​​型(您的实体类)以及它们之间的映射。在 Visual Studio 中应用于 .edmx 文件的自定义生成操作会将这 3 个部分拆分为三个单独的文件,并将它们作为嵌入式资源添加到程序集中。创建 ObjectContext 时,这三个文件的路径在 ConnectionString 中使用(这对我来说总是有点混乱)。你在这里实际上可以做的,就是自己做这一切。这意味着在 XML 编辑器(很像 NHibernate)中编写存储模式、概念模型和映射,并将它们嵌入到包含您的模型的程序集中。

基础实体框架基类“ObjectContext”可以从这三个文件(它需要一个 MetadataWorkspace 和 EntityConnection)构建,但重点是,您可以完全控制如何创建 ObjectContext。这为实体框架提供的许多功能打开了大门。例如:您可以在同一个程序集中嵌入多个 SSDL 存储模式以匹配特定的数据库类型(我通常为 SQL Server 添加一个,为 SQL Server CE 4.0 添加一个)。并创建一个构造函数重载,为特定类型的 DbConnection 选择适当的存储模式。

既然你现在有了自己的 ObjectContext 实现,你可以在上面实现各种接口。就像你自己的 IRepository,但因为我喜欢 ObjectContext 方法,所以我创建了类似的东西:

interface ICatalog
{
    IEntitySet<Article> { get; }
    void Save();
}

interface IEntitySet<T> : IQueryable<T>
{
    void Add(T);
    void Remove(T); 
}

class EntityFrameworkCatalog : ICatalog
{
    ...
}

但是,如果您有一个实体框架 ObjectContext,那么创建一个存储库真的很容易,而且您还可以获得一个 IQueryable。基于这些信息,您可以避免服务和 ORM 之间的强类耦合,并在测试中完全模拟实体框架。此外,在测试您的实体框架实现时,您可以在单元测试期间使用 SQL Server CE 数据库以确保您的映射正常(通常 CE 的存储架构与完整的 SQL Server 之间的差异只是一些数据-类型)。因此,您实际上可以很好地测试实体框架实现的所有行为。

这使得 Entity Framework 与现代软件概念很好地结合在一起,但它不会对您强制执行此类做法,这使得“入门”更容易。

现在回到复杂的部分:实体框架有一小部分受支持的 CLR 类型,它们基本上只包括原始类型,如整数、字符串和字节数组。它还提供了某种级别的复杂类型,它们遵循相同的规则。但是,如果您有一个复杂的实体属性,例如文档的 DOM 表示,您希望将其序列化为数据库中的 XML。据我所知,NHibernate 提供了一个名为 IUserType 的功能,它允许您为自己定义这样的映射。在实体框架中,这变得更加复杂,但它仍然以它自己的方式漂亮。概念模型允许您包含程序集内部的复杂类型(只要您将它告诉 ObjectContext (ObjectContext.CreateProxyTypes(Type[]))。因此您可以为您的原始类型创建一个包装器,它只知道像这样的实体框架:

 class Document : IXmlSerializable { }
 class Article
 {
     public virtual Document Content { get; set; }
 }
 internal class EntityFrameworkDocument : Document
 {
     public string Xml
     {
         get
         {
              // Use XmlSerializer to generate the XML-string for this instance.
         }
         set
         {
              // Use XmlSerializer to read the XML-string for this instance.
         }
     }
 }

尽管 EF 现在可以从存储中返回那些序列化的文档,将它们写入其中,但需要您截取文章的存储并用 EntityFrameworkDocument 替换一个简单的文档,以确保 EF 可以对其进行序列化。我确信其他 ORM 很容易做到这一点,而且情况会变得更糟。目前没有办法对 System.Uri 类(它是不可变的,但可以正常工作)或枚举做同样的事情。除了这些限制之外,您还可以使 EF 满足您的大部分需求。但是你会花很多时间在上面(就像我一样)。

由于我对其他 ORM 的经验有限,我总结一下:

  • 实体框架在 GAC 中,甚至在客户端配置文件中
  • 可以自定义实体框架以表示甚至复杂的实体类型(包括一些自引用的多对多,例如上面的 XML 序列化)
  • 它可以被“抽象”掉,所以你可以坚持使用 IRepository 等。
  • IQueryable 实现(虽然它不像 DataObjects.Net 那样完整)
  • 它只需要 System.Data 和 System.Data.Entity,您甚至可以为通常需要引用的其他提供者包含多个存储模式,但如果您坚持使用 DbConnection,您可以这样做:

    ICatalog Create(DbConnection connection, string storageSchemaPath) ICatalog CreateMySql(DbConnection mySqlConnection) { return Create(connection, "res://Assembly/Path.To.Embedded.MySql.Storage.ssdl"); }

编辑 我最近发现,如果您的实体和“目录”实现在同一个程序集中,您可以使用内部属性进行 XML 序列化过程。因此,与其从Document 派生内部EntityFrameworkDocument,不如向Document 类本身添加一个名为Xml 的内部属性。这仍然仅适用于您对实体具有完全控制权的情况,但它无需拦截对目录的任何更改,以确保使用您的派生类。 CSDL 看起来一样,EF 只允许映射属性是内部的。我仍然必须确保这可以在中等信任环境中工作。

【讨论】:

  • 很好的答案!关于 EF4 中的枚举,请看这里:blogs.msdn.com/b/alexj/archive/2009/06/05/…。相同的解决方案可以用于像 System.Uri 这样的不可变类型
  • 这会起作用,但它需要修改 Entity 类以适应 ORM 的需要。我通常会尽量避免。但它肯定比普通的 int 更接近枚举。
  • 当然,我同意,如果不需要它会更好。但它是一种解决方案,使对象处于有用的设计中
  • 非常感谢这个非常完整的答案!让很多事情变得清晰。
  • “这是微软的那种“入门”方法,您不想在实际应用程序中使用它”- 很好的说法,不幸的是,它适用于许多其他 MS 技术。跨度>
【解决方案3】:

由于 J. Tihon 在解释 EF 特性方面做得很好,我将仅列出 NHibernate 围绕 EF 运行的区域:

  • 缓存
    • EF 没有开箱即用的功能;只有一个unsupported sample
    • NH 具有完整的缓存支持,包括基于 DB 的失效。它还具有可扩展性和基于提供者的特性,这意味着它适用于不同类型的本地和分布式缓存
  • 批处理
    • EF 没有
    • NH 广泛支持一次延迟加载实体或集合组(在任何数据库中),并以相同的方式持久化更改(Oracle 和 SQL Server)。还有 MultiQueries 和 Future Queries,让您可以任意组合不同的查询以在一次往返中发送。
  • 用户类型
    • EF 根本没有可扩展性。它甚至不支持枚举属性
    • 在 NH 中没有硬编码类型映射。您可以对其进行扩展以支持您可以创建的任何值类型、修改现有类型的映射方式等
  • 收藏支持
    • EF 仅支持简单的实体集合。多对多总是使用复合键
    • NH 支持实体集合、值类型、组件类型以及索引集合和字典(其中键和值都可以是任何类型)。支持具有自己的密钥的多对多集合 (idbag)
  • 记录
    • EF 没有开箱即用的登录功能。上面列出了相同的不受支持的示例
    • NH 具有广泛的日志记录,可让您轻松调试问题。它默认使用 log4net,但你可以使用任何你想要的日志框架
  • 查询
    • EF 将 LINQ 作为主要查询语言。映射到关系数据库时,LINQ 具有高阻抗。 EF 的提供者不支持使用实体作为参数;你总是必须使用 ID。还有一种查询语言记录不充分
    • NH 具有 LINQ(虽然不如 EF 完整)、HQL、QueryOver 和 Criteria。
  • 事件系统和拦截器
    • EF 几乎一无所有
    • NH 有一个强大的事件系统,允许您在会话生命周期的任何时候扩展或替换其行为:加载对象、持久更改、刷新等。

我认为可扩展性是主要卖点。 NH 的每个方面都与其他方面正确解耦,使用您可以随时扩展的接口和基类,并在配置选项中公开。

EF 遵循通常的 MS 模式,默认情况下关闭,我们稍后会看到什么是可扩展的。

【讨论】:

  • 我将补充一点,EF 有一些事件 - 一个在您实现对象时,一个在保存更改之前。
  • @JeanHominal:你是对的。不过,它们不是很有用……
  • 不要冒犯,但就您而言,您没有提到 NHibernate 的缺点。我之所以这么说,是因为我想学习,根据EF有什么不足的地方吗?
  • @oruchreis NHibernate 有点难学,而且 LINQ 提供程序更有限。而已。其他方面都优于EF。
  • +1 @Diego Mijelshon 如果我能放更多我会的,谢谢你非常好!!!
【解决方案4】:

当我们迟早从头开始使用 ADO.NET 时,我们会感到沮丧并开始寻找其他解决方案。 我已经测试了其中的许多。这些 ORM 框架中的大多数都具有许多功能并且需要大量知识。有些一开始看起来很容易(例如:EF、Castle ActiveRecord),但有很多事情你应该关心:

  • 缓存
  • 多对多关系
  • 延迟加载
  • 继承
  • 复合键
  • 如何封装来自调用者的基础架构
  • SQL 语句是如何生成的
  • 性能
  • 如何进行高级数据库查询

如果您是一位经验丰富的开发人员,并且您已经准备好应对所有这些陷阱和问题,那么我问您:您的同事也是吗?

有更简单的方法来编写 ADO.NET,而不是放松对正在发生的事情的控制。看看PainlessDAL

“优雅”的编码并不总是最好的方式。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-02-09
    • 1970-01-01
    相关资源
    最近更新 更多