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

问题描述 投票:11回答:2

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

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的更简单格式。我的问题是,您认为图的这种深度导航是一种很好的做法,还是您将对图下方的对象的检索抽象为存储库?

c# asp.net asp.net-mvc entity-framework repository-pattern
2个回答
13
投票

我认为,这里的重要问题是-您是否已禁用LazyLoading?

如果未执行任何操作,则默认情况下处于启用状态。

因此,当您执行Person.Pathway.Country时,您将调用另一个对数据库服务器的调用(除非您正在进行急切的加载,我将在稍后说明)。考虑到您正在使用存储库模式-这是一个很大的禁忌。控制器不应导致直接调用数据库服务器。

一旦[[C发起人从M odel接收到信息,就应该准备好进行投影(如有必要),并传递到V iew,而不要去返回到M odel。

这就是为什么在我们的实现(我们也使用存储库,ef4和工作单元)中,我们

禁用延迟加载

,并允许通过我们的服务层传递导航属性(一系列“包含“语句,通过枚举和扩展方法使它更甜美。]我们然后

eager-load

这些属性,因为控制器需要它们。但是重要的是,控制器必须明确请求它们。基本上告诉用户界面-“嘿,您仅获得有关该实体的核心信息。如果您需要其他任何东西,请索取。”

我们还有一个

Service Layer

在控制器和存储库之间进行中介(我们的存储库返回IQueryable<T>)。这使存储库摆脱了处理复杂关联的业务。急切的加载是在服务层(以及分页之类的)完成的。服务层的好处很简单-耦合更松散。存储库仅处理“添加”,“删除”,“查找”(返回IQueryable),工作单元处理DC的“更新”,以及变更提交,服务层将实体的实现具体化为具体集合。

这是一种类似于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中的地方。再说一遍,这取决于控制器来决定它想要多少信息。

同样,都是关于松散耦合的。您的控制器应尽可能简化,而不必担心复杂的关联。

关于

多少个存储库

,这是一个备受争议的话题。有些人喜欢每个实体一个(如果您问我,那就太过分了),有些喜欢根据功能进行分组(在功能上很有意义,更易于使用),但是每个聚合根只有一个。我只能在您的模型上猜测“人”应该是我可以看到的唯一聚合根。

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

再次-也许如果您将EDMX设置为上限,我们可以为您提供更多提示。

根据问题的范围,这个答案可能会扩展得太远,但是我想我会提供一个深入的答案,因为我们现在正在处理这种确切的情况。

HTH。


3
投票
取决于您一次使用的信息量。

例如,如果您只想获取某人的国家/地区名称(person.Pathway.Country.Name),那么为数据库中的所有其他对象添加水合物有什么意义?

[当我只需要一小部分数据时,我倾向于只提取我将要使用的数据。换句话说,我将投影到一个匿名类型(如果我

必须有一个,则是一个特殊的具体类型)。

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

尽管我一开始就说过,没有一个适合所有规则的大小,但是我要说您很少需要大量的信息。

© www.soinside.com 2019 - 2024. All rights reserved.