所以我在Specialism和SpecialismCombo之间有很多关系。我要做的是取一个int []的id并检查是否已经有一个包含这些id的特殊主义的组合。
我很接近但不太对劲。 说我对Ids 1和I有专长,并且我用这些专业创建了一个组合。
如果我通过3& 1然后它返回预期的组合ID。
如果我传入1,则返回同时包含1和3的组合ID。
我不能仅依靠与组合相关的专业总数。因为如果一个组合有两个项目,1和4以及匹配的项目是1和3我不希望它作为匹配的组合返回。
因此我需要计算此结果,并匹配与组合相关的总专业数。我不知道我是在追查子查询还是在detatchedcriteria之后,或者如何使用nhibernate标准得到我想要的结果。谢谢你的帮助!
int[] SpecialismIds = ArrayExtensions.ConvertArray<int>(idCollection.Split(new char[] { '|' }));
ICriteria query = m_SpecialismComboRepository.QueryAlias("sc");
query.CreateAlias("sc.Specialisms", "s", NHibernate.SqlCommand.JoinType.InnerJoin);
ICriterion lastCriteria = null;
foreach(int i in SpecialismIds)
{
ICriterion currentCriteria = Restrictions.Eq("s.SpecialismId", i);
if (lastCriteria != null)
lastCriteria = Restrictions.Or(lastCriteria, currentCriteria);
else
lastCriteria = currentCriteria;
}
if (lastCriteria != null)
query.Add(lastCriteria);
IProjection IdCount = Projections.Count("s.SpecialismId").As("IdCount");
query.SetProjection(
Projections.GroupProperty("sc.SpecialismComboId"),
IdCount
);
query.Add(Restrictions.Eq(IdCount, SpecialismIds.Count()));
var comboId = query.List();
生成的sql是:
SELECT this_.SpecialismComboId as y0_, count(s1_.SpecialismId) as y1_
FROM dbo.SpecialismCombo this_
inner join SpecialismComboSpecialism specialism3_ on this_.SpecialismComboId=specialism3_.SpecialismId
inner join dbo.Specialism s1_ on specialism3_.SpecialismComboId=s1_.SpecialismId WHERE s1_.SpecialismId = @p0
GROUP BY this_.SpecialismComboId HAVING count(s1_.SpecialismId) = @p1',N'@p0 int,@p1 int',@p0=3,@p1=1
编辑 - 似乎我要么必须像...那样......
HAVING count(s1_.SpecialismId)=(选择计数(SpecialismId)) 来自specialismComboSpecialism 其中SpecialismComboId = y0 group by SpecialismComboId)== @ p2
或者它可能比这更简单,我需要排除SpecalismCombos,其中combo.specialisms不在ids的集合中。
IE中。如果组合具有专家1和3,但该集合只有1 ..那么我们可以排除这个组合基于3不在集合...
编辑2011年8月8日 回过头来关注如何在SQL中获得我需要的结果 - 我相信这个查询有效。
WITH CustomQuery AS
(
SELECT sc.SpecialismComboId,
count(s.SpecialismId) AS ItemCount
FROM SpecialismCombo sc
inner join SpecialismComboSpecialism scs on sc.SpecialismComboId = scs.SpecialismComboId
inner join Specialism s on s.SpecialismId = scs.SpecialismId
GROUP BY sc.SpecialismComboId
HAVING count(s.SpecialismId) = 2
)
SELECT CustomQuery.SpecialismComboId FROM CustomQuery
INNER JOIN SpecialismComboSpecialism scs on CustomQuery.SpecialismComboId = scs.SpecialismComboId
WHERE scs.SpecialismId in (1,4)
GROUP BY CustomQuery.SpecialismComboId
HAVING count(scs.SpecialismId) = 2
所以现在我只需要弄清楚如何从我的nhibernate代码调用此过程传递适当的值:)
我还在流程中发现我的映射类是错误的 - 因为它在映射表中放入了错误的值(即,specialismid最终出现在specialismcomboid字段中!)
答案 0 :(得分:0)
您的解决方案实际上应该运作良好。专业按ID过滤,不应该有任何未被搜索的内容,因此计数应该有效。除非你有同样的专业,否则加入一次。这个currentCriteria
lastCriteria
的东西看起来有点奇怪,可能有错误。只需使用Expression.In
或Conjunction
。
IProjection IdCount = Projections.Count("s.SpecialismId").As("IdCount");
IQuery query = session
.CreateCriteria<SpecialismCombo>("sc")
.CreateCriteria("Specialism", "s");
.Add(Expression.In("s.SpecialismId", SpecialismIds));
.SetProjection(
Projections.GroupProperty("sc.SpecialismComboId"),
IdCount);
.Add(Restrictions.Eq(IdCount, SpecialismIds.Count()));
应该导致这样的查询:
select ...
from
SpecialismCombo sc
inner join -- linktable ...
inner join Specialism s on ...
where
s.SpecialismId in (1, 4)
Group By sc.SpecialismComboId
having count(*) = 2
在HQL中相同
from SpecialismCombo sc
join sc.Specialism s
where s.id in (:ids)
group by sc
having count(*) = :numberOfIds
您也可以多次加入专业,因为您有ID可以找到:
IQuery query = session.CreateCriteria<SpecialismCombo>("sc")
int counter = 0;
foreach(int id in ids)
{
string alias = "s" + counter++;
query
.CreateCriteria("Specialism", alias);
.Add(Expression.Eq(alias + ".SpecialismId", id));
}
应该创建一个这样的查询:
select ...
from
SpecialismCombo sc
inner join -- linktable ...
inner join Specialism s0 on ...
inner join -- linktable ...
inner join Specialism s1 on ...
where
s0.SpecialismId = 1
and s1.SpecialismId = 4
答案 1 :(得分:0)
所以我最终创建了一个存储过程并使用SQL CTE,以便只获得具有正确计数专业的专业组合。发布此信息以防其他人遇到类似问题。
使用nhibernate 8个月后重新发现,我忘记了很多SQL的东西:)
DECLARE @IdCollectionCount INT
, @IdCollection VARCHAR(250)
, @CollectionDelimiter NVARCHAR
SET @IdCollectionCount = 2;
SET @IdCollection = '1,4';
SET @CollectionDelimiter= ',';
WITH CustomQuery AS
(
SELECT sc.SpecialismComboId,
count(s.SpecialismId) AS ItemCount
FROM SpecialismCombo sc
inner join SpecialismComboSpecialism scs on sc.SpecialismComboId = scs.SpecialismComboId
inner join Specialism s on s.SpecialismId = scs.SpecialismId
GROUP BY sc.SpecialismComboId
HAVING count(s.SpecialismId) = @IdCollectionCount
)
SELECT Top 1 CustomQuery.SpecialismComboId FROM CustomQuery
INNER JOIN SpecialismComboSpecialism scs on CustomQuery.SpecialismComboId = scs.SpecialismComboId
INNER JOIN dbo.fn_SplitDelimited(@IdCollection,@CollectionDelimiter) AS ids
ON scs.SpecialismId = CAST(ids.ListValue AS INT)
GROUP BY CustomQuery.SpecialismComboId
HAVING count(scs.SpecialismId) = @IdCollectionCount