2010-09-28 26 views
1

我正在使用Castle ActiveRecord和NHibernate。使用HQL查找匹配关系的行

我有一个实例类与组件类具有多对多的关系。我想找到与特定组件组件相关的实例。这可能在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查询添加一个子选择。那是一次非常冗长的斟酌。它加入实例表,实例/组件连接表和组件表。它只需要实例/组件连接表。

由于数据的性质,我将实施混合解决方案。缩小查询中的实例,然后使用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

使用NHibernate.Linq提供商,下面应该工作:

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

您也可以下载提供商here和阅读更多关于它herehere

+0

您确定这是否行?我很确定Contains只包含一个对象,而不是一个列表。 ActiveRecord自带一个不允许的Linq提供程序。我也检查了nhcontrib中的NHibernate.Linq,它在那里也不起作用。 – oillio 2010-09-28 15:51:40

+0

@oillio:我的错误,我很抱歉。不过,我已经编辑过该代码的帖子,以便比较一个列表是否包含另一个列表,后面是http://bit.ly/aQSE31。但是,我不是100%,它会与NHibernate.Linq一起工作。 – rebelliard 2010-09-28 16:02:02

+0

该版本比我上面的linq代码好得多。不幸的是,它不会与NHibernate一起工作。 – oillio 2010-09-28 16:23:37