Lambda 表达式
每当您在 LINQ 中看到 Func<...> 或 Expressions<Func<...>> 格式的参数时,您需要提供一个具有正确输入参数和正确返回值的函数。
Func<Ta, Tb, Tc> 表示具有两个输入参数和一个返回值的任何方法。第一个参数是 Ta 类型,第二个参数是 Tb 类型。返回值的类型为 Tc。以下方法可以:
bool String.Equals(string x, string y);
Shop FindShop(Product product, decimal maximumPrice);
当然,这些类型必须与通用 LINQ 方法中的其他类型相匹配。
例如,如果您有Customers 和Orders,并且您想创建PackingSlips,您可能需要为此使用Enumerable.Join。
public static IEnumerable<TResult> Join<TOuter,TInner,TKey,TResult> (
this IEnumerable<TOuter> outer,
IEnumerable<TInner> inner,
Func<TOuter,TKey> outerKeySelector,
Func<TInner,TKey> innerKeySelector,
Func<TOuter,TInner,TResult> resultSelector);
TOuter 的实际类型是Customer,TInner 的实际类型是Order。要生成结果,请使用参数 resultSelector:
Func<TOuter,TInner,TResult> resultSelector
在你的情况下:
Func<Customer, Order , PackingSlip> resultSelector
这意味着,您必须提供一个函数,该函数将具有两个输入参数:Customer 和 Order,并返回 PackingSlip:
PackingSlip CreatePackingSlip(Customer customer, Order order);
因此您将按如下方式使用 Join:
IEnumerable<Customer> customers = ...
IEnumerable<Order> orders = ...
IEnumerable<PackingSlip> packingSlips = customers.Join(orders,
... // parameter keySelector, see later,
// parameter resultSelector:
CreatePackingSlip);
这可以,但不是很方便,因此不会经常使用。例如,如果你有以下方法:
PackingSlip CreatePackingSlip(Order order, Customer customer);
为此创建了 lambda 表达式。它的格式为:
(...) => ...
这意味着:创建一个Func<...>,或一个Action
Func<Customer, Order, PackingSlip> resultSelector
(customer, order) => CreatePackingSlip(order, customer);
等同于:
PackingSlip CreatePackingSlip(Customer customer, Order order)
{
return CreatePackingSlip(order, customer); // call the other overload
}
但实际上你可以为此使用任何代码块:
(customer, order) => new PackingSlip()
{
Customer = customer,
Order = Order,
});
甚至是一小段代码:
(customer, order) =>
{
string addressLines = this.CreateAddressLines(customer);
var orderLines = this.CreateOrderLines(order);
decimal totalPrice = this.CalculateTotalPrice(order);
PackingSlip packingSlip = new PackingSlip()
{
Address = addressLines,
OrderLines = orderLines,
TotalPrice = totalPrice,
};
return packingSlip;
});
什么都可以,只要括号(..., ...)之间的部分以正确的顺序提及Func<...>的参数,=>之后的部分返回func的返回值。
我答应了上面Join的参数keySelector。它们用于指定您要加入的内容。在这种情况下:我们要匹配主键Customer.Id和外键Order.CustomerId:
IEnumerable<Customer> customers = ...
IEnumerable<Order> orders = ...
IEnumerable<PackingSlip> packingSlips = customers.Join(orders,
customer => customer.Id, // from every customer take the primary key in Id
order => order.CustomerId, // from every order take the foreign key CustomerId
// parameter resultSelector take the Customer and its matching Order
// to make one new PackingSlip:
(customer, order) => new PackingSlip()
{
Address = this.CreateAddressLines(customer),
OrderLines = this.CreateOrderLines(order),
TotalPrice = this.CalculateTotalPrice(order),
});
在使用 LINQ 时,使用复数名词来命名项目集合和使用单数名词来命名集合的元素会有所帮助。
因此,如果您加入 customers 和 orders(集合!),您的 lambda 表达式应该使用
// Get Schools, each with their Students:
schools.GroupJoin(students
school => school.Id,
student => student.SchoolId,
(school, studentsOfThisSchool) => new {...})
schools.GroupJoin(students
x => x.Id,
y => y.SchoolId,
(z, a) => new {...})
您确实必须查看代码才能了解 a 中的内容。
回到你的问题
显然您有一个带有EventParticipants 的表,其中每个EventParticipant 都有一个属性CustomerId。您只想获取具有特定值CustomerId 的那些 EventParticipants。
int requestedCustomerId = Session["CustomerId"];
var result = dbContext.EventParticipants.
.Where(eventParticipant => eventParticipant.CustomerId == requestedCustomerId);
因为我使用复数和单数名词,所以很容易阅读:“从EventParticipants表中的每个eventParticipant中,检查其属性CustomerId的值是否等于requestedCustomerId。如果是,请保留eventParticipant,如果不是,不要'不要使用它。
现在您要计算Where 之后剩下的CustomerIds。假设每个 EventParticipant 都只有一个 CustomerId,您可以统计 EventParticipants:
var eventParticipantCount = dbContext.EventParticipants.
.Where(eventParticipant => eventParticipant.CustomerId == requestedCustomerId)
.Count();
但如果您真的想计算 CustomerId,您首先必须选择它们。如果您期望重复的 CustomerId,这将很有用:
var uniqueCustomerIdCount = dbContext.EventParticipants.
.Where(eventParticipant => eventParticipant.CustomerId == requestedCustomerId)
// from every remaining eventParticipant select its CustomerId
.Select(eventParticipant => eventParticipant.CustomerId)
// remove duplicate CustomerIds:
.Distinct()
// and count what is left:
.Count();