简体   繁体   中英

How can I speed up my LINQ query without using a table twice?

So I am using a table twice in my query, and I dont know of another way to only use it once. Here is my query:

var result = (from t1 in (from t1 in db.Students.Where(en => en.Progress == MyEnum.Accepted).GroupBy(en => en.Class).AsEnumerable()
                          join t2 in dbOther.Classes on t1.Key equals t2.Class 
                          select t2)
              join t3 in (db.Students).AsEnumerable() on t1.Class equals t3.Class into t4
              select new
                          {
                              ClassNum = t1.Class,
                              StartDate = t1.StartDate,
                              Weeks = t1.Weeks,
                              Accepted = t4.Where(e => e.Progress == MyEnum.Accepted).Count(),
                              NotAccepted = t4.Where(e => e.Progress < MyEnum.Accepted).Count()
                          }).ToList();

I need to only get classes that have students in the accepted state. Then I want to get the classes and the count of its entire roster, even the students that are not accepted. Is there a better way to do this? It seems like reading from the same table twice is not the fastest way to do this.

Thank you for the help.

Unless you're really simplifying the query here, you don't really need to hit dbOther to find out what classes has any students in the Accepted state. That information is in db .

var studentCountPerClass = (from s in db.Students
                            group s by s.Class into studentsByClass    
                            where studentsByClass.Any(x => x.Progress == MyEnum.Accepted)
                            select new
                            {
                                ClassNum = studentsByClass.Key,
                                Accepted = studentsByClass.Count(s => s.Progress == MyEnum.Accepted),
                                NotAccepted = studentsByClass.Count(s => s.Progress < MyEnum.Accepted),
                            })
                            .ToList();

var classCodes = studentCountPerClass.Select(x => x.ClassNum).ToList(); 
var classData = (from c in dbOther.Classes
                    where classCodes.Contains(c.Class)
                    select new {
                        c.Class,
                        // Any other data you want about the class
                    })

First, fetch information about student enrollment from db.Students table:

var stats = db.Students
    .GroupBy(en => en.Class)
    .Select(g => new {
        Class = g.Key
    ,   Accepted = g.Count(en => en.Progress == MyEnum.Accepted)
    ,   NotAccepted = g.Count(en => en.Progress < MyEnum.Accepted)
    })
    .Where(g => g.Accepted != 0)
    .ToList();

Next, fetch classes from the other database:

var classIds = stats.Select(en => en.Class).ToList();
var classes = dbOther.Classes.Where(c => classIds.Contains(c.Class)).ToList();

Finally, join the two into the result:

var result = (from s in stats
    join c in classes on c.ClassId = s.ClassId
    select new {
        ClassNum = c.Class
    ,   c.StartDate
    ,   c.Weeks
    ,   s.Accepted
    ,   s.NotAccepted
    }).ToList();

Instead of USING ". Enumerable()" over the student db object, use Querable. This will create an expression which gets evaluated at database level rather than fetching entire student table first and then doing the comparison.

Check this for details Returning IEnumerable<T> vs. IQueryable<T>

Just to try, set the profiler and see the generated queries for both Enumerable vs Queryable.. The difference will get illustrated there.

Entity framework is easiest showcased with differences in execution with both these methods. Also the simplest ORM to support these functions.

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