我是 EF 的新手,所以如果有什么地方做得不对,请提前道歉。我正在努力让分页与 EF 6 异步工作。
我已经按照本文实现了分页机制:如何通过分页提高实体框架的性能 https://developingsoftware.com/entity-framework-paging/,我认为这是干净且切题的(但也不完美),但我无法让它异步工作,这是一个问题。
根据文章,我创建了界面:
public interface IPageList
{
int TotalCount { get; }
int PageCount { get; }
int Page { get; }
int PageSize { get; }
}
我创建了该类:
public class PageList<T> : List<T>, IPageList
{
public int TotalCount { get; private set; }
public int PageCount { get; private set; }
public int Page { get; private set; }
public int PageSize { get; private set; }
public PageList(IQueryable<T> source, int page, int pageSize)
{
TotalCount = source.Count();
PageCount = GetPageCount(pageSize, TotalCount);
Page = page < 1 ? 0 : page - 1;
PageSize = pageSize;
AddRange(source.Skip(Page * PageSize).Take(PageSize).ToList());
}
private int GetPageCount(int pageSize, int totalCount)
{
if (pageSize == 0)
return 0;
var remainder = totalCount % pageSize;
return (totalCount / pageSize) + (remainder == 0 ? 0 : 1);
}
}
最后是扩展:
public static class PageListExtensions
{
public static PageList<T> ToPageList<T>(this IQueryable<T> source, int pageNumber,
int pageSize)
{
return new PageList<T>(source, pageNumber, pageSize);
}
}
所以在我的数据层中,我有以下函数:
public async Task<List<LogEntity>> GetLogsAsync(int pageNumber, int pageSize)
{
using (_dbContext = new DatabaseContext())
{
var results = _dbContext.Logs.Select(l => new
{
LogId = l.LogId,
Message = l.Message,
})
.OrderBy(o => o.DateTime)
.ToPageList(pageNumber, pageSize).ToList().Select(x => new LogEntity()
{
LogId = x.LogId,
Message = x.Message,
});
return await results.AsQueryable<LogEntity>().ToListAsync();
}
}
当我运行上面的代码时,我得到:
附加信息:源 IQueryable 未实现
IDbAsyncEnumerable。仅来源
实现 IDbAsyncEnumerable 可用于实体框架
异步操作。欲了解更多详情,请参阅http://go.microsoft.com/fwlink/?LinkId=287068 http://go.microsoft.com/fwlink/?LinkId=287068.
我已经用谷歌搜索了这个错误,虽然我读了很多文章,但我仍然在努力让它工作。
谁能确切地告诉我如何解决这个问题,因为我现阶段不知道从哪里开始。
Thanks
UPDATE-1
正如伊万在评论中强调的那样,我认为我不需要 2Select
,所以这是简化版本:
var results = _dbContext.Logs.OrderBy(o=>o.DateTime)
.ToPageList(pageNumber, pageSize).Select(l => new
{
LogId = l.LogId,
Message = l.Message,
});
仍然没有解决我的异步问题。我目前正在查看这篇文章,希望对您有所帮助:
如何在异步存储库方法中返回空 IQueryable https://stackoverflow.com/questions/33305495/how-to-return-empty-iqueryable-in-an-async-repository-method
UPDATE-2
我想我已经弄清楚了,但它仍然没有像我希望的那样响应,所以我不能 100% 确定它是否正确完成。我认为当交换到 WPF 应用程序中的日志选项卡时,交换会是瞬时的,但事实并非如此!
无论如何,这是我改变的:
public async Task<List<LogEntity>> GetLogsAsync(int pageNumber, int pageSize)
{
using (_dbContext = new DatabaseContext())
{
var results = _dbContext.Logs.OrderBy(o=>o.DateTime).ToPageList(pageNumber, pageSize).Select(l => new LogEntity
{
LogId = l.LogId,
Message = l.Message,
}).AsAsyncQueryable();
return await results.ToListAsync();
}
}
如果有的话,代码肯定比我原来的代码简单。
更新3:
当我这样称呼时:
return new PageList<LogEntity>(_dbContext.Logs, pageNumber, pageSize);
它返回 TotalCount = 100,000、PageCount = 200、Page = 0、PageSize 500,但在调用 AddRange 时会抛出错误,即
发生“System.NotSupportedException”类型的异常
EntityFramework.SqlServer.dll 但未在用户代码中处理
附加信息:“Skip”方法仅支持排序
在 LINQ to Entities 中输入。必须先调用方法“OrderBy”
方法“跳过”。
所以我通过调用解决了这个问题:
return new PageList<LogEntity>(_dbContext.Logs.OrderBy(o=>o.DateTime),
pageNumber, pageSize);
当我尝试调用 @krillgar 最简单的建议时,即
return _dbContext.Logs
.Select(l => new LogEntity // Cast here so your .ToPageList
{ // will start as the object type you want.
LogId = l.LogId,
Message = l.Message
})
.OrderBy(l => l.DateTime)
.ToPageList(pageNumber, pageSize);
我收到以下错误:
发生“System.NotSupportedException”类型的异常
EntityFramework.SqlServer.dll 但未在用户代码中处理
附加信息:实体或复杂类型
无法在 LINQ to 中构造“MyCompany.DataLayerSql.LogEntity”
实体查询。
on the this.TotalCount = source.Count();
在 PageList 类中。
有任何想法吗?