2011-08-26 36 views
3

有時您需要定義一些業務規則,並且規範模式是一個有用的工具。例如:在規範中組合C#代碼和數據庫代碼

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

我們在實體框架中使用了規範模式。下面是我們如何走近它

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到實體,如

db.Customers.Where(canBorrowBooksSpec.Predicate); 

在LINQ到對象,如

customerCollection.Where(canBorrowBooksSpec.Predicate.Compile()); 
+0

基本上,你應該有一個linq規範等價。 – Neelesh

+0

好的,只要您的ORM可以處理所需的LINQ規範,就可以。我想這取決於ORM,但這可能很難。 – cbp