2

私はNHibernateの初心者ですが、グーグルで検索しましたが、この問題に役立つものは何も見つかりませんでした。皆さんができることを願っています!;) このコードは会社の所有物であるため、プロパティとメソッドの名前を変更していますが、基本的にこれは私が助けを必要としているものです。

次のシナリオがあります。

私のドメイン エンティティ:

public class Structure
{
    public virtual int Id { get; set; }
    public virtual string Name { get; set; }
    public virtual Person Manager { get; set; } //I need to fill here.
    //and others
}

私のマップクラス:

public class MapStructure : ClassMap<Structure>
{
    public MapStructure()
    {
        Table("TB_Structure");
        Id(x => x.Id).Column("Id").GeneratedBy.Identity();
        Map(x => x.Name).Column("Name");
        References<Person>(x => x.Manager).Column("PersonId").Fetch.Join().NotFound.Ignore();
        //...
    }
}

リポジトリ:

    public IEnumerable<T> SelectByColumns()
    {
        ICriteria searchCriteria = _sessao.CreateCriteria<T>("this");

        searchCriteria.CreateAlias("this.Manager", "Manager");

        //Only for example purpose. Those columns come as an array string parameter, but the treatment is the same one.
        var columns = Projections.ProjectionList();
        columns.Add(Projections.Property("Manager.Id"));
        columns.Add(Projections.Property("Manager.Name"));
        columns.Add(Projections.Property("Manager.Document"));

        searchCriteria.SetProjection(columns);
        searchCriteria.SetResultTransformer(Transformers.AliasToBean<T>());

        return searchCriteria.List<T>();
    }

そして最後に呼び出し:

public IEnumerable<Person> GetManager()
{
    using (IDbSession dbSession = _sessionFactory.Create())
    {
        try
        {
            IRepository<Structure> _repository = dbSession.CreateRepository<Structure>();
            IEnumerable<Structure> structureList = _repository.SelectByColumns();

            var managerList = (from structure in structureList
                                where structure.Manager != null
                                select new Person()
                                {
                                    Id = structure.Manager.Id,
                                    Name = structure.Manager.Name,
                                    Document = structure.Manager.Document
                                });

            return managerList.OrderBy(x => x.Name);
        }
        catch (Exception)
        {
            throw;
        }
    }
}

これにより、以下のようなSQLクエリが生成されます。

SELECT manager1_.PersonId as y0_, manager1_.Name as y1_, manager1_.Document as y2_
FROM TB_Structure this_
inner join TB_Person manager1_ on this_.ManagerId=manager1_.PersonId

そして、これはまさに私が必要としているものです。このクエリを管理スタジオで実行すると、期待していたすべての結果が得られました。

結果

しかし、var managerList に到達すると、structureList にはすべてのレコードが sql から返されますが、次のようにすべて null 値が含まれます。

SQLクエリを実行した後

私はすでに CreateAlias、CreateCriteria、return IList<>、return IEnumerable を試しました。私はすでに Transformers.AliasToBean() を Transformers.AliasToEntityMap に変更しました。グーグルで見つけたさまざまなものがたくさんありましたが、常に同じ結果が得られました。

お時間をいただきありがとうございました。

4

1 に答える 1

2

あなたはほとんどそこにいます。必要なのは、プロジェクションをエンティティ/オブジェクト ツリーに適切に変換することです。それには次の 2 つの手順が必要です。

I.各列にエイリアスを使用する

列エイリアスは、SQL ステートメントの生成よりも事後処理に役立ちます。しかし、それは次のステップのために必須です。したがって、これの代わりに:

columns.Add(Projections.Property("Manager.Id"));
columns.Add(Projections.Property("Manager.Name"));
columns.Add(Projections.Property("Manager.Document"));

これが必要です:

columns.Add(Projections.Property("Manager.Id").As("Manager.Id");
columns.Add(Projections.Property("Manager.Name").As("Manager.Name"));
columns.Add(Projections.Property("Manager.Document").As("Manager.Document"));

実際、最初のレベル(JOIN なし)エンティティを使用している場合は、これで十分です。結合された参照ツリー(多対 1)では機能しません。しかし

Ⅱ.カスタム結果トランスフォーマーを使用する

いつものように、NHibernate はカスタム拡張機能に対して多くのオープン ポイントを提供します。それらの 1 つはカスタム IResultTransformer です。必要な参照ツリーを処理する準備が整ったものは次のとおりです。

これをソリューションに含めると、次のようになります。

searchCriteria.SetResultTransformer(Transformers.AliasToBean<T>());

これを使って:

searchCriteria.SetResultTransformer(new DeepTransformer<T>());

この実装は、適切なエイリアス設定に大きく依存し、実際のエンティティ プロパティを記述します (リフレクションを使用して設定対象を見つけるため)。最初のポイント - 列/プロパティのエイリアスは本当に重要です

于 2014-09-27T04:44:46.583 に答える