NHibernate FetchMany на более чем двух столах сломан? - PullRequest
6 голосов
/ 11 августа 2011

Учитывая это:

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 не создавал дубликаты объектов для ответа, вопроса, ответа, ответа, в то время как 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);

Это не приводит к дублированию объектов, однако энергичная загрузка предназначена только для двух уровней и двух отношений, то есть от вопроса к ответу. Для комментариев к вопросу и комментариев для ответа они выполняются по отдельному запросу.

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

Если NHibernate может хорошо выполнять свою работу только для двух уровней FetchMany только с двумя отношениями, зачем беспокоиться о создании ThenFetchMany (используется на трех уровнях, но имеет ошибку, содержит дубликаты объектов)? На самом деле, даже FetchMany также бесполезен, если вы хотите использовать его и для трех отношений, он также создает дубликаты объектов.

Может ли команда NHibernate позаботиться об удалении ThenFetchMany, поскольку она не может работать должным образом?

Там нет ошибки в моем отображении, все работает правильно (то есть не создает дубликаты объектов), когда я удалил стратегии извлечения.

Ответы [ 2 ]

6 голосов
/ 12 августа 2011

для получения уникальных результатов сделайте

для 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

выглядит немного странно, но стоит сделать

0 голосов
/ 12 августа 2011

Попробуйте:

    query.QueryOptions.RegisterCustomAction(c => c.SetResultTransformer(new DistinctRootEntityResultTransformer()));
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...