【问题标题】:data access layer - modularity and reusability数据访问层 - 模块化和可重用性
【发布时间】:2011-04-15 22:52:56
【问题描述】:

我在这方面真的很陌生,我正在努力寻找最适合我的数据访问层架构。 我的解决方案中有 3 层:

  1. 表示层 - ASP.net 应用程序
  2. 业务逻辑层——c#对象和逻辑
  3. 数据访问层 - 调用存储过程的函数。

我想更换数据访问层。

如果我使用 Entity Framework 或 NHibernate,例如,什么可以确保我以后能够在不更改业务逻辑层的情况下替换该数据访问层?
Entity Framework 或 NHibernate 中的接口在哪里使用?

【问题讨论】:

    标签: c# .net design-patterns


    【解决方案1】:

    设计一个接口,映射出您将在 DAL 中使用的所有关键方法。然后只通过接口引用 DAL 类。这将通过将层彼此解耦来赋予它模块化。

    每当您需要换出上述 DAL 时,您只需插入一个实现上述接口的新 DAL。您的其余代码将不会更明智地进行更改。

    只有一种方法可以解决您的问题。

    【讨论】:

    • 和POCO有关系吗? POCO 解决了这个问题吗?
    • @Naor:Matthew 指的是 DAL 层。在 DAL 层,您确实需要接口。与 POCO 相关的是您从 DAL 层传递和接收的模型对象。
    • +1 DAL 层需要实现接口,但它们应该在外部定义(通常与消费者一起)。
    【解决方案2】:

    为了保留业务层,您还必须保留模型。因为业务与模型有着非常紧密的联系。

    您可以更改的是将模型映射到数据库的层。

    NHibernateEntity Framework 4.1 都允许我们称之为 POCO 对象。 POCO 对象是纯 CLR 对象,不引用任何特定于持久性的类。也就是说:它不包含将此类耦合到程序集的任何属性或基类或方法调用。在使用 NHibernate 时,您可以使用 XML 文件或使用 Fluent NHibernate 的流畅方法将这些 POCO 类映射到数据库。在 EF4.1 中,您只能使用 fluent 方法。

    您必须关心的一件事是stored procedures 的使用。这本质上会损害持久层替换。 EF4.1 POCO 方式目前不支持存储过程。 NHibernate 可能会,但我不确定。

    编辑

    正如马修·考克斯所说。当然,当涉及到 DAL 类时,将需要接口。因为 CRUD 操作在持久层之间会有所不同。这些接口将允许持久性替换。

    例子:

    public class IPersonDAL {
        IList<Person> GetPeople();
        void InsertPerson(Person person);
        ...
    }
    

    【讨论】:

    • 那么你说的是在数据访问层我实际上需要模型对象、接口和 ef/nhibernate 类?
    • @Naor:更清楚一点:在您的模型层上,您将拥有代表您的数据库的实体。在您的业务层上,您将拥有您的业务逻辑。在这一层上,您将引用模型层并通过代表您的 DAL 的接口对其进行操作。如果您更换数据库,那么到目前为止我提到的所有内容都不需要更换。需要的另一层是将实现这些接口并将 POCO 类从模型映射到数据库的层。将来可能需要更换这一层
    • 感谢您提供有用的信息!最后要确定的是,在业务逻辑层中,我还有代表数据库数据的对象,但这些对象在逻辑中使用,它们不是 POCO。所以过程将是:首先使用DAL从db加载数据,然后将数据转换为模型层的POCO对象,最后将poco对象转换为业务对象。这是正确的顺序吗?
    【解决方案3】:

    特别是 nHibernate (3.0+) 和 EF 支持 LINQ,因此您的代码创建了一个简单的 IRepository 接口,该接口接受 Expression&lt;Func&lt;TItemType,bool&gt;&gt; 并避免拥有具有 GetPersonByID、getPersonByName 等的存储库。虽然这可能会妨碍您交换 ORM I认为您不会使用不支持 LINQ 的 ORM。

    这个接口可能看起来像这样(这不是一个完整的实现!这只是一个演示,真正的接口需要更好的改进!这只是我现在已经模拟了一些东西!这可能还需要实现 IDisposable 等):

    interface IRepository<TPersistant>
    {
          void Save(TPersistant item);
          void Delete(TPersistant item);
    
          TPersistant Find(Expression<Func<TPersistant,bool>> predicate); 
          // maybe findOne or findMany
    
          // maybe something like this
          IQueryable<TPersistant> Query();
          /* Other stuff like updating, transactions, commiting, etc.*/
    }
    

    不过,我想提一下人们在抽象 DAL 时会忽略的一些事情。 这个o/c是我的全部意见

    虽然抽象可以帮助您在未来“交换” DAL,但如果您从中获得任何好处,我会认真思考,除了创建符合“最佳实践”和“人们说你应该做的”的软件,等等另一只手朝自己的脚开枪。

    当您完全抽象 DAL 时,您可能会失去其他 ORM 特定的特性,这些特性实际上使一个 ORM 比另一个更好,甚至为了抽象而失去未来的性能优化。 i/e nHibernate 中的未来查询(imo 是一个巨大的功能),如果将其抽象出来,您基本上会丢失。由于无法使用 Fetch (nHibernate) 或 Include (EF),您可能还会失去惰性初始化优化(选择 N+1 问题)。甚至像 enum 支持这样的小东西(我相信 EF STILL 不支持)。

    我还想补充一点,许多开发人员为了未来的变化而创建抽象,而实际上这些变化几乎从未发生过。

    所以虽然我说不要抽象 DAL,因为它有 很多 优点,例如单元测试、解耦等(尽管您总是可以创建一个有助于单元测试的耦合到 dal 存储库),如果值得为一些实际上使 nhibernate/EF 比其他。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2012-11-23
      • 2012-03-19
      • 2019-10-20
      • 2015-11-14
      • 2010-11-06
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多