【问题标题】:What DAL strategy do you use or suggest?你使用或建议什么 DAL 策略?
【发布时间】:2009-07-14 13:54:11
【问题描述】:

我的情况是我基本上搞砸了。大约 1.5 年前,当我担任这个职位时,我继承了我的代码库,而不是重新发明轮子,尽管我现在知道我应该这样做,但我将 DAL 保持在与以前的开发人员几乎相同的结构中。

本质上,有一个文件(现在有 15k 行代码)充当一组使用 DataSet 和 TableAdapter 检索数据的 DAO 之间的过渡。我的 xsd 文件已经增长到这样的大小,以至于每次打开时都会导致 R# 崩溃 Visual Studio,并且现在是 15k 行的中间类也需要很长时间才能让 R# 进行分析。更不用说它很丑,它可以工作但效果不佳,而且调试起来绝对是一场噩梦。

到目前为止,我尝试的是切换到 NHibernate。 NHibernate 是一个很棒的库,但不幸的是,它的适应性不足以与我的应用程序一起使用,根据首席开发人员 (Fabio Maulo) 的说法,它几乎是我的应用程序要求和使用身份作为数据库时对 NHibernate 的限制的组合PK策略。

所以现在我又回到了设计我自己的 DAL 上。我正在为此研究几种不同的模式,但想了解您的 DAL 设计策略。以特定方式实施 DAL 有很多方法和理由,因此如果您能解释一下您的策略以及为什么它最适合您,我将不胜感激。

提前致谢!

编辑:让我解释一下为什么 NHibernate 不起作用,因为这似乎是立即响应。我的用户创建了一个“工作”,它实际上只是我的 Job 类的临时表示。在这项工作中,他们将为其提供一个或一系列权重因子,这些权重因子在创建时也是暂时的。最后,他们提供了一份工作详细信息列表,这些详细信息具有与其相关的特定权重因子。因为,在数据库中,当我继续工作时,权重因子是独一无二的,当它发现重复的权重因子时,它会下降到权重因子。我尝试在将权重因子分配给细节之前运行检查(我不想这样做,因为我不希望对 db 进行额外调用)但在 NH 中调用 CreateCriteria 也会导致会话中的刷新,根据Fabio,它破坏了我的缓存,从而杀死了作业的整个内存表示。 NH 邮件列表中的人说我应该切换到 GUID,但这不是一个可行的选择,因为转换过程将是一场噩梦。

【问题讨论】:

  • 您在使用 NHibernate 时遇到什么问题?我一直将它与身份 PK 一起使用,没有问题。
  • 嗯,也许他使用了长时间运行的会话(每个业务事务的会话模型),并且在这种方法中,不鼓励使用身份,因为它会破坏您的工作单元(它需要在插入新的后直接刷新实体)。一个解决方案可能是放弃身份,并使用 HiLo 身份生成器。
  • 啊,是的,这是一种可能性(以及您的解决方案)。
  • 我完全按照 Frederik 说的做了,我必须使用 CpBT(每个业务事务的对话),因为我使用了延迟加载。我知道没有任何软件包可以满足所有人的需求,而 NHibernate 不能,或者它在开发周期的早期就被选择为不处理此类问题。

标签: c# .net database design-patterns


【解决方案1】:

我对 NHibernate 的体验是,虽然它包含许多功能和非常高性能,但您最终需要成为 NHibernate 专家才能修复一些意外行为。阅读亲 NHibernate 的答案并查看

嗯,也许他用的是长跑 会话(每个企业的会话 交易模型),并且在这样一个 方法,使用身份是 气馁,因为它打破了你的 unitofwork(需要直接flush 插入新实体后)。一种 解决方案可能是放弃 身份,并使用 HiLo 身份 生成器。

准确地说明了我的意思。

我所做的是创建一个在某种程度上模仿 ActiveRecord 模式的基类,我从继承的类继承并标记继承的类,这些属性将其附加到一个存储过程,每个用于选择、插入、更新和删除。基类使用反射读取属性并将类的属性值分配给 SP 参数,在 Select() 的情况下,将结果 SQLDataReader 的列值分配给泛型列表的属性。

这就是 DataObjectBase 的样子:

interface IDataObjectBase<T>
    {
        void Delete();
        void Insert();
        System.Collections.Generic.List<T> Select();
        void Update();
    }

这是一个派生自它的数据类的示例:

[StoredProcedure("usp_refund_CustRefundDetailInsert", OperationType.Insert)]
    [StoredProcedure("usp_refund_CustRefundDetailSelect", OperationType.Select)]
    [StoredProcedure("usp_refund_CustRefundDetailUpdate", OperationType.Update)]
    public class RefundDetail : DataObjectBase<RefundDetail>
    {

        [StoredProcedureParameter(null, OperationType.Update, ParameterDirection.Input)]
        [StoredProcedureParameter(null, OperationType.Insert, ParameterDirection.Output)]
        [StoredProcedureParameter(null, OperationType.Select, ParameterDirection.Input)]
        [ResultColumn(null)]
        public int? RefundDetailId
        { get; set; }

        [StoredProcedureParameter(null, OperationType.Update, ParameterDirection.Input)]
        [StoredProcedureParameter(null, OperationType.Insert, ParameterDirection.Input)]
        [StoredProcedureParameter(null, OperationType.Select, ParameterDirection.Input)]
        [ResultColumn(null)]
        public int? RefundId
        { get; set; }
        [StoredProcedureParameter(null, OperationType.Update, ParameterDirection.Input)]
        [StoredProcedureParameter(null, OperationType.Insert, ParameterDirection.Input)]
        [ResultColumn(null)]
        public int RefundTypeId
        { get; set; }

        [StoredProcedureParameter(null, OperationType.Update, ParameterDirection.Input)]
        [StoredProcedureParameter(null, OperationType.Insert, ParameterDirection.Input)]
        [ResultColumn(null)]
        public decimal? RefundAmount
        { get; set; }        
        [StoredProcedureParameter(null, OperationType.Update, ParameterDirection.Input)]
        [StoredProcedureParameter(null, OperationType.Insert, ParameterDirection.Input)]
        [ResultColumn(null)]
        public string ARTranId
        { get; set; }

    }

我知道我似乎在重新发明轮子,但我发现的所有库要么过于依赖其他库(例如 ActiveRecord + NHibernate,紧随其后),要么使用起来过于复杂和管理。

我制作的库非常轻量级(可能有几百行 C#),除了为参数赋值和执行 SP 之外,什么也不做。它也非常适合代码生成,所以最终我不希望编写任何数据访问代码。我也喜欢它使用类实例而不是静态类,这样我就可以将数据传递给查询,而无需使用一些尴尬的标准集合或 HQL。 Select() 的意思是“变得更像我”。

【讨论】:

  • 这很有趣,有点冗长,但很有趣。您的策略是否允许缓存?
  • 还有一件事:这也适用于现有存储过程的库。不要求它们以某种方式命名或具有非任意参数名称或顺序。
  • 我是一个老派的 VB 人,我很啰嗦 :) 还没有内置缓存。我正在玩弄使用 PostSharp 通过拦截方法调用并返回预设数据来实现缓存 AOP 样式的想法。目前,这比他们正在做的原始 ADO.net 早了几光年。
  • 您的实现与我在这里尝试的非常接近。为什么我停下来,我很好奇你是如何处理这个问题的,因为我发现自己生成了大量非常琐碎的存储过程。我真的不想必须筛选数百个存储过程的列表来找到我正在寻找的那个(即使命名方案很方便。)所以我开始研究动态 sql 生成器,但我开始遇到深度加载和延迟加载的概念问题。你有很多 Sprocs 吗?你的深度加载计划是什么?延迟加载?
  • 我工作的组织是“大量存储过程”类型之一。根据我的经验,大多数组织已经停止在“使用 SP 进行数据访问”方面进行创新,并且拥有庞大的 SP 库和开发人员为数据库中的每个表创建 CRUD SP 的策略。我所做的是使用生成器(Codesmith)为每个项目生成我需要的所有 SP,所以我什至不必考虑它。
【解决方案2】:

对我来说,最合适的是一个非常简单的概念 - 使用 DAO 类定义并通过反射创建填充和保存它们所需的所有 SQL。这种方式没有映射文件,只有简单的类。我的 DAO 需要一个实体基类,所以它不是 POCO,但这不会打扰我。它确实支持任何类型的主键,无论是单个标识列还是多列。

【讨论】:

  • 您是否将它与元数据映射器和/或数据映射器结合使用?另外,您如何处理联接或引用的类?
  • @joshlrogers 没有数据映射器 - 每个表都由一个 DAO 类表示。连接是通过在每个 DAO 中实现一个 GetJoin 方法来定义的,该方法根据其他表返回适当的连接语句。每个连接的 DAO 都有一个用于连接表的列表或对象。联接是通过在查询时链接构造函数来定义的 - 示例:List = SQL.Read(searchCriteria, new (Products(new Orders())) 返回 Products 和 Orders 之间的联接。
【解决方案3】:

如果您的 DAL 被写入接口,则切换到 NHibernate 或类似的东西会容易得多(我更喜欢 Fluent-NHibernate,但我离题了)。那么为什么不花时间重构 DAL 以使用接口,然后使用 NH 或您选择的 ORM 编写新的实现呢?

【讨论】:

    【解决方案4】:

    在最近的项目中,我们已经停止编写单独的 DAL。

    相反,我们使用对象关系映射器(在我们的例子中是实体框架)。然后我们让业务层直接针对 ORM 进行编程。

    在某些情况下,这为我们节省了 90% 以上的开发工作量。

    【讨论】:

    • 这正是我想切换到 NHibernate 的原因。不幸的是,它没有成功。
    【解决方案5】:

    我的第一步是破解一个 15 KLOC 怪物的代码,然后想出一个策略来创建一个新的 DAL。

    【讨论】:

      【解决方案6】:

      如果您使用的是 SQL Server,Linq to SQL 非常好。 Access 和 MySQL 的 LinqToSQL 提供程序有源代码。不过我还没有测试过。 LinqToSql 遵循与 ADO.NET 功能类似的 UnitOfWork 模型。您对数据的本地副本进行一系列更改,然后通过一次更新调用提交所有更改。我觉得挺干净的。

      您还可以自己扩展 DataRow 类,以提供对字段的强类型访问。我使用 XSLT 根据每个表的元数据生成 DataRow 后代。我有一个通用的 DataTable 后代。 MyDataTable 其中 T 是我的派生行。我知道 MS 的强类型数据集做类似的事情,但我想要一个我完全控制的轻量级通用版本。一旦你有了这个,你就可以编写查询数据库并填充数据表的静态访问方法。

      您将负责将数据表中的更改写回数据源。我会编写一个通用类或方法来创建更新、插入和删除。

      祝你好运!

      【讨论】:

        【解决方案7】:

        当性能不是目标时,我使用我的 SP 包装器来实现最快的数据检索和 L2S。我的 DAL 使用存储库模式和封装的 TDD 逻辑。

        【讨论】:

          猜你喜欢
          • 2010-09-13
          • 1970-01-01
          • 1970-01-01
          • 2011-12-04
          • 1970-01-01
          • 2010-09-26
          • 2021-02-11
          • 2018-10-21
          相关资源
          最近更新 更多