LINQ to NHibernate,“通过数组获取”查询

时间:2009-06-12 13:16:02

标签: .net linq nhibernate

代码:

 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.

IDS = {1}; T是typeof(foo),它具有正确的映射。

foo table有预期的数据。

foo继承了具有名为Id的公共虚拟道具的entityBase。 simple _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 beta有帮助吗?

目前就是这样:

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找到了一个解决方法(我稍后会添加代码) 并且this允许优雅地按id数组对实体进行排序。

4 个答案:

答案 0 :(得分:8)

该死。我忘了添加有效的解决方案:

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;
}

答案 1 :(得分:6)

请记住,NHibernate会继承您的类,并且不会根据IList的实现直接使用它们。可能不是你想听到的,但由于你的类被代理并且当前的Linq实现根本没有正确处理它,这就是问题出现的地方。

在Linq的标准中使用代理类的泛型方法的组合在当前实现中以很多方式爆炸。就像ShaneC在他的评论中所说的那样,他们有充分的理由回去并开始从头开始重写。

我知道你的修复后,但遗憾的是,在这种情况下,答案是等待NHibernate 2.1完成或者像现在一样使用解决方法。

答案 2 :(得分:1)

我的理解是目前Linq对NHibernate的实现相当有限 目前正在努力重写它,并在此处提供最新的更新:

Linq To NHibernate Update

答案 3 :(得分:1)

这个问题的最新答案是它现在有效(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