【问题标题】:FindAsync and Include LINQ statementsFindAsync 和 Include LINQ 语句
【发布时间】:2016-11-01 12:57:01
【问题描述】:

到目前为止我得到的代码运行良好

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);
}

但我想多包含 1 个表,不能使用 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);
}

所以我遇到了这个错误

严重性代码描述项目文件行抑制状态 错误 CS1061 'IQueryable' 不包含 'FindAsync' 并且没有扩展方法 'FindAsync' 接受第一个 可以找到“IQueryable”类型的参数(您是否缺少 使用指令还是程序集引用?)

有什么办法解决吗?

【问题讨论】:

  • This post 可能会给你一些答案。看起来.Include 返回一个ObjectQuery&lt;T&gt; 而不是DbSet(它有FindAsync 方法)。
  • 看看这个question

标签: c# linq entity-framework-6


【解决方案1】:

最简单的方法是改用FirstOrDefaultAsyncSingleOrDefaultAsync

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

您收到错误的原因是因为Find / FindAsync 方法是为DbSet&lt;T&gt; 定义的,但Include 的结果是IQueryable&lt;T&gt;

另一种方法是将FindAsyncexplicit loading结合起来:

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

【讨论】:

  • 您可以通过解释为什么他尝试的方法不起作用来改进这个答案(请参阅我在问题下的评论)。
  • 使用了第二个选项。切斯
【解决方案2】:

如果您使用的是通用存储库并且您不知道运行时的 PK,则此方法会有所帮助:

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;
    }
}

【讨论】:

  • 我希望这对数据库进行 2 次访问,而不是在 DbSet 上使用 Include 时访问一次。遗憾的是 FindAsync 没有提供直接包含其他字段的功能。
【解决方案3】:

当您使用可靠的原则和领域设计进行编程时,请使用泛型。存储库模式使用泛型类。我将 lambda 表达式传递给 GetObjectsQueryable 函数。我已经设置了延迟加载,使用代码优先处理栏。但是,我正在摆脱延迟加载并实现微服务架构。包含表是一个字符串,您可以使用 nameof(xxclass) 函数来确保名称正确。该函数返回 IQueryable 结果。存储库类的方法可以通过其派生类增强方法受到保护。这是一个 dotnet.core 演示。

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;
    }
}

【讨论】:

  • 在实体框架的 OnConfiguring(DbContextOptionsBuilder optionsBuilder) 方法中添加延迟加载代理,调用如下 optionsBuilder.UseLazyLoadingProxies().UseSqlServer(connectionString);
猜你喜欢
  • 2016-02-05
  • 2018-09-25
  • 1970-01-01
  • 2016-03-21
  • 2018-10-17
  • 2010-11-04
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多