FindAsync and Include LINQ statements

C#LinqEntity Framework-6

C# Problem Overview


The code I have got so far works fine

public async Task<ActionResult> Details(Guid? id)
{
	if (id == null)
	{
		return new HttpStatusCodeResult(HttpStatusCode.BadRequest);
	}

	ItemDetailModel model = new ItemDetailModel();
	model.Item = await db.Items.FindAsync(id);
	if (model.Item == null)
	{
		return HttpNotFound();
	}

	return View(model);
}

But I want to include 1 table more and cannot use FindAsync

public async Task<ActionResult> Details(Guid? id)
{
	if (id == null)
	{
		return new HttpStatusCodeResult(HttpStatusCode.BadRequest);
	}

	ItemDetailModel model = new ItemDetailModel();
	model.Item = await db.Items.Include(i=>i.ItemVerifications).FindAsync(id);

	if (model.Item == null)
	{
		return HttpNotFound();
	}           

	return View(model);
}

So I am facing this error

> Severity Code Description Project File Line Suppression State > Error CS1061 'IQueryable' does not contain a definition for > 'FindAsync' and no extension method 'FindAsync' accepting a first > argument of type 'IQueryable' could be found (are you missing a > using directive or an assembly reference?)

Any clue how to fix it?

C# Solutions


Solution 1 - C#

The simplest is to use FirstOrDefaultAsync or SingleOrDefaultAsync instead:

model.Item = await db.Items.Include(i => i.ItemVerifications)
    .FirstOrDefaultAsync(i => i.Id == id.Value);

The reason you are getting the error is because Find / FindAsync methods are defined for DbSet<T>, but the result of Include is IQueryable<T>.

Another way is to combine FindAsync with explicit loading:

model.Item = await db.Items.FindAsync(id);
if (model.Item == null)
{
    return HttpNotFound();
}
await db.Entry(model.Item).Collection(i => i.ItemVerifications).LoadAsync();    

Solution 2 - C#

If you are using a generic repository and you don't know the PK at runtime, this approach can help:

public interface IGenericRepository<TEntity> where TEntity : class
{
    Task<TEntity> Get(int id, string[] paths = null);
}

public class GenericRepository<TEntity> : IGenericRepository<TEntity> where TEntity : class
{
    private readonly ApplicationDbContext _context;
    private readonly DbSet<TEntity> _dbSet;

    public GenericRepository(ApplicationDbContext context)
    {
        _context = context;
        _dbSet = _context.Set<TEntity>();
    }

    public async Task<TEntity> Get(int id, string[] paths = null)
    {
        var model = await _dbSet.FindAsync(id);
        foreach (var path in paths)
        {
            _context.Entry(model).Reference(path).Load();
        }
        return model;
    }
}

Solution 3 - C#

When you program using solid principles and domain design then use generics. The Repository pattern uses a generic class. I pass a lambda express to the GetObjectsQueryable function. I have setup lazy loading to be on, using code first handle bars. However, I am moving away from lazy loading and implement a microservice architecture. The include table is a string and you can use the nameof(xxclass) function to ensure the correct name. The function returns and IQueryable results. The repository class methods can be used by its derived class enhance the method is protected. This is a dotnet.core demonstration.

public class Repository
    where T : class
{
    public IQueryable<T> GetObjectsQueryable(Expression<Func<T, bool>> predicate, string includeTable="")
    {
        IQueryable<T> result = _dbContext.Set<T>().Where(predicate);
        if (includeTable != "")
            result = result.Include(includeTable);

        return result;
    }
}

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionNoWarView Question on Stackoverflow
Solution 1 - C#Ivan StoevView Answer on Stackoverflow
Solution 2 - C#sbroccardiView Answer on Stackoverflow
Solution 3 - C#Golden LionView Answer on Stackoverflow