2012-03-22 66 views
6

在Web應用程序場景中,通常有兩個關於數據檢索的要求: 1.所有查詢都需要分頁選擇 2.用戶需要很多「過濾」查詢搜索人的名字和郵件和年齡) 3.排序查詢一些客戶方電網NHibernate在Web應用程序中的查詢策略

當然合併案暗示:過濾器,分頁其排序:)

這些要求可能會導致很多的疑問數據庫中的存儲庫方法,每個方法都有很多參數。 是否有任何常見模式給這個過程更動態的行爲(例如,根據域類屬性自動生成查詢)?

我知道存儲庫方法應該是乾淨和明確的。但是現在,當我向MVC視圖或某種排序的分頁表中添加一些過濾表單時,我覺得需要編寫大量的樣板代碼。

其他開發人員如何處理此類需求?

預先感謝您

回答

7

知識庫,generic repositories和暴露IQueryable的知識庫是一個激烈的爭論。

底線是一個通用或公開的存儲庫IQueryable根本不是一個真正的存儲庫,它只是數據層的抽象。

現在,這不是一件壞事,但不要稱之爲存儲庫,稱它是什麼。數據層抽象允許您快速將某些內容插入到讀取和寫入實體的UI中,而不會將數據層框架泄漏到UI中。你當然可以注入一個ISession並完成它。

public interface IRepository<T> {} 

public class NHibernateRepository<T> : IRepository<T> 
{ 
    private ISession session; 

    public NHibernateRepository(ISession session) 
    { 
     this.session = session; 
    } 

    T Get(object id) { return session.GetById<T>(id)); } 

    IQueryable<T> Query { get { return session.Query<T>(); } 
} 

new NHibernateRepository<Customer>(session).Query().Where(customer => customer.Name == Fred); 

但是,如果你想捕捉一些可重複使用的邏輯,並提供你的服務或UI和數據層之間的明確合同,然後,一個Repository做到了這一點。您可以定義明確的方法,說明正在檢索的內容以及方式。除了存儲庫,您只需要公開您的aggregate roots,這些是所有其他數據掛起的根實體,可能是CustomerSupplier。你不會嘗試直接到達地址,你會加載一個客戶然後查詢他的地址。您可以根據供應商提供的內容加載供應商列表,但不會通過「ItemsRepository」進行訪問。我的例子可能不是最好的,但它們會給你一個想法。

public class CustomerRepository 
{ 
    public Customer GetCustomerWithName(string name); 
} 

public class SupplierRepository 
{ 
    public IEnumerable<Supplier> GetSuppliersWhoStockItem(string itemName) 
} 

最後,如果你的你可能想看看CQRS冒險,這是一個大的主題在這裏概括,但有很多的例子。

首先是更快地實現,第二個讓你更清晰的可重用代碼,第三個給你你的UI層之間的分離,但需要更多的基礎工作。這取決於你需要和想要什麼,應該按照這個順序來解決。

+0

謝謝Bronumski ,我想我會結合使用:Web服務調用的定義明確的方法和額外的IQueryable接口來處理來自Web前端的通用查詢。 – mbue 2012-03-22 12:45:56

1

你可以讓你的庫提供一個IQueryable,讓ActionMethod弄清楚顯示的內容。例如:

public System.Linq.IQueryable<Models.MyModel> Query() 
    { 
     return mSession.Query<Models.MyModel>(); 
    } 
3

在我們的項目中,我們也使用了知識庫,每個實體都使用知識庫,但我不喜歡它。 當你用很多交互實體編寫複雜查詢時,它可能會遇到很多問題。 我認爲這將是對基本操作的一個通用庫,和所有查詢應該存在與查詢對象的圖案,像每次查詢單獨的類,但看看:

http://richarddingwall.name/2010/06/15/brownfield-cqrs-part-1-commands/

http://codebetter.com/gregyoung/2009/01/20/ddd-specification-or-query-object/

http://devlicio.us/blogs/casey/archive/2009/02/13/ddd-command-query-separation-as-an-architectural-concept.aspx

http://blog.jonathanoliver.com/2009/10/dddd-why-i-love-cqrs/

http://www.udidahan.com/2007/03/28/query-objects-vs-methods-on-a-repository/

3

您使用存儲庫枚舉聚合根。通常情況下,您的控制器可以使用聚合根目錄,您可以根據用戶需要過濾,排序等。

因此,我用什麼沿着已經提到的行庫。

然而,有時我需要,其中使用聚合根和/或儲存庫的一大堆要麼是痛苦的,低效的,或者是不可能的,以更復雜的規範,內工作。例如,您可能需要運行大型商業報告,或者執行批處理命令。

在這種情況下,我也定義了ICommand/IQuery,NH基地實施照顧管道的東西(就像一般的Repository一樣)。

什麼話,我要做的就是讓代表進行了規範合同,露出我可能需要幫助我建立所需要的參數的任何成員的接口。然後,我使用NH作爲主幹來實現該規範,使用任何最適合的技術(HQL語句,原始SQL,Criteria,QueryOver等等)完成規範。

下面是我的意思的一個粗略的例證。請注意,我使用任意ICommandProvider,這是一些根據需要創建新命令實例的對象(如果需要在一個操作中發出多個命令)。我將向IoC註冊我的命令,並讓提供者使用它來創建命令實例。在控制器

public interface ICommand 
{ 

} 

public interface ICommandProvider 
{ 
    TCommand Create<TCommand>() 
     where TCommand : ICommand; 

} 

public interface IQuery<TResult> : ICommand 
{ 
    TResult Execute(); 
} 

public class NhCommand : ICommand 
{ 
    // plumbing stuff here, like finding the current session 
} 

public class DelinquentAccountViewModel 
{ 
    public string AccountName { get; set; } 
    public decimal Amount { get; set; } 
} 

public interface IDelinquentAccountsQuery : IQuery<IEnumerable<DelinquentAccountViewModel>> 
{ 
    void AmountGreaterThan(decimal amount); 
    // you could define members for specifying sorting, etc. here 
} 

public class DelinquentAccountsQuery : NhCommand 
{ 
    public IEnumerable<DelinquentAccountViewModel> Execute() 
    { 
     // build HQL and execute results, resulting in a list of DelinquentAccountViewModels 
     // using _amountGreaterThan as a parameter 
     return null; 
    } 

    private Decimal _amountGreaterThan; 

    public void AmountGreaterThan(Decimal amount) 
    { 
     _amountGreaterThan = amount; 
    } 
} 

用法可能是這樣的:

public class DelinquentAccountsController : Controller 
{ 
    protected ICommandProvider CommandProvider { get; private set; } 

    public DelinquentAccountsController(ICommandProvider commandProvider) 
    { 
     CommandProvider = commandProvider; 
    } 

    public ActionResult Index(decimal amount) 
    { 
     var query = CommandProvider.Create<IDelinquentAccountsQuery>(); 
     query.AmountGreaterThan(amount); 
     return View(query.Execute()); 

    } 
} 

沒有說所有的數據訪問使用命令/查詢你不能這樣做,但它更多的工作比我更需要。我發現標準存儲庫方法(使用針對NHibernate的LINQ)處理我的應用程序需要的95%左右的數據訪問。

1

Imho orm已經足夠抽象了。最重要的是你不需要知識庫。你只需要抽象,如果你打算用某種設置即時更改orm。 Where,Skip,Take,OrderBy等是orm不可知的,可以通過公開IQueryable來使用。但是一些功能特定於orm(如fetch vs.包括)和那些做倉庫真難看(千萬方法或有600萬個參數法)

我通常只是做擴展方法

public static class QueryExtensions 
{ 
    public static IQueryable<T> Published(this IQueryable<T> pages) where T : IPage 
    { 
     return pages.Where(p => p.State == PageState.Public && p.Published <= DateTime.UtcNow); 
    } 
    public static IQueryable<T> By(this IQueryable<T> pages, User author) where T : IPage 
    { 
     return pages.Where(p => p.Author == author); 
    } 

    public static IEnumerable<Foo> AdvancedThing(this ISession session, string text) 
    { 
     // I get all the power of NHibernate :) 
     return session.CreateQuery("...").SetString("text", text).List<Foo>(); 
    } 
} 

,並直接在操作方法使用的Isession

var posts = session.Query<Post>().By(user).Published().FetchMany(p => p.Tags).ToList(); 
相關問題