Nenhum método FindAsync () no IDbSet

Existe uma razão que o método FindAsync() é omitido da interface IDbSet ? Find faz parte da interface, parece estranho que a versão assíncrona não esteja disponível. Eu estou precisando lançar para DbSet para acessá-lo, o que é um pouco complicado:

 User user = await ((DbSet)db.Users) .FindAsync("de7d5d4a-9d0f-48ff-9478-d240cd5eb035"); 

Se você possui o consumidor de IDbSet , o que eu suponho que você faça porque deseja ter access a FindAsync() de dentro do consumidor, uma solução simples é criar sua própria interface que inclui IDbSet e contém qualquer FindAsync() método que você deseja usar:

 public interface IAsyncDbSet : IDbSet where T : class { Task FindAsync(params Object[] keyValues); } 

Isso resolve o problema de não ter que converter para o DbSet – que, a propósito, afasta o benefício de abstração da codificação do contrato. Mas isso também introduz seu próprio conjunto de problemas.

Uma solução melhor (imo) que requer um pouco mais de trabalho é definir uma interface que contenha apenas os membros que você deseja usar no que seria seu object DbSet, subclass DbSet ao implementar a interface e use essa interface em seu código :

 public interface IMyAsyncDbSet where TEntity : class { TEntity Add(TEntity entity); TEntity Remove(TEntity entity); // Copy other methods from IDbSet as needed. Task FindAsync(params Object[] keyValues); } public class MyDbSet : DbSet, IMyAsyncDbSet where T : class { } 

Este é um padrão de adaptador, na verdade. Ele desacopla a interface que seu código espera da interface fornecida pelo Entity Framework. Agora, eles são idênticos – e é por isso que a implementação não faz nada, exceto herdar o DbSet . Mas mais tarde eles podem divergir. Nesse ponto, você ainda poderá usar o DbSet mais recente sem quebrar seu código.

Aqui está como eu enfrentei isso em um dos nossos projetos:

 using System.Threading.Tasks; namespace System.Data.Entity { public static class IDbSetExtensions { ///  /// If possible asynchronously finds an entity with the given primary key values /// otherwise finds the entity synchronously. /// If an entity with the given primary key values exists in the context, then it is /// returned immediately without making a request to the store. Otherwise, a /// request is made to the store for an entity with the given primary key values /// and this entity, if found, is attached to the context and returned. If no /// entity is found in the context or the store, then null is returned. ///  ///  ///  /// The values of the primary key for the entity to be found. /// A task that represents the asynchronous find operation. The task result contains /// the entity found, or null. ///  public static async Task FindAsync(this IDbSet @this, params object[] keyValues) where TEntity : class { DbSet thisDbSet = @this as DbSet; if (thisDbSet != null) { return await thisDbSet.FindAsync(keyValues); } else { return @this.Find(keyValues); } } } } 

Pode-se considerar envolver o método Find em um padrão async-over-sync, que forneceria descarregamento (e não escalabilidade, como fazem os methods asynchronouss verdadeiros). No entanto, o chamador deve estar ciente disso para garantir que eles não chamarão methods no contexto após chamar o método FindAsync que pode interferir. Tornar os chamadores conscientes de uma implementação específica não é um bom design, porque pode facilmente levar a problemas. Para o OP, o IDbSet é um DbSet, portanto a chamada será assíncrona.

Eu acredito que a maneira correta nos dias de hoje (desde a EF 6) envolve herdar do DbSet ao invés de implementar o IDbSet.

Altere o método FindAsync para FirstOrDefaultAsync (x => x.Id == yourId);

Use esta extensão para resolver o problema do FindAsync

 ///  /// IDbSet extension ///  public static class IDbSetExtension { public static Task FindAsync(this IDbSet set, params object[] keyValues) where TEntity : class { return Task.Run(() => { var entity = set.Find(keyValues); return entity; }); } }