2011-08-04 86 views
1

工作,所以我有很多的東西稱爲專修和SpecialismCombo之間一對多的關係。我想要做的是接受一個int []的ids,並檢查是否有一個組合已經包含這些id的專長。NHibernate的 - 越來越具有計數和子查詢

我很接近,但並不完全正確。 假設我對Ids 1和Ids擁有專業知識,並且創建了這些專業組合。

如果我通過在3 & 1則返回預期的組合標識。

如果我通過在1然後返回同時具有1和3

我不能僅僅依靠與組合相關專長的總數組合ID。因爲如果一個組合有兩個項目,1和4以及匹配的項目是1和3,我不希望這會回來作爲匹配的組合。

所以這就像我確實需要這一結果的數量,並匹配相關聯的組合總專長的計數。我不太清楚我是在使用子查詢還是使用detatched標準,或者如何使用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計數(s1_.SpecialismId)=(選擇計數從specialismComboSpecialism 其中SpecialismComboId = Y0 組由SpecialismComboId)== P2 @

(SpecialismId)

或者也許它比這更簡單,我需要排除SpecalismCombos,其中combo.specialisms不在ID集合中。

IE瀏覽器。如果組合有專長1和3,但集合只有1 ..那麼我們可以排除基於3集合中不是這個組合...

編輯8/8/2011 回到專注於如何在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

你爲什麼要爲這個標準的NHibernate後重新發現? HQL對於這樣的事情更加強大。 –

+0

介紹HQL與其他應用程序不一致。感謝您提出的解決方案 - 會給它一個:) – Jen

+0

我想我需要添加一個條件,檢查屬於每個組合的專業總數 - 即。獨立於查詢。我只是不知道如何將其轉換爲代碼:( – Jen

回答

0

所以我結束了創建一個存儲過程,爲了使用SQL CTE只得到與專長的正確計數的專長連擊。發佈此信息以防其他人遇到類似問題。

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 
0

您的解決方案實際上應該很好地工作。專家按ID過濾,不應該有任何剩餘的沒有搜索,所以計數應該工作。除非你有同樣的專業加入更多的一次。這currentCriterialastCriteria東西看起來有點奇怪,可能是有錯誤。只需使用Expression.InConjunction即可。

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 
+0

問題依然存在 - 如果我在SpecialismId = 1上進行查找(即我想要組合中只有1個專用ID爲1的組合) - 它仍然返回組合有兩個專長 - 因爲它根據查詢找到1條記錄(即針對組合的專業總數爲2,但查詢不包括該條件)但是您的方法更簡潔,方法是檢查In條件- 謝謝! – Jen