4

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

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

但是,我经常发现我需要将这些规则“推送”到 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)");
    }
}

然而,这对我来说似乎很丑陋,因为我们现在将关注点混合在一起。

另一种选择是使用 Linq-To-YourORM 解决方案,因为 LINQ 代码可以针对集合运行,也可以转换为 SQL。但我发现,除了最琐碎的场景之外,这种解决方案几乎不可能出现。

你做什么工作?

4

1 回答 1

4

我们将规范模式与实体框架一起使用。以下是我们的处理方式

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()} 
    }
}

然后你可以使用它来对抗 LINQ-to-Entities,比如

db.Customers.Where(canBorrowBooksSpec.Predicate);

在 LINQ-to-Objects 中

customerCollection.Where(canBorrowBooksSpec.Predicate.Compile());
于 2011-08-26T07:26:58.667 回答