Как вы определяете критерии сортировки для ассоциации в NHibernate? - PullRequest
2 голосов
/ 06 января 2010

Для сущности ParentEntity с коллекцией типа ChildEntity, которая содержит свойство Order типа int, как можно извлечь родительскую сущность с дочерней коллекцией, отсортированной по Order специально с помощью использования Criteria API, как описано в разделе 12.4 документации NHibernate здесь ?

Я пытался использовать код, подобный следующему:

public ParentEntity GetById(int id)
{
    ICriteria criteria = _sessionFactory.GetCurrentSession().CreateCriteria(typeof (ParentEntity));
    criteria.Add(Restrictions.Eq("Id", id))
        .CreateCriteria("Children")
        .AddOrder(Order.Desc("Order"));            
    return (ParentEntity) criteria.List()[0];
}

К сожалению, этот код выдает 2 SELECT операторов. Первый выбор содержит order by, который сортирует связанные извлеченные столбцы, но второй - нет, и, похоже, это тот, из которого заполняется коллекция.

Обратите внимание, я пытался настроить NHibernate для выполнения извлечения из внешнего соединения, без которого работает, как ожидается, без критериев. Таким образом, он создает два запроса без настроенного внешнего соединения, но только один с настроенным внешним соединением. Добавление добавленных критериев, кажется, вызывает дополнительный запрос независимо от того.

Пожалуйста, ограничьте ответы на то, как это можно сделать с помощью API критериев или объяснений, почему это не сработает. Я знаю, что сортировку можно выполнить с помощью сопоставления, но я пытаюсь понять, в чем конкретно проблема, используя метод критериев.

==== РЕДАКТИРОВАТЬ ====

Ниже приведены модель и сопоставления:

public class ParentEntity
{
    public virtual int Id { get; private set; }
    public virtual IList<ChildEntity> Children { get; set; }

    public ParentEntity()
    {
        Children = new List<ChildEntity>();
    }
}

public class ChildEntity
{
    public virtual int Id { get; private set; }
    public virtual ParentEntity Parent { get; private set; }
    public virtual int Order { get; private set; }

    protected ChildEntity()
    {
    }

    public ChildEntity(int order)
    {
        Order = order;
    }
}

public class ParentEntityMap : ClassMap<ParentEntity>
{

    public ParentEntityMap()
    {
        WithTable("Parent");
        Id(p => p.Id);
        HasMany(p => p.Children)
            .KeyColumnNames.Add("Parent_Id")
            .Cascade.All();
    }
}

public class ChildEntityMap : ClassMap<ChildEntity>
{

    public ChildEntityMap()
    {
        WithTable("Child");
        Id(c => c.Id);
        Map(c => c.Order, "[Order]");
        References(c => c.Parent, "Parent_Id")
            .Cascade.All();
    }
}

==== РЕДАКТИРОВАТЬ 2 ====

В качестве обновления после добавления Not.LazyLoad () в Parent генерируется только один SELECT, однако результаты по-прежнему не отсортированы.

Ответы [ 3 ]

1 голос
/ 07 января 2010

Из поведения, которое я наблюдаю, проблема заключается в том, что, хотя ограничение может быть наложено на ассоциацию (как показано в разделе 12.4 документов ), такие ограничения относятся только к в той степени, в которой они служат значимым фильтром для корневого объекта. Рассмотрим следующий пример из документов:

IList cats = sess.CreateCriteria(typeof(Cat))
.Add( Expression.Like("Name", "F%")
.CreateCriteria("Kittens")
    .Add( Expression.Like("Name", "F%") )
.List();

Это говорит, что верните мне всех кошек, имя которых начинается с "F", но только тех кошек, у которых есть котята с именем, начинающимся с "F". Здесь не сказано возвращать котят с именами, начинающимися с "F" . Заказ работает аналогичным образом. Мы могли бы попросить, чтобы котята были заказаны по имени, что NHibernate с радостью передает как часть критериев, но такое упорядочение не имело бы никакого отношения к тому, как котята возвращаются. Поэтому я пришел к выводу, что использование Criteria API нельзя использовать для фильтрации или упорядочения возвращаемых ассоциаций.

В вышеупомянутом разделе документов указано, что возвращенные ассоциации не были предварительно отфильтрованы по критериям, но я не совсем понял, что имелось в виду, пока не понял, для чего использовались критерии ассоциации.

0 голосов
/ 07 января 2010

Вроде сложно, не видя твоей модели и картографии. Но может быть что-то подобное?

 var criteria = session.CreateCriteria<ParentEntity>();
 criteria.Add(Restrictions.Eq("Id", id))
                .CreateAlias("Children", "children")
                .AddOrder(Order.Desc("children.Order"));
0 голосов
/ 06 января 2010

Как вы картировали детей? Вы можете только указать, что NHibernate должен извлекать детей упорядоченным способом, если вы отобразили их как «упорядоченный список» (карта / список / словарь).

Например: http://ayende.com/Blog/archive/2009/06/02/nhibernate-mapping-ltlistgt.aspx

Если вы сопоставили детей как неупорядоченный список (набор / пакет), то NHibernate не сможет отсортировать детей за вас. В таком случае вам придется сортировать дочерние элементы, когда пользователь обращается к ним

public class Parent
{
    private ISet<Child> _children = new HashedSet<Child>();

    public ReadOnlyCollection<Child> Children
    {
        new List<Child>(_children).OrderBy(child => child.SequenceNr).ToList().AsReadOnly();
    }

}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...