2009-03-10 5 views
11

Calling Obtener en el siguiente código funciona bien:extraña LINQ a nhibernate cuestión, el reparto no válida del 'System.Int32'

public class ContractService : IContractService 
{ 
    private readonly IRepository<Contract> repository; 

    public ContractService(IRepository<Contract> repository) 
    { 
     this.repository = repository; 
    } 

    public Contract Get(int contractId) 
    { 
     return repository.Query().Where(x => x.Id == contractId).FirstOrDefault(); 
    } 

pero cuando hago esto:

public class ContractService : CRUDService<Contract>, IContractService 
{ 
    public ContractService(IRepository<Contract> repository) : base(repository) 
    { 
    } 
} 


public class CRUDService<TEntity> : ICRUDService<TEntity> where TEntity : IEntity 
{ 
    protected readonly IRepository<TEntity> repository; 

    public CRUDService(IRepository<TEntity> repository) 
    { 
     this.repository = repository; 
    } 

    public TEntity Get(int id) 
    { 
     var entities = this.repository.Query().Where(s => s.Id == id); 
     return entities.FirstOrDefault(); 
    } 

"entidades" dentro de el método get arroja una excepción cuando itera sobre él:

Invalid cast from 'System.Int32' to 'TEntity' (where TEntity is the type name) 

¿Alguien tiene alguna idea de por qué?

Editar: esto es lo que las diferentes expresiones se ven como:

En la versión genérica (arriba uno), parece estar tratando de convertir x por alguna razón, que debe ser a causa de los medicamentos genéricos: s

{value(NHibernate.Linq.Query`1[Contract]).Where(x => (Convert(x).Id = value(CRUDService`1+<>c__DisplayClass0[Contract]).Id)).FirstOrDefault()} 

{value(NHibernate.Linq.Query`1[Contract]).Where(x => (x.Id = value(ContractService+<>c__DisplayClass2).Id)).FirstOrDefault()} 

(espacios de nombres omitidos para mayor claridad)

segunda edición: parece que es cuando se intenta convertir entre IEntity y el tipo de instancia (TEntity)

aquí es IEntity:

public interface IEntity 
{ 
    int Id { get; } 
} 

tercera edición: parece ser el Convert (x) que hace que el AssociationVisitor a no visitar adecuadamente el árbol de expresión y convertir "Convertir (x) .ID"

cuarto Editar: Y ahí vamos, alguien ya encontró el error https://nhibernate.jira.com/browse/NHLQ-11!

Gracias

Andrew

+0

Eso suena muy extraño. ¿Tienes algún registro de qué SQL se está ejecutando? ¿Cómo se ve el resto de la pila? –

+0

Parece que no se ejecuta ningún SQL, parece que el Linq falla antes de llegar a cualquier punto cercano al DB. Acabo de descargar la fuente para una depuración http://sourceforge.net/project/showfiles.php?group_id=216446&package_id=306405&release_id=654054 –

+0

¡También me encontré con este problema! – bleevo

Respuesta

1

He encontré con esto en el pasado y por lo general se reduce al campo de la tabla de base de datos que está leyendo no es en un formato compatible. Al igual que los booleanos, no se convierten en enteros.

Verifique los tipos de campo en la tabla y asegúrese de que sean compatibles. Tal vez su columna Id es un BIGINT?

+0

acepto que podría causar una excepción de "publicación inválida", pero eso no está sucediendo aquí. Lee el código y el informe de errores en jira. Es un error causado por los genéricos –

3

Creo que el problema es que Linq/NHibernate está tratando de asignar IEntity.Id a una columna de tabla en lugar de a TEntity.Id. Tuve este problema con la implementación de un repositorio LinqToSql. La manera de evitarlo era utilizar una expresión como la siguiente:

private static Expression<Func<TEntity, bool>> GetFindExpression(string propertyName, object value) 
{ 
    ParameterExpression parameterExpression = Expression.Parameter(typeof (TEntity), "id"); 
    MemberExpression propertyExpression = Expression.Property(parameterExpression, propertyName); 

    Expression bodyExpression = Expression.Equal(propertyExpression, Expression.Constant(value)); 

    return Expression.Lambda<Func<TEntity, bool>>(bodyExpression, parameterExpression); 
} 

Así que esto cambiaría Get (id) a:

public TEntity Get(int id) 
{ 
    var entities = Query.Where(GetFindExpression("Id", id)); 
    return entities.FirstOrDefault(); 
} 

Actualización:

Si no quieren para manejar las expresiones (¡pueden ser complicadas!), Se puede usar la biblioteca dinámica LINQ como se describe por Scott Guthrie aquí: http://weblogs.asp.net/scottgu/archive/2008/01/07/dynamic-linq-part-1-using-the-linq-dynamic-query-library.aspx

que cambiaría Get (id) a:

public TEntity Get(int id) 
{ 
    var entities = Query.Where("Id = @0", id); 
    return entities.FirstOrDefault(); 
} 
+1

"Creo que el problema es que Linq/NHibernate está tratando de asignar IEntity.Id a una columna de tabla en lugar de a TEntity.Id". Estoy totalmente de acuerdo. Me gusta la idea de transformar la lambda, voy a intentar hacer una versión genérica que se encargará de todas las transformaciones ... estad atentos –

1

estoy teniendo el mismo problema :(

el siguiente no funciona.

public override T Load(int id) 
{ 
    return (from t in _sessionFactory.Session.Linq<T>() 
      where t.ID == id 
      select t).SingleOrDefault(); 
} 

la siguiente no!

public override Product Load(int id) 
{ 
    return (from t in _sessionFactory.Session.Linq<Product>() 
      where t.ID == id 
      select t).SingleOrDefault(); 
} 
1

El error se ha informado, pero aún no fija:

https://nhibernate.jira.com/browse/NHLQ-11

He publicado un caso de prueba sencilla para reproducirlo.

¡Esperamos que se solucione pronto!

+0

noté que añadiste un caso de prueba, buen trabajo. ¡Espero que lo arreglen pronto! –

Cuestiones relacionadas