【问题标题】:LINQ to SQL and the repository patternLINQ to SQL 和存储库模式
【发布时间】:2009-01-20 11:22:03
【问题描述】:

我觉得我在兜圈子。对于使用LINQ to SQL 的正确存储库模式,我似乎无法下定决心。如果您熟悉Rob Conery'sMVC Storefront,您会看到他的实现用另一个类包装了LINQ 生成的模型,并将LINQ 生成的模型简单地视为data transfer object (DTO)。它看起来像这样:

//Custom wrapper class.
namespace Data
{
    public class Customer
    {
         public int Id {get;set;}
         public string Name {get;set;}
         public IList<Address> Addresses {get;set;}
    }
}

//Linq-Generated Class - severly abbreviated
namespace SqlRepository
{
    public class Customer
    {
         public int Id {get;set;}
         public string Name {get;set;}
         public EntitySet<Address> {get;set;}
    }
}

//Customer Repository
namespace SqlRepository
{
    public class UserRepository : IUserRepository
    {
        private _db = new DB(); //This is the Linq-To-Sql datacontext

        public IQueryable GetCusomters()
        {
            return
                from c in _db.Customers
                select new Customer // This is the wrapper class not the gen'd one
                {
                   Id = c.Id,
                   Name = c.Name,
                   Addresses = new LazyList(c.Addresses)
                };
        }

与 Mike Hadlow 在他的 IRepository 版本中 Using the IRepository pattern with LINQ to SQL 中建议的方式相反,这样做的好处是什么(使用包装类),他只是返回存储库中的 DTO 对象?

应该在哪里执行和检查业务逻辑?这是在一个单独的层中,由存储库在保存/更新时一起调用,还是内置到包装器类中?

【问题讨论】:

    标签: .net asp.net-mvc linq-to-sql repository-pattern


    【解决方案1】:

    事情是这样的,LINQ to SQL 不是真正的Object Relation Mapper (ORM),它是一个数据访问层生成器。您可以通过手动编辑 XML 文件并使用 SqlMetal 和诸如此类的东西来使其成为 ORM,但它的亮点在于 DAL

    ORM 背后的想法是这样的。您拥有 SQL 数据库和域对象。要正确设计数据库,您将执行逻辑上无法转换为正确设计的对象模型的事情(如规范化),反之亦然。这被称为“阻抗失配”,ORM 的作用是以干净、有效和高效的方式处理这种失配。不那么痛苦的数据库交互几乎是次要的。

    存储库背后的想法是,它封装了应用程序其余部分对基础架构的所有持久性逻辑和依赖项。当您的应用程序需要一个 Customer 对象时,它不必知道它是来自 SQL Server、MySQL、XML 文件还是 ASP.NET Membership。解耦后,您对持久性故事所做的任何更改都不会影响应用程序的其余部分。

    考虑到这一点,他为什么要这么做就更清楚了。 LINQ to SQL 用于生成 DAL,但关于 DAL 唯一应该知道的是存储库,因此对他的域对象进行了翻译。这样他就可以重构他的领域模型而不用担心他的持久性故事,他可以重构他的数据库而不用担心他的应用程序的涟漪效应。他还可以在决定使用什么 ORM 甚至在哪里存储他的数据等问题之前开始编写业务逻辑。

    如果他要使用真正的 ORM(如 NHibernate),则映射代码将在其他地方处理(在 XML 或引导类中)。我认为 LINQ to SQL(和 Robs 开源 DAL,SubSonic)是很棒的项目,但更多的是为较小的两层应用程序设计的,其中存储库模式之类的东西是多余的。店面也很好地说明了 NHibernate 的额外复杂性为何如此重要。他本可以使用专为处理这种情况而构建的东西来为自己节省大量代码,而不是手动完成。

    【讨论】:

    • 但是,一旦您切换到 NHIBERNATE 之类的东西,您将如何处理您在存储库中使用的 linq to sql 扩展方法?创建一个新的存储库?
    • 这是一个很好的解释。我认为很多人(阅读“I”)的问题是试图将 L2S 对象视为不仅仅是 DAL 的东西。但是,为验证等构建各种钩子,难道不是那个 MS 的错吗?
    • 2 层架构没有任何问题,如果这就是我们所需要的。在这种情况下,L2S 是一个很棒的产品,它生成的模型对象是非常可定制和可扩展的。问题是扩展到 n 层模式,我觉得像 L2S 这样的项目开始崩溃
    【解决方案2】:

    这取决于DTOs 的定义位置以及您希望如何测试它。如果您使用 DBML,则 LINQ to SQL 想要在数据层生成数据对象。虽然 LINQ to SQL 支持持久性无知,但它并没有竭尽全力让它变得简单。 Entity Framework 根本不支持。

    这意味着在标准模型中,您的数据层定义了所有域实体,如果您想在与数据层真正隔离的情况下测试用户界面/业务层,这将是一个棘手的问题。

    一种实用的方法可能是在单元测试中使用来自数据层的数据对象定义,而不是数据上下文(即隐藏存储库接口后面的数据上下文,但公开实体类型) - 但这是搅浑水,意味着你的 UI 等需要强引用数据层。但是,如果您将其视为“恰好也包含我们可能会或可能不会使用的存储库实现的域模型层”,您可能会证明它是合理的。

    保持完全独立的域实体使单元测试和inversion of control (IoC) 更加“纯粹”,但增加了您拥有的代码量(所以是双刃剑)。

    【讨论】:

      【解决方案3】:

      生成的对象是否可序列化?我的印象不是他们。正如上面 Marc Gravel 所说,这只是一个孤立的例子。

      如果您切换存储库并拥有 MySQL、Oracle、XML 文件、Web 服务或任何数据提供程序(存储库)会怎样?您将被绑定到 LINQ to SQL 程序集以引用实体,对吗?这当然是你不想要的。

      【讨论】:

      • 您可以将它们作为一个选项进行序列化。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2011-04-29
      • 2010-10-25
      • 1970-01-01
      • 1970-01-01
      • 2010-12-12
      • 2010-10-19
      • 2012-02-21
      相关资源
      最近更新 更多