3

次のようなエンティティがあります。

public class Employment
{
    public virtual Company Company {get; set;}
    public virtual Person Person {get; set;}
    public virtual string Description {get; set;}
}

他の 2 つのエンティティ間の関係を提供します。それらには対応する DTO があり、個人と企業に関するすべての情報を含む結果セットを返したいと考えています。クエリは Employment テーブルに対して実行されます。私の問題は、Hibernate が会社と個人ごとに 1 つの select ステートメントを生成することです。

私のデータベースでは、Employment テーブルには 1000 行あります。Nhibernate は 2001 の select ステートメントを生成します。1 つは雇用リスト用、もう 1 つは個人と会社ごとに 1 つの select ステートメントを DTO にマップします。

ハイバネートで一度にすべての情報を取得したいのですが、SQL では次のようにします。

SELECT e.Description, c.A, c.B, c.C, p.D, p.E, p.F
FROM Employment e
JOIN Company c ON e.Company_Id = c.Company_Id
JOIN Person p ON e.Person_Id = p.Person_Id;

あるいは

SELECT Description FROM Employment;

SELECT c.A, c.B, c.C FROM Employment e
JOIN Company c ON e.Company_Id = c.Company_Id;

SELECT p.D, p.E, p.F FROM Employment e
JOIN Person p ON e.Person_Id = p.Person_Id;

私は nHibernate、QueryOver のかなり新しいユーザーです。Linq-To-Entities の回答も歓迎しますが、LINQ クエリ式は避けたいと思います。

私はウェブ全体を見て、JoinQuery、JoinAlias、および Fetch について読んで、次のようなものに到達しました。

//This works, but the objects are retrieved as PersonProxy and CompanyProxy,
//generating 2 SELECT statements for each Employment I map to EmploymentDto
var queryOver =
    session.QueryOver<Employment>()
    .Fetch(x => x.Person).Eager
    .Fetch(x => x.Company).Eager
var mapResult = MappingEngine.Map<IList<EmploymentDto>>(queryOver.List());    


//This works, but the objects are still retrieved as PersonProxy and CompanyProxy,
var queryOver =
    session.QueryOver<Employment>()
        .JoinAlias(x => x.Person, () => personAlias, JoinType.InnerJoin)
        .JoinAlias(x => x.Company, () => companyAlias, JoinType.InnerJoin);
var mapResult = MappingEngine.Map<IList<EmploymentDto>>(queryOver.List());

JoinQuery でも同じ結果が得られました。ここで重要な何かが欠けているように感じます。PersonProxy および CompanyProxy でロードされた多数の Employment エンティティを含むリストをロードする代わりに、クエリ内または .List() の前に何かを実行して、すべての子エンティティをフェッチする必要があります。しかし、私は方法を見つけることができません...

編集:マッピングを追加

データベース テーブル:

TABLE Company(
Id,
A,
B,
C)

TABLE Person(
Id,
D,
E,
F);

TABLE Employment(
Person_Id,
Company_Id,
Description);

エンティティ

public class Company
{
    public virtual string Id { get; set; }
    public virtual string A { get; set; }
    public virtual bool B { get; set; }
    public virtual bool C { get; set; }
}

public class Person
{
    public virtual string Id { get; set; }
    public virtual string D { get; set; }
    public virtual string E { get; set; }
    public virtual string F { get; set; }
}

public class Employment
{
    public virtual Person Person { get; set; }
    public virtual Company Company { get; set; }
    public virtual string Description { get; set; }

    public override bool Equals(object obj)
    {
        Employment toCompare = obj as Employment;
        if (toCompare == null)
            return false;
        return (this.GetHashCode() != toCompare.GetHashCode());
    }

    public override int GetHashCode()
    {
        unchecked
        {
            int results = Person != null ? Person.GetHashCode() : 0;
            results = (results * 397) ^ (Company != null ? Company.GetHashCode() : 0);
            results = (results * 397) ^ (Description != null ? Description.GetHashCode() : 0);
            return results;
        }
    }
}

マッピング

public class CompanyMap : SyncableClassMap<Company>
{
    public CompanyMap()
    {
        Table("Company");
        Id(x => x.Id).Column("Id").GeneratedBy.Assigned();
        Map(x => x.A).Column("A");
        Map(x => x.B).Column("B").CustomType<YesNoType>();
        Map(x => x.C).Column("C").CustomType<YesNoType>();
    }
}

public class PersonMap : SyncableClassMap<Person>
{
    public PersonMap()
    {
        Table("Person");
        Id(x => x.Id).Column("Id").GeneratedBy.Assigned();
        Map(x => x.D).Column("D");
        Map(x => x.E).Column("E");
        Map(x => x.F).Column("F");
    }
}

public class EmploymentMap : ClassMap<Employment>
{
    public EmploymentMap()
    {
        Table("Employment");
        CompositeId()
            .KeyReference(x => x.Person, "Person_Id")
            .KeyReference(x => x.Company, "Company_Id");
        Map(x => x.Description, "Description");
    }
}
4

2 に答える 2

4

編集後、通常の多対一ではなくキー参照があることがわかります。

残念ながら、これは Fetchmode が指定されていてもキー参照を積極的にロードしない QueryOver/Criteria の制限のようです。ただし、Linq to NH にはこの制限はありません。クエリを次のように変更します

using NHibernate.Linq;

var results = session.Query<Employment>()
    .Fetch(x => x.Person)
    .Fetch(x => x.Company)
    .ToList();
于 2012-05-23T05:44:41.373 に答える
0

ここで説明しているのと同じ問題が発生しました。それが私がそれを機能させた方法であるため、例として最後のコードスニペットを取り上げます。

//This works, but the objects are still retrieved as PersonProxy and CompanyProxy,
var queryOver =
    session.QueryOver<Employment>()
        .JoinAlias(x => x.Person, () => personAlias, JoinType.InnerJoin)
        .JoinAlias(x => x.Company, () => companyAlias, JoinType.InnerJoin);
var mapResult = MappingEngine.Map<IList<EmploymentDto>>(queryOver.List());

まず、これがJoinType.InnerJoinデフォルトの結合タイプであるため、指定する必要はありません。あなたと同じように、個人や企業がこの方法で遅延ロードされていることもわかりました。

ただし、結合タイプを に変更するとJoinType.LeftOuterJoin、すべてが積極的にロードされることがわかります。少なくともそれは私が経験したことです。したがって、コードを次のように変更してみてください。

//This works, but the objects are still retrieved as PersonProxy and CompanyProxy,
var queryOver =
    session.QueryOver<Employment>()
        .JoinAlias(x => x.Person, () => personAlias, JoinType.LeftOuterJoin)
        .JoinAlias(x => x.Company, () => companyAlias, JoinType.LeftOuterJoin);
var mapResult = MappingEngine.Map<IList<EmploymentDto>>(queryOver.List());

なぜこのようになるのかは説明できませんが、自分の経験からこれがうまくいくことを発見しただけです。また、左外部結合を実行することが問題になる場合は、代わりに、マッピングを実行する前 (または実行中に) に応じてコードでフィルター処理を試みることができます。

于 2012-05-15T06:10:01.583 に答える