简体   繁体   English

如何使用 EF Core 创建异步存储库?

[英]How to create an asynchronous repository with EF Core?

I'm trying to abstract EF Core with a repository and can't figure out how to make it asynchronous.我正在尝试使用存储库抽象 EF Core,但无法弄清楚如何使其异步。 This is the synchronous version:这是同步版本:

public class UserRepository
{
    private DbSet<User> users;
    public UserRepository(ApplicationDbContext context)
    {
        users = context.Set<User>();
    }
    public IQueryable<User> GetAll()
    {
        return users;
    }
    ...
}

The problem is that in order to make the query asynchronous, we need to use the special extension methods from EF like ToListAsync() or CountAsync() , and if the project that uses the repository references EF namespaces, what's the point of the abstraction?问题是,为了使查询异步,我们需要使用 EF 的特殊扩展方法,如ToListAsync()CountAsync() ,如果使用存储库的项目引用 EF 命名空间,那么抽象的意义何在?

Another thing I looked into was returning IAsyncEnumerable<User> , and then using this official library to use LINQ asynchronously.我研究的另一件事是返回IAsyncEnumerable<User> ,然后使用这个官方库异步使用 LINQ。 However, I couldn't get it to behave properly because when using these new LINQ methods, the query is processed in .NET rather than converting the LINQ syntax to SQL.但是,我无法让它正常运行,因为在使用这些新的 LINQ 方法时,查询是在 .NET 中处理的,而不是将 LINQ 语法转换为 SQL。 Let's take the following query as an example:我们以下面的查询为例:

var result = await Repository.GetAll()
    .Limit(10)
    .ToListAsync();

When using EF's extension methods, I saw this query in SSMS:在使用 EF 的扩展方法时,我在 SSMS 中看到了这个查询:

exec sp_executesql N'SELECT [u].[Id], [u].[Deleted], [u].[EmailAddress], [u].[FirstName], [u].[LastName], [u].[PhoneNumber], [u].[Status], [u].[VerifiedEmailAddress], [u].[VerifiedPhoneNumber]
FROM [Users] AS [u]
ORDER BY (SELECT 1)
OFFSET @__p_0 ROWS FETCH NEXT @__p_1 ROWS ONLY',N'@__p_0 int,@__p_1 int',@__p_0=0,@__p_1=10

Meaning only 10 records will be selected from the DB, which is what I wanted.这意味着只会从数据库中选择 10 条记录,这正是我想要的。

But when using System.Linq.Async 's extension methods, I still got the same result back to my C# code, but this query showed in SSMS:但是当使用System.Linq.Async的扩展方法时,我的 C# 代码仍然得到相同的结果,但是这个查询显示在 SSMS 中:

SELECT [u].[Id], [u].[Deleted], [u].[EmailAddress], [u].[FirstName], [u].[LastName], [u].[PhoneNumber], [u].[Status], [u].[VerifiedEmailAddress], [u].[VerifiedPhoneNumber]
FROM [Users] AS [u]

No limit at all, meaning if I had millions of rows in the Users table, all of them would be selected every time I run the query, when I only need the first 10.完全没有限制,这意味着如果我在 Users 表中有数百万行,那么每次运行查询时都会选择所有这些行,而我只需要前 10 行。

Is there a way to work with LINQ to SQL and async streams?有没有办法使用 LINQ to SQL 和异步流? Or maybe another idea of how to abstract EF but still allow async querying?或者也许是如何抽象 EF 但仍然允许异步查询的另一个想法?

I do not recommend abstracting EFCore, you can abstract the context using an IApplicationDbContext .我不建议抽象 EFCore,您可以使用IApplicationDbContext抽象上下文。 Mostly because EF is already an abstract layer and secondly because leaving 'users' access to the IQueryable could create unexpected behavior or exceptions.主要是因为 EF 已经是一个抽象层,其次是因为让“用户”访问 IQueryable 可能会产生意外行为或异常。

If you really need to do this, what I am thinking about is something like:如果你真的需要这样做,我在想的是:

public Task<List<User>> GetAsync(Action<IQueryable<User>> filter)
{
    filter(_users);
    return _users.ToListAsync();
}

and using it like:并使用它:

var result = await Repository.GetAsync(x => x.Take(10));

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

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