2010-03-11 25 views
2

我有一個用戶表和一個到多個UserSkills表。我需要能夠根據技能搜索用戶。該查詢獲取所需技能的列表並搜索具有這些技能的用戶。我想根據他們擁有的期望技能的數量對用戶進行排序。所以如果一個用戶只有3個所需技能中的1個,他將比具有3個所需技能3個的用戶更低。有沒有更好的方式來編寫這個frankenstein LINQ查詢,它在子表中搜索值並按相關性對它們進行排序?

我開始與我的逗號分隔正在搜索技能ID列表:

List<short> searchedSkillsRaw = skills.Value.Split(',').Select(i => short.Parse(i)).ToList(); 

我再過濾出的類型可搜索用戶:

List<User> users = (from u in db.Users 
        where 
         u.Verified == true && 
         u.Level > 0 && 
         u.Type == 1 && 
         (u.UserDetail.City == city.SelectedValue || u.UserDetail.City == null) 
        select u).ToList(); 

,然後來瘋狂的部分:

var fUsers = from u in users 
      select new 
      { 
       u.Id, 
       u.FirstName, 
       u.LastName, 
       u.UserName, 
       UserPhone = u.UserDetail.Phone, 
       UserSkills = (from uskills in u.UserSkills 
           join skillsJoin in configSkills on uskills.SkillId equals skillsJoin.ValueIdInt into tempSkills 
           from skillsJoin in tempSkills.DefaultIfEmpty() 
           where uskills.UserId == u.Id 
           select new 
           { 
            SkillId = uskills.SkillId, 
            SkillName = skillsJoin.Name, 
            SkillNameFound = searchedSkillsRaw.Contains(uskills.SkillId) 
           }), 
       UserSkillsFound = (from uskills in u.UserSkills 
            where uskills.UserId == u.Id && searchedSkillsRaw.Contains(uskills.SkillId) 
            select uskills.UserId).Count() 
      } into userResults 
      where userResults.UserSkillsFound > 0 
      orderby userResults.UserSkillsFound descending 
      select userResults; 

這個工程!但對我來說,它似乎超級臃腫和低效。特別是計算所發現技能數量的次要部分。

感謝您的任何建議,你可以給。

--R

回答

0

爲什麼不讓人呢,比如說,fUsers.UserSkills.Count()?這將首先減少從服務器檢索的數據量。

或者,您可以創建一個包含計算字段的視圖,然後將其映射到類型。將查詢倒計數到數據庫中。

3

我認爲應該做的伎倆:

(from u in users 
where u.UserSkills.Any(skill => searchedSkillsRaw.Contains(skill.SkillId)) 
select new 
{ 
    u.Id, 
    u.FirstName, 
    u.LastName, 
    u.UserName, 
    UserPhone = u.UserDetail.Phone, 
    UserSkills = u.UserSkills, 
    UserSkillsFound = u.UserSkills.Where(skill => searchedSkillsRaw.Contains(skill.SkillId)).Count() 
} into userResults 
orderby userResults.UserSkillsFound descending 
select userResult).ToList(); 

然而,由於這是獲取SQL服務器上執行我強烈建議刪除「ToList()」第一個查詢電話查詢。因爲這實際上導致LINQ在SQL服務器上運行兩個單獨的查詢。您應該將其更改爲IQueryable。 LINQ的強大之處在於可以通過多個步驟構建查詢,而無需在兩者之間實際執行查詢。所以'ToList'應該在整個查詢結構完成時才被調用。實際上你現在做的是在內存中而不是在數據庫服務器上運行第二個查詢。

關於您的UserSkills一對多關係,您不需要在LINQ中進行明示加入。您可以改爲訪問集合屬性。

讓我知道你是否需要更多的解釋。

Michael

+0

謝謝。查詢更改工作。 re:IQueryable。我將我的第一個查詢更改爲IQueryable,但後來我得到本地序列不能用於LINQ to SQL實現錯誤,當我嘗試DataBind第二個查詢的結果時。 – MRV 2010-03-12 07:19:22

+0

re:UserSkills表的顯式連接,我在嵌套的DataBind中使用它。 – MRV 2010-03-12 07:22:00

+0

只需調用ToList(),以便數據綁定列表......這是否工作? – 2010-03-17 18:00:31

相關問題