在一个规范中结合c#代码和数据库代码

本文关键字:代码 结合 数据库 范中 一个 | 更新日期: 2023-09-27 18:06:38

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

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。但我发现,除了在最琐碎的场景中,这种解决方案很少是可行的。

你是做什么的?

在一个规范中结合c#代码和数据库代码

我们使用实体框架的规范模式。这是我们如何处理它的

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