我们一直在寻找一种很好的方法来查询我们的数据库,重点是易于开发,可读性和业务规则遵从性。
我在网上发现了两篇有趣的文章,它们描述了相似但略有不同的方法,一篇是使用查询对象和表达式,另一篇主要使用与业务相关的扩展方法,最终也使用了表达式。
- 查询对象方法
- 扩展方法方法
下面是一些示例代码,我们可以(在存储库中)用于这两种情况:
public IEnumerable<ControlOverview> GetRoutineControlOverviewsForTest(string testId, DateTime dateOfInterest)
{
var controlOverviewQuery = new ControlOverviewQuery()
.ForTest(testId)
.ForLotUsage(ControlLotUsageStatus.Routine)
.ForControlStatusAt(dateOfInterest)
.ForControlConfigurationAt(dateOfInterest)
.ForControlLotConfigurableAt(dateOfInterest);
return this.Context.ControlOverviews.Where(controlOverviewQuery.AsExpression());;
}
第二个案例:
public IEnumerable<ControlOverview> GetRoutineControlOverviewsForTest(string testId, DateTime dateOfInterest)
{
return this.Context.ControlOverviews.ForTest(testId)
.ForLotUsage(ControlLotUsageStatus.Routine)
.ForControlStatusAt(dateOfInterest)
.ForControlConfigurationAt(dateOfInterest)
.ForControlLotConfigurableAt(dateOfInterest);
}
如您所见,从开发人员的角度来看,这或多或少是相同的。可读性也是一样。唯一不同的是实现细节(扩展方法vs查询对象)在我的团队中,对于使用哪种方法存在分歧,我找不到一组好的论据(赞成/反对)来支持一种方法或另一种方法。
我个人更喜欢第一种方法(查询对象),因为我是面向对象的家伙,喜欢它使用的构建器模式,但为了不使用扩展方法,我找不到比这更好的论据。我非常希望你能给我一些见解。也许这只是编码偏好很难或者说根本不可能用一个强有力的参数
在我看来,这些是重要的优点
查询方法- 由于方法实际上是类方法,因此它们可以访问内部,特别是可以限制访问。因此,您可以强制开发人员使用查询对象,而不是自定义LINQ。这确保了一致性和可维护性,但降低了灵活性
- 您获得了使用多态性的灵活性。在您所链接的文章中,这并不是重点,但是一旦您开始使用不同的查询类实现(例如,使用不同模式 对不同来源的数据进行统一访问),它就可能变得很重要。
扩展方法
- 可以与接口一起使用。事实上,我最常使用扩展方法来实现接口的标准成员,我认为这是它们最有用的地方。然而,这只有在您有一些预定义的接口时才有意义,例如,在平台中已经可用,例如
IQueryable
。如果你使用的是你自己的类,你可以完全控制它,这一点是相当弱的。 - 简洁性略好(我知道,不是那么多,但我想说这很重要)
我确实更喜欢第一种方法,因为它不会隐藏有IQueryable<>
的事实(this.Context.ControlOverviews
不是通过调用其他方法链"隐藏"),所以如果你想链一个额外的.Where()
或额外的.Select()
,很明显你可以做到。