如何在LINQ中执行子查询?

mar*_*l_g 67 c# linq linq-to-sql

这是我试图转换为LINQ的查询示例:

SELECT *
FROM Users
WHERE Users.lastname LIKE '%fra%'
    AND Users.Id IN (
         SELECT UserId 
         FROM CompanyRolesToUsers 
         WHERE CompanyRoleId in (2,3,4) )
Run Code Online (Sandbox Code Playgroud)

CompanyRolesToUsers和之间存在FK关系Users,但它是多对多的关系,并且CompanyRolesToUsers是联结表.

我们已经构建了大部分网站,并且我们已经通过使用PredicateExtensions类构建Expressions来完成大部分过滤工作.

简单过滤器的代码如下所示:

 if (!string.IsNullOrEmpty(TextBoxLastName.Text))
 {
     predicateAnd = predicateAnd.And(c => c.LastName.Contains(
                                     TextBoxLastName.Text.Trim()));
 }

e.Result = context.Users.Where(predicateAnd);
Run Code Online (Sandbox Code Playgroud)

我正在尝试在另一个表中为子选择添加谓词.(CompanyRolesToUsers)

我希望能够添加的内容是:

int[] selectedRoles = GetSelectedRoles();
if( selectedRoles.Length > 0 )
{
    //somehow only select the userid from here ???:
    var subquery = from u in CompanyRolesToUsers
                   where u.RoleID in selectedRoles
                   select u.UserId;

    //somehow transform this into an Expression ???:
    var subExpression = Expression.Invoke(subquery);

    //and add it on to the existing expressions ???:
    predicateAnd = predicateAnd.And(subExpression);
}
Run Code Online (Sandbox Code Playgroud)

有没有办法做到这一点?这很令人沮丧,因为我可以轻松编写存储过程,但我是这个LINQ的新手,我有一个截止日期.我找不到匹配的例子,但我确定它在某处.

Amy*_*y B 77

这是给你的子查询!

List<int> IdsToFind = new List<int>() {2, 3, 4};

db.Users
.Where(u => SqlMethods.Like(u.LastName, "%fra%"))
.Where(u =>
    db.CompanyRolesToUsers
    .Where(crtu => IdsToFind.Contains(crtu.CompanyRoleId))
    .Select(crtu =>  crtu.UserId)
    .Contains(u.Id)
)
Run Code Online (Sandbox Code Playgroud)

关于这部分问题:

predicateAnd = predicateAnd.And(c => c.LastName.Contains(
                                TextBoxLastName.Text.Trim()));
Run Code Online (Sandbox Code Playgroud)

我强烈建议在创建查询之前从文本框中提取字符串.

string searchString = TextBoxLastName.Text.Trim();
predicateAnd = predicateAnd.And(c => c.LastName.Contains( searchString));
Run Code Online (Sandbox Code Playgroud)

您希望对发送到数据库的内容保持良好的控制.在原始代码中,一个可能的读取是未修剪的字符串被发送到数据库进行修剪 - 这对数据库来说不是一件好事.

  • 感谢您提供有用的代码.这无疑表明事物可以链接在一起.在将它交给Linq之前你也可能正确执行字符串操作,将事情分开肯定不会有害. (2认同)

The*_*edi 22

此语句不需要子查询,更好地编写为

select u.* 
from Users u, CompanyRolesToUsers c
where u.Id = c.UserId        --join just specified here, perfectly fine
and u.lastname like '%fra%'
and c.CompanyRoleId in (2,3,4)
Run Code Online (Sandbox Code Playgroud)

要么

select u.* 
from Users u inner join CompanyRolesToUsers c
             on u.Id = c.UserId    --explicit "join" statement, no diff from above, just preference
where u.lastname like '%fra%'
  and c.CompanyRoleId in (2,3,4)
Run Code Online (Sandbox Code Playgroud)

话虽如此,在LINQ中它会是

from u in Users
from c in CompanyRolesToUsers 
where u.Id == c.UserId &&
      u.LastName.Contains("fra") &&
      selectedRoles.Contains(c.CompanyRoleId)
select u
Run Code Online (Sandbox Code Playgroud)

要么

from u in Users
join c in CompanyRolesToUsers 
       on u.Id equals c.UserId
where u.LastName.Contains("fra") &&
      selectedRoles.Contains(c.CompanyRoleId)
select u
Run Code Online (Sandbox Code Playgroud)

这也是表达这一点的可敬方式.在这两种情况下,我更喜欢显式的"连接"语法,但它有......

  • 嗯,当你可以"加入和分离"时,为什么要"过滤".是因为"加入和分离"是自然而令人兴奋的SQL而"过滤器"只是不够令人兴奋吗? (2认同)
  • 好吧,既然我被邀请了......事实:没有优化器可以将Distinct(n ^ 2)变成过滤器(n). (2认同)

Noa*_*oah 6

这就是我在LINQ中做子查询的方式,我认为这应该得到你想要的.您可以将显式CompanyRoleId == 2 ...替换为您想要的不同角色的另一个子查询,也可以将其加入.

from u in Users
join c in (
    from crt in CompanyRolesToUsers
    where CompanyRoleId == 2
    || CompanyRoleId == 3
    || CompanyRoleId == 4) on u.UserId equals c.UserId
where u.lastname.Contains("fra")
select u;
Run Code Online (Sandbox Code Playgroud)

  • 他要求一个子查询!但我确信LINQ无论如何都将它改为同一个SQL ...... (5认同)
  • 我必须在"== 4"之后加上"select crt"以避免错误"查询正文必须以select子句或group子句结束" (2认同)