3

Fluent マッピングで NHibernate を使用していますが、多対多の関係に参加するとエントリが重複するという問題が発生します。以下の簡単な例には、PurchaseOrder と Product の 2 つのクラスがあります。PurchaseOrder は多くの製品を持つことができ、製品は多くの PurchaseOrder の一部になることができます。

PurchaseOrder とその製品を取得しようとすると、製品ごとに同じ PurchaseOrder が繰り返されます。(したがって、 PurchaseOrder に 5 つの製品がある場合、同じ PurchaseOrder が結果に 5 回表示されます。それぞれに 5 つの製品すべてが含まれます。)

これが私のセットアップです:

テーブル

PurchaseOrder
    OrderID  OrderDate
    1        2013-01-01
    2        2013-01-02

Product
    ProductID   Name
    1           Widget
    2           Thing

OrderProducts
    OrderID ProductID
    1       1
    1       2
    2       1
    2       2

クラス

public class PurchaseOrder
{
    public virtual int OrderID { get; set; }
    public virtual DateTime? OrderDate { get; set; }
    public virtual IList<Product> Products { get; set; }
}

public class Product
{
    public virtual int ProductID { get; set; }
    public virtual string Name { get; set;  }
    public virtual IList<PurchaseOrder> Orders { get; set; }
}

マッピング

public class PurchaseOrderMapping : ClassMap<PurchaseOrder>
{
    public PurchaseOrderMapping()
    {
        Id(x => x.OrderID, "OrderID");
        Map(x => x.OrderDate, "OrderDate");

        HasManyToMany(x => x.Products)
            .Table("OrderProducts")
            .Schema("dbo")
            .ParentKeyColumn("OrderID")
            .ChildKeyColumn("ProductID");

        Schema("dbo");
        Table("PurchaseOrder");
    }
}

public class ProductMapping : ClassMap<Product>
{
    public ProductMapping ()
    {
        Id(x => x.ProductID, "ProductID");
        Map(x => x.Name, "Name");

        HasManyToMany(x => x.Orders)
            .Table("OrderProducts")
            .Schema("dbo")
            .ParentKeyColumn("OrderID")
            .ChildKeyColumn("ProductID")
            .Inverse();

        Schema("dbo");
        Table("Product");
    }
}

クエリオーバー

var orderList = session.QueryOver<PurchaseOrder>()
               .JoinQueryOver<Product>(o => o.Products)
               .List();

orderList には 2 つの PurchaseOrders があるはずですが、実際には 4 あります。OrderID=1 に対応するオブジェクトが繰り返され、OrderID=2 も同様です。

foreach(var o in orderList) { Console.WriteLine(o.OrderID); }

Output:
1
1
2
2

さらに言えば、同じ ID のオブジェクトを比較すると、それらは同じオブジェクトです。

System.Console.WriteLine(Object.ReferenceEquals(orderList[0], orderList[1]));
System.Console.WriteLine(Object.ReferenceEquals(orderList[2], orderList[3]));

Output:
True
True

NHibernate が結果のオブジェクトを複製するのはなぜですか? それらを除外して、それぞれに対応する 2 つの製品を含む 2 つの注文のリストを取得するにはどうすればよいですか?

4

4 に答える 4

5

他の人が指摘しているように、ProductMapping で親キーと子キーが間違っています。結合により、クエリは複数の結果を返します。異なるルート エンティティのみを返すには、トランスフォーマーを使用する必要があります。

var orderList = session.QueryOver<PurchaseOrder>()
           .JoinQueryOver<Product>(o => o.Products)
           .TransformUsing(Transformers.DistinctRootEntity)
           .List();

製品コレクションのみを熱心に取得したい場合は、Fetch を使用して指定できます。

var orderList = session.QueryOver<PurchaseOrder>()
           .Fetch(o => o.Orders).Eager
           .TransformUsing(Transformers.DistinctRootEntity)
           .List();
于 2013-10-03T20:58:37.173 に答える