奇怪的linq到nhibernate问题,来自'System.Int32'的无效转换

时间:2009-03-10 09:49:30

标签: nhibernate linq-to-nhibernate

调用以下代码中的Get工作正常:

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

但是当我这样做时:

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();
    }
当你迭代它时,get方法中的

“entities”会引发异常:

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

任何人都知道为什么?

编辑:这是不同表达式的样子:

在通用版本(顶部版本)中,似乎是出于某种原因试图转换x,这必须是因为泛型: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()}

(为清晰起见省略了名称空间)

第二次编辑:似乎是在尝试在IEntity和实例类型(TEntity)之间进行转换时

这是IEntity:

public interface IEntity
{
    int Id { get; }
}

3rd Edit:似乎是Convert(x)导致AssociationVisitor没有正确访问表达式树并转换为“Convert(x).Id”

第四编辑:我们走了,有人已经找到了错误https://nhibernate.jira.com/browse/NHLQ-11

由于

安德鲁

4 个答案:

答案 0 :(得分:3)

我认为问题在于Linq / NHibernate试图将IEntity.Id映射到表列而不是TEntity.Id。我有一个LinqToSql存储库实现的这个问题。解决它的方法是使用这样的表达式:

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

所以这会将Get(id)改为:

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

<强>更新

如果您不想处理表达式(它们可能很棘手!),您可以使用Scott Guthrie所描述的Dynamic LINQ库: http://weblogs.asp.net/scottgu/archive/2008/01/07/dynamic-linq-part-1-using-the-linq-dynamic-query-library.aspx

这会将Get(id)更改为:

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

答案 1 :(得分:1)

我过去遇到过这种情况,它通常归结为您正在阅读的数据库表中的字段不是兼容的格式。像布尔值不会转换为整数。

检查表格中的字段类型,确保它们兼容。也许你的Id专栏是BIGINT?

答案 2 :(得分:1)

我遇到同样的问题:(

以下不起作用。

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

以下是!

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

答案 3 :(得分:1)

已报告该错误但尚未修复:

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

我发布了一个简单的测试用例来重现它。

让我们希望很快得到解决!