Is NHibernate FetchMany on more than two tables?

Considering this:

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 did not create duplicate objects for the answer, QuestionComment, AnswerComment, while NHibernate does.

 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(); } 

It also creates repeating objects (three levels deep, using three relationships):

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

It also creates duplicate objects (only at two levels, but with three relationships):

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

This does not create duplicate objects, however intensive loading is performed only for two levels and two relations, i.e. from the answer to the question. For comments on the question and comments for the answer, they are carried out by separate request.

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

If NHibernate can only do its work on two levels of FetchMany with only two relationships, why create ThenFetchMany (used on three levels, but has an error, has duplicate objects)? In fact, even FetchMany is also useless, if you want to use it also in three ways, it also creates duplicate objects.

Can the NHibernate team work hard to remove AfterFetchMany, since it cannot work properly?

There are no errors in my comparison, everything works correctly (i.e. does not create duplicate objects) when I deleted the selection strategies.

+6
source share
2 answers

to get unique do results

for Linq:

 .Distinct() 

for QueryOver

 .TrasformUsing(Transformers.DistinctRootentity) 

for criteria

 .SetResulttransformer(Transformers.DistinctRootentity) 

EDIT: Effectively, this is a shortcoming of NH, it produces Cartesian products, but it can be improved.

 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(); 

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

looks a little strange but needs to be done

+6
source

Try:

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

Source: https://habr.com/ru/post/894851/


All Articles