【问题标题】:How to escape from ORMs limitations or should I avoid them?如何摆脱 ORM 的限制,或者我应该避免它们?
【发布时间】:2011-08-14 05:27:51
【问题描述】:

简而言之,像实体框架这样的 ORM 提供了一个快速的解决方案,但有很多限制,什么时候应该避免使用它们(ORM)?

我想创建一个DMS系统的引擎,不知道如何创建业务逻辑层。

我将讨论以下选项:

  • 使用实体框架并将其作为业务提供给引擎的客户。

    问题是缺少对属性和验证的控制,因为它是生成的代码。

  • 不使用实体框架或任何 ORM 手动创建我自己的业务层类:

    问题在于这是一项艰巨的任务,就像重新发明轮毂一样。

  • 在实体框架上创建我自己的业务层类(使用它)

    问题似乎是通过创建具有相同名称的新类来重复代码,并且每个属性都将覆盖由 ORM 生成的相反的类。

我是否以正确的方式讨论这个问题?

【问题讨论】:

    标签: entity-framework orm business-logic software-design


    【解决方案1】:

    根据我的经验,当您的应用程序执行以下数据操作时,您应该避免使用 ORM:

    1)批量删除:大多数ORM工具不会真正删除数据,它们会用垃圾收集ID(GC记录)标记它以保持数据库的一致性。最糟糕的是,ORM 在将其标记为已删除之前会收集您要删除的所有数据。这意味着如果您想删除 1000000 行,ORM 将首先获取数据,将其加载到您的应用程序中,将其标记为 GC,然后更新数据库;。我认为这是一个巨大的资源腰围。

    2) 批量插入和数据导入:大多数 ORM 工具将在业务类上创建业务层验证,如果您想验证 1 条记录,这很好,但如果您要插入/导入数百甚至数百万条记录记录该过程可能需要几天时间。

    3) 报表生成:ORM 工具非常适合创建简单的列表报表或简单的表连接,例如在 order-order_details 场景中。但在大多数情况下,ORM 只会减慢数据的检索速度,并且会添加更多报表所需的连接。与通常使用 SQL 方法相比,它为 DB 引擎提供了更多的工作

    【讨论】:

    • 我必须对此发表评论:“...但是如果您要插入/导入数百甚至数百万条记录,则该过程可能需要数天...” 几天前,我编写了一个数据使用 EF 4.1 将包含 550.000 条记录的文件导入表中(不是很复杂,只有 8 列):使用本地安装的 SQL Server 2008 Express 导入需要 3 分钟。
    • 嗯...您可能是对的,您是否有一个基准可以使用直接 SQL 插入相同数量的记录?
    • 我想我忘了谈论这个,ORM 的使用速度将取决于业务类的设计方式。如果你在课堂上进行验证,这个过程会更慢。
    • 不,我没有直接导入 SQL 的基准。 (但我毫不怀疑它会更快。)而且我在课堂上没有验证。我的批评者主要反对你的极端时间跨度(“过程可能需要 ”),根据我的经验,这看起来不像是一个有根据的估计。
    • 是的,你的权利我想我反应过度了,我记得很久以前我在数据库中上传了大约 9000 万条记录(来自电话),我花了 3 或 4 天,我猜是简单到很多数据和网络,硬件还不够。
    【解决方案2】:

    免责声明:我在 Mindscape 工作,为 .NET 构建 LightSpeed ORM

    由于您没有询问具体问题,而是询问使用 ORM 解决灵活性问题的方法,所以我想我会从供应商的角度提出一些观点。它可能对你有用也可能没用,但可能会给你一些思考:-)

    在设计 O/R 映射器时,重要的是要考虑我们所说的“逃生舱口”。 ORM 将不可避免地推动一组特定的默认行为,这是开发人员获得生产力提升的一种方式。

    我们从 LightSpeed 中吸取的教训之一是开发人员需要这些逃生舱口。例如,KeithS 在这里指出 ORM 不适合批量操作 - 在大多数情况下这是正确的。我们让一些客户遇到这种情况,并为我们的 Remove() 操作添加了一个重载,允许您传入一个删除所有匹配记录的查询。这样就不必将实体加载到内存中并删除它们。倾听开发人员的痛点并帮助快速解决这些问题对于帮助构建可靠的解决方案非常重要。

    所有 ORM 都应该高效地批量查询。话虽如此,我们惊讶地发现许多 ORM 没有。这很奇怪,因为通常批处理可以相当容易地完成,并且可以捆绑多个查询并一次发送到数据库以节省往返行程。这是我们从第一天开始就为任何支持它的数据库所做的事情。这只是在这个线程中进行批处理的一个问题。这些批量查询的质量是真正的挑战,坦率地说,一些 ORM 会生成一些糟糕的 SQL 语句。

    总体而言,您应该选择一个可以立即提高生产力的 ORM(几乎是演示软件样式的“请参阅我在 30 秒内查询数据!”),但也要注意更大规模的解决方案,即逃生舱和一些较小的解决方案演示过,但需要非常有用的功能。

    我希望这篇文章的销量不会太高,但我想提请注意,在选择任何产品时要考虑到其背后的思考过程。如果哲学与您需要的工作方式相匹配,那么您可能会比选择不匹配的方式更快乐。

    如果您有兴趣,可以了解我们的LightSpeed ORM for .NET

    【讨论】:

      【解决方案3】:

      简而言之,在以下情况下应避免使用 ORM:

      • 您的程序将执行批量插入/更新/删除(例如插入选择,以及以非唯一内容为条件的更新/删除)。 ORM 并非旨在有效地执行此类批量操作;您最终将一次删除每条记录。

      • 您正在使用高度自定义的数据类型或转换。 ORM 通常不擅长处理 BLOB,并且在告诉它们如何“映射”对象方面存在限制。

      • 在与 SQL Server 的通信中,您需要绝对最高的性能。 ORM 可能会遇到 N+1 问题和其他查询效率低下的问题,总体而言,它们在您对对象的请求和 SQL 语句之间添加了一层(通常是反射式)转换,这会减慢您的速度。

      ORM 应该用于大多数基于应用程序的记录维护,其中用户正在查看汇总结果和/或更新由简单数据类型组成的单个记录,一次一个。 ORM 在使用 Linq 提供程序提供编译器检查查询的能力方面比原始 SQL 具有极大的优势;几乎所有流行的 ORM(Linq2SQL、EF、NHibernate、Azure)都有一个 Linq 查询接口,可以捕捉到很多“胖手指”和其他常见的查询错误,而这些错误在使用“魔术字符串”形成时不会捕捉到SQL 命令。 ORM 通常还提供数据库独立性。经典的 NHibernate HBM 映射是 XML 文件,可以根据需要换出以将存储库指向 MSS、Oracle、SQLite、Postgres 和其他 RDBMS。如果架构正确,即使是代码文件中的类的“流利”映射也可以被换掉。 EF 也有类似的功能。

      【讨论】:

      • 你提到了application-based record maintenance。但实际上我想知道在引擎中使用 ORM 作为 BBL 是否可以(没有提供 UI)
      • 只要您一次保存一条记录,ORM 通常不会将这些类型的过程减慢到足以成为批处理过程中的主要问题的程度;在这个过程中通常会有一些慢得多的东西,比如简单地通过网络查询。当您已经拥有来自用户应用程序的域模型和 DAL 时,我通常会在 ETL 类型的流程中看到基于 ORM 的 DAL;与从头开始编写 ETL 相比,它可以为您节省大量时间来构建 ETL 以使用现有 DAL。
      【解决方案4】:

      那么你是在问如何在不做“X”的情况下做“X”? ORM 是一种抽象,与任何其他抽象一样,它也有缺点,但不是你提到的那些。

      • 代码(EFv4)可以通过T4模板生成,T4模板是可以修改的代码
      • 生成的代码是部分类,可以与包含逻辑的部分部分结合
      • 手动编写类是非常常见的情况 - 使用实体框架中可用的设计器更为罕见

      【讨论】:

      • 实际上我已经提到“我是否以正确的方式讨论这个问题”,因为我不确定我是否正确地讨论了我的问题。
      • 我不确定的问题是,如果我为引擎的客户端提供上下文,使用 ORM 会错过对整个层的控制吗?那是我的问题。
      • 您正在部分失去对 ORM 生成的数据库查询以及 ORM 与数据库交互方式的控制,但您并没有失去对业务逻辑的控制。
      猜你喜欢
      • 2012-04-18
      • 2019-01-12
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-04-29
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多