.net - sqlquery - nhibernate sql query string
LINQ to NHibernate, consulta "obtener por matriz de ids" (4)
Código:
public IList<T> GetByMultipleIds(int[] ids)
{
List<T> result =
_session.Linq<T>()
.Where(x => ids.Contains(x.Id)).ToList();
return result;
}
Lanza:
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 es typeof (foo) que tiene un mapeo correcto.
la tabla foo tiene datos esperados.
foo hereda entityBase que tiene un elemento virtual público llamado Id. simple _session.Get (ids [0]) funciona.
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
Este tampoco funciona:
IList<T> result =
(_session.Linq<T>().Where(a => new[] {1}.Contains(a.Id))).ToList();
Extraño, pero esto funciona :
IList<foo> result =
(_session.Linq<foo>().Where(a => new[] {1}.Contains(a.Id))).ToList();
Este también funciona :
IList<T> result =_session.Linq<T>()
.Where(x => 1==1).ToList();
Pero necesito que sea genérico.
¿Alguna idea de lo que podría estar mal?
Tal vez cambiar a nhibernate 2.1 beta ayudaría?
Por el momento es así:
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;
}
Pero eso es solo un parche cojo. : /
En realidad, mi compañero de trabajo encontró una solución con ICriteria (agregaré el código más adelante).
Y esto permite ordenar entidades por matriz de id con elegancia.
La última respuesta a esta pregunta es que ahora funciona (NHib 3.3 y probablemente> 3.0)
var entities = from m in Session.Query<MyEntity>()
where ids.Contains(m.ID)
select m;
return entities.ToList()
Ejecuta la consulta correcta, algo así como
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
Maldita sea. Olvidé agregar una solución que funciona:
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;
}
Recuerda que NHibernate hereda tus clases y no las usa directamente por su implementación de IList. Probablemente no sea lo que quiere escuchar, pero dado que sus clases están procesadas y la implementación actual de Linq no lo maneja correctamente, ahí es donde entra el problema.
La combinación de un método genérico que utiliza una clase proxy en los criterios para Linq simplemente explota de muchas maneras con la implementación actual. Al igual que ShaneC dijo en sus comentarios, hay buenas razones por las que regresaron y comenzaron a reescribirlo desde cero.
Lo sé después de una solución, pero lamentablemente la respuesta en este caso es esperar a que NHibernate 2.1 esté completo o usar una solución temporal como lo está haciendo por ahora.
Tengo entendido que la implementación actual de Linq a NHibernate es bastante limitada.
Actualmente hay un esfuerzo para reescribirlo con la última actualización disponible aquí: