我最近读到,将存储库模式与ORM结合使用不是一种好习惯。从我的理解来看,这是因为它们在SQL数据库上提供的抽象太泄漏而无法包含在模式中。
我对此有两个问题:
如果要转出ORM,该怎么办?如果您未在存储库中包含ORM特定代码,则您的应用程序中将包含该代码。
当不使用ORM且您正在使用ADO.NET进行数据访问并自己填充对象数据时,存储库模式仍然有效吗?
如果您使用ORM而不是存储库模式,那么将常用查询保留在哪里?将每个查询表示为一个类并具有某种查询工厂来创建实例是否明智?
我最近读到,将存储库模式与ORM结合使用不是一种好习惯。从我的理解来看,这是因为它们在SQL数据库上提供的抽象太泄漏而无法包含在模式中。
我对此有两个问题:
如果要转出ORM,该怎么办?如果您未在存储库中包含ORM特定代码,则您的应用程序中将包含该代码。
当不使用ORM且您正在使用ADO.NET进行数据访问并自己填充对象数据时,存储库模式仍然有效吗?
如果您使用ORM而不是存储库模式,那么将常用查询保留在哪里?将每个查询表示为一个类并具有某种查询工厂来创建实例是否明智?
Answers:
1)是的,但是您多长时间切换一次ORM?
2)我会这样说,因为ORM上下文是一种存储库,并且隐藏了很多工作,涉及创建查询,检索数据,映射等。如果您不使用ORM,则该逻辑仍必须保留在某个地方。我不知道从严格意义上来说,它是否可以作为存储库模式...
3)我经常看到封装查询,但是通常用于测试/存根。除此之外,在跨应用程序的不同部分重用查询时,我会格外小心,因为那样的话,您可能会创建一个依赖项,该依赖项可能会更改n倍(n是您使用查询的位置数)。
1)如果要转出ORM,该怎么办,如果不将其包含在存储库中,则应用程序中将具有特定的ORM代码。
我还没到公司突然决定转换数据访问技术的位置。如果发生这种情况,将需要做一些工作。我倾向于通过接口抽象数据访问操作。存储库是解决此问题的一种方法。
然后,我将有一个不同的程序集来具体实现我的数据访问层。例如,我可能有:
Company.Product.Data
和Company.Product.Data.EntityFramework
程序集。第一个程序集将纯粹用于接口,而另一个程序集将是Entity Framework数据访问逻辑的具体实现。
2)当不使用ORM且您正在使用ADO.net进行数据访问并自己填充对象数据时,存储库模式是否仍然有效?
我认为由您决定哪种模式有效或无效。我在表示层中使用了存储库模式。要记住的一件事是,人们喜欢将责任扔到存储库中。在不知不觉中,您的存储库课程将是跳舞,唱歌和做各种事情。您要避免这种情况。
我看到一个存储库类是通过承担GetAll,GetById,Update和Delete职责而开始的,这很好。到项目完成时,同一个类已经拥有了数十种本不应该存在的方法(职责)。例如,GetByForename,GetBySurname,UpdateWithExclusions和各种疯狂的东西。
这是查询和命令起作用的地方。
3)如果您使用ORM而不是存储库模式,则在哪里保留常用查询。将每个查询表示为一个类并具有某种查询工厂来创建实例是否明智?
我认为使用查询和命令代替存储库是一个很好的主意。我执行以下操作:
定义查询的接口。这将帮助您进行单元测试。例如public interface IGetProductsByCategoryQuery { ... }
定义查询的具体实现。您将能够通过您选择的IoC框架注入这些内容。例如public class GetProductsByCategoryQuery : IGetProductsByCategoryQuery
现在,我不再需要承担数十种责任来污染存储库,而只是将查询分组到命名空间中。例如,上述查询的接口可能位于:Company.SolutionName.Products.Queries
而实现可能位于Company.SolutionName.Products.Queries.Implementation
在更新或删除数据时,我以相同的方式使用命令模式。
有人可能会不同意,并说在项目完成之前,您将拥有数十个类和名称空间。是的你将会。在我看来,这是一件好事,因为您可以浏览所选IDE中的解决方案,并立即查看某些组件承担什么样的责任。如果您决定改用存储库模式,则必须查看每个存储库类以尝试确定其职责。
免责声明:以下内容基于我对上述模式(即存储库)的理解和简要经验。我可能做错了...事实上,我很肯定自己做错了:)。因此,尽管这是一个答案,但它也是一个变相的问题。
我正在使用“存储库”模式来抽象化数据访问层,该数据访问层在大多数情况下是ORM。到目前为止,它是一个通用接口,具有用于LINQ to SQL和EF的Create,Read,Update,Delete和实现类的方法。我可以实现一个写入磁盘上XML文件的实现(这只是我可以用它做的一个疯狂的例子)。我没有实现工作单元,因为它受ORM支持。如果需要,我可能可以实现它。我喜欢这种方式,因为到目前为止,它给了我很好的分离。我并不是说没有更好的选择。
要回答您的问题:
再举一个例子,Umbraco的员工已经摘除了DI容器,以防万一他们可能想要切换到其他容器。
如果ORM提供LINQ的灵活性,渴望加载等。我不会将其隐藏在任何额外的层后面。
如果涉及原始sql(微型ORM),则无论如何都应使用“每个查询的方法”以实现可重用性,从而使存储库模式非常合适。
What do you do if you want to switch out ORMs?
You would have ORM specific code in your application if you do not contain it in a repository.
为什么需要切换?
应该使用具有大多数所需功能的软件。新版的ormX可能会带来新功能,并且可能会比当前功能更好。但是...
如果选择隐藏orm,则只能使用所有候选者都具有的功能。
例如,您无法Dictionary<string, Entity>
在实体中使用属性,因为ormY无法处理这些属性。
假设使用LINQ,则大多数orm开关只是切换库引用并替换session.Query<Foo>()
为context.Foos
或类似,直到编译为止。无聊的任务,但是比对抽象层进行编码所需的时间更少。
Is the repository pattern still valid when not using an ORM and you are using ADO.NET for data access and populating object data yourself?
是。代码应该是可重用的,这意味着将sql构建,对象实现等放在一个位置(单独的类)。您也可以调用类“ XRepository”并从中提取接口。
If you use an ORM but not the repository pattern where do you keep commonly used queries?
Would it be wise to represent each query as a class and have some sort of query factory to create instances?
假设使用LINQ,那么类包装器将是恕我直言。更好的方法是扩展方法
public static IQueryable<T> Published<T>(this IQueryable<T> source) where T : Page
{
// at some point someone is going to forget to check that status
// so it makes sense to extract this thing
return source.Where(x => x.Status == Status.Published && x.PublishTime <= DateTime.UtcNow);
}
在多个位置(或可能)使用且足够复杂(容易出错)的任何代码都应提取到集中位置。