使用HQL查找具有匹配关系的行

时间:2010-09-28 01:37:20

标签: nhibernate hql

我正在使用Castle ActiveRecord和NHibernate。

我有一个 Instance 类,它与 Component 类有多对多的关系。我想找到与一组特定组件相关的实例。这在HQL(或NHibernate中的其他任何东西)中是否可行?

此函数的linq版本为:

public Instance find(IEnumerable<Component> passed_components)
{
    return Instance.Queryable.Single(i => passed_components.All(x => i.Components.Contains(x)));
}

当然NHibernate linq实现无法解决这个问题。

我可以编写HQL来为其中一个组件执行此操作:

Instance.FindOne(new DetachedQuery("from Instance i where :comp in elements(i.Components)").SetParameter("comp", passed_components.First()));

但看起来 只将一个项目与一个集合进行比较,它无法将一个集合与一个集合进行比较。

修改

这是我能做的最好的事情:

IQueryable<Instance> q = Queryable;
foreach(var c in components) {
    q = q.Where(i => i.Components.Contains(c));
}

但这是非常低效的。它为每个where子句的SQL查询添加一个子选择。一个不必要的长子选择。它连接Instance表,Instance / Component连接表和Component表。它只需要Instance / Component连接表。

由于我的数据的性质,我将实施混合解决方案。缩小查询中的实例,然后使用linq对象以在必要时获取正确的对象。 代码如下所示:

IQueryable<Instance> q = Queryable;
foreach(var c in components.Take(2)) {
    q = q.Where(i => i.Components.Contains(c));
}

var result = q.ToArray();
if(result.Length > 1) {
    return result.SingleOrDefault(i => !components.Except(i.Components).Any());
}
else return result.FirstOrDefault();

任何人都有更好的方法吗?

1 个答案:

答案 0 :(得分:1)

使用 NHibernate.Linq 提供程序,以下内容应该有效:

var passed_components = new List<Component>();
var instance = session.Linq<Instance>()
                      .Where(i => !passed_components.Except(i.Components).Any())
                      .SingleOrDefault();

您可以下载提供商here并详细了解here here