Tengo un repositorio genérico que tiene métodos asíncronos FindAsync:

public class GenericRepository<TEntity> : IRepository<TEntity> where TEntity : class
{
    private dynamic _context;
    private DbSet<TEntity> _dbSet;

    protected DbContext Context
    {
        get
        {
            if (_context == null)
            {
                _context = DataContextFactory.GetDataContext();
            }

            return _context;
        }
    }

    protected DbSet<TEntity> DBSet
    {
        get
        {
            if (_dbSet == null)
            {
                _dbSet = Context.Set<TEntity>();
            }

            return _dbSet;
        }
    }

    public virtual IQueryable<TEntity> GetQuery(Expression<Func<TEntity, bool>> predicate = null, Func<IQueryable<TEntity>, IOrderedQueryable<TEntity>> orderExpression = null)
    {
        IQueryable<TEntity> qry = DBSet;

        if (predicate != null)
        {
            qry = qry.Where(predicate);
        }

        if (orderExpression != null)
        {
            return orderExpression(qry);
        }

        return qry;
    }

    public virtual IQueryable<T> GetQuery<T>(Expression<Func<T, bool>> predicate = null, Func<IQueryable<T>, IOrderedQueryable<T>> orderExpression = null) where T : class
    {
        DbSet<T> dbSet = Context.Set<T>();
        IQueryable<T> qry = dbSet;

        if (predicate != null)
        {
            qry = qry.Where(predicate);
        }

        if (orderExpression != null)
        {
            return orderExpression(qry);
        }

        return qry;
    }

    public virtual async Task<IEnumerable<TEntity>> FindAsync(Expression<Func<TEntity, bool>> predicate, Func<IQueryable<TEntity>, IOrderedQueryable<TEntity>> orderExpression = null)
    {
        return await GetQuery(predicate, orderExpression).ToListAsync();
    }

    public virtual async Task<IEnumerable<T>> FindAsync<T>(Expression<Func<T, bool>> predicate, Func<IQueryable<T>, IOrderedQueryable<T>> orderExpression = null) where T : class
    {
        return await GetQuery<T>(predicate, orderExpression).ToListAsync();
    }
}

Y luego creé un CustomerRepository que llama a FindAsync desde un repositorio genérico:

public class CustomerRepository
{
    private readonly IRepository<Customer> _repo;

    /// <summary>
    /// Hookup dependencies
    /// </summary>
    /// <param name="repo"></param>
    public CustomerRepository(IRepository<Customer> repo)
    {
        _repo = repo;

        //Disable entity proxy creation and  lazy loading.
        _repo.LazyLoadingEnabled(false);
    }

    /// <summary>
    /// Gets customer by id
    /// </summary>
    /// <param name="id"></param>
    /// <returns></returns>
    public async Task<Customer> GetByIdAsync(Guid id)
    {
        return await _repo.FindAsync(p => p.Id == id).Result.SingleOrDefaultAsync();
    }
}

El problema que tengo es que cuando llamo a await _repo.FindAsync(p => p.Id == id).Result.SingleOrDefaultAsync();

Dice

IEnumerable Customer no contiene una definición para SingleOrDefaultAsync.

Alguien sabe lo que me perdí?

1
Andrew Reyes 3 may. 2017 a las 21:40

3 respuestas

La mejor respuesta

Creo que hay un malentendido sobre cómo await siendo utilizado.

Utilice el operador await en un método async que devuelve un tipo Task para suspender la ejecución del método hasta que se complete la tarea esperada.

Entonces el valor de retorno se asignará a la variable.

public async Task<Customer> GetByIdAsync(Guid id)
{
    // Call the async method to get the task returning the customers
    Task<IEnumerable<Customer>> customersTask = _repo.FindAsync(p => p.Id == id);

    // Wait for the customers to be fetched
    IEnumerable<Customer> customers = await customersTask;

    // Get the customer
    return customers.SingleOrDefault();
}

Esto es análogo a:

public async Task<Customer> GetByIdAsync(Guid id)
{
    var customers = await _repo.FindAsync(p => p.Id == id);
    return customers.SingleOrDefault();
}
4
Dustin Kingen 3 may. 2017 a las 18:59

Agregue el uso de System.Data.Entity a las declaraciones de uso en la parte superior de CustomerRepository.cs

Cambiar el tipo de devolución de FindAsync para devolver IQueryable

Consulte QueryableExtensions para mayor orientación

Además, no mezcle llamadas de bloqueo (.Result) con asíncrono / espera como sugieren los comentarios posteriores.

1
earloc 3 may. 2017 a las 18:52

Ese es uno de tus problemas. el otro es que está mezclando llamadas de bloqueo .Result con async/await llamadas.

/// <summary>
/// Gets customer by id
/// </summary>
/// <param name="id"></param>
/// <returns></returns>
public async Task<Customer> GetByIdAsync(Guid id) {
    var records = await _repo.FindAsync(p => p.Id == id);
    return records.AsQueryable().SingleOrDefaultAsync();
}

También asegúrese de tener la referencia adecuada QueryableExtensions.SingleOrDefaultAsync Método (IQueryable)

3
Nkosi 3 may. 2017 a las 18:47