NHibernate的FetchMany在两个以上的表上是否坏了?



鉴于此:

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会。

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

这也会产生重复的对象(三层深度,使用三个关系):

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

这也会产生重复对象(仅两层深度,但使用三个关系):

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

这不会产生重复的对象,但是热切加载只针对两层深度和两个关系,即从Question到Answer。对于要提问的注释和要回答的注释,它们在单独的查询中执行。

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

如果NHibernate只能很好地完成两个级别的FetchMany只有两个关系,为什么要创建ThenFetchMany(在三个级别上使用,但有错误,有重复的对象)?事实上,即使FetchMany也没有用,如果你想在三个关系上使用它,它也会产生重复的对象。

NHibernate团队可以被打扰删除ThenFetchMany,因为它不能正常工作?

在我的映射中没有错误,当我删除抓取策略时,事情正常工作(即不产生重复对象)。

获取唯一结果

Linq:

.Distinct()
为QueryOver

.TrasformUsing(Transformers.DistinctRootentity)
为标准

.SetResulttransformer(Transformers.DistinctRootentity)

编辑:实际上这是NH的一个缺点,它会生成一个笛卡尔积,但这是可以改进的

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/eagerly-loading-entity-associations-efficiently-with-nhibernate

看起来有点奇怪,但应该是

尝试:

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

相关内容

最新更新