2011-08-11 25 views
6

Với này:NHibernate FetchMany có nhiều hơn hai bảng bị hỏng không?

namespace TheEntities 
{ 
    [DataContract(IsReference=true)]  
    public class Question 
    { 
     [DataMember] public virtual int QuestionId { get; set; } 
     [DataMember] public virtual string Text { get; set; } 
     [DataMember] public virtual string Poster { get; set; } 

     [DataMember] public virtual IList<QuestionComment> Comments { get; set; } 
     [DataMember] public virtual IList<Answer> Answers{ get; set; } 



     [DataMember] public virtual byte[] RowVersion { get; set; } 
    } 

    [DataContract] 
    public class QuestionComment 
    { 
     [DataMember] public virtual Question Question { get; set; }   

     [DataMember] public virtual int QuestionCommentId { get; set; } 
     [DataMember] public virtual string Text { get; set; } 
     [DataMember] public virtual string Poster { get; set; } 
    } 


    [DataContract(IsReference = true)] 
    public class Answer 
    { 
     [DataMember] public virtual Question Question { get; set; } 

     [DataMember] public virtual int AnswerId { get; set; } 
     [DataMember] public virtual string Text { get; set; } 
     [DataMember] public virtual string Poster { get; set; } 

     [DataMember] public virtual IList<AnswerComment> Comments { get; set; } 

    } 

    [DataContract] 
    public class AnswerComment 
    { 
     [DataMember] public virtual Answer Answer { get; set; } 

     [DataMember] public virtual int AnswerCommentId { get; set; } 
     [DataMember] public virtual string Text { get; set; } 
     [DataMember] public virtual string Poster { get; set; } 
    } 

} 

Entity Framework đã không tạo ra đối tượng trùng lặp cho trả lời, QuestionComment, AnswerComment khi NHibernate không.

public Question OpenQuestion(int id) 
{ 
    var repo = QuestionRepository; 

    var query = repo.All.Where(y => y.QuestionId == id); 

    if (QuestionRepository.GetType() == typeof(EfRepository<Question>)) 
    {     
     query = query 
       .Include("Answers") 
        .Include("Answers.Comments") 
       .Include("Comments"); 

     return query.Single(); 
    } 
    else if (QuestionRepository.GetType() == typeof(NhRepository<Question>)) 
    {     
     // kinda sad, produces duplicate objects 
     query = query 
       .FetchMany(x => x.Answers) 
        .ThenFetchMany(x => x.Comments) 
       .FetchMany(x => x.Comments); 
    } 
    else 
     throw new Exception("Something unsupported"); 

    return query.Single(); 
} 

cũng Điều này tạo ra đối tượng trùng lặp (ba cấp độ sâu, sử dụng ba mối quan hệ):

query = query 
    .FetchMany(x => x.Answers) 
    .ThenFetchMany(x => x.Comments) 

này cũng tạo ra đối tượng trùng lặp (hai cấp độ sâu mà thôi, nhưng sử dụng ba mối quan hệ):

query = query 
    .FetchMany(x => x.Answers) 
    .FetchMany(x => x.Comments); 

Điều này không tạo ra các đối tượng trùng lặp, tuy nhiên tải mong muốn chỉ dành cho hai cấp độ sâu và hai quan hệ, tức là từ Câu hỏi đến Trả lời. Đối với nhận xét cho câu hỏi và nhận xét để trả lời, chúng được thực hiện trên truy vấn riêng biệt.

query = query 
    .FetchMany(x => x.Answers); 

Nếu NHibernate chỉ có thể làm công việc của mình cũng cho hai cấp độ FetchMany chỉ với hai mối quan hệ mà thôi, tại sao bận tâm tạo ThenFetchMany (sử dụng trên ba cấp độ, nhưng có lỗi, có đối tượng trùng lặp)? Trong thực tế, ngay cả FetchMany cũng vô dụng nếu bạn muốn sử dụng nó trên ba mối quan hệ, nó cũng tạo ra các đối tượng trùng lặp.

Nhóm NHibernate có thể bị làm phiền để xóa ThenFetchMany vì nó không hoạt động đúng không?

Không có lỗi trong ánh xạ của tôi, mọi thứ đang hoạt động đúng cách (tức là không tạo ra các đối tượng trùng lặp) khi tôi xóa các chiến lược tìm nạp.

+0

bạn có thể làm những gì bạn muốn - nối thêm '.TrasformUsing (Transformers.DistinctRootentity)'. điều này là khó chịu chắc chắn. – Firo

+0

Chỉ có trên QueryOver, tôi đang sử dụng LINQ (IQueryable) của NH. Phương pháp mở rộng NH Linq tương đương với '.TransformUsing' là gì? –

+0

Điều này là do Entity Framework tạo một truy vấn bằng cách sử dụng một số UNION trong khi NHibernate thực hiện JOIN. JOIN gây ra các sản phẩm Descartes, do đó các thực thể trùng lặp. Chiến lược của EF tốt hơn trong trường hợp này bởi vì nó cho phép nhận được nhiều thông tin trong một truy vấn. – Sebazzz

Trả lời

6

để có được kết quả độc đáo làm

cho LINQ:

.Distinct() 

cho QueryOver

.TrasformUsing(Transformers.DistinctRootentity) 

cho Tiêu chuẩn

.SetResulttransformer(Transformers.DistinctRootentity) 

EDIT: effectivly đây là một thiếu sót của NH, nó sẽ phát hành một sản phẩm Descartes, nhưng điều này có thể được cải thiện

repo.All.Where(y => y.QuestionId == id) 
     .FetchMany(x => x.Answers) 
      .ThenFetchMany(x => x.Comments) 
     .Future() 

query = repo.All.Where(y => y.QuestionId == id) 
     .FetchMany(x => x.Comments) 

var result = query.AsEnumerable().Single(); 

thấy http://ayende.com/blog/4367/eagerly-loading-entity-associations-efficiently-with-nhibernate

nó trông hơi lạ, nhưng nên làm

0

Hãy thử:

query.QueryOptions.RegisterCustomAction(c => c.SetResultTransformer(new DistinctRootEntityResultTransformer())); 
+0

Chỉ khả dụng trên NH 2.0 Linq. Trên NH 3.0 LINQ nó thiếu –

+0

LINQ không bị thiếu trong NH3.0. Nó có nhà cung cấp LINQ riêng. Bạn truy cập nó qua .Query. Bạn có thể sử dụng Transformer trên QueryOver. Tuy nhiên, bạn không bao giờ nên sử dụng FetchMany nhiều lần trên một truy vấn. – Phill

+0

Vâng tôi biết rằng, NHibernate 3 có LINQ hỗ trợ, nó có thể truy cập thông qua .Quer , trên LINQ 2, nó là trên .Linq . Trong thực tế kể từ khi tôi bắt đầu sử dụng NH, tôi chỉ làm các truy vấn thông qua HQL và LINQ (làm việc độc quyền về điều này bây giờ, không giống như chuỗi ma thuật HQL). Tôi chỉ cần đặt '.Query ' vào thuộc tính 'All' của giao diện kho lưu trữ của tôi. Những gì tôi có nghĩa là 'Trên NH 3.0 Linq, nó là mất tích', tôi chỉ quên đặt một dấu phẩy giữa từ ** LINQ ** và ** nó ** ;-) ** Nó **, là:' QueryOptions .RegisterCustomAction' –

Các vấn đề liên quan