LINQ to SQL和存储库模式
我觉得我在圈子里跑来跑去。 我似乎无法确定正确的存储库模式使用LINQ to SQL 。 如果您熟悉Rob Conery的 MVC店面,您将看到他的实现将LINQ生成的模型与另一个类包装在一起,并将LINQ生成的模型简单地视为数据传输对象 (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的版本中使用IRepository模式与LINQ to SQL一样build立的方式<T>,他只是从中返回DTO对象库?
业务逻辑应该在哪里执行和检查? 这是在一个单独的层一起调用存储库保存/更新,或者它是内置到包装类?
事情是这样的,LINQ to SQL不是一个真正的对象关系映射器 (ORM),它是一个数据访问层生成器。 您可以通过深入手工编辑XML文件并使用SqlMetal进行操作 ,而不需要将其作为DAL进行操作 。
ORM背后的想法是这样的。 你有你的SQL数据库和你的域对象。 要正确devise一个数据库,你将要做的事情(如标准化),逻辑上不会转化为一个devise正确的对象模型,反之亦然。 这被称为“阻抗不匹配”,ORM的作用是以一种干净,有效和高效的方式处理这种不匹配。 不太痛苦的数据库交互几乎是次要的。
存储库背后的想法是,它封装了应用程序其余部分的基础架构上的所有持久性逻辑和依赖关系。 当您的应用程序需要一个Customer对象时,它不应该知道它是来自SQL Server,MySQL,XML文件还是ASP.NET Membership。 一旦你有了这种解耦,你对持久性故事的任何修改都不会对你的其他应用程序产生影响。
考虑到这一点,他更清楚为什么他做了他所做的事情。 LINQ to SQL用于生成DAL,但唯一需要了解的DAL是存储库,因此需要对其域对象进行翻译。 这样他就可以重构他的领域模型,而不用担心他的持久性故事,他可以重构他的数据库,而不必担心通过他的应用程序的波及效果。 他还可以开始编写业务逻辑,然后再决定使用什么样的ORM,甚至是在哪里存储数据。
如果他要使用一个真正的ORM(如NHibernate ),那么这个映射代码可以在其他地方(在XML或引导类中)处理。 我认为LINQ to SQL(以及Robs开放源码DAL, SubSonic )是伟大的项目,但更多的是为更小的双层应用程序devise的,其中类似于存储库模式的东西是过分的。 店面也是为什么NHibernate的额外复杂性可能很重要的一个很好的例子。 他本来可以通过构build一些处理这种情况的东西来节省大量代码,而不是手动完成。
这取决于DTO的定义以及如何testing。 如果您使用DBML,那么LINQ to SQL想要在数据层中生成数据对象。 虽然LINQ to SQL 支持无知,但它不会让事情变得简单。 entity framework根本不支持它。
这意味着在标准模型中,您的数据层正在定义所有的域实体,如果您想要在与数据层真正隔离的情况下testing用户界面/业务层,这是非常棘手的。
一个实用的方法可能是在unit testing中使用来自数据层的数据对象定义,而不是数据上下文(即隐藏存储库接口后面的数据上下文,但暴露实体types) – 但这是混浊的水域一点点,并且意味着你的UI等需要强烈引用数据层。 但是如果你认为这是一个“域模型层,它恰好也包含了一个我们可能使用或者可能不使用的存储库实现”,那么你可以certificate它是正确的。
保持完全独立的域实体使得unit testing和控制反转 (IoC)更“纯”,但增加了代码量(所以是双边的)。
生成的对象是可序列化的吗? 我有他们没有的印象。 正如Marc Gravel上面所说,这只是一个孤立的例子。
如果切换存储库并拥有MySQL,Oracle,XML文件,Web服务或任何数据提供程序(Repository),该怎么办? 你会被绑定到LINQ to SQL程序集来引用实体,对吧? 当然,你不会想要的。