12

次のコードで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メソッド内の「エンティティ」は、反復すると例外をスローします。

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

(わかりやすくするために名前空間は省略されています)

2番目の編集:IEntityとインスタンスタイプ(TEntity)の間で変換しようとしたときのようです

これがIEntityです:

public interface IEntity
{
    int Id { get; }
}

3番目の編集:AssociationVisitorが式ツリーに適切にアクセスして「Convert(x).Id」を変換しない原因はConvert(x)のようです。

4番目の編集:そして、誰かがすでにバグhttps://nhibernate.jira.com/browse/NHLQ-11を見つけました!

ありがとう

アンドリュー

4

4 に答える 4

3

問題は、Linq/NHibernate が TEntity.Id ではなく IEntity.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();
}
于 2009-03-19T16:21:22.670 に答える
1

バグは報告されていますが、まだ修正されていません:

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

それを再現するための簡単なテストケースを投稿しました。

すぐに対処されることを望みましょう!

于 2009-08-07T10:44:36.603 に答える
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();
}
于 2009-05-21T06:49:56.627 に答える