Joe*_*oeG 2 c# nhibernate fluent-nhibernate
我正在使用NHibernate与Fluent映射,并且当我加入多对多关系时遇到重复条目的问题.我下面的简单示例有两个类,PurchaseOrder和Product.PurchaseOrder可以有许多产品,而产品可以是许多PurchaseOrders的一部分.
当我尝试检索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
Run Code Online (Sandbox Code Playgroud)
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; }
}
Run Code Online (Sandbox Code Playgroud)
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");
}
}
Run Code Online (Sandbox Code Playgroud)
var orderList = session.QueryOver<PurchaseOrder>()
.JoinQueryOver<Product>(o => o.Products)
.List();
Run Code Online (Sandbox Code Playgroud)
我希望orderList有2个PurchaseOrders,但实际上有4个.重复对应于OrderID = 1的对象,OrderID = 2
foreach(var o in orderList) { Console.WriteLine(o.OrderID); }
Output:
1
1
2
2
Run Code Online (Sandbox Code Playgroud)
更进一步,如果我比较具有相同ID的对象,它们是同一个对象.
System.Console.WriteLine(Object.ReferenceEquals(orderList[0], orderList[1]));
System.Console.WriteLine(Object.ReferenceEquals(orderList[2], orderList[3]));
Output:
True
True
Run Code Online (Sandbox Code Playgroud)
为什么NHibernate会复制结果中的对象?如何排除它们并获得我的2个订单列表,每个订单包含相应的2个产品?
由于某种原因session.QueryOver<T>,不会立即返回明显的结果,您必须通过结果转换器或Linq显式定义它.Distinct()
var orderList = session.QueryOver<PurchaseOrder>()
.Fetch(p => p.Products).Eager
.List()
.Distinct();
Run Code Online (Sandbox Code Playgroud)
要么
var orderListFetch = session.QueryOver<PurchaseOrder>()
.Fetch(p => p.Products).Eager
.TransformUsing(Transformers.DistinctRootEntity)
.List();
Run Code Online (Sandbox Code Playgroud)
或者你也可以使用Nhibernate.Linq:session.Query<T>接口,这个接口确实会默认返回一个不同的结果:
var linqQuery = session.Query<PurchaseOrder>()
.Fetch(p => p.Products).ToList();
Run Code Online (Sandbox Code Playgroud)
所有3个查询都会生成几乎完全相同的SQL语句,这些语句都将返回4行,因为它使用左外连接 ...
结果将始终转换为内存中的不同结果集!
测试设置
我稍微更改了你的代码,切换了父键和子键.对于插入/更新/删除子记录,您可能还希望保留级联
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("ProductID")
.ChildKeyColumn("OrderID")
.Cascade.All();
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");
}
}
Run Code Online (Sandbox Code Playgroud)
正如其他人指出的那样,您在 ProductMapping 中的父键和子键是错误的。由于连接,您的查询返回多个结果。您需要使用转换器来仅返回不同的根实体:
var orderList = session.QueryOver<PurchaseOrder>()
.JoinQueryOver<Product>(o => o.Products)
.TransformUsing(Transformers.DistinctRootEntity)
.List();
Run Code Online (Sandbox Code Playgroud)
请注意,如果您只想预先获取产品集合,则可以使用 Fetch 指定:
var orderList = session.QueryOver<PurchaseOrder>()
.Fetch(o => o.Orders).Eager
.TransformUsing(Transformers.DistinctRootEntity)
.List();
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
4356 次 |
| 最近记录: |