项目可以有很多部分。 Part上的属性是Ipn,它是一串数字。
我想找到所有与之关联的所有指定部件的项目。我当前的查询是
var ipns = new List<String> { "2", "3" }
var criteriaForIpns = DetachedCriteria
.For<Part>()
.SetProjection(Projections.Id())
.Add(Expression.In("Ipn", ipns));
_criteriaForProject
.CreateCriteria("Ipns")
.Add(Subqueries.PropertyIn("Id", criteriaForIpns));
这使我返回所有包含任何部分的项目,因此结果集是项目A,B,C和D.
生成的SQL where子句类似于
WHERE part1_.Id in (SELECT this_0_.Id as y0_
FROM Parts this_0_
WHERE this_0_.Ipn in ('2' /* @p0 */,'3' /* @p1 */))
我想要的结果只是项目A和B.如何构建NHibernate标准以获得我需要的结果集?
我搜索的部件数量可能会有所不同,可能是n个部件。
答案 0 :(得分:2)
public class Project
{
public virtual int ProjectId{get;set;}
public virtual IList<Part> Parts{get;set;}
...
}
public class Part
{
public virtual int PartId{get;set;}
public virtual Project Project{get;set;} // *1 this is the drawback: I need a public property for the ForegienKey from the child to the parent
...
}
标准来了:
DetachedCriteria top = DetachedCriteria.For<Project>();
foreach(Part part in searchedParts)
{
DetachedCriteria sub = DetachedCriteria.For<Part>();
sub.Add(Expresion.Eq("PartId",part.PartId));
sub.SetProjection("Project");
top.Add(Subqueries.PropertyIn("ProjectId",sub));
}
回到你的例子:SQL看起来像这样。
SELECT * FROM project
WHERE
projectid IN ( SELECT projectid FROM part WHERE partid = 1 /* @p0 */ )
AND projectid IN ( SELECT projectid FROM part WHERE partid = 2 /* @p1 */ )
Basicaly我为每个孩子添加一个子查询,用于检查它在项目中的存在并将它们与之结合起来,因此只选择与所有孩子一起进行项目。
问候
Juy Juka
在此之后我没有完成我的代码,如果somone需要我必须找到的东西,我会在这里添加它。我希望附加信息属于这里,但我不确定,因为这是我在stackoverflow.com上的第一篇文章
对于以下示例,我们需要一个更复杂的part-class:
public class Part
{
public virtual int PartId{get;set;}
public virtual Project Project{get;set;}
public virtual PartType PartType{get;set;}
...
}
public class PartType
{
public virtual int PartTypeId{get;set;}
public virtual string Name{get;set;}
...
}
关于子对象的不同标准
当您没有搜索到的部分的主键时,可以使用相同的代码,但希望找到具有其他属性的部分。
// I am asuming building-projects with houses, gardens, garages, driveways, etc.
IEnumerable<PartType> searchedTypes = new PartType[]{housePart, gardenPart};
// could be a parameter or users choise or what ever
DetachedCriteria top = DetachedCriteria.For<Project>();
foreach(PartType type in searchedTypes)
{
DetachedCriteria sub = DetachedCriteria.For<Part>();
sub.Add(Expresion.Eq("PartType",type)); // this is all that had to be changed. We could even use more complex operations with and, or, not, etc.
sub.SetProjection("Project");
top.Add(Subqueries.PropertyIn("ProjectId",sub));
}
预期SQL
SELECT * FROM project
WHERE
projectid IN ( SELECT projectid FROM part WHERE parttype = 1 /* @p0 // aka. housePart */ )
AND projectid IN ( SELECT projectid FROM part WHERE parttype = 2 /* @p1 // aka. gardenPart */ )
排除儿童
通过使用Subqueries.PropertyNotIn而不是Subqueries.PropertyIn,可以轻松完成 的搜索。
完全/仅搜索过的孩子
这是我在最长时间内工作的棘手部分。我希望父母完全按照给定的部件列表。 继续建筑项目的例子:我正在寻找带有房屋部分和guarden部分但没有其他部分的项目
IEnumerable<PartType> searchedTypes = new PartType[]{housePart, gardenPart};
DetachedCriteria top = DetachedCriteria.For<Project>();
ICriterion notCriterion = null;
foreach(PartType type in searchedTypes)
{
ICriterion subCriterion = Expresion.Eq("PartType",type);
DetachedCriteria sub = DetachedCriteria.For<Part>();
sub.Add(subCriterion);
sub.SetProjection("Project");
top.Add(Subqueries.PropertyIn("ProjectId",sub));
// I am collecting all valid criterions for child-objects and negate them
subCriterion = Expresion.Not(subCriterion);
notCriterion = notCriterion == null ? subCriterion:Expresion.And(notCriterion,subCriterion);
}
// with the negated criterions I exclude all parent-objects with an invalid child-object
DetachedCriteria not = DetachedCriteria.For<Part>();
not.Add(notCriterion);
sub.SetProjection("Project");
top.Add(Subqueries.PropertyNotIn("ProjectId",not));
预期SQL
SELECT * FROM project
WHERE
projectid IN ( SELECT projectid FROM part WHERE parttype = 1 /* @p0 // aka. housePart */ )
AND projectid IN ( SELECT projectid FROM part WHERE parttype = 2 /* @p1 // aka. gardenPart */ )
AND projectid NOT IN ( SELECT projectid FROM part
WHERE
NOT ( parttype = 1 /* @p2 // aka. housePart */ )
AND NOT ( parttype = 2 /* @p3 // aka. gardenPart */ )
)
(更多一个房子和/或一个guarden是可能的,因为没有检查“重复”条目)
答案 1 :(得分:0)
您的查询要求我们从Project到Part进行两次连接。这在标准中是不可能的。
<强> HQL 强>
您可以直接在HQL中表达此查询。
var list = session.CreateQuery( @"
select proj from Project proj
inner join proj.Parts p1
inner join proj.Parts p2
where p1.Id=:id1
and p2.Id=:id2
" )
.SetInt32( "id1", 2 )
.SetInt32( "id2", 3 )
.List<Master>();
<强>标准强>
使用Criteria API,您将查询具有指定部件之一的那些项目,并使用C#过滤结果。
要么标记为预先加载Project.Parts,要么将其映射为lazy =“extra”。
然后,使用上面的现有条件查询。
// Load() these if necessary
List<Parts> required_parts;
var list = _criteriaForProject.List<Project>()
.Where( proj => {
foreach( var p in required_parts ) {
if (!proj.Parts.Contains( p ))) {
return false;
}
return true;
}
});
// if _criteriaForProject is a Detached Criteria, that would be:
var list = _criteriaForProject.GetExecutableCriteria( session )
.List<Project>()
.Where( // etc