困惑为什么我没有可用的扩展方法



我正在实现一个工作单元模式(不是我的选择,我知道它被一些人认为是反模式)。

我遇到了一个我不能完全理解的情况。

我的通用repo构造函数:

this.context = context;
this.dbSet = context.Set<T>();

通用方法:

public virtual async Task<IEnumerable<T>> All()
{
return await dbSet.ToListAsync();
}

像这样使用:

var languages = await _unitOfWork.Languages.All();
languages = languages.OrderBy(x => x.Order);
如上面所示,我需要往下走一行,这样我就可以使用OrderBy,我不明白为什么。

第二个问题是,ToListAsync应该返回一个列表,为什么我得到一个IEnumerable?

第二个问题是,ToListAsync应该返回一个列表,为什么我得到一个IENUMERABLE?

ListIEnumerable的实现。检查"程序到接口"是什么意思

如上所示,我需要往下走一行,这样我就可以使用OrderBy,我不知道为什么。

_unitOfWork.Languages.All()返回一个Task,你应该得到IEnumerable的解包裹结果来应用OrderBy

要使此工作如您所期望的那样,您应该在等待的结果上应用OrderBy:

(await _unitOfWork.Languages.All()).OrderBy(x => x.Order);

你的困惑,只要有他们在同一行似乎是如何应用await。这应该可以正常工作:

var languages = (await _unitOfWork.Languages.All()).OrderBy(x => x.Order);

您需要这样做,因为您的All函数返回Task,而OrderBy不是。

另外,你可能一开始就不想调用.ToListAsync(),那只是一个没有任何限制的SELECT *或where子句,可能不是"世界末日"。但往往会对你的表现极为不利。

至于你的第二个问题,为什么它返回IEnumerable<T>,这是因为List<T>实现了IEnumerable<T>,你的函数签名表明它返回IEnumerable<T>

public virtual async Task<IEnumerable<T>> All()

我强烈建议不要处理.ToListAsyncIEnumerable<T>,让IQueryable<T>对数据库做正确的工作。

编辑在评论中有人问为什么使用IQueryable<T>很重要。答案是因为利用.Where,.Any()等…对IQueryable的查询将根据DB建模底层查询。

例如,假设您要查找具有123Id的单个实体。如果您留下您的.ToListAsync()没有任何其他修改,它将拉回数据库中的每一行到您的程序在内存中,然后迭代每一行寻找那一行。

如果,相反,你使用IQueryable<T>-在你应用.FirstOrDefault(e => e.Id == 123)的地方,它将应用于数据库,它将像SELECT TOP(1) * FROM MyEntity WHERE [Id] = 123一样应用-拉回单行而不是现有的每一行。

EDIT2注意,这也适用于投影。这意味着像.Select(e => new { FullName = e.FirstName + " " + e.LastName, State = e.Address.State})这样的东西只会拉这2列,而不是所有列和任何导航属性,你包括。在.ToList().ToListAsync之后这样做将拉回所有列/实体并迭代它们以创建一组全新的其他实体。这可能导致两种方法之间存在巨大的CPU/内存差异。