c# - 有没有更好的方法来编写这个 Frankenstein LINQ 查询,在子表中搜索值并按相关性对它们进行排序?

标签 c# asp.net linq linq-to-sql

我有一个用户表和一个一对多的用户技能表。我需要能够根据技能搜索用户。此查询获取所需技能的列表并搜索具有这些技能的用户。我想根据用户拥有的所需技能的数量对用户进行排序。因此,如果用户仅拥有 3 种所需技能中的 1 种,那么他将比拥有 3 种所需技能中的 3 种的用户在列表中的位置更靠后。

我从正在搜索的技能 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;

这有效!但对我来说,它似乎 super 臃肿且效率低下。尤其是计算找到的技能数量的次要部分。

感谢您提供的任何建议。

--r

最佳答案

我认为这应该可以解决问题:

(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 Server 上执行的查询,我强烈建议从第一个查询中删除“ToList()”调用。因为这实际上会导致 LINQ 在 SQL 服务器上运行两个单独的查询。您应该将其更改为 IQueryable。 LINQ 的强大之处在于可以通过几个步骤构建查询,而无需在中间实际执行它。因此,仅应在构建整个查询的最后调用“ToList”。事实上,您当前所做的是在内存中而不是在数据库服务器上运行第二个查询。

对于您的 UserSkills 一对多关系,您不需要在 LINQ 中进行显式联接。您可以只访问集合属性。

如果您需要更多解释,请告诉我。

迈克尔

关于c# - 有没有更好的方法来编写这个 Frankenstein LINQ 查询,在子表中搜索值并按相关性对它们进行排序?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/2428121/

相关文章:

使用 RDP 8.0 的 C# 自定义远程桌面客户端

c# - 默认响应 Content-Type 有问题

c# - 重载基础构造函数

c# - 如何将查询字符串转换为 json 字符串?

c# - 将多个表转换为数据集

javascript - 使用 JavaScript 变量作为路由参数

c# - 合并数组中的多个 LINQ 表达式

c# - LINQ OrderBy().ThenBy() 不工作

c# - LINQ:跳过并获取重复项

c# - 录制编码播放并保存一个 wav 文件