быстрая загрузка многоуровневых дочерних объектов в NHibernate вызывает проблему дублирования

#nhibernate #nhibernate-criteria

#nhibernate #nhibernate-критерии

Вопрос:

у меня есть класс модели, который содержит некоторые изображения и некоторые функции :

 public class Model
{
    public int ModelId { get; set; }
    public string ModelName { get; set; }
    public virtual IList<Feature> ModelFeatures { get; set; }
    public virtual IList<ModelImage> ModelImages { get; set; }
}

public class ModelImage
{
    public virtual int ModelImageId { get; set; }
    public virtual Model Model { get; set; }
    public virtual Resource Image { get; set; }
    public virtual int DisplayOrder { get; set; }
}

public class Feature
{
    public virtual int FeatureId { get; set; }
    public virtual string Title { get; set; }
    public virtual string Text { get; set; }
}
  

теперь я хочу с готовностью загружать изображения модели и функции модели, которые я использую :

 item = session.CreateCriteria<Model>()
       .Add(NHibernate.Criterion.Expression.Where<Model>(o => o.ModelId == id))
       .SetFetchMode("ModelImages", NHibernate.FetchMode.Eager)
       .SetFetchMode("ModelImages.Image", NHibernate.FetchMode.Eager)
       .SetFetchMode("ModelFeatures", NHibernate.FetchMode.Eager)
       .SetResultTransformer(NHibernate.Transform.Transformers.DistinctRootEntity)
       .UniqueResult<Model>();
  

но результат содержит повторяющиеся ModelImage и ModelFeatures,
как я мог бы применить преобразователь результатов, такой как DistinctRoot, к этим дочерним коллекциям?

Спасибо

Ответ №1:

Я бы разделил запрос на две части:

 item = session.CreateCriteria<Model>()
   .Add(NHibernate.Criterion.Expression.Where<Model>(o => o.ModelId == id))
   .SetFetchMode("ModelFeatures", NHibernate.FetchMode.Eager)
   .UniqueResult<Model>();

session.CreateCriteria<Model>()
   .Add(NHibernate.Criterion.Expression.Where<Model>(o => o.ModelId == id))
   .SetFetchMode("ModelImages", NHibernate.FetchMode.Eager)
   .SetFetchMode("ModelImages.Image", NHibernate.FetchMode.Eager)
   .UniqueResult<Model>();
  

Второй запрос просто продолжает заполнять коллекции объекта «item», возвращаемого из первого запроса, поэтому нет необходимости использовать возвращаемое значение из второго запроса.

Если вы хотите, чтобы эти два запроса выполнялись за один цикл, вы можете использовать Future () вместо uniqueResult(), а затем использовать item.Value для фактического выполнения запросов.

Ответ №2:

Спасибо, Эрик,

действительно раздражает, что в NHibernate нет стандартного способа сделать это. или, может быть, у меня проблема с дизайном? в любом случае, я также вспомнил, что во избежание дублирования объектов мы могли бы использовать Set вместо использования Bag в нашем отображении.

поэтому я изменил :

 <bag name="ModelImages" table="ModelImages" cascade="all-delete-orphan" inverse="true">
  <key column="ModelId"/>
  <one-to-many class="ModelImage"/>
</bag>
  

Для

 <set name="ModelImages" table="ModelImages" cascade="all-delete-orphan" inverse="true">
  <key column="ModelId"/>
  <one-to-many class="ModelImage"/>
</set>