我觉得我在乱跑。我似乎无法决定使用LINQ to SQL正确的存储库模式。如果您熟悉Rob Conery's MVC 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&lt; T&gt;版本中 Using the IRepository pattern with LINQ to SQL 中建议的方式。他刚刚从存储库中返回DTO对象?
应该在哪里执行和检查业务逻辑?这是一个单独的层,它是由存储库在保存/更新时调用的,还是内置到包装类中?
答案 0 :(得分:48)
问题是,LINQ to SQL不是真正的Object Relation Mapper(ORM),它是一个数据访问层生成器。您可以通过深入手动编辑XML文件并使用SqlMetal和诸如此类的东西来制作ORM,但是它闪耀的地方是DAL。
ORM背后的想法是这样的。您拥有SQL数据库和域对象。要正确设计数据库,您将要做的事情(如规范化)在逻辑上不会转换为正确设计的对象模型,反之亦然。这被称为“阻抗不匹配”,ORM的作用是以干净,有效和高效的方式处理这种不匹配。数据库交互不那么痛苦几乎是次要的事情。
存储库背后的想法是它从应用程序的其余部分封装基础结构的所有持久性逻辑和依赖性。当您的应用程序需要Customer对象时,它不应该知道它是来自SQL Server,MySQL,XML文件还是ASP.NET成员资格。一旦进行了解耦,您对持久性故事所做的任何更改都不会对应用程序的其余部分产生任何影响。
考虑到这一点,它更清楚为什么他做了他做的事情。 LINQ to SQL用于生成DAL,但唯一应该知道的DAL是存储库,因此会对其域对象进行转换。这样他就可以重构他的领域模型而不必担心他的持久性故事,他可以重构他的数据库而不用担心他的应用程序会产生波纹效应。在决定使用什么样的ORM,甚至在哪里存储数据之前,他还可以开始编写业务逻辑编码。如果他要使用真正的ORM(如NHibernate),则该映射代码将在其他地方处理(在XML或bootstrapping类中)。我认为LINQ to SQL(和Robs开源DAL,SubSonic)是很棒的项目,但更适用于较小的双层应用程序,其中类似于存储库模式的东西是过度的。店面也很好地说明了为什么NHibernate的额外复杂性很重要。他本可以通过构建处理这种场景的东西来节省大量代码,而不是手动完成所有代码。
答案 1 :(得分:13)
这取决于DTOs的定义位置以及测试方式。如果使用DBML,则LINQ to SQL希望在数据层中生成数据对象。虽然LINQ to SQL 支持持久性无知,但它并不会让它变得简单。 Entity Framework根本不支持它。
这意味着在标准模型中,您的数据层正在定义所有域实体,如果您希望测试与数据层真正隔离的用户界面/业务层,这将非常棘手。
实用的方法可能是在单元测试中使用数据层中的数据对象定义,而不是数据上下文(即隐藏存储库接口后面的数据上下文,但是暴露实体类型) - 但这是稍微混淆水域,意味着你的UI等需要强烈引用数据层。但是,如果您将此视为“域模型层,它恰好也包含我们可能使用或未使用的存储库实现”,那么您可能会证明这一点。
保持完全独立的域实体使得单元测试和inversion of control(IoC)更“纯粹”,但会增加你拥有的代码量(所以双刃剑)。
答案 2 :(得分:2)
生成的对象是否可序列化?我的印象他们不是。正如马克·格拉维尔(Marc Gravel)所说,这只是一种孤立的情况。
如果切换存储库并拥有MySQL,Oracle,XML文件,Web服务或任何数据提供程序(存储库),该怎么办?您将被绑定到LINQ to SQL程序集以引用实体,对吧?当然,你不想要的。