你使用或建议什么DAL策略?

时间:2009-07-14 13:54:11

标签: c# .net database design-patterns

我的情况是我搞砸了。大约1。5年前,当我采用这个位置而不是重新发明轮子时,我继承了我的代码库,尽管我现在已经知道我应该拥有,但我保持DAL的结构与之前的开发人员完全相同。

基本上有一个文件(现在是15k行代码),用作一堆使用DataSets和TableAdapter来检索数据的DAO。我的xsd文件已经发展到这样的大小,每次打开时它们都会导致R#崩溃视觉工作室,而现在15k行的中间类也需要永远让R#进行分析。更不用说它是丑陋的,它可以工作,但不是很好,并且是调试的绝对噩梦。

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

所以现在我回到基本上设计我自己的DAL。我正在考虑一些不同的模式,但是想获得你的DAL设计策略。有很多方法和理由以特定的方式实施DAL,所以如果你能解释你的策略以及为什么它最适合你,我将非常感激。

提前致谢!

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

7 个答案:

答案 0 :(得分:1)

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

答案 1 :(得分:1)

我对NHibernate的体验是,虽然它具有丰富的功能和非常高的性能,但您最终需要成为NHibernate专家才能修复一些意想不到的行为。阅读pro-NHibernate的答案并看到

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

完全说明了我的意思。

我所做的是创建一个基于ActiveRecord模式建模的基类,我继承并使用将其附加到存储过程的属性标记继承类,每个存储过程用于Select,Insert,Update和Delete。基类使用Reflection来读取属性并将类的属性值分配给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。选择()意味着“变得更像我”。

答案 2 :(得分:0)

如果您的DAL被写入接口,那么切换到NHibernate或者可以比较的东西会更容易(我更喜欢Fluent-NHibernate,但我离题了)。那么为什么不花时间而不是重构DAL来使用接口,然后用NH或你选择的ORM编写一个新的实现呢?

答案 3 :(得分:0)

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

相反,我们使用对象关系映射器(在我们的案例中为Entity Framework)。然后我们直接针对ORM使用业务层程序。

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

答案 4 :(得分:0)

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

答案 5 :(得分:0)

如果您使用SQL Server,Linq to SQL很不错。有一个LinqToSQL提供商可以访问Access和MySQL。我没有测试过它。 LinqToSql遵循UnitOfWork模型,它类似于ADO.NET的运行方式。您对数据的本地副本进行一系列更改,然后通过一次更新调用提交所有更改。我觉得这很干净。

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

您将负责将DataTable中的更改写回DataSource。我会写一个创建更新,插入和删除的泛型类或方法。

祝你好运!

答案 6 :(得分:0)

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