簡體   English   中英

我如何在 LINQ 中使用帶條件的計數

[英]How can i use Count with condition in LINQ

我想獲得客戶參與我們活動的次數。 所以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

您需要傳遞一個接受實體並返回bool的 lambda ,就像這樣

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

請注意,您還需要將 id 放入一個單獨的變量中,因為 EF 將無法將Session轉換為 SQL。

在 EF Linq 查詢中使用該值之前,您需要將Session["CustomerID"]值分配給一個變量。

此外,您無需過濾然后獲取計數,您可以直接在 LINQ 計數函數中提及條件。 請參考以下

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

試試這個:

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

當你稍后進行Count ,它會在獲得所有結果后在內存中進行計數。 本質上它會做SELECT * FROM EventsParticipants WHERE (CustomerID == Session["CustomerID"]); 然后在內存中它會找到有多少項目。 (不要這樣做)

如果您執行上面顯示的操作,將創建與您預期相同的查詢,並且速度會更快。

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 方法中的其他類型相匹配。

例如,如果您有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的實際類型Customer的實際類型TInner是秩序。 要生成結果,請使用參數 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<...>的參數,並且=>后面的部分返回函數的返回值功能

我答應了上面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();

但如果您真的想計算 CustomerIds,您首先必須選擇它們。 如果您期望重復的 CustomerIds,這將很有用:

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();

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM