2009-06-12 18 views
13

Codice:LINQ to NHibernate, "get dalla matrice di ID" di query

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

     return result; 
} 

Produce:

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) che ha una mappatura corretta.

la tabella foo ha i dati previsti.

foo eredita entityBase che dispone di supporto virtuale pubblico denominato ID. simple _session.Get (ids [0]) funziona.

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 

Questo non funziona neanche:

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

Strano, ma questo funziona:

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

Questo funziona troppo:

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

Ma ho bisogno di essere generico.

Qualche idea cosa potrebbe essere sbagliato?

Forse passare a nibernare 2.1 beta potrebbe essere d'aiuto?

Al momento è come questo:

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

Ma questa è solo una patch zoppo. :/


In realtà - il mio collega trovato una soluzione utilizzando ICriteria (io aggiungere codice in seguito).
E this consente di ordinare le entità con la matrice id in modo elegante.

risposta

6

Ricorda che NHibernate eredita le vostre classi e non li usa direttamente per la sua implementazione di IList. Probabilmente non è quello che vuoi sentire, ma dal momento che le tue classi sono delegate e l'attuale implementazione di Linq non la gestisce correttamente, è qui che il problema si presenta.

La combinazione di un metodo generico che utilizza una classe proxy nei criteri per Linq esplode in tanti modi con l'attuale implementazione. Come ha detto ShaneC nei suoi commenti, ci sono buone ragioni per cui sono tornati indietro e hanno iniziato a riscriverlo da zero.

Conosco il tuo dopo una correzione, ma purtroppo la risposta in questo caso è attendere che NHibernate 2.1 sia completo o utilizzare un work-around come per il momento.

+0

2.1 Help 2.1? –

+0

Non sarà, non ancora del tutto ... la stima è ancora che faccia il 2.1 GA ma non è nella beta, per riferimento ecco l'ultimo post di blog sullo stato: http://nhforge.org/blogs/ NHibernate/archive/2009/06/11/LINQ to NHibernate-update.aspx –

1

La mia comprensione è che l'attuale implementazione da Linq a NHibernate è piuttosto limitata.
V'è attualmente un tentativo di riscrivere con l'ultimo aggiornamento di essere disponibile qui:

Linq To NHibernate Update

+0

Non penso che sto chiedendo troppo. :/ –

+0

Sulla base delle modifiche che hanno dovuto apportare alla nuova implementazione di Linq su NHibernate (qualcuno ha riscritto/portato l'intero parser HQL), sospetto che esistessero alcune limitazioni piuttosto grandi con la vecchia maniera. –

+1

Per esperienza personale, non mi fiderei dei progetti per animali domestici di Ayende per il codice di produzione. Gli aggiornamenti sono sporadici e raramente vedono la luce del giorno sotto forma di rilascio –

8

Accidenti. Ho dimenticato di aggiungere soluzione che funziona:

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

L'ultima risposta a questa domanda è che funziona ora (NHib 3.3 e probabilmente> 3,0)

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

return entities.ToList() 

esegue la query giusta, qualcosa di simile

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