Как создать асинхронный репозиторий с EF Core? - PullRequest
0 голосов
/ 11 марта 2020

Я пытаюсь абстрагировать EF Core с помощью репозитория и не могу понять, как сделать его асинхронным. Это синхронная версия:

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

Проблема в том, что для того, чтобы сделать запрос асинхронным, нам нужно использовать специальные методы расширения из EF, такие как ToListAsync() или CountAsync(), и если проект он использует репозиторий, ссылающийся на пространства имен EF, в чем смысл абстракции?

Еще одна вещь, которую я изучал, - возвращение IAsyncEnumerable<User>, а затем использование этой официальной библиотеки для асинхронного использования LINQ. Однако я не смог заставить его работать должным образом, потому что при использовании этих новых методов LINQ запрос обрабатывается в. NET вместо преобразования синтаксиса LINQ в SQL. Давайте возьмем следующий запрос в качестве примера:

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

При использовании методов расширения 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

То есть из БД будет выбрано только 10 записей. , что я и хотел.

Но при использовании методов расширения 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]

Нет ограничений вообще, то есть, если бы в таблице Users были миллионы строк, все они были бы выбраны каждый раз, когда я запускаю запрос, когда мне нужны только первые 10.

Есть ли способ работы с LINQ для SQL и asyn c потоков? Или, может быть, еще одна идея о том, как абстрагировать EF, но все же разрешать асинхронные c запросы?

1 Ответ

0 голосов
/ 11 марта 2020

Я не рекомендую абстрагировать EFCore, вы можете абстрагировать контекст, используя IApplicationDbContext. Главным образом потому, что EF уже является абстрактным уровнем, а во-вторых, потому что предоставление доступа «пользователям» к IQueryable может привести к неожиданному поведению или исключениям.

Если вам действительно нужно это сделать, я думаю о чем-то вроде:

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

и используя его как:

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