存储库和持久性再次无知

时间:2011-02-17 16:06:03

标签: c# repository

这是我要去的地方。

我有一个通用的Repository类Repository<TKey, TValue>。它具有通常的存储库模式方法。

每个存储库在其构造函数中使用IContext<TKey, TValue>,它为存储库提供持久性。

我有专门的存储库,它们由通用存储库组成,然后是针对专用对象特定的存储库操作定制的方法。因此,如果我有一个专门的Kitten对象存储库,它将有ClimbTree(可能采用树对象)但不是BuryBone(骨骼骨骼)方法的方法。我做得很糟糕的一点是它在小猫和它的树之间建立了一种需要持久化的关联。 void CleanWhiskers()可能是一个更简单的例子。这使小猫的胡须清洁。

所以我现在正在考虑一个相关子对象持久化的方案,并开始怀疑我是否已经有点错误了。

我从存储库中稍微丑陋的方法开始创建子对象。因此,Kitten存储库将有一个方法CreateFurBall(),它将FurBall对象添加到Kitten的FurBall集合中,并将Furball添加到要保留的FurBall存储库(实际上是相同的对象)。

我现在已经改为一个系统,我有一个类似于ObservableCollection的东西,它在添加POCO时通知其父存储库。所以我可以创建一个POCO furball并将其添加到集合中,然后将自动注册到furball存储库。

首先我会在上下文中实现nHibernate,我觉得这个映射得相当好。这是一个非常开放的问题,对于之前一直沿着这条路走下去的人来说,你能看到任何让你“停止!!”的东西。

4 个答案:

答案 0 :(得分:5)

我应该认为ClimbTree(),BuryBone(),CreateFurBall()和CleanWhiskers()等方法属于域对象,而不属于存储库。

存储库应该处理聚合根的持久性 - 即让您查询小猫,保存并更新它们。 你想在实例化和持久性之间做小猫的任何事情都是域的特权。

答案 1 :(得分:4)

尼尔森是对的。

我认为创造毛球的两种方式之间可能存在混淆。如果一只小猫用三个毛球存放在数据库中,那么当它从数据库中拉出时,小猫应该注入他的毛球数据,并且毛球集合应该从毛球数据初始化。

当应用程序想要向小猫添加毛球时,应该通过Kitten.CreateFurBall()小猫来制作毛球。我在这里假设毛球是由小猫拥有的,毛球并不是其他小猫常见的。如果毛球足够复杂,您可能需要将毛球的创建抽象为小猫持有懒惰引用的FurballFactory。

就Kitten实体的创建而言,可能最好通过在KittenRepository中引用KittenFactory来接收小猫的dto并从中构建小猫。

您演示的最大问题是Kitten.BuryBone(骨骼骨骼)方法。小猫不埋骨头。狗狗。

答案 2 :(得分:3)

我可能稍微偏离主题,但我只想把我的两分钱放在存储库模式中。

存储库模式非常棒,特别是当您将它们全部放在接口后面时,可以轻松地将它们换出。我为每个实体创建了一个存储库。 BrokenGlass是正确的,因为这些方法通常非常通用,并且除了持久性逻辑之外不包含太多内容。对于使其成为存储库的逻辑类型,我通常不那么严格。例如,有些人认为将分页逻辑放在存储库中是有罪的,但我不同意。

我使用Entity Framework和LINQ to SQL。为了从这些页面中分页结果,我需要LINQ在IQueryable<entity>上运行,以便在数据库级别进行分页。我不想在我的存储库之外公开IQueryable。因为如果有一天我的存储库需要重写并且数据存储不能再使用IQueryable怎么办?所以不是从我的存储库返回这个:

IQueryable<entity> GetEntities();

...并在我的控制器或我的应用程序的其他地方分页结果。我反而这样做了:

IEnumerable<entity> GetEntities_byPage(int page);

...我在存储库中执行分页逻辑,以便可以将其转换为数据源中的表达式。

我认为你的存储库应该返回一些相当定制的数据,而不仅仅是你的控制器必须清理的原始数据转储(通常是先将它们全部加载到内存中,YECK!)。

答案 3 :(得分:1)

我过去使用Repository模式的方式,就像持久性提供者和数据对象之间的一个非常薄的中介 - 每个存储库只包含非常通用的方法(即通常添加/更新/删除)。

我认为您的方案中的业务逻辑,即CreateFurBall()使用存储库,但不是由它公开的方法。