using System.Collections.Concurrent;
using Pf2eModel;
using Pf2eModel.Model.Base;
using Pf2eModel.Model.Enum;
namespace Pf2eViewer.DatabaseViewer;
///
/// Класс, выполняющий страничные запросы к базе данных.
///
internal class DatabaseQueryPerformer
{
///
/// Тип сущностей, которую необходимо получить.
///
public required EntityType Type;
///
/// Номер страницы, которую необходимо получить.
///
public required int Page;
///
/// Количество элементов на странице.
///
public required int PerPage;
///
/// Поисковая строка, по которой будет производиться фильтрация.
///
public required string Search = "";
///
/// Поток, в котором будет выполняться запрос к базе данных.
///
private readonly Thread _queryThread;
///
/// Конструктор класса, который инициализирует поток для выполнения запроса к базе данных.
///
public DatabaseQueryPerformer()
{
_queryThread = new(PerformQuery);
}
///
/// Запускает поток для выполнения запроса к базе данных.
///
public void Query()
{
_queryThread.Start();
}
///
/// Прерывает выполнение потока, если он ещё не завершён.
///
public void Abort()
{
_queryThread.Interrupt();
}
///
/// Выполняет запрос к базе данных и обрабатывает результаты.
///
private void PerformQuery()
{
try
{
Pf2eDbContext dbContext = new();
IQueryable query =
Search == ""
? dbContext.Entities.Where(e => e.Type == Type)
:
// ReSharper disable once EntityFramework.UnsupportedServerSideFunctionCall
dbContext.Entities.Where(e =>
e.Type == Type && Pf2eDbContext.LocaleSearch(e.Name, Search)
);
int count = query.Count();
List entities = query
.OrderBy(e => e.Id)
.Skip((Page - 1) * PerPage)
.Take(PerPage)
.ToList();
DatabaseQueryResult result = new(count, entities);
OnQueryCompleted?.Invoke(this, result);
}
catch (ThreadInterruptedException)
{
// Ignore
}
}
///
/// Делегат, который будет вызван по завершении выполнения запроса к базе данных.
///
/// Объект класса, выполневшего запрос.
/// Результат запроса.
public delegate void DatabaseQueryPerformerDelegate(
DatabaseQueryPerformer sender,
DatabaseQueryResult result
);
///
/// Событие, которое будет вызвано по завершении выполнения запроса к базе данных.
///
public event DatabaseQueryPerformerDelegate? OnQueryCompleted;
}
///
/// Класс, который содержит результат выполнения запроса к базе данных.
///
/// Общее количество найденных сущностей.
/// Набор найденных сущностей.
internal class DatabaseQueryResult(int count, ICollection entities)
{
///
/// Общее количество найденных сущностей.
///
public int Count { get; } = count;
///
/// Набор найденных сущностей.
///
public ConcurrentBag Entities { get; } = new(entities);
}