【问题标题】:How can i use Count with condition in LINQ如何在 LINQ 中使用 Count 和条件
【发布时间】:2020-09-09 02:27:50
【问题描述】:

我想知道客户参与我们活动的次数。所以sql代码应该是这样的。

SELECT COUNT(CustomerID)
FROM EventsParticipants
WHERE (CustomerID == Session["CustomerID"]);

而LINQ代码是这样的,我没记错,它会返回Count()的值对。

var recordcount = db.EventParticipants.Where(Session["CustomerID] == db.EventParticipants.CustomerID).Count();

但它返回此错误代码

'DbSet<EventParticipants>' does not contain a definition for 'CustomerID' and no accessible extension method 'CustomerID' accepting a first argument of type 'DbSet<EventParticipants>' could be found (are you missing a using directive or an assembly reference?)    LeafLife

【问题讨论】:

    标签: c# linq linq-to-sql sql-to-linq-conversion


    【解决方案1】:

    您需要传递一个接受实体并返回 bool 的 lambda,像这样

    var id = Session["CustomerID"];
    var recordcount = db.EventParticipants.Where(x => x.CustomerID == id).Count();
    

    请注意,您还需要将 id 放入单独的变量中,因为 EF 无法将 Session 转换为 SQL。

    【讨论】:

      【解决方案2】:

      在 EF Linq 查询中使用之前,您需要将 Session["CustomerID"] 值分配给变量。

      另外,您无需过滤然后获取计数,您可以直接在 LINQ 计数函数中提及条件。请参考下文

      var id = Convert.ToInt32(Session["CustomerID"]); // Assuming this as int
      var recordcount = db.EventParticipants.Count(x => x.CustomerID == id);
      

      【讨论】:

        【解决方案3】:

        试试这个:

        var id = Session["CustomerID"];    
        var recordcount = db.EventParticipants.Count(t=> id == t.CustomerID);
        

        当您稍后执行Count 时,它会在获得所有结果后计入内存。本质上它会做SELECT * FROM EventsParticipants WHERE (CustomerID == Session["CustomerID"]);,然后在内存中它会找到有多少项目。 (不要这样做)

        如果您按照上面显示的方式进行操作,将创建与您预期相同的查询,并且会更快。

        【讨论】:

        • 只是为了清楚使用Where(predicate).Count()Count(predicate) 将导致相同的SQL,修复实际上是传递一个适当的lambda。
        【解决方案4】:

        Lambda 表达式

        每当您在 LINQ 中看到 Func&lt;...&gt;Expressions&lt;Func&lt;...&gt;&gt; 格式的参数时,您需要提供一个具有正确输入参数和正确返回值的函数。

        Func&lt;Ta, Tb, Tc&gt; 表示具有两个输入参数和一个返回值的任何方法。第一个参数是 Ta 类型,第二个参数是 Tb 类型。返回值的类型为 Tc。以下方法可以:

        bool String.Equals(string x, string y);
        Shop FindShop(Product product, decimal maximumPrice);
        

        当然,这些类型必须与通用 LINQ 方法中的其他类型相匹配。

        例如,如果您有CustomersOrders,并且您想创建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 的实际类型是CustomerTInner 的实际类型是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&lt;...&gt;,或一个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&lt;...&gt;的参数,=&gt;之后的部分返回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 时,使用复数名词来命名项目集合和使用单数名词来命名集合的元素会有所帮助。

        因此,如果您加入 customersorders(集合!),您的 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();
        

        【讨论】:

        • 感谢您分享的信息和知识。
        猜你喜欢
        • 2016-10-27
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2020-02-25
        • 1970-01-01
        • 2018-05-08
        • 2020-10-02
        相关资源
        最近更新 更多