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; /// /// Класс, обрабатывающий запросы к сущностям и подключающий необходимые данные. /// public class FullEntity { /// /// Корневая сущность. /// public Entity Entity { get; } /// /// Основная сущность. /// public IEntity? SubEntity { get; } /// /// Контекст базы данных, используемый для получения сущностей. /// private Pf2eDbContext Context { get; } /// /// Конструктор класса, который получает сущность из базы данных по типу и идентификатору и заполняет её данными. /// /// Контекст базы данных. /// Тип запрашиваемой сущности. /// Идентификатор запрашиваемой сущности. public FullEntity(Pf2eDbContext context, EntityType type, int id) { Context = context; Entity = GetEntity(type, id); SubEntity = GetSubEntity(type, id); } /// /// Конструктор класса, который получает сущность из базы данных по переданной сущности и заполняет её данными. /// /// Контекст базы данных. /// Сущность, которую нужно обработать. public FullEntity(Pf2eDbContext context, Entity entity) { Context = context; Entity = entity; SubEntity = GetSubEntity(entity.Type, entity.Id); } /// /// Получает сущность из базы данных по типу и идентификатору. /// /// Тип сущности. /// Идентификатор сущности. /// Сущность, соответствующая указанному типу и идентификатору. 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"); /// /// Получает подчинённую сущность по типу и идентификатору. /// /// Тип сущности. /// Идентификатор сущности. /// Подчинённая сущность, соответствующая указанному типу и идентификатору. 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); } /// /// Словарь, содержащий методы получения сущностей из базы данных. /// private readonly ICollection _getters = [ new Getter(EntityType.Action, context => context.Actions), new Getter( EntityType.Ancestry, context => context.Ancestries.Include(a => a.AncestryBoosts) ), new Getter( EntityType.Archetype, context => context .Archetypes.Include(a => a.DedicationFeat) .ThenInclude(f => f.Entity) .Include(a => a.Feats) .ThenInclude(f => f.Entity) ), new Getter( EntityType.Background, context => context .Backgrounds.Include(b => b.BackgroundBoosts) .Include(b => b.BackgroundSkills) .ThenInclude(t => t.Training) .Include(b => b.BackgroundItems) ), new Getter( 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(EntityType.Condition, context => context.Conditions), new Getter( 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(EntityType.DeityCategory, context => context.DeityCategories), new Getter( EntityType.Domain, context => context .Domains.Include(d => d.DomainSpell) .Include(d => d.AdvancedDomainSpell) .Include(d => d.ApocryphalSpell) .Include(d => d.AdvancedApocryphalSpell) ), new Getter( EntityType.Feat, context => context.Feats.Include(f => f.Archetypes).ThenInclude(a => a.Entity).AsQueryable() ), new Getter( EntityType.Heritage, context => context.Heritages.Include(h => h.Ancestry) ), new Getter(EntityType.Language, context => context.Languages), new Getter( EntityType.Ritual, context => context .Rituals.Include(r => r.Area) .Include(r => r.Checks) .ThenInclude(c => c.Training) .AsQueryable() ), new Getter( EntityType.Rule, context => context.Rules.Include(r => r.Parent).Include(r => r.Children) ), new Getter( EntityType.Spell, context => context.Spells.Include(s => s.SpellAreas).Include(s => s.SpellDefenses) ), new Getter( EntityType.Subclass, context => context .Subclasses.Include(s => s.Trainings) .ThenInclude(t => t.Training) .Include(s => s.Entities) ), new Getter(EntityType.Trait, context => context.Traits), ]; /// /// Абстрактный класс, который определяет метод получения сущности из базы данных. /// /// Связанный тип сущности. private abstract class Getter(EntityType type) { public readonly EntityType Type = type; public abstract IEntity? Get(int id, Pf2eDbContext context); } /// /// Класс, определяющий метод получения сущности из базы данных. /// /// Тип данных основной сущности. /// Связанный тип сущности. /// Метод получения сущности из базы данных. private class Getter(EntityType type, Func> method) : Getter(type) where T : IEntity { public override IEntity? Get(int id, Pf2eDbContext context) { return method.Invoke(context).FirstOrDefault(c => c.Id == id); } } }