存储库模式困境:冗余查询与数据库往返

时间:2018-07-10 20:24:43

标签: sql design-patterns asp.net-core entity-framework-core repository-pattern

这种情况:

说我有一个存在两种实体类型的应用程序:

  • Company
  • Person

此外,Person通过Company引用了Person.employer,这表示一个人受雇的公司。

在我的应用程序中,我正在使用存储库将数据库操作与与业务模型相关的服务分开:我有一个PersonRepository.findOne(id)方法来检索Person实体和一个使用CompanyRepository.findOne(id)方法来检索Company。到目前为止一切顺利。

这是一个难题:

现在,如果我致电PersonRepository.findOne(id)来获取Person实体,则还需要通过Company属性内联包含一个完全解析的Person.employer,并且这就是我面临的难题,即两个实现选项都不是最优的实现选项:

选项A) 整个存储库中的冗余查询,但数据库往返次数较少:

PersonRepository中,我可以建立一个查询,该查询可以选择用户,也可以在单个查询中选择公司–但是,公司的select表达式很困难,并且为了实现该目的而包含了一些联接正确组装公司。 CompanyRepository已经包含了对select公司的逻辑,将其重写在UserRepository中是多余的。因此,理想情况下,我只希望CompanyRepository照顾公司选择逻辑,以避免必须在两个存储库中重复编码相同的查询表达式。

选项B): 没有查询代码冗余但以额外的数据库往返和存储依赖为代价的关注点分离:

PersonRepository内,我可以引用CompanyRepository来处理Company对象,然后将该实体添加到{{ 1}}。这样,我保留了查询封装在Person.employer内的公司的逻辑,通过该公司可以实现关注点的清晰分离。这样做的缺点是,由于两个存储库执行两个单独的查询,因此我需要进行额外的数据库往返行程。

所以一般来说,解决这个难题的首选方法是什么?

此外,在ASP.NET Core和EF Core中处理这种情况的首选方法是什么?

编辑:为避免基于观点的答案,我想强调:我并不是在寻找上述两种选择的利弊,而是力求将两者的优点融为一体的解决方案选项–因为也许我在这里列出的两个选项走错了路。我也很满意,可以解释为什么没有这种综合解决方案,所以我可以睡得更好并继续前进。

1 个答案:

答案 0 :(得分:1)

要通过ID检索公司,您需要读取Person的数据,并从中获取公司ID。因此,如果您希望将公司查询逻辑放在一个地方,那么最终将导致两次往返-一次获取公司ID(以及Person拥有的所有其他属性),再一次获取公司本身。

您可以重用从DbDataReader组成公司的代码,但是person + company查询可能需要将“ {forward””的人的companyId加入到Company查询中,因此这些查询的文本必须不同。

如果将查询逻辑移到存储过程中,则可以同时使用两种方法(一次往返,没有重复查询)。这样,您的person_sp将执行company_sp,并返回所有相关数据。如有必要,您的C#代码将能够使用reader.NextResult()来收集多部分结果集。现在,公司ID的“移交”将在RDBMS端进行,从而消除了第二次往返。但是,这种方法将需要在RDBMS端维护存储过程,从而有效地将某些存储库逻辑从C#代码库中运送出去。