在规范中组合C#代码和数据库代码

有时您需要定义一些业务规则,而规范模式是一个有用的工具。 例如:

public class CanBorrowBooksSpec : ISpecification { public bool Satisfies(Customer customer) { return customer.HasLibraryCard && !customer.UnpaidFines.Any(); } } 

但是,我经常发现我需要将这些规则“推送”到SQL中以提高性能或满足分页记录列表等内容。

然后我不得不为规则编写代码两次,一次在CLR代码中,一次在SQL(或ORM语言)中。

你如何组织这样的代码?

如果代码在同一个类中保存在一起似乎是最好的。 这样,如果开发人员更新业务规则,他们忘记更新两组代码的可能性就会降低。 例如:

 public class CanBorrowBooksSpec : ISpecification { public bool Satisfies(Customer customer) { return customer.HasLibraryCard && !customer.UnpaidFines.Any(); } public void AddSql(StringBuilder sql) { sql.Append(@"customer.HasLibraryCard AND NOT EXISTS (SELECT Id FROM CustomerUnpaidFines WHERE CustomerId = customer.Id)"); } } 

然而,这对我来说似乎很难看,因为我们现在正在将问题混合在一起。

另一种选择是使用Linq-To-YourORM解决方案,因为LINQ代码可以针对集合运行,也可以转换为SQL。 但是我发现除了最微不足道的场景之外,很少有这样的解决方案。

你是做什么?

我们使用了entity framework的规范模式。 以下是我们如何处理它

 public interface ISpecification { Expression> Predicate { get; } } public class CanBorrowBooksSpec : ISpecification { Expression> Predicate { get{ return customer => customer.HasLibraryCard && !customer.UnpaidFines.Any()} } } 

然后你可以使用它来对抗LINQ到实体

 db.Customers.Where(canBorrowBooksSpec.Predicate); 

在LINQ-to-Objects之类的

 customerCollection.Where(canBorrowBooksSpec.Predicate.Compile());