2010-03-11 24 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

相关问题