Я новичок в EF, поэтому извиняюсь в продвинутом, если что-то сделано неправильно. Я изо всех сил пытаюсь заставить пейджинг работать асинхронно с EF 6.Асинхронный пейджинг с платформой Entity 6.1.3
Я реализовал механизм поискового вызова в соответствии с этой статьей: How to Increase the Performance of Entity Framework with 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();
}
}
Когда я бегу выше, я получаю:
Additional information: The source IQueryable doesn't implement IDbAsyncEnumerable. Only sources that implement IDbAsyncEnumerable can be used for Entity Framework asynchronous operations. For more details see http://go.microsoft.com/fwlink/?LinkId=287068 .
Я гугле ошибку и в то время как я прочитал множество статей, я все еще изо всех сил, чтобы заставить его работать.
Может ли кто-нибудь сказать мне, как решить эту проблему, поскольку я понятия не имею, с чего начать на этом этапе.
Благодаря
UPDATE-1
Как Иван подчеркнул в своем комментарии, я не думаю, что мне нужно 2 Select
, так вот упрощенный вариант:
var results = _dbContext.Logs.OrderBy(o=>o.DateTime)
.ToPageList(pageNumber, pageSize).Select(l => new
{
LogId = l.LogId,
Message = l.Message,
});
Все еще не сортирует мою проблему асинхронности. Я в настоящее время, глядя на эту статью, которая, надеюсь, поможет:
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();
}
}
Если что-нибудь, код, безусловно, проще, чем мой оригинал.
Update-3:
Когда я называю это:
return new PageList<LogEntity>(_dbContext.Logs, pageNumber, pageSize);
Он возвращает TOTALCOUNT = 100000, PageCount = 200, Page = 0, PageSize 500, но потом выдает ошибку когда AddRange называется т.е.
An exception of type 'System.NotSupportedException' occurred in EntityFramework.SqlServer.dll but was not handled in user code Additional information: The method 'Skip' is only supported for sorted input in LINQ to Entities. The method 'OrderBy' must be called before the method 'Skip'.
Так я это исправил по телефону:
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);
Я получаю следующее сообщение об ошибке:
An exception of type 'System.NotSupportedException' occurred in EntityFramework.SqlServer.dll but was not handled in user code Additional information: The entity or complex type 'MyCompany.DataLayerSql.LogEntity' cannot be constructed in a LINQ to Entities query.
на this.TotalCount = source.Count();
в классе PageList.
Любые идеи?
Похоже, вам не нужен класс 'PagedList', потому что вы его не используете. И в чем причина 2 'Select's? –
@IvanStoev Я использую его. Он используется в строке 10 в функции GetLogsAsync. Что касается выбора 2, это хороший вопрос, и я не хотел задавать здесь несколько вопросов. Я только что попробовал, и я упростил это. Я загружу его через секунду. – Thierry
Не используя его, я имею в виду, что вы не возвращаете 'PagedList', что является цельной целью этого класса. Если вы хотите получить простой результат, просто включите 'Skip' /' Take' в свой запрос. например 'return await _dbContext.Logs.OrderBy (o => o.DateTime). Выберите (...). Skip ((номер страницы - 1) * pageSize) .Take (pageSize) .ToListAsync();' –