Abh*_*nyu 3 c# linq lambda asynchronous entity-framework
我正在尝试将数据访问同步查询转换为异步查询,到目前为止,除了选择return的列表之外,我都进行了转换IQueryable<T>。
到目前为止,这是我所做的:
[Dependency]
public SampleContext db { get; set; }
public async System.Threading.Tasks.Task<Profile> Add(Profile item)
{
db.Profiles.Add(item);
await db.SaveChangesAsync();
return item;
}
public async System.Threading.Tasks.Task<Profile> Get(string id)
{
return await db.Profiles.AsNoTracking().Where(i => i.Id == id).FirstOrDefaultAsync();
}
public async System.Threading.Tasks.Task Remove(string id)
{
Profile item = db.Profiles.Find(id);
item.IsDeleted = 1;
db.Entry(item).State = EntityState.Modified;
await db.SaveChangesAsync();
}
public async System.Threading.Tasks.Task<bool> Update(Profile item)
{
db.Set<Profile>().AddOrUpdate(item);
await db.SaveChangesAsync();
return true;
}
Run Code Online (Sandbox Code Playgroud)
上面的代码运行良好,我被困在转换这段代码:
public IQueryable<Profile> GetAll()
{
return db.Profiles.AsNoTracking().Where(i => i.IsDeleted == 0);
}
Run Code Online (Sandbox Code Playgroud)
如何将上述代码转换为异步代码?我尝试了Stephen Cleary的示例代码,但无法弄清楚是什么ProcessEventAsync以及如何将其应用于我的代码。另外,我不能使用.ToList(),这将太昂贵了,无法将所有数据加载到内存中。
您必须知道查询的区别和查询的结果之间的差异。An IQueryable拥有执行查询的所有内容。这不是查询本身,创建IQueryable不会执行查询。
如果你看起来更密切合作,以LINQ语句,你会看到有两种类型:那些回报率IQueryable(和IEnumerable),以及那些回报List<TResult>,TResults,TKey,等等,任何不是IQueryable/IEnumerable。如果返回值是IQueryable,则可以说该函数使用了延迟执行(或延迟执行):Expression创建了执行查询的,但尚未执行查询。
这样做的好处是,您可以连接LINQ语句,而不必对每个语句执行查询。
当您要求IQueryable获取枚举数并且是否开始枚举时,将执行查询,可以使用隐式地使用foreach,也可以使用IQueryable.GetEnumerator()和显式地使用IEnumerator.MoveNext()(也称为foreach)。
因此,只要创建查询并返回IQueryable,创建Task就没有用了。串联LINQ语句只会更改的Expression IQueryable,而您不必等待。
只有当你创建一个将实际执行查询的功能,你需要一个异步版本:ToListAsync,FirstOrDefaultAsync,MaxAsync等国内这些功能将GetEnumerator与MoveNextAsync < -这是实际的异步功能
结论:通常返回的
IQueryable<...>所有函数都不需要Async版本,所有返回实际获取的数据的函数都需要Async版本
例子。不需要异步:不执行查询:
// Query customer addresses:
static IQueryable<Address> QueryAddresses(this IQueryable<Customer> customers)
{
return customers.Select(customer => customer.Address);
}
Run Code Online (Sandbox Code Playgroud)
需要异步:
static async Task<List<Address>> FetchAddressesAsync (this IQueryable<Customer> customers)
{
var query = customers.QueryAddresses; // no query executed yet
return await query.ToListAsync(); // execute the query
// could of course be done in one statement
}
static async Task<Address> FetchAddressAsync(this.IQueryable<Customer> customers, int customerId)
{
var query = customers.Where(customer => customer.Id == customerId)
.FetchAddresses();
// no query executed yet!
// execute:
return await query.FirstOrDefaultAsync();
}
Run Code Online (Sandbox Code Playgroud)
用法:
int customerId = ...
using (var dbContext = new InvoiceContext())
{
Address fetchedCustomerAddress = await dbContext.Customers
.FetchAddressAsync(customerId);
}
Run Code Online (Sandbox Code Playgroud)
在极少数情况下,您必须枚举自己,您将在MoveNextAsync:
IQueryable<Customer> myCustomers = ...
IEnumerator<Customer> customerEnumerator = myCustomers.GetEnumerator();
while (await customerEnumerator.MoveNextAsync())
{
Customer customer = customerEnumerator.Current;
Process(customer);
}
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
3106 次 |
| 最近记录: |