在规范中组合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());