实现此目的的一种方法是创建由 AND 连接的尽可能多的子查询,因为必须找到许多属性/与搜索的文件相关
我搜索名称/值
第一个解决方案适用于上层的名称/值对。即用户选择的模式为只读... (第二个会更容易一些,期望我们已经拥有搜索属性的 ID)
// Below I am using C# properties, which I guess are correct
// based on the mapping. Naming convention is more Java (camel)
// but this should work with above mapping
// (also - class name Contact, not File)
Files file = null; // this is an alias used below
// here the attributes collection represents search filter
// ... settings for which is user looking for
var attributes = new List<Attrs>
{
new Attrs{ name = "mode", value = "read-only" },
new Attrs{ name = "view", value = "visible" }
};
// Let's start with definition of the outer/top query
// which will return all files, which do meet all filter requirements
var query = session.QueryOver<Files>(() => file);
下一步,我们将遍历属性,即过滤器集合
// here we will take each attribute and create a subquery
// all these subqueries, will be joined with AND
// so only these files, which do have all attributes, will be selected
foreach (var attr in attributes)
{
// create the subquery, returning the FileId
Attrs attribute = null;
var subQueryForAttribute = QueryOver.Of<Files_Attrs>()
.JoinQueryOver(fa => fa.attr, () => attribute)
.Select(x => x.file.id)
;
// now, take name and value
var name = attr.name;
var value = attr.value;
// and convert them into where condition
subQueryForAttribute.Where(() => attribute.name == name);
subQueryForAttribute.Where(() => attribute.value == value);
// finally, add this subquery as a restriction to the top level query
query.WithSubquery
.WhereProperty(() => file.id)
.In(subQueryForAttribute);
}
现在我们有一个查询,它已准备好支持分页 - 因为我们正在处理文件的平面结构。所以我们可以根据需要使用 Take 和 skip ,然后获取搜索到的文件列表
// query.Take(25);
// query.Skip(100);
var list = query.List<Files>();
这是一个查询,将导致这样的 SELECT
SELECT ...
FROM files
WHERE id IN (SELECT file_Id FROM files_attrs
INNER JOIN attrs ON attrs.id = file_attrs.attr_id
WHERE name = 'mode' AND value = 'read-only' )
AND id IN (SELECT file_Id FROM files_attrs
INNER JOIN attrs ON attrs.id = file_attrs.attr_id
WHERE name = 'view' AND value = 'visible' )
II 按属性 ID 搜索
第二种解决方案具有更简单的起始条件,而不是属性(名称和值),我们已经有了它们的 ID(引用问题:)
给定一组属性 ID,我希望运行一个查询,为我提供具有所有这些匹配属性的文件。
// Below I am using C# properties, which I guess are correct
// based on the mapping. Naming convention is more Java (camel)
// but this should work with above mapping
// (also - class name Files, not File)
Files file = null; // this is an alias used below
// here the attributeIds collection represents attributes to be found
var attributeIds = new List<int> { 1, 4, 5 };
// Let's again start with definition of the outer/top query
// which will return all files, which do meet all filter requirements
var query = session.QueryOver<Files>(() => file);
接下来是通过一组已知 ID 的迭代,这些 ID 必须作为关系存在(所有这些)
// here we will take each attribute and create a subquery
// all these subqueries, will be joined with AND
// so only these files, which do have all attributes, will be selected
foreach (var attrId in attributeIds)
{
// create the subquery, returning the Files.id
var subQueryForAttribute = QueryOver.Of<Files_Attrs>()
// no need to join, all the stuff is in the pairing table
.Select(x => x.file.id)
;
var id = attrId; // local variable
// and convert them into where condition
subQueryForAttribute.Where(pair => pair.attr.id == id);
// finally, add this subquery as a restriction to the top level query
query.WithSubquery
.WhereProperty(() => file.id)
.In(subQueryForAttribute);
}
var list = query.List<Files>();
已知 IDS 的解决方案更容易一些(在 SQL 语句中需要更少的表)
注意:不得不说:很高兴看到您引入了many-to-one
andone-to-many
而不是多对多。我个人会说,这个例子正好说明了它可以带来多大的利润......即使使用复杂的过滤器也能搜索
一些链接,以显示QueryOver
:Query on HasMany reference的力量,以及为什么不使用many-to-many
映射的一些充分理由: many-to-many with extra columns nhibernate