LINQ to NHibernate, запрос "получить по массиву идентификаторов" - PullRequest
13 голосов
/ 12 июня 2009

Код:

 public IList<T> GetByMultipleIds(int[] ids)
 {
        List<T> result =
            _session.Linq<T>()
                .Where(x => ids.Contains(x.Id)).ToList();

        return result;
 }

Выдает:

An exception of type 'System.NullReferenceException' occurred in 
NHibernate.DLL but was not handled in user code

Additional information: Object reference not set to an instance of an object.

Идентификаторы = {1}; T является typeof (foo), который имеет правильное отображение.

Таблица foo содержит ожидаемые данные.

foo наследует entityBase, у которого есть публичная виртуальная опора с именем Id просто _session.Get (ids [0]) работает.

Трассировка стека:

[NullReferenceException: Object reference not set to an instance of an object.]
NHibernate.Loader.Criteria.CriteriaQueryTranslator.GetEntityName(ICriteria 
subcriteria, String propertyName) +13
NHibernate.Loader.Criteria.CriteriaQueryTranslator.GetType(ICriteria 
subcriteria, String propertyName) +19
NHibernate.Loader.Criteria.CriteriaQueryTranslator.GetTypeUsingProjection
(ICriteria subcriteria, String
propertyName) +94
NHibernate.Criterion.InExpression.AssertPropertyIsNotCollection(ICriteriaQuery 
criteriaQuery, ICriteria
criteria) +19
NHibernate.Criterion.InExpression.ToSqlString(ICriteria criteria, ICriteriaQuery 
criteriaQuery, IDictionary`2 enabledFilters) +38
NHibernate.Loader.Criteria.CriteriaQueryTranslator.GetWhereCondition
(IDictionary`2 enabledFilters) +223
NHibernate.Loader.Criteria.CriteriaJoinWalker..ctor(IOuterJoinLoadable 
persister, CriteriaQueryTranslator
translator, ISessionFactoryImplementor factory, CriteriaImpl criteria, String 
rootEntityName, IDictionary`2 enabledFilters) +296
NHibernate.Loader.Criteria.CriteriaLoader..ctor(IOuterJoinLoadable persister, 
ISessionFactoryImplementor
factory, CriteriaImpl rootCriteria, String rootEntityName, IDictionary`2 
enabledFilters) +131
NHibernate.Impl.SessionImpl.List(CriteriaImpl criteria, IList results) +173
NHibernate.Impl.CriteriaImpl.List(IList results) +41
NHibernate.Impl.CriteriaImpl.List() +35

Этот тоже не работает:

IList<T> result =  
  (_session.Linq<T>().Where(a => new[] {1}.Contains(a.Id))).ToList();

Странно, но это работает :

IList<foo> result =  
  (_session.Linq<foo>().Where(a => new[] {1}.Contains(a.Id))).ToList();

Этот работает тоже:

IList<T> result =_session.Linq<T>()
  .Where(x => 1==1).ToList();

Но мне нужно, чтобы оно было общим.

Есть идеи, что может быть не так?

Может, поможет переход на бета-версию nhibernate 2.1?

На данный момент это так:

public IList<TEntity> GetByMultipleIds(int[] ids)
    {
        //TODO: somehow query whole list at once
        List<TEntity> result = new List<TEntity>();

        foreach (var id in ids) {
            int tempId = id;
            result.Add(_session.Get<TEntity>(tempId));
        }

        return result;
    }

Но это всего лишь патч. : /


На самом деле - мой коллега нашел обходной путь, используя ICriteria (я добавлю код позже).
И это позволяет элегантно сортировать объекты по массиву id.

Ответы [ 4 ]

8 голосов
/ 29 марта 2010

Черт. Я забыл добавить решение, которое работает:

public virtual IList<TEntity> GetByMultipleIds(int[] ids)
{
    var result = Session
      .CreateCriteria(typeof (TEntity))
      .Add(Restrictions.In("Id", ids))
      .List<TEntity>();

    result = ids.Join //to order list by passed ids
      (result, id => id, r => r.Id, (i, r) => r).ToList();

    return result;
}
6 голосов
/ 18 июня 2009

Помните, что NHibernate наследует ваши классы и не использует их напрямую в соответствии с реализацией IList. Возможно, это не то, что вы хотите услышать, но поскольку ваши классы проксируются, а текущая реализация Linq не обрабатывает их вообще, вот в чем проблема.

Сочетание универсального метода, использующего прокси-класс в критериях для Linq, просто во многих отношениях разрушает текущую реализацию. Как сказал в своих комментариях ShaneC, есть веская причина, по которой они вернулись и начали переписывать его с нуля.

Я знаю, что вы после исправления, но, к сожалению, ответ в этом случае - дождаться завершения NHibernate 2.1 или использовать обходной путь, как вы делаете сейчас.

1 голос
/ 29 марта 2016

Последний ответ на этот вопрос заключается в том, что теперь он работает (NHib 3.3 и, вероятно,> 3.0)

 var entities = from m in Session.Query<MyEntity>()
                where ids.Contains(m.ID)
                select m;

 return entities.ToList()

Запускает правильный запрос, что-то вроде

exec sp_executesql N'select MyEntity0_.ID as ID47_, MyEntity0_.Name as Name47_ from Groups MyEntity0_ where MyEntity0_.ID in (@p0 , @p1)',N'@p0 int,@p1 int',@p0=175,@p1=176
1 голос
/ 12 июня 2009

Насколько я понимаю, текущая реализация Linq для NHibernate довольно ограничена.
В настоящее время предпринимаются попытки переписать его с последним доступным обновлением здесь:

Обновление Linq To NHibernate

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