如何在内存List与可异步执行的EF查询对象进行LINQ关联查询时正确使用await关键字
Let's walk through what's going wrong here and how to fix it properly—there are a couple of key issues to address:
1. Fix Your Broken GetAll() Method
Your current GetAll() has two critical problems that need fixing first:
- It claims to return
IQueryable<ClassB>but doesn't actually return anything (noreturnstatement). - You're calling an async method
_entityframeworkService.GetAllAsync()without awaiting it, which is a fire-and-forget anti-pattern here (it won't work as intended).
Here are two valid fixes depending on your service's implementation:
Option A: Return a deferred IQueryable (synchronous)
If your EF Core service has a synchronous method that returns the raw IQueryable (which defers the actual DB call until you execute it), use this:
public IQueryable<ClassB> GetAll() { // Return the IQueryable directly—we'll execute it later with async methods return _entityframeworkService.GetAll(); }
Option B: Make GetAll fully async
If _entityframeworkService.GetAllAsync() returns Task<List<ClassB>> (common for immediate DB reads), update your method to properly await it:
public async Task<List<ClassB>> GetAllAsync() { return await _entityframeworkService.GetAllAsync(); }
2. Fix the Join & Await Error
The main error you're seeing happens because:
- Your LINQ join is missing the required
onclause (you need to define howClass1andClassBare related). - You can't
awaita rawIQueryableorIEnumerabledirectly—you need to use an async execution method likeToListAsync()to get an awaitableTask<T>.
You have two solid approaches based on your data sizes:
Approach 1: Fetch DB Data First, Join Locally
If the ClassB dataset from the DB is large, pull it into memory first, then join with your local List<Class1>:
List<Class1> listClass = data; // Your prepped local list // First, fetch ClassB data asynchronously from the database var classBRecords = await _getAll.GetAll().ToListAsync(); // Perform the join locally (no more DB calls needed) var result = from c1 in listClass join c2 in classBRecords on c1.ClassBId equals c2.Id // Replace with your actual matching properties select c1; // Or project to a custom object if you need combined data // result is an IEnumerable<Class1>—no await needed here, it's already in memory
Approach 2: Let the Database Handle the Join
If your local listClass is small enough to send to the database, convert it to IQueryable and let EF Core generate the join SQL:
List<Class1> listClass = data; // Convert your local list to IQueryable so EF Core can translate it to SQL var class1Query = listClass.AsQueryable(); // Build the deferred join query var joinedQuery = from c1 in class1Query join c2 in _getAll.GetAll() on c1.ClassBId equals c2.Id // Your matching properties here select c1; // Execute the query asynchronously and get the final result var extractedResult = await joinedQuery.ToListAsync();
Quick Reminders
- Always await async methods unless you specifically want fire-and-forget behavior (you almost never do this for DB calls).
- You can only await
Task<T>types—use EF Core's async extensions likeToListAsync(),FirstOrDefaultAsync()to trigger the DB call and get an awaitable task. - LINQ joins require an
onclause to define the relationship between the two collections—don't skip this!
内容的提问来源于stack exchange,提问作者VA1267

