Using Count with Take with LINQ

Is there a way to get the entire invoice using the Take statement?

+2


a source to share


3 answers


You can do both.

IEnumerable<T> query = ...complicated query;
int c = query.Count();
query = query.Take(n);

      

Just complete the count before taking. this will execute the query twice, but I believe this is inevitable.

if it is in the Linq2SQL context as your comment suggests, then this will actually query the database twice. As lazy loading goes though it will depend on how the query result is actually used.

For example: if two tables contain Product

and ProductVersion

, where each Product

has several ProductVersions

, linked through a foreign key.



if this is your request:

var query = db.Products.Where(p => complicated condition).OrderBy(p => p.Name).ThenBy(...).Select(p => p);

      

where you just select Products

, but after doing the query:

var results = query.ToList();//forces query execution
results[0].ProductVersions;//<-- Lazy loading occurs

      

if you are referencing any foreign key or related object that was not part of the original request, then it will be lazy. In your case, the counter won't trigger any lazy loading because it just returns an int. but depending on what you are actually doing with the result Take()

, you may or may not have Lazy loading. Sometimes it can be tricky to determine if you have a LazyLoading ocurring to check that you should be logging your requests using a property DataContext.Log

.

+6


a source


The easiest way is to just execute Count

queries and then do Take

:



var q = ...;
var count = q.Count();
var result = q.Take(...);

      

+4


a source


This can be done in a single Linq-to-SQL query (where only one SQL statement will be executed). The generated SQL does look nasty, so performance may vary.

If this is your request:

IQueryable<Person> yourQuery = People
    .Where(x => /* complicated query .. */);

      

You can add the following to it:

var result = yourQuery
    .GroupBy (x => true) // This will match all of the rows from your query ..
    .Select (g => new {
        // .. so 'g', the group, will then contain all of the rows from your query.
        CountAll = g.Count(),
        TakeFive = g.Take(5),
        // We could also query for a max value.
        MaxAgeFromAll = g.Max(x => x.PersonAge)
    })
    .FirstOrDefault();

      

This will allow you to access your data like this:

// Check that result is not null before access.
// If there are no records to find, then 'result' will return null (because of the grouping)
if(result != null) {

    var count = result.CountAll;

    var firstFiveRows = result.TakeFive;

    var maxPersonAge = result.MaxAgeFromAll;

}

      

+2


a source







All Articles