2013-08-20 54 views
5

Tôi đang sử dụng NHibernate 3.3.1 với FluentNhibernate 1.3 cho Lớp dữ liệu.NHibernate: Làm thế nào để háo hức tìm nạp thực thể phụ với một bộ lọc trên thực thể phụ thông qua một truy vấn sql mà không lười biếng?

tôi có các đối tượng sau:

enter image description here

Database Diagram: enter image description here

Tôi cần một phương pháp mà được các Sản phẩm theo MediaCategory của Medias của sản phẩm. Tôi muốn NHibernate chỉ gửi một truy vấn đến db và tìm nạp tất cả các thuộc tính phụ của sản phẩm.

Tôi muốn NHibernate gửi một truy vấn như thế này:

declare @mediaCategoryId int = 13 
select * 
from Product p 
inner join Media m on m.ProductId=p.Id 
inner join MediaCategoryMedia mcm on mcm.MediaId=m.Id 
inner join MediaCategory mc on mc.Id=mcm.MediaCategoryId 
left join ProductSeller ps on ps.ProductId=p.Id 
left join Seller s on ps.SellerId=s.Id 
where [email protected] 

Tôi đã thử các tùy chọn sau đây để giải quyết thách thức này;

  1. phiên .QueryOver<ProductEntity>() ...
    Tôi đã thử Inner.JoinQueryOver<..>().Fetch.Eager ... nhưng tôi không thể lấy tất cả các đối tượng phụ.

  2. session.CreateCriteria<ProductEntity>().SetFetchMode("",FetchMode.Eager) ...
    Trong trường hợp này tải chậm hoạt động và tôi không muốn tải xuống. Nếu tôi vô hiệu hóa lazyload từ ánh xạ NH gửi rất nhiều truy vấn .. những gì tôi muốn là mong muốn tải với một truy vấn duy nhất mà lấy tất cả các thực thể phụ.

  3. session.Query<ProductEntity>().FetchMany(p=>p.MediaList).ThenFetchMany(m=>m.SellerList) ...
    Tôi không thể tạo bí danh để vượt qua bộ lọc mediaCategoryId trong trường hợp này. Thay vào đó, tôi đã sử dụng .Where(x=>x.MediaList.Any(m=>m.CategoryList.Any(...))) và truy vấn được tạo cũng không tối ưu.

  4. (từ p trong session.Query < ProductEntity>()
    từ m p.MediaList
    từ c trong m.MediaCategoryList
    nơi c.Id == 23
    chọn p) .Fetch (x => x.MediaList);

    này đã không làm việc như tôi mong muốn, quá ..

  5. var [email protected]"select p from ProductEntity as p join fetch p.MediaList as m join fetch m.MediaCategoryList as mc left join fetch p.SellerList as s where mc.Id=:catId ";
    này làm việc với "join fetch" trong HQL.
    Tôi cần thực hành tốt nhất của trường hợp này, tuy nhiên Hql là vua.

    Chúng tôi có thể xử lý trường hợp này với session.Query<>() hoặc session.CreateCriteria, hoặc QueryOver?

+0

Bạn cũng cần 'Media.MediaCategoryList' để trở về dân cư? Hay bạn chỉ quan tâm đến 'Product.MediaList' và' Product.SellerList'? –

Trả lời

6

Đối với một bản dịch trực tiếp truy vấn của bạn ...

Media mediaAlias = null; 
MediaCategory categoryAlias = null; 

return session.QueryOver<Product>() 
    .JoinAlias(x => x.Medias,() => mediaAlias) 
    .JoinAlias(() => mediaAlias.Categories,() => categoryAlias) 
    .Fetch(x => x.Sellers).Eager 
    .Where(() => categoryAlias.Id == mediaCategoryId) 
    .List(); 

JoinAlias làm một bên tham gia theo mặc định và Fetch(...).Eager làm một trái bên ngoài tham gia. JoinAlias cho phép chúng tôi đào sâu qua Phương tiện theo các danh mục và cũng tìm nạp dữ liệu một cách háo hức.

Lưu ý rằng có một sản phẩm Descartes giữa Người bán và Phương tiện trong truy vấn này.Nếu có 20 Phương tiện và 20 Người bán trên một Sản phẩm, thì truy vấn này sẽ trả lại 20 * 20 = 400 hàng, điều này không lý tưởng cho hiệu suất. Bạn có thể giải quyết vấn đề này bằng cách tách tìm nạp Phương tiện và Người bán tìm nạp các truy vấn riêng lẻ, nhưng gộp chúng lại với nhau trong một chuyến đi khứ hồi tới cơ sở dữ liệu bằng cách sử dụng Future(), có nghĩa là truy vấn sẽ trả về 20 + 20 = 40 hàng. Tốt hơn nhiều.

Ngoài ra, truy vấn này sẽ không trả lại tất cả các danh mục được liên kết với Phương tiện. Nếu bạn cần điều này, thì bạn nên áp dụng ràng buộc mediaCategoryId trong truy vấn phụ Hiện có.

+1

Tạo hai truy vấn với tương lai là câu trả lời hay nhất ở đây nếu bạn cần phân trang. Đây là một blog tôi luôn đề cập đến hai. http://ayende.com/blog/4367/eagerly-loading-entity-associations-efficiently-with-nhibernate – Rippo

+0

Tuy nhiên, giải pháp này tốt, nếu mọi phương tiện có một đứa con khác như MediaSubitems và tôi muốn tìm nạp chúng một cách háo hức trong cùng một truy vấn. Với phương thức Fetch (x => x ...), tôi chỉ có thể chỉ định các thực thể con của Sản phẩm được tìm nạp háo hức, làm thế nào tôi có thể chỉ định mọi MediaSubitems của Media được tải xuống háo hức? – mecek

+0

Tôi * chỉ * trả lời một câu hỏi khác có cùng một điều: http://stackoverflow.com/a/18478819/221708. Để háo hức tìm MediaSubitems, sử dụng 'JoinAlias ​​(() => mediaAlias.SubItems,() => mediaSubItemAlias, JoinType.LeftOuterJoin)' thay vì 'Tìm nạp'. –