内连接后防止多个实例

时间:2012-12-28 21:46:12

标签: nhibernate queryover

在连接到另一个表之后,我有一个小的问题,包含同一个对象的多个实例。为了测试,我创建了一个Store,其中包含两个Products(ManyToMany-Relation)。以下片段有希望描述我的问题。

var preResult = _session.QueryOver<Store>().List(); // One store

Product productAlias = null;
var result = _session.QueryOver<Store>()
    .JoinAlias(s => s.Products, () => productAlias)
    .List();                                        // Two instances of the same store

我甚至认为这种行为是正确的但是如何防止多个实例呢?在查询中是否可以?


仅供参考,为什么我需要进行不必要的加入:我想根据不同的标准扩展查询,类似于:

Product productAlias = null;
var query = _session.QueryOver<Store>().JoinAlias(s => s.Products, () => productAlias);
if (!string.IsNullOrWhiteSpace(criteria.ProductName))
{
    query.Where(Restrictions.On(() => productAlias.Name).IsInsensitiveLike(criteria.ProductName));
}

if (criteria.ProductType != null)
{
    query.Where(s => productAlias.Type == criteria.ProductType);
}

var result = query.List();

在这里,我遇到了不同的问题,具体取决于标准。

2 个答案:

答案 0 :(得分:6)

尝试在您的方案中使用Transformers.DistinctRootEntity来消除笛卡尔积。

Product productAlias = null;
var query = _session.QueryOver<Store>()
                    .JoinAlias(s => s.Products, () => productAlias)

query = query.TransformUsing(Transformers.DistinctRootEntity);

var result = query.List();

答案 1 :(得分:5)

让我们将解决方案分成两个查询。

  1. 前一个QueryOver<Store>()将正确返回一个不同的列表。而且,根据设计,它将支持分页(Take()Skip())。
  2. 内部的,将只返回商店ID列表,完全符合任何标准......
  3. 结果SQL将如下所示

    SELECT ... // top one 
    FROM Store
    WHERE StoreID IN ( SELECT StoreID ...) // inner one
    

    内在

    让我们从内部选择开始,NHibernate分离QueryOver

    Store storeAlias = null;
    Product productAlias = null;
    
    // detached query, resulting in a set of searched StoreID 
    var subQuery = QueryOver.Of<Store>(() => storeAlias)
        .JoinAlias((s) => s.Products, () => productAlias)
        .Select((s) => s.ID); // ID projection
    
    if (!string.IsNullOrWhiteSpace(criteria.ProductName))
    {
        subQuery.Where(Restrictions.On(() => productAlias.Code)
            .IsInsensitiveLike(criteria.ProductName));
    }
    

    一旦我们过滤了商店,我们就可以在前一个中使用这个子查询

    var query = session.QueryOver<Store>()
       // IN clause
       .Where(Subqueries.PropertyIn("ID", subQuery.DetachedCriteria))
       .Skip(100) 
       .Take(50) // paging over already distinct resultset
       ;
    
    var result = query.List<Store>();
    

    现在我们可以对内部查询应用任何过滤器,并获取满足过滤条件的商店ID列表...同时使用顶级查询,这是不同的......