简体   繁体   中英

How can i use Count with condition in LINQ

I wanted to get the number of times that , the customer participant our events. So the sql code is suppose to be like this.

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

And LINQ code is like this is I am not mistaken, it will return the value of the Count() right.

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

But it return this error code

'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

You need to pass a lambda that takes the entity and returns a bool , like this

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

Note you'll also want to put the id into a separate variable as EF will not be able to translate Session into SQL.

You need to assign the Session["CustomerID"] value to a variable before you use that in the EF Linq query.

Also, You need not filter and then get the count you can mention the condition inside the LINQ count function directly. Please refer below

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

Try this instead:

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

When you do Count later, it will do count in memory after getting all results. Essentially it will do SELECT * FROM EventsParticipants WHERE (CustomerID == Session["CustomerID"]); and then in memory it will find how many items are there. (Don't do this)

If you do what is shown above will create the same query as you intended and will be faster.

Lambda Expressions

Whenever you see in LINQ a parameter in the format of Func<...> , or Expressions<Func<...>> , you need to provide a function with the correct input parameters and the correct return value.

Func<Ta, Tb, Tc> represents any method that has two input parameters and a return value. The first parameter is of type Ta, the second parameter is of type Tb. The returnvalue is of type Tc. The following methods will do:

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

Of course the types must match the other types in your generic LINQ method.

For example, if you have Customers and Orders , and you want to create PackingSlips , you might want to use Enumerable.Join for this.

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

The actual type of TOuter is Customer , the actual type of TInner is Order. To produce the result you use parameter resultSelector:

Func<TOuter,TInner,TResult> resultSelector

In your case:

Func<Customer, Order , PackingSlip> resultSelector

This means, that you have to provide a function that will have two input parameters: Customer and Order, and that returns a PackingSlip:

PackingSlip CreatePackingSlip(Customer customer, Order order);

So you will use the Join as follows:

IEnumerable<Customer> customers = ...
IEnumerable<Order> orders = ...
IEnumerable<PackingSlip> packingSlips = customers.Join(orders,
    ... // parameter keySelector, see later,

    // parameter resultSelector:
    CreatePackingSlip);

This will do, but it is not very handy, and thus will not be used very often. For instance, what if you have the following method:

PackingSlip CreatePackingSlip(Order order, Customer customer);

For this the lambda expression is created. It has the format of:

(...) => ...

This means: create a Func<...> , or an Action<with the input parameters between the brackets and the code that is after the arrow. For example

Func<Customer, Order, PackingSlip> resultSelector

(customer, order) => CreatePackingSlip(order, customer);

is the same as:

PackingSlip CreatePackingSlip(Customer customer, Order order)
{
    return CreatePackingSlip(order, customer); // call the other overload
}

But in fact you can use any code block for this:

(customer, order) => new PackingSlip()
                     {
                          Customer = customer,
                          Order = Order,
                     });

Or even a small piece of Code:

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

Anything will do, as long as the part between the brackets (..., ...) mention the arguments of the Func<...> in the correct order, and the part after the => returns the return value of the func.

I promised the parameters keySelector of the Join above. They are use to specify what you want to join on. In this case: we want to match the primary key Customer.Id with the foreign key 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),
    });

When using LINQ it helps to use plural nouns to name collections of items, and to use singular nouns to name elements of the collections.

So if you Join customers and orders (collections!), your lambda expressions should use

// 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 {...})

You really have to look at the code to understand what is in a .

Back to your question

Apparently you have a table with EventParticipants , where every EventParticipant has a property CustomerId . You want to get only those EventParticipants that have a specific value of CustomerId .

int requestedCustomerId = Session["CustomerId"];
var result = dbContext.EventParticipants.
    .Where(eventParticipant => eventParticipant.CustomerId == requestedCustomerId);

Because I use plurals and singular nouns, it is easy to read: "From every eventParticipant in the table of EventParticipants, ckeck if the value of its property CustomerId equals requestedCustomerId. If so, keep the eventParticipant, if not, don't use it.

Now you want to count the CustomerIds that are left after your Where . Assuming that every EventParticipant has exactly one CustomerId, you can count the EventParticipants:

var eventParticipantCount = dbContext.EventParticipants.
    .Where(eventParticipant => eventParticipant.CustomerId == requestedCustomerId)
    .Count();

But if you really want to count the CustomerIds, you'll first to have to select them. This would be useful if you expect duplicate 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();

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM