关于实体框架:NHibernate FetchMany是否超过两个表?

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