【问题标题】:Combining C# code and database code in a Specification在规范中组合 C# 代码和数据库代码
【发布时间】:2011-08-26 06:28:00
【问题描述】:

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

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# specification-pattern


【解决方案1】:

我们在实体框架中使用了规范模式。以下是我们的处理方式

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

【讨论】:

  • 基本上,你应该有一个 linq 规范等价。
  • 好的,是的,只要您的 ORM 可以处理所需的 LINQ 规范,它就可以工作。我想这取决于 ORM,但这可能很难。
猜你喜欢
  • 2018-09-22
  • 1970-01-01
  • 2014-06-09
  • 1970-01-01
  • 1970-01-01
  • 2013-01-22
  • 1970-01-01
  • 1970-01-01
  • 2013-05-31
相关资源
最近更新 更多