views:

1227

answers:

3

Code:

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

        return result;
 }

Throws:

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 is typeof(foo) which has correct mapping.

foo table has expected data.

foo inherits entityBase which has public virtual prop named Id. simple _session.Get(ids[0]) works.

Stack trace:

[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

This one does not work either:

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

Strange, but this works:

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

This one works too:

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

But i need it to be generic.

Any ideas what might be wrong?

Maybe switching to nhibernate 2.1 beta would help?

At the moment it's like this:

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

But that's just a lame patch. :/


Actually - my co-worker found a workaround using ICriteria (i'll add code later).
And this allows to sort entities by id array elegantly.

A: 

My understanding is that the current Linq to NHibernate implementation is fairly limited.
There is currently an effort to rewrite it with the latest updating being available here:

Linq To NHibernate Update

ShaneC
I don't think that i'm asking too much. :/
Arnis L.
Based on the changes they've had to make to start on the new Linq to NHibernate implementation (someone rewrote/ported? the entire HQL parser) I suspect there were some rather large limitations with the old way.
ShaneC
From personal experience, I wouldn't trust Ayende's pet projects for production code. Updates are sporadic and rarely see light of day in the form of a release
Chris S
I believe that sooner or later NHibernate will support LINQ. No matter who will help.
Arnis L.
The work is occurring right now to implement LINQ to NHibernate. I wouldn't be surprised to see something in the next few months.
ShaneC
That would be grand...
Arnis L.
@chris, probably best not to trust anybody's pet projects for production code
James L
+3  A: 

Remember that NHibernate inherits your classes and doesn't use them directly per it's implementation of IList. Probably not what you want to hear but since your classes are proxied and the current Linq implementation doesn't handle it correctly at all, that's where the problem comes in.

The combination of a generic method using a proxied class in criteria for Linq just blows up in so many ways with the current implementation. Like ShaneC said in his comments, there's good reason they went back and started re-writing it from scratch.

I know your after a fix, but sadly the answer in this case is wait for NHibernate 2.1 to be complete or use a work-around like you are doing for now.

Nick Craver
Would 2.1 beta help?
Arnis L.
It won't, not quite yet...the estimate is still for it to make the 2.1 GA but it's not in the beta, for reference here's the latest blog entry on status: http://nhforge.org/blogs/nhibernate/archive/2009/06/11/linq-to-nhibernate-update.aspx
Nick Craver
+1  A: 

Damn. I've forgot to add solution that works:

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;
}
Arnis L.