Is NHibernate FetchMany on more than two tables broken?
鉴于此:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 | 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; } } } |
实体框架没有为answer、questioncomment和answercomment生成重复的对象,而nhibernate没有。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 | 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(); } |
这也会生成重复的对象(三层深度,使用三个关系):
1 2 3 | query = query .FetchMany(x => x.Answers) .ThenFetchMany(x => x.Comments) |
这也会生成重复的对象(仅两层深度,但使用三个关系):
1 2 3 | query = query .FetchMany(x => x.Answers) .FetchMany(x => x.Comments); |
这不会产生重复的对象,但是热切的加载只针对两个层次的深度和两个关系,即从问题到答案。对于要提问的注释和要回答的注释,它们是在单独的查询上执行的。
1 2 | query = query .FetchMany(x => x.Answers); |
如果nHibernate只能在只有两个关系的情况下为两个级别的fetchmany做好它的工作,为什么还要创建fetchmany(用于三个级别,但有错误,有重复的对象)?事实上,即使fetchmany也没用,如果你想在三个关系上使用它,它也会产生重复的对象。
NHibernate团队是否会因为不能正常工作而费心移除fetchmany?
在我的映射中没有错误,当我删除提取策略时,事情正常工作(即不产生重复的对象)。
要获得独特的结果,请执行以下操作
对于LINQ:
1 | .Distinct() |
用于查询
1 | .TrasformUsing(Transformers.DistinctRootentity) |
对于标准
1 | .SetResulttransformer(Transformers.DistinctRootentity) |
编辑:很有效,这是NH的一个缺点,它会发布一个笛卡尔积,但这可以改进。
1 2 3 4 5 6 7 8 9 | 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(); |
请参阅http://ayende.com/blog/4367/chengly-loading-entity-associations-effective-with-nhibernate
看起来有点奇怪,但应该是这样的
尝试:
1 | query.QueryOptions.RegisterCustomAction(c => c.SetResultTransformer(new DistinctRootEntityResultTransformer())); |