2012-06-06 82 views
1

這是我寫的更復雜的HQL查詢之一。在這個容量下,我對HQL仍然很陌生,可以使用一些反饋。如何優化此Nhibernate HQL查詢?

有一件事我會在本地SQL做的是改變日期comarison東西來自單個查詢作爲表,即

FROM 
(
    SELECT MIN, MAX 
    FROM .. 
) T 

這裏的方法:

public IList<Order> GetOrdersBy(string referenceNumber = null, int? customerId = null, int? carrierId = null, DateTime? startDate = null, 
      DateTime? endDate = null, int? websiteId = null, OrderStatus? status = null) 
     { 


      var byStatusHql = 
      @" 
      select odor 
      from Order odor 
      join fetch odor._orderStatusLog statusLog 
      where 
      (:referenceNumber is null or odor.Quote.ReferenceNumber=:referenceNumber) and 
      (:customerId is null or odor.Quote.Customer.CustomerID=:customerId) and 
      (:carrierId is null or odor.Quote.Carrier.CarrierID=:carrierId) and 
      (:websiteId is null or odor.Quote.Customer.Website.WebsiteID=:websiteId) and 
      (
       :startDate is null or :startDate > 
       (select min(CreatedDate) from OrderStatusLog lg where lg in elements(odor._orderStatusLog)) 
      ) and 
      (
       :endDate is null or :endDate <= 
       (select max(CreatedDate) from OrderStatusLog lg where lg in elements(odor._orderStatusLog)) 
      ) and 
      (
       :status is null or :status = 
       (
        select Status from OrderStatusLog lg where lg in elements(odor._orderStatusLog) 
        and lg.OrderStatusLogID = (select max(OrderStatusLogID) from OrderStatusLog lgg where lgg in elements(odor._orderStatusLog)) 
       ) 

      ) 
      "; 

      var query = Session.CreateQuery(byStatusHql); 
      query.SetParameter("referenceNumber", referenceNumber) 
       .SetParameter("customerId", customerId) 
       .SetParameter("carrierId", carrierId) 
       .SetParameter("websiteId", websiteId) 
       .SetParameter("startDate", startDate) 
       .SetParameter("endDate", endDate) 
       .SetParameter("status", status) 
      ; 

      return query.List<Order>();    
     } 
+1

有沒有考慮過使用Criteria或QueryOver?它們在動態查詢中要好得多,您只需添加實際使用的過濾條件。 –

+1

我考慮過了,但是當事情變得更加複雜時,這兩者都非常複雜,閱讀和理解,imo。我完全得到linq,並且最初使用groupby編寫,但是我得到了一個N​​otImplemented錯誤。 –

回答

0

你的意思在性能或可讀性方面「優化」?

考慮到性能,我會使用Criteria或QueryOver僅添加實際使用的過濾器參數。 Criteria功能並不強大,在這種情況下,語法會更復雜,但動態組合查詢更容易。

您可以嘗試使用一個子查詢的日誌骨料:

and exists (
    select min(CreatedDate), max(CreatedDate), max(OrderStatusLogID) 
    from OrderStatusLog lg 
    where lg in elements(odor._orderStatusLog) 
    having 
     :startDate is null or :startDate > min(CreatedDate) 
     and :endDate is null or :endDate <= max(CreatedDate) 
     and :status is null or :status = (
     select lgg.Status from OrderStatusLog lgg 
     where lgg.id = max(OrderStatusLogID))) 

我不知道,如果它的所有工作。最後一個與狀態有關的條款可能太多了。

但是,它的表現不是很好,因爲當參數爲空時可以省略子查詢。我懷疑數據庫管理系統是否足夠聰明來優化它。

+0

瞭解可讀性和性能建議。感謝您的建議。我仍然需要您的更改中的CreatedDate屬性,我昨晚試過。我在Sqlite中的測試總是將這一部分留空,導致我相信它無法弄清楚。 我會喜歡使用Criteria或QueryOver,但由於缺乏對構造和時間限制的理解,我無法使其工作。我發佈到nhusers並沒有收到任何愛,所以走了我知道我可以工作。 –

+0

我想我錯過了CreatedDate部分,這是行不通的。我會刪除它。 –