Files
Pf2eDataScrapper/Pf2e/Common/FullEntity.cs
T

216 lines
8.8 KiB
C#

using Microsoft.EntityFrameworkCore;
using Pf2e.Database;
using Pf2e.Database.Model;
using Pf2e.Database.Model.Base;
using Pf2e.Database.Model.Enum;
using Pf2e.Database.Model.Structure;
using Action = Pf2e.Database.Model.Structure.Action;
namespace Pf2e.Common;
/// <summary>
/// Класс, обрабатывающий запросы к сущностям и подключающий необходимые данные.
/// </summary>
public class FullEntity
{
/// <summary>
/// Корневая сущность.
/// </summary>
public Entity Entity { get; }
/// <summary>
/// Основная сущность.
/// </summary>
public IEntity? SubEntity { get; }
/// <summary>
/// Контекст базы данных, используемый для получения сущностей.
/// </summary>
private Pf2eDbContext Context { get; }
/// <summary>
/// Конструктор класса, который получает сущность из базы данных по типу и идентификатору и заполняет её данными.
/// </summary>
/// <param name="context">Контекст базы данных.</param>
/// <param name="type">Тип запрашиваемой сущности.</param>
/// <param name="id">Идентификатор запрашиваемой сущности.</param>
public FullEntity(Pf2eDbContext context, EntityType type, int id)
{
Context = context;
Entity = GetEntity(type, id);
SubEntity = GetSubEntity(type, id);
}
/// <summary>
/// Конструктор класса, который получает сущность из базы данных по переданной сущности и заполняет её данными.
/// </summary>
/// <param name="context">Контекст базы данных.</param>
/// <param name="entity">Сущность, которую нужно обработать.</param>
public FullEntity(Pf2eDbContext context, Entity entity)
{
Context = context;
Entity = entity;
SubEntity = GetSubEntity(entity.Type, entity.Id);
}
/// <summary>
/// Получает сущность из базы данных по типу и идентификатору.
/// </summary>
/// <param name="type">Тип сущности.</param>
/// <param name="id">Идентификатор сущности.</param>
/// <returns>Сущность, соответствующая указанному типу и идентификатору.</returns>
private Entity GetEntity(EntityType type, int id) =>
Context
.Entities.Where(e => e.Id == id && e.Type == type)
.Include(e => e.Sources)
.ThenInclude(s => s.Source)
.Include(e => e.Keywords)
.Include(e => e.Externals)
.ThenInclude(x => x.Target)
.Include(e => e.Traits)
.ThenInclude(t => t.Entity)
.FirstOrDefault() ?? throw new("Entity is null");
/// <summary>
/// Получает подчинённую сущность по типу и идентификатору.
/// </summary>
/// <param name="type">Тип сущности.</param>
/// <param name="id">Идентификатор сущности.</param>
/// <returns>Подчинённая сущность, соответствующая указанному типу и идентификатору.</returns>
private IEntity? GetSubEntity(EntityType type, int id)
{
Getter? getter = _getters.FirstOrDefault(g => g.Type == type);
return (getter != null)
? getter.Get(id, this.Context)
: (IEntity?)Context.Find(EntityOfTypeAttribute.Resolve(Entity), id);
}
/// <summary>
/// Словарь, содержащий методы получения сущностей из базы данных.
/// </summary>
private readonly ICollection<Getter> _getters =
[
new Getter<Action>(EntityType.Action, context => context.Actions),
new Getter<Ancestry>(
EntityType.Ancestry,
context => context.Ancestries.Include(a => a.AncestryBoosts)
),
new Getter<Archetype>(
EntityType.Archetype,
context =>
context
.Archetypes.Include(a => a.DedicationFeat)
.ThenInclude(f => f.Entity)
.Include(a => a.Feats)
.ThenInclude(f => f.Entity)
),
new Getter<Background>(
EntityType.Background,
context =>
context
.Backgrounds.Include(b => b.BackgroundBoosts)
.Include(b => b.BackgroundSkills)
.ThenInclude(t => t.Training)
.Include(b => b.BackgroundItems)
),
new Getter<Class>(
EntityType.Class,
context =>
context
.Classes.Include(c => c.ClassKeyAbilities)
.Include(c => c.ClassTrainings)
.ThenInclude(t => t.Training)
.Include(c => c.ClassProgressions)
.Include(c => c.SubclassGroups)
),
new Getter<Condition>(EntityType.Condition, context => context.Conditions),
new Getter<Deity>(
EntityType.Deity,
context =>
context
.Deities.Include(d => d.DeityAttributes)
.Include(d => d.DeityDomains)
.ThenInclude(dd => dd.Domain)
.Include(d => d.DeitySpells)
.ThenInclude(ds => ds.Spell)
.Include(d => d.DeityWeapons)
//.ThenInclude(dw => dw.Weapon)
.Include(d => d.CategoryEntity)
.Include(d => d.Skills)
),
new Getter<DeityCategory>(EntityType.DeityCategory, context => context.DeityCategories),
new Getter<Domain>(
EntityType.Domain,
context =>
context
.Domains.Include(d => d.DomainSpell)
.Include(d => d.AdvancedDomainSpell)
.Include(d => d.ApocryphalSpell)
.Include(d => d.AdvancedApocryphalSpell)
),
new Getter<Feat>(
EntityType.Feat,
context =>
context.Feats.Include(f => f.Archetypes).ThenInclude(a => a.Entity).AsQueryable()
),
new Getter<Heritage>(
EntityType.Heritage,
context => context.Heritages.Include(h => h.Ancestry)
),
new Getter<Language>(EntityType.Language, context => context.Languages),
new Getter<Ritual>(
EntityType.Ritual,
context =>
context
.Rituals.Include(r => r.Area)
.Include(r => r.Checks)
.ThenInclude(c => c.Training)
.AsQueryable()
),
new Getter<Rule>(
EntityType.Rule,
context => context.Rules.Include(r => r.Parent).Include(r => r.Children)
),
new Getter<Spell>(
EntityType.Spell,
context => context.Spells.Include(s => s.SpellAreas).Include(s => s.SpellDefenses)
),
new Getter<Subclass>(
EntityType.Subclass,
context =>
context
.Subclasses.Include(s => s.Trainings)
.ThenInclude(t => t.Training)
.Include(s => s.Entities)
),
new Getter<Trait>(EntityType.Trait, context => context.Traits),
];
/// <summary>
/// Абстрактный класс, который определяет метод получения сущности из базы данных.
/// </summary>
/// <param name="type">Связанный тип сущности.</param>
private abstract class Getter(EntityType type)
{
public readonly EntityType Type = type;
public abstract IEntity? Get(int id, Pf2eDbContext context);
}
/// <summary>
/// Класс, определяющий метод получения сущности из базы данных.
/// </summary>
/// <typeparam name="T">Тип данных основной сущности.</typeparam>
/// <param name="type">Связанный тип сущности.</param>
/// <param name="method">Метод получения сущности из базы данных.</param>
private class Getter<T>(EntityType type, Func<Pf2eDbContext, IQueryable<T>> method)
: Getter(type)
where T : IEntity
{
public override IEntity? Get(int id, Pf2eDbContext context)
{
return method.Invoke(context).FirstOrDefault(c => c.Id == id);
}
}
}