我正在使用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();
任何人都有更好的方法吗?