Объединение кода C # и кода базы данных в Спецификации - PullRequest
4 голосов
/ 26 августа 2011

Иногда вам нужно определить некоторые бизнес-правила, и шаблон спецификации является полезным инструментом.Например:

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.Но я обнаружил, что такие решения редко возможны ни в чем, кроме самых тривиальных сценариев.

Что вы делаете?

1 Ответ

4 голосов
/ 26 августа 2011

Мы использовали шаблон спецификации с Entity Framework.Вот как мы подошли к нему

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