C# 可以组合SELECT和WHERE LINQ子句吗?
下面是我为C# 可以组合SELECT和WHERE LINQ子句吗?,c#,linq,C#,Linq,下面是我为选择用户到我的模型中,然后删除所有null记录所做的操作: model.Users = users .Select(u => { var membershipUser = Membership.GetUser(u.UserName); return membershipUser != null ? new UserBriefModel
选择用户到我的模型中,然后删除所有null
记录所做的操作:
model.Users = users
.Select(u =>
{
var membershipUser = Membership.GetUser(u.UserName);
return membershipUser != null
? new UserBriefModel
{
Username = u.UserName,
Fullname = u.FullName,
Email = membershipUser.Email,
Roles = u.UserName.GetRoles()
}
: null;
})
.Where(u => u != null)
.ToList();
想知道是否有办法将SELECT
和WHERE
子句组合起来
我试过:
model.Users = users
.Select(u =>
{
var membershipUser = Membership.GetUser(u.UserName);
if (membershipUser != null)
return new UserBriefModel
{
Username = u.UserName,
Fullname = u.FullName,
Email = membershipUser.Email,
Roles = u.UserName.GetRoles()
};
})
.ToList();
但是智能感知提示了一个语法错误。这迫使我添加一个返回null
语句:
model.Users = users
.Select(u =>
{
var membershipUser = Membership.GetUser(u.UserName);
if (membershipUser != null)
return new UserBriefModel
{
Username = u.UserName,
Fullname = u.FullName,
Email = membershipUser.Email,
Roles = u.UserName.GetRoles()
};
return null;
})
.ToList();
那么,编写此SELECT
语句以便只在我的模型中选择有效记录的正确方法是什么
model.Users = users
.Where(u => u.Membership != null)
.Select(u => new UserBriefModel
{
Username = u.UserName,
Fullname = u.FullName,
Email = u.Membership.Email,
Roles = u.UserName.GetRoles()
})
.ToList();
首先筛选,然后选择。对于此解决方案,您需要具有导航属性,以便可以执行u.Membership.Email
而不是membershipUser.Email
我的用户看起来像:
public class UserProfile
{
// other properties
public virtual Membership Membership { get; set; }
}
其中,Membership
是表示成员资格表的实体,通过以下方式映射:
modelBuilder.Entity<Membership>()
.HasRequired<UserProfile>(m => m.User)
.WithOptional(u => u.Membership);
modelBuilder.Entity()
.HasRequired(m=>m.User)
.可选(u=>u.Membership);
然后,您可以通过一个查询选择所有内容。这里的一些其他解决方案也可以很好地工作,但是每次调用成员资格。GetUser(u.UserName)
都会导致一个额外的DB调用。我认为这是不可能的,Select
会将所有内容映射到我所知道的1-1……如果您试图筛选,您将需要一个Where
编辑:
我不再相信SelectMany
可以做到这一点(如Servy所示) 我不知道有哪种Linq方法允许您任意添加或不将值添加到生成的IEnumerable中
为此,lambda(选择器、谓词、过滤器…)应该能够控制此添加。并且只有谓词(Where)能够执行此操作。在您的情况下,您必须执行谓词(Where)并选择。除了答案末尾描述的一种非直接方法外,没有任何组合方法可以同时为您提供这两种方法
model.Users = users
.Where(u => Membership.GetUser(u.UserName) != null)
.Select(u =>
{
return new UserBriefModel
{
Username = u.UserName,
Fullname = u.FullName,
Email = Membership.GetUser(u.UserName).Email,
Roles = u.UserName.GetRoles()
};
})
.ToList();
我们可以通过这样的预筛选获得两个Membership.GetUser(u.UserName)成员身份,也可以以您最初的后筛选结束
这只是改变了复杂性。而且很难说哪里的表现会更好。
这取决于Membership.GetUser
是否很快,并且有很多非成员用户——例如我的例子。或者,如果Membership.GetUser
消耗资源,并且几乎没有非成员用户,那么使用postfilter的示例会更好
与任何基于性能的决策一样,应对其进行全面考虑和检查。在大多数情况下,差别很小
正如另一篇文章中已经显示的,并由“Servy”先生指出,可以通过调用SelectMany
SelectMany选择空IEnumerable或1元素数组来实现。但我仍然认为第一个语句在技术上是正确的,因为SelectMany返回元素集合(它不直接添加或不直接添加单个元素):
model.Users=用户
.选择多个(u=>
{
var membership=membership.GetUser(u.UserName);
if(成员资格==null)
返回可枚举的.Empty();
返回新的UserBriefModel[]
{
新用户模型()
{
用户名=u.Username,
Fullname=u.Fullname,
电子邮件=会员资格。电子邮件,
Roles=u.UserName.GetRoles()
}
};
})
.ToList();
从概念上讲,这里实际上有三个操作:
将用户名投影到成员资格用户
筛选出空成员资格用户
将成员资格用户投影到模型
这就是您的查询的外观。你的第一个查询已经尝试将步骤1和3结合在一起,但是你正在挣扎,因为第二步真的应该在这两个中间,而你需要跳过的环来绕开那些不漂亮的。
当您分别表示所有三个操作时,查询实际上变得更简单和可读(并成为习惯用法的LINQ代码)
model.Users = users
.Select(user => new
{
user,
membershipUser = Membership.GetUser(user.UserName)
})
.Where(pair => pair.membershipUser != null)
.Select(pair => new UserBriefModel
{
Username = pair.user.UserName,
Fullname = pair.user.FullName,
Email = pair.membershipUser.Email,
Roles = pair.user.UserName.GetRoles()
})
.ToList();
这是一个可以更有效地用查询语法编写的查询:
model.Users = from user in users
let membershipUser = Membership.GetUser(user.UserName)
where membershipUser != null
select new UserBriefModel
{
Username = user.UserName,
Fullname = user.FullName,
Email = membershipUser.Email,
Roles = user.UserName.GetRoles()
};
至于字面上的问题,即是否可以将滤波投影组合到单个LINQ操作中,这当然是可能的。这将是一个不合适的问题解决方案,但使用SelectMany
可以让您同时进行筛选和投影。这可以通过将项投影到包含要将其投影到的值的单项序列或基于谓词的空序列来实现
model.Users = users
.SelectMany(u =>
{
var membershipUser = Membership.GetUser(u.UserName);
return membershipUser != null
? new[]{ new UserBriefModel
{
Username = u.UserName,
Fullname = u.FullName,
Email = membershipUser.Email,
Roles = u.UserName.GetRoles()
}}
: Enumerable.Empty<UserBriefModel>();
}).ToList();
model.Users=用户
.选择多个(u=>
{
var membershipUser=Membership.GetUser(u.UserName);
返回membershipUser!=null
?新建[]{new UserBriefModel
{
用户名=u.Username,
Fullname=u.Fullname,
Email=会员身份用户。Email,
Roles=u.UserName.GetRoles()
}}
:Enumerable.Empty();
}).ToList();
当然,每次你使用这个密码,都会有一只小猫被杀。不要杀小猫;改用前面的查询。您可以使用一种方法来完成此操作:
private IEnumerable<UserBriefModel> SelectUserBriefModels(IEnumerable<User> users)
{
foreach (var user in users)
{
var membershipUser = Membership.GetUser(user.UserName);
if (membershipUser != null)
{
yield return new UserBriefModel
{
Username = user.UserName,
Fullname = user.FullName,
Email = membershipUser.Email,
Roles = user.UserName.GetRoles()
};
}
}
}
您得到的构建错误是什么?另外,我建议在尝试使用实体之前进行空检查,否则会在linq中得到空引用,这是一个令人痛苦的问题,为什么?将where和select分开有什么问题?只想知道是否可以将两者结合起来。首先用一些无用的记录填充模型,然后过滤掉它们,感觉有点难看。在SELECT
子句中丢弃null
s不是更好吗?在第二个代码示例中,lambda不正确-当membership为null时,它返回什么?Lambda,匿名方法是相同的方法-它们应该是正确的方法
private IEnumerable<UserBriefModel> SelectUserBriefModels(IEnumerable<User> users)
{
foreach (var user in users)
{
var membershipUser = Membership.GetUser(user.UserName);
if (membershipUser != null)
{
yield return new UserBriefModel
{
Username = user.UserName,
Fullname = user.FullName,
Email = membershipUser.Email,
Roles = user.UserName.GetRoles()
};
}
}
}
model.Users = SelectUserBriefModels(users);