以下是我尝试转换为LINQ的查询示例:
SELECT *
FROM Users
WHERE Users.lastname LIKE '%fra%'
AND Users.Id IN (
SELECT UserId
FROM CompanyRolesToUsers
WHERE CompanyRoleId in (2,3,4) )
CompanyRolesToUsers
和Users
之间存在FK关系,但它是多对多关系,CompanyRolesToUsers
是联结表。
我们已经构建了大部分网站,并且我们已经通过使用PredicateExtensions类构建表达式来完成大部分过滤工作。
直接过滤器的代码如下所示:
if (!string.IsNullOrEmpty(TextBoxLastName.Text))
{
predicateAnd = predicateAnd.And(c => c.LastName.Contains(
TextBoxLastName.Text.Trim()));
}
e.Result = context.Users.Where(predicateAnd);
我正在尝试在另一个表中为子选择添加谓词。 (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);
}
有没有办法做到这一点?这很令人沮丧,因为我可以轻松编写存储过程,但我是这个LINQ的新手,我有一个截止日期。我无法找到匹配的例子,但我确定它在某处。
答案 0 :(得分:76)
这是给你的子查询!
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)
)
关于这部分问题:
predicateAnd = predicateAnd.And(c => c.LastName.Contains(
TextBoxLastName.Text.Trim()));
我强烈建议在创作查询之前从文本框中提取字符串。
string searchString = TextBoxLastName.Text.Trim();
predicateAnd = predicateAnd.And(c => c.LastName.Contains( searchString));
您希望对发送到数据库的内容保持良好的控制。在原始代码中,一个可能的读取是未修剪的字符串被发送到数据库中进行修剪 - 这对数据库来说不是一件好事。
答案 1 :(得分: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)
或
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)
话虽如此,在LINQ中它将是
from u in Users
from c in CompanyRolesToUsers
where u.Id == c.UserId &&
u.LastName.Contains("fra") &&
selectedRoles.Contains(c.CompanyRoleId)
select u
或
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
这又是表达这一点的可敬方式。在这两种情况下,我更喜欢显式的“连接”语法,但它就是......
答案 2 :(得分:5)
这就是我在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;
答案 3 :(得分:2)
你可以为你的情况做这样的事情 - (语法可能有点偏离)。另请查看此link
subQuery = (from crtu in CompanyRolesToUsers where crtu.RoleId==2 || crtu.RoleId==3 select crtu.UserId).ToArrayList();
finalQuery = from u in Users where u.LastName.Contains('fra') && subQuery.Contains(u.Id) select u;
答案 4 :(得分:2)
好的,这是一个获得正确记录的基本连接查询:
int[] selectedRolesArr = GetSelectedRoles();
if( selectedRolesArr != null && selectedRolesArr.Length > 0 )
{
//this join version requires the use of distinct to prevent muliple records
//being returned for users with more than one company role.
IQueryable retVal = (from u in context.Users
join c in context.CompanyRolesToUsers
on u.Id equals c.UserId
where u.LastName.Contains( "fra" ) &&
selectedRolesArr.Contains( c.CompanyRoleId )
select u).Distinct();
}
但是这里的代码最容易与我们已有的算法集成:
int[] selectedRolesArr = GetSelectedRoles();
if ( useAnd )
{
predicateAnd = predicateAnd.And( u => (from c in context.CompanyRolesToUsers
where selectedRolesArr.Contains(c.CompanyRoleId)
select c.UserId).Contains(u.Id));
}
else
{
predicateOr = predicateOr.Or( u => (from c in context.CompanyRolesToUsers
where selectedRolesArr.Contains(c.CompanyRoleId)
select c.UserId).Contains(u.Id) );
}
这要归功于LINQtoSQL forum
上的海报答案 5 :(得分:1)
这是返回正确记录的SQL版本:
select distinct u.*
from Users u, CompanyRolesToUsers c
where u.Id = c.UserId --join just specified here, perfectly fine
and u.firstname like '%amy%'
and c.CompanyRoleId in (2,3,4)
另外,请注意(2,3,4)是从Web应用程序用户的复选框列表中选择的列表,我忘了提到我只是为了简单而硬编码。实际上它是一组CompanyRoleId值,因此它可以是(1)或(2,5)或(1,2,3,4,6,7,99)。
另外我应该更清楚地指出的是,PredicateExtensions用于动态地将谓词子句添加到查询的Where中,具体取决于Web应用程序用户填写的表单字段。所以棘手的部分是我是如何将工作查询转换为LINQ表达式,我可以附加到动态表达式列表。
我将给出一些示例LINQ查询,看看我是否可以将它们与我们的代码集成,然后发布我的结果。谢谢!
烫发