使用实体框架的存储库模式检索复杂对象图的模式

时间:2010-10-13 09:34:01

标签: asp.net asp.net-mvc entity-framework repository-pattern

我们有一个ASP.NET MVC站点,它使用Entity Framework抽象与Repository和UnitOfWork模式。我想知道的是其他人如何使用这些模式实现复杂对象图的导航。让我举一个控制器的例子:

var model = new EligibilityViewModel
   {
       Country = person.Pathway.Country.Name,
       Pathway = person.Pathway.Name,
       Answers = person.Answers.ToList(),
       ScoreResult = new ScoreResult(person.Score.Value),
       DpaText = person.Pathway.Country.Legal.DPA.Description,
       DpaQuestions = person.Pathway.Country.Legal.DPA.Questions,
       Terms = person.Pathway.Country.Legal.Terms,
       HowHearAboutUsOptions = person.Pathway.Referrers
   };

这是一个注册过程,几乎所有东西都悬挂在POCO类Person上。在这种情况下,我们通过注册过程缓存此人。我现在开始实现注册过程的后半部分,这需要访问对象图中更深层次的数据。具体而言,DPA数据在国内法律中徘徊。

上面的代码只是将模型信息映射为ViewModel的更简单格式。我的问题是你是否认为图形良好实践的这种相当深的导航,或者你是否会将图形中的对象检索抽象到存储库中?

2 个答案:

答案 0 :(得分:14)

在我看来,这里的重要问题是 - 您是否禁用了LazyLoading?

如果你还没有做任何事情,那么它默认开启。

所以,当你执行Person.Pathway.Country时,你将调用另一个对数据库服务器的调用(除非你正在进行急切加载,我将在稍后讨论)。鉴于您正在使用存储库模式 - 这是一个很大的禁忌。控制器不应该直接调用数据库服务器。

一旦 C ontroller收到来自 M odel的信息,就应该准备进行投影(如有必要),并传递到 V iew,不要返回 M odel。

这就是为什么在我们的实现中(我们还使用存储库,ef4和工作单元),我们禁用延迟加载,并允许通过我们的服务层传递导航属性(a一系列“包含”声明,通过枚举和扩展方法更加甜美。)

然后我们急切加载这些属性,因为控制器需要它们。但重要的是, Controller必须明确请求它们。

这基本上告诉用户界面 - “嘿,你只获得有关这个实体的核心信息。如果你还需要其他任何东西,请提出它。”

我们还有一个服务层在控制器和存储库之间进行调解(我们的存储库返回IQueryable<T>)。这允许存储库摆脱处理复杂关联的业务。急切的加载是在服务层完成的(以及分页等)。

服务层的好处很简单 - 更松散的耦合。存储库仅处理Add,Remove,Find(返回IQueryable),Unit of Work处理DC的“newing”,以及Commiting of changes,Service层处理实体的具体化为具体集合。

这是一个很好的1-1堆栈式方法:

personService.FindSingle(1, "Addresses") // Controller calls service
 |
 --- Person FindSingle(int id, string[] includes) // Service Interface
      |
       --- return personRepository.Find().WithIncludes(includes).WithId(id); // Service calls Repository, adds on "filter" extension methods
           |
            --- IQueryable<T> Find() // Repository
                |
                 -- return db.Persons; // return's IQueryable of Persons (deferred exec)

我们还没有达到MVC层(我们正在做TDD),但是服务层可能是另一个你可以将核心实体保存到ViewModels中的地方。再一次 - 由控制器来决定它想要多少信息。

同样,这是松散耦合的全部。您的控制器应该尽可能简单,不必担心复杂的关联。

多少个存储库而言,这是一个备受争议的主题。有些人喜欢每个实体有一个(如果你问我就过度杀戮),有些人喜欢根据功能进行分组(在功能方面有意义,更容易使用),但是每个聚合根都有一个。

我只能猜测你的模型“人”应该是我能看到的唯一聚合根。

因此,当路径始终与特定“人员”相关联时,使用另一个存储库来处理“路径”没有多大意义。 Person存储库应该处理这个问题。

再一次 - 也许如果你屏蔽了你的EDMX,我们可以给你更多的提示。

根据问题的范围,这个答案可能会有点过分,但我认为我会给出一个深入的答案,因为我们正在处理这个确切的情况。

HTH。

答案 1 :(得分:3)

这取决于您在任何时间使用的信息量。

例如,如果您只想获取某个人的国家名称(person.Pathway.Country.Name),那么从数据库中保护所有其他对象的重点是什么?

当我只需要一小部分数据时,我倾向于提取出我将要使用的内容。换句话说,如果我必须有一个,我会投射到一个匿名类型(或特制的具体类型)。

每次要访问某些属性时,拔出整个对象以及与该对象相关的所有内容并不是一个好主意。如果你每回发一次,甚至多次这样做,该怎么办?通过这样做,您可能会在短期内让生活更轻松,但代价是您的应用程序长期可扩展性较差。

正如我在开始时所说的那样,没有一个适合所有规则,但我会说你很少需要补充那么多信息。