cbp*_*cbp 5 c# specification-pattern
有时您需要定义一些业务规则,规范模式是一个有用的工具。例如:
public class CanBorrowBooksSpec : ISpecification<Customer>
{
public bool Satisfies(Customer customer)
{
return customer.HasLibraryCard
&& !customer.UnpaidFines.Any();
}
}
Run Code Online (Sandbox Code Playgroud)
然而,我经常发现我需要将这些规则“推送”到 SQL 中以提高性能或满足记录分页列表之类的要求。
然后,我必须为规则编写代码两次,一次使用 CLR 代码,一次使用 SQL(或 ORM 语言)。
您如何组织这样的代码?
最好将代码放在同一个类中。这样,如果开发人员正在更新业务规则,他们忘记更新两组代码的可能性就较小。例如:
public class CanBorrowBooksSpec : ISpecification<Customer>
{
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)");
}
}
Run Code Online (Sandbox Code Playgroud)
然而,这对我来说似乎很难看,因为我们现在将担忧混合在一起。
另一种替代方案是使用 Linq-To-YourORM 解决方案,因为 LINQ 代码可以针对集合运行,也可以转换为 SQL。但我发现,除了最琐碎的场景之外,这种解决方案几乎不可能实现。
你做什么工作?
我们将规范模式与实体框架一起使用。我们是这样处理的
public interface ISpecification<TEntity>
{
Expression<Func<TEntity, bool>> Predicate { get; }
}
public class CanBorrowBooksSpec : ISpecification<Customer>
{
Expression<Func<Customer, bool>> Predicate
{
get{ return customer => customer.HasLibraryCard
&& !customer.UnpaidFines.Any()}
}
}
Run Code Online (Sandbox Code Playgroud)
然后你可以将它用于 LINQ-to-Entities,例如
db.Customers.Where(canBorrowBooksSpec.Predicate);
Run Code Online (Sandbox Code Playgroud)
在 LINQ 到对象中,例如
customerCollection.Where(canBorrowBooksSpec.Predicate.Compile());
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
4508 次 |
| 最近记录: |