diff --git a/Pf2eDataScrapper.sln.DotSettings b/Pf2eDataScrapper.sln.DotSettings
index 06f6382..c2f1f1d 100644
--- a/Pf2eDataScrapper.sln.DotSettings
+++ b/Pf2eDataScrapper.sln.DotSettings
@@ -46,4 +46,5 @@
True
True
2025.1.0.0
- 2025.1.0.0
\ No newline at end of file
+ 2025.1.0.0
+ True
\ No newline at end of file
diff --git a/Pf2eDataScrapper/Importers/Implementations/Aonprd/DataBuilder/AonprdProcessorCollection.cs b/Pf2eDataScrapper/Importers/Implementations/Aonprd/DataBuilder/AonprdProcessorCollection.cs
index c10f7d1..5cd4052 100644
--- a/Pf2eDataScrapper/Importers/Implementations/Aonprd/DataBuilder/AonprdProcessorCollection.cs
+++ b/Pf2eDataScrapper/Importers/Implementations/Aonprd/DataBuilder/AonprdProcessorCollection.cs
@@ -52,8 +52,26 @@ internal class AonprdProcessorCollection
}
}
+ private void CheckDependencies()
+ {
+ foreach (ProcessorItem item in Items)
+ {
+ foreach (string dependency in item.Attribute.Dependencies)
+ {
+ if (Items.All(i => i.Attribute.Name != dependency))
+ {
+ throw new(
+ $"Dependency '{dependency}' for processor '{item.Attribute.Name}' not found."
+ );
+ }
+ }
+ }
+ }
+
private void SortItems()
{
+ CheckDependencies();
+
Dictionary priorities = [];
while (priorities.Count < Items.Count)
diff --git a/Pf2eDataScrapper/Importers/Implementations/Aonprd/DataBuilder/AonprdProcessorInput.cs b/Pf2eDataScrapper/Importers/Implementations/Aonprd/DataBuilder/AonprdProcessorInput.cs
index 67e9b3f..6f9aa5f 100644
--- a/Pf2eDataScrapper/Importers/Implementations/Aonprd/DataBuilder/AonprdProcessorInput.cs
+++ b/Pf2eDataScrapper/Importers/Implementations/Aonprd/DataBuilder/AonprdProcessorInput.cs
@@ -60,6 +60,12 @@ internal class AonprdProcessorInput(JObject input) : ProcessorInput(input)
result.MaxActions = 3;
break;
+ case "Two Actions to 2 rounds":
+ result.Actions = 2;
+ result.MaxActions = 3;
+ result.TwoRounds = true;
+ break;
+
case "Reaction or One Action":
result.IsReaction = true;
result.Actions = result.MaxActions = 1;
@@ -90,5 +96,6 @@ internal class AonprdProcessorInput(JObject input) : ProcessorInput(input)
public bool IsPassive;
public bool IsReaction;
public bool IsFreeAction;
+ public bool TwoRounds;
}
}
diff --git a/Pf2eDataScrapper/Importers/Implementations/Aonprd/DataBuilder/Helpers/AonprdEnumResolver.cs b/Pf2eDataScrapper/Importers/Implementations/Aonprd/DataBuilder/Helpers/AonprdEnumResolver.cs
index 8b3af91..f503a86 100644
--- a/Pf2eDataScrapper/Importers/Implementations/Aonprd/DataBuilder/Helpers/AonprdEnumResolver.cs
+++ b/Pf2eDataScrapper/Importers/Implementations/Aonprd/DataBuilder/Helpers/AonprdEnumResolver.cs
@@ -33,6 +33,33 @@ public static class AonprdEnumResolver
{ "other", AttributeValues.Free },
}
),
+ new Solver(
+ new()
+ {
+ { "Single Action", ActionEnum.SingleAction },
+ { "Two Actions", ActionEnum.TwoActions },
+ { "Three Actions", ActionEnum.ThreeActions },
+ { "Reaction", ActionEnum.Reaction },
+ { "Free Action", ActionEnum.FreeAction },
+ { "Single Action to Three Actions", ActionEnum.SingleActionToThreeActions },
+ { "Single Action or more Actions", ActionEnum.SingleActionToThreeActions },
+ { "Single Action or Two Actions", ActionEnum.SingleActionToTwoActions },
+ { "Single Action to Two Actions", ActionEnum.SingleActionToTwoActions },
+ { "Two Actions or Three Actions", ActionEnum.TwoActionsToThreeActions },
+ { "Two Actions to 2 rounds", ActionEnum.TwoActionsToTwoRounds },
+ { "Reaction or One Action", ActionEnum.ReactionOrOneAction },
+ { "Reaction or Two Actions", ActionEnum.ReactionOrTwoAction },
+ { "Reaction or Three Actions", ActionEnum.ReactionOrThreeAction },
+ { "Free Action or One Action", ActionEnum.FreeActionOrOneAction },
+ { "1 Minute", ActionEnum.OneMinute },
+ { "1 minute", ActionEnum.OneMinute },
+ { "5 minutes", ActionEnum.FiveMinutes },
+ { "10 minutes", ActionEnum.TenMinutes },
+ { "30 minutes", ActionEnum.ThirtyMinutes },
+ { "1 hour", ActionEnum.OneHour },
+ { "Nethys Note: No cast time was printed", ActionEnum.Unknown },
+ }
+ ),
];
public static T Resolve(string value)
diff --git a/Pf2eDataScrapper/Importers/Implementations/Aonprd/DataBuilder/Helpers/StringHelper.cs b/Pf2eDataScrapper/Importers/Implementations/Aonprd/DataBuilder/Helpers/StringHelper.cs
index 9968b36..134fbf2 100644
--- a/Pf2eDataScrapper/Importers/Implementations/Aonprd/DataBuilder/Helpers/StringHelper.cs
+++ b/Pf2eDataScrapper/Importers/Implementations/Aonprd/DataBuilder/Helpers/StringHelper.cs
@@ -6,6 +6,24 @@ internal partial class StringHelper
{
private StringHelper() { }
+ public List ParseMarkdown(string input)
+ {
+ List links = [];
+ Match match = MarkdownRegex().Match(input);
+ if (match.Captures.Count > 0)
+ {
+ links.Add(
+ new()
+ {
+ Prefix = match.Groups[1].Value.Trim(),
+ Text = match.Groups[2].Value.Trim(),
+ Url = match.Groups[3].Value.Trim(),
+ }
+ );
+ }
+ return links;
+ }
+
public string ResolveSource(string input)
{
Match match = SourceSuffixRegex().Match(input);
@@ -16,4 +34,14 @@ internal partial class StringHelper
[GeneratedRegex(@"^\[.*?\]\(.*?\)\s+(.*)$")]
private static partial Regex SourceSuffixRegex();
+
+ [GeneratedRegex(@"(.*?)\[(.*?)\]\((.*?)\)")]
+ private static partial Regex MarkdownRegex();
+}
+
+internal class MarkdownLink
+{
+ public string Prefix { get; set; } = "";
+ public string Text { get; set; } = "";
+ public string Url { get; set; } = "";
}
diff --git a/Pf2eDataScrapper/Importers/Implementations/Aonprd/DataBuilder/Processors/Common/TrainingProcessor.cs b/Pf2eDataScrapper/Importers/Implementations/Aonprd/DataBuilder/Processors/Common/SkillProcessor.cs
similarity index 55%
rename from Pf2eDataScrapper/Importers/Implementations/Aonprd/DataBuilder/Processors/Common/TrainingProcessor.cs
rename to Pf2eDataScrapper/Importers/Implementations/Aonprd/DataBuilder/Processors/Common/SkillProcessor.cs
index 80342ce..1c8a112 100644
--- a/Pf2eDataScrapper/Importers/Implementations/Aonprd/DataBuilder/Processors/Common/TrainingProcessor.cs
+++ b/Pf2eDataScrapper/Importers/Implementations/Aonprd/DataBuilder/Processors/Common/SkillProcessor.cs
@@ -1,16 +1,21 @@
using Pf2eModel.Model.Common;
+using Pf2eModel.Model.Common.I18n;
using Pf2eModel.Model.Enum;
namespace Pf2eDataScrapper.Importers.Implementations.Aonprd.DataBuilder.Processors.Common;
[AonprdProcessor("skill", [])]
-internal class TrainingProcessor(AonprdProcessorInput input) : AbstractProcessor(input)
+internal class SkillProcessor(AonprdProcessorInput input) : AbstractProcessor(input)
{
public Training Training = null!;
public override void Process()
{
- Training = new() { Name = Input.GetRequired("name"), Type = TrainingType.Skill };
+ Training = new()
+ {
+ Name = new() { { LocaleType.English, Input.GetRequired("name") } },
+ Type = TrainingType.Skill,
+ };
}
public override void Save()
diff --git a/Pf2eDataScrapper/Importers/Implementations/Aonprd/DataBuilder/Processors/Subclasses/ApparitionProcessor.cs b/Pf2eDataScrapper/Importers/Implementations/Aonprd/DataBuilder/Processors/Subclasses/ApparitionProcessor.cs
index e3e01cb..b094c8b 100644
--- a/Pf2eDataScrapper/Importers/Implementations/Aonprd/DataBuilder/Processors/Subclasses/ApparitionProcessor.cs
+++ b/Pf2eDataScrapper/Importers/Implementations/Aonprd/DataBuilder/Processors/Subclasses/ApparitionProcessor.cs
@@ -1,8 +1,15 @@
-using Pf2eModel.Model.Structure;
+using Microsoft.EntityFrameworkCore;
+using Pf2eDataScrapper.Importers.Implementations.Aonprd.DataBuilder.Helpers;
+using Pf2eModel;
+using Pf2eModel.Model.Base;
+using Pf2eModel.Model.Common;
+using Pf2eModel.Model.Common.I18n;
+using Pf2eModel.Model.Enum;
+using Pf2eModel.Model.Structure;
namespace Pf2eDataScrapper.Importers.Implementations.Aonprd.DataBuilder.Processors.Subclasses;
-[AonprdProcessor("apparition", ["class"])]
+[AonprdProcessor("apparition", ["class", "spell", "trainings"])]
internal class ApparitionProcessor(AonprdProcessorInput input) : AbstractSubclassProcessor(input)
{
public override Subclass Object { get; } = new();
@@ -11,7 +18,54 @@ internal class ApparitionProcessor(AonprdProcessorInput input) : AbstractSubclas
public override string GroupName => "Apparition";
- public override void ProcessObject() { }
+ public override void ProcessObject()
+ {
+ // Spells
+ string spellMd = Input.GetRequired("spells_markdown");
+ List spellUrls = StringHelper.ParseMarkdown(spellMd).Select(l => l.Url).ToList();
+
+ List spellIds = Context
+ .EntityExternals.Where(x => spellUrls.Contains(x.Suffix))
+ .Select(x => x.Entity.Id)
+ .ToList();
+
+ List spells = Context
+ .Spells.Where(s => spellIds.Contains(s.Id))
+ .Select(s => s.Entity)
+ .ToList();
+
+ foreach (Entity spellEntity in spells)
+ {
+ Object.Entities.Add(spellEntity);
+ }
+
+ // Trainings
+ string trainingMd = Input.GetRequired("skill_markdown");
+
+ List trainingNames = trainingMd.Split(", ").ToList();
+ List trainings = Context
+ .Trainings.Where(t => Pf2eDbContext.LocaleSearchArray(t.Name, trainingNames))
+ .ToList();
+
+ foreach (string name in trainingNames)
+ {
+ Training? training = trainings.FirstOrDefault(t => t.Name!.Contains(name));
+ training ??= new()
+ {
+ Name = new() { { LocaleType.English, name } },
+ Type = TrainingType.Lore,
+ };
+
+ Object.Trainings.Add(
+ new()
+ {
+ Subclass = Object,
+ Training = training,
+ Stage = TrainingStage.Trained,
+ }
+ );
+ }
+ }
protected override string GetDescription() =>
base.GetDescription()
diff --git a/Pf2eDataScrapper/Importers/Implementations/Aonprd/DataBuilder/Processors/Types/ActionProcessor.cs b/Pf2eDataScrapper/Importers/Implementations/Aonprd/DataBuilder/Processors/Types/ActionProcessor.cs
index 3f45cf6..e236e34 100644
--- a/Pf2eDataScrapper/Importers/Implementations/Aonprd/DataBuilder/Processors/Types/ActionProcessor.cs
+++ b/Pf2eDataScrapper/Importers/Implementations/Aonprd/DataBuilder/Processors/Types/ActionProcessor.cs
@@ -2,7 +2,7 @@
namespace Pf2eDataScrapper.Importers.Implementations.Aonprd.DataBuilder.Processors.Types;
-[AonprdProcessor("action")]
+// [AonprdProcessor("action")]
internal class ActionProcessor(AonprdProcessorInput input) : AbstractEntityProcessor(input)
{
public override EntityType Type => EntityType.Action;
@@ -29,16 +29,7 @@ internal class ActionProcessor(AonprdProcessorInput input) : AbstractEntityProce
base.Process();
- AonprdProcessorInput.ActionStruct action = Input.ResolveActionString(
- Input.GetOptional("actions") ?? ""
- );
-
- Object.Actions = action.Actions;
- Object.MaxActions = action.MaxActions;
- Object.IsFreeAction = action.IsFreeAction;
- Object.IsPassive = action.IsPassive;
- Object.IsReaction = action.IsReaction;
-
+ Object.Actions = Input.EnumOptional("actions", ActionEnum.Passive);
Object.Extra = GenerateExtra("school");
}
diff --git a/Pf2eDataScrapper/Importers/Implementations/Aonprd/DataBuilder/Processors/Types/ClassProcessor.cs b/Pf2eDataScrapper/Importers/Implementations/Aonprd/DataBuilder/Processors/Types/ClassProcessor.cs
index 10ae2e4..bff7d17 100644
--- a/Pf2eDataScrapper/Importers/Implementations/Aonprd/DataBuilder/Processors/Types/ClassProcessor.cs
+++ b/Pf2eDataScrapper/Importers/Implementations/Aonprd/DataBuilder/Processors/Types/ClassProcessor.cs
@@ -1,6 +1,8 @@
using System.Text.RegularExpressions;
using Newtonsoft.Json.Linq;
+using Pf2eModel;
using Pf2eModel.Model.Common;
+using Pf2eModel.Model.Common.I18n;
using Pf2eModel.Model.Enum;
using Pf2eModel.Model.Structure;
using Pf2eModel.Model.Structure.ClassRelation;
@@ -82,13 +84,14 @@ internal class ClassProcessor(AonprdProcessorInput input) : AbstractEntityProces
protected ICollection GetSkillTrainings()
{
- string[] skillNames = Input
+ List skillNames = Input
.GetRequired("skill_proficiency")
.Select(token => token.ToString())
- .ToArray();
+ .ToList();
- Training[] skills = Context.Trainings.Where(t => skillNames.Contains(t.Name)).ToArray();
- // Training[] skills = Context.Trainings.Where(t => Pf2eDbContext.LocaleSearchArray(t.Name, skillNames)).ToArray();
+ Training[] skills = Context
+ .Trainings.Where(t => Pf2eDbContext.LocaleSearchArray(t.Name, skillNames))
+ .ToArray();
return skills
.Select(skill => new ClassTraining()
@@ -121,12 +124,16 @@ internal class ClassProcessor(AonprdProcessorInput input) : AbstractEntityProces
foreach (string part in parts)
{
Training? training = Context.Trainings.FirstOrDefault(t =>
- t.Name == part && t.Type == type
+ Pf2eDbContext.LocaleSearch(t.Name, part) && t.Type == type
);
if (training == null)
{
- training = new Training() { Name = part, Type = type };
+ training = new Training()
+ {
+ Name = new() { [LocaleType.English] = part },
+ Type = type,
+ };
Context.Trainings.Add(training);
}
@@ -160,7 +167,7 @@ internal class ClassProcessor(AonprdProcessorInput input) : AbstractEntityProces
{
Dictionary result = Context
.Trainings.Where(t => t.Type == TrainingType.Save)
- .ToDictionary(t => t.Name);
+ .ToDictionary(t => t.Name[LocaleType.English]);
foreach (string name in new[] { "Will", "Fortitude", "Reflex", "Perception" })
{
@@ -171,7 +178,7 @@ internal class ClassProcessor(AonprdProcessorInput input) : AbstractEntityProces
Training training = new()
{
- Name = name,
+ Name = new() { [LocaleType.English] = name },
Type = (name == "Perception") ? TrainingType.Perception : TrainingType.Save,
};
diff --git a/Pf2eDataScrapper/Importers/Implementations/Aonprd/DataBuilder/Processors/Types/SpellProcessor.cs b/Pf2eDataScrapper/Importers/Implementations/Aonprd/DataBuilder/Processors/Types/SpellProcessor.cs
new file mode 100644
index 0000000..59158f2
--- /dev/null
+++ b/Pf2eDataScrapper/Importers/Implementations/Aonprd/DataBuilder/Processors/Types/SpellProcessor.cs
@@ -0,0 +1,67 @@
+using Pf2eModel.Model.Common.I18n;
+using Pf2eModel.Model.Enum;
+using Pf2eModel.Model.Structure;
+using Pf2eModel.Model.Structure.SpellRelation;
+
+namespace Pf2eDataScrapper.Importers.Implementations.Aonprd.DataBuilder.Processors.Types;
+
+[AonprdProcessor("spell")]
+internal class SpellProcessor(AonprdProcessorInput input) : AbstractEntityProcessor(input)
+{
+ public override EntityType Type => EntityType.Spell;
+
+ public override Spell Object { get; } = new();
+
+ public override void Add() => Context.Spells.Add(Object);
+
+ public override void Process()
+ {
+ base.Process();
+
+ Object.Level = Input.GetRequired("level");
+ Object.Actions = Input.EnumOptional("actions", ActionEnum.Unknown);
+ Object.IsFocus = Input.GetRequired("spell_type") == "Focus";
+
+ switch (Input.GetRequired("spell_type"))
+ {
+ case "Focus":
+ Object.IsFocus = true;
+ break;
+ case "Cantrip":
+ Object.Level = 0;
+ break;
+ }
+
+ foreach (string areaType in Input.GetOptional("area_type") ?? [])
+ {
+ Object.SpellAreas.Add(
+ new()
+ {
+ Spell = Object,
+ Type = Input.EnumRequired(areaType),
+ Value = 0,
+ }
+ );
+ }
+ }
+
+ protected override string GetDescription() =>
+ base.GetDescription()
+ + AddedDescription(
+ [
+ "area_raw",
+ "bloodline_markdown",
+ "deity_markdown",
+ "domain_markdown",
+ "lesson_markdown",
+ "mystery_markdown",
+ "requirement_markdown",
+ "summary_markdown",
+ "tradition_markdown",
+ "patron_theme_markdown",
+ "trigger_markdown",
+ "saving_throw_markdown",
+ "target_markdown",
+ ]
+ );
+}
diff --git a/Pf2eModel/Migrations/20250428065903_1.Designer.cs b/Pf2eModel/Migrations/20250505114131_1.Designer.cs
similarity index 95%
rename from Pf2eModel/Migrations/20250428065903_1.Designer.cs
rename to Pf2eModel/Migrations/20250505114131_1.Designer.cs
index 21536e1..9ac18ea 100644
--- a/Pf2eModel/Migrations/20250428065903_1.Designer.cs
+++ b/Pf2eModel/Migrations/20250505114131_1.Designer.cs
@@ -13,7 +13,7 @@ using Pf2eModel.Model.Enum;
namespace Pf2eModel.Migrations
{
[DbContext(typeof(Pf2eDbContext))]
- [Migration("20250428065903_1")]
+ [Migration("20250505114131_1")]
partial class _1
{
///
@@ -417,8 +417,7 @@ namespace Pf2eModel.Migrations
b.Property("Name")
.IsRequired()
- .HasMaxLength(255)
- .HasColumnType("character varying(255)")
+ .HasColumnType("jsonb")
.HasColumnName("name")
.HasColumnOrder(2);
@@ -873,16 +872,10 @@ namespace Pf2eModel.Migrations
.HasColumnName("class_id")
.HasColumnOrder(2);
- b.Property("Name")
- .HasMaxLength(255)
- .HasColumnType("character varying(255)")
- .HasColumnName("name")
- .HasColumnOrder(4);
-
b.Property("Stage")
.HasColumnType("training_stage")
.HasColumnName("stage")
- .HasColumnOrder(5);
+ .HasColumnOrder(4);
b.Property("TrainingId")
.HasColumnType("integer")
@@ -901,6 +894,62 @@ namespace Pf2eModel.Migrations
b.ToTable("class_trainings", (string)null);
});
+ modelBuilder.Entity("Pf2eModel.Model.Structure.ClassRelation.SubclassProvidedEntities", b =>
+ {
+ b.Property("SubclassId")
+ .HasColumnType("integer")
+ .HasColumnName("subclass_id");
+
+ b.Property("EntityId")
+ .HasColumnType("integer")
+ .HasColumnName("entity_id");
+
+ b.HasKey("SubclassId", "EntityId")
+ .HasName("pk_subclass_provided_entities");
+
+ b.HasIndex("EntityId")
+ .HasDatabaseName("ix_subclass_provided_entities_entity_id");
+
+ b.ToTable("subclass_provided_entities", (string)null);
+ });
+
+ modelBuilder.Entity("Pf2eModel.Model.Structure.ClassRelation.SubclassTrainings", b =>
+ {
+ b.Property("Id")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("integer")
+ .HasColumnName("id")
+ .HasColumnOrder(1);
+
+ NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id"));
+
+ b.Property("Stage")
+ .HasColumnType("training_stage")
+ .HasColumnName("stage")
+ .HasColumnOrder(4);
+
+ b.Property("SubclassId")
+ .HasColumnType("integer")
+ .HasColumnName("subclass_id")
+ .HasColumnOrder(2);
+
+ b.Property("TrainingId")
+ .HasColumnType("integer")
+ .HasColumnName("training_id")
+ .HasColumnOrder(3);
+
+ b.HasKey("Id")
+ .HasName("pk_subclass_trainings");
+
+ b.HasIndex("SubclassId")
+ .HasDatabaseName("ix_subclass_trainings_subclass_id");
+
+ b.HasIndex("TrainingId")
+ .HasDatabaseName("ix_subclass_trainings_training_id");
+
+ b.ToTable("subclass_trainings", (string)null);
+ });
+
modelBuilder.Entity("Pf2eModel.Model.Structure.Condition", b =>
{
b.Property("Id")
@@ -1870,6 +1919,44 @@ namespace Pf2eModel.Migrations
b.Navigation("Training");
});
+ modelBuilder.Entity("Pf2eModel.Model.Structure.ClassRelation.SubclassProvidedEntities", b =>
+ {
+ b.HasOne("Pf2eModel.Model.Base.Entity", null)
+ .WithMany()
+ .HasForeignKey("EntityId")
+ .OnDelete(DeleteBehavior.Cascade)
+ .IsRequired()
+ .HasConstraintName("fk_subclass_provided_entities_entities_entity_id");
+
+ b.HasOne("Pf2eModel.Model.Structure.Subclass", null)
+ .WithMany()
+ .HasForeignKey("SubclassId")
+ .OnDelete(DeleteBehavior.Cascade)
+ .IsRequired()
+ .HasConstraintName("fk_subclass_provided_entities_subclasses_subclass_id");
+ });
+
+ modelBuilder.Entity("Pf2eModel.Model.Structure.ClassRelation.SubclassTrainings", b =>
+ {
+ b.HasOne("Pf2eModel.Model.Structure.Subclass", "Subclass")
+ .WithMany("Trainings")
+ .HasForeignKey("SubclassId")
+ .OnDelete(DeleteBehavior.Cascade)
+ .IsRequired()
+ .HasConstraintName("fk_subclass_trainings_subclasses_subclass_id");
+
+ b.HasOne("Pf2eModel.Model.Common.Training", "Training")
+ .WithMany()
+ .HasForeignKey("TrainingId")
+ .OnDelete(DeleteBehavior.Cascade)
+ .IsRequired()
+ .HasConstraintName("fk_subclass_trainings_trainings_training_id");
+
+ b.Navigation("Subclass");
+
+ b.Navigation("Training");
+ });
+
modelBuilder.Entity("Pf2eModel.Model.Structure.Condition", b =>
{
b.HasOne("Pf2eModel.Model.Base.Entity", "Entity")
@@ -2198,6 +2285,11 @@ namespace Pf2eModel.Migrations
b.Navigation("SpellRitual");
});
+ modelBuilder.Entity("Pf2eModel.Model.Structure.Subclass", b =>
+ {
+ b.Navigation("Trainings");
+ });
+
modelBuilder.Entity("Pf2eModel.Model.Structure.SubclassGroup", b =>
{
b.Navigation("Subclasses");
diff --git a/Pf2eModel/Migrations/20250428065903_1.cs b/Pf2eModel/Migrations/20250505114131_1.cs
similarity index 94%
rename from Pf2eModel/Migrations/20250428065903_1.cs
rename to Pf2eModel/Migrations/20250505114131_1.cs
index 750c5af..7ac8590 100644
--- a/Pf2eModel/Migrations/20250428065903_1.cs
+++ b/Pf2eModel/Migrations/20250505114131_1.cs
@@ -120,7 +120,7 @@ namespace Pf2eModel.Migrations
{
id = table.Column(type: "integer", nullable: false)
.Annotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn),
- name = table.Column(type: "character varying(255)", maxLength: 255, nullable: false),
+ name = table.Column(type: "jsonb", nullable: false),
type = table.Column(type: "integer", nullable: false)
},
constraints: table =>
@@ -633,7 +633,6 @@ namespace Pf2eModel.Migrations
.Annotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn),
class_id = table.Column(type: "integer", nullable: false),
training_id = table.Column(type: "integer", nullable: true),
- name = table.Column(type: "character varying(255)", maxLength: 255, nullable: true),
stage = table.Column(type: "training_stage", nullable: false)
},
constraints: table =>
@@ -1020,6 +1019,57 @@ namespace Pf2eModel.Migrations
onDelete: ReferentialAction.Cascade);
});
+ migrationBuilder.CreateTable(
+ name: "subclass_provided_entities",
+ columns: table => new
+ {
+ subclass_id = table.Column(type: "integer", nullable: false),
+ entity_id = table.Column(type: "integer", nullable: false)
+ },
+ constraints: table =>
+ {
+ table.PrimaryKey("pk_subclass_provided_entities", x => new { x.subclass_id, x.entity_id });
+ table.ForeignKey(
+ name: "fk_subclass_provided_entities_entities_entity_id",
+ column: x => x.entity_id,
+ principalTable: "entities",
+ principalColumn: "id",
+ onDelete: ReferentialAction.Cascade);
+ table.ForeignKey(
+ name: "fk_subclass_provided_entities_subclasses_subclass_id",
+ column: x => x.subclass_id,
+ principalTable: "subclasses",
+ principalColumn: "id",
+ onDelete: ReferentialAction.Cascade);
+ });
+
+ migrationBuilder.CreateTable(
+ name: "subclass_trainings",
+ columns: table => new
+ {
+ id = table.Column(type: "integer", nullable: false)
+ .Annotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn),
+ subclass_id = table.Column(type: "integer", nullable: false),
+ training_id = table.Column(type: "integer", nullable: false),
+ stage = table.Column(type: "training_stage", nullable: false)
+ },
+ constraints: table =>
+ {
+ table.PrimaryKey("pk_subclass_trainings", x => x.id);
+ table.ForeignKey(
+ name: "fk_subclass_trainings_subclasses_subclass_id",
+ column: x => x.subclass_id,
+ principalTable: "subclasses",
+ principalColumn: "id",
+ onDelete: ReferentialAction.Cascade);
+ table.ForeignKey(
+ name: "fk_subclass_trainings_trainings_training_id",
+ column: x => x.training_id,
+ principalTable: "trainings",
+ principalColumn: "id",
+ onDelete: ReferentialAction.Cascade);
+ });
+
migrationBuilder.CreateIndex(
name: "ix_ancestry_boosts_ancestry_id",
table: "ancestry_boosts",
@@ -1171,6 +1221,21 @@ namespace Pf2eModel.Migrations
table: "subclass_groups",
column: "class_id");
+ migrationBuilder.CreateIndex(
+ name: "ix_subclass_provided_entities_entity_id",
+ table: "subclass_provided_entities",
+ column: "entity_id");
+
+ migrationBuilder.CreateIndex(
+ name: "ix_subclass_trainings_subclass_id",
+ table: "subclass_trainings",
+ column: "subclass_id");
+
+ migrationBuilder.CreateIndex(
+ name: "ix_subclass_trainings_training_id",
+ table: "subclass_trainings",
+ column: "training_id");
+
migrationBuilder.CreateIndex(
name: "ix_subclasses_group_id",
table: "subclasses",
@@ -1268,7 +1333,10 @@ namespace Pf2eModel.Migrations
name: "spell_rituals");
migrationBuilder.DropTable(
- name: "subclasses");
+ name: "subclass_provided_entities");
+
+ migrationBuilder.DropTable(
+ name: "subclass_trainings");
migrationBuilder.DropTable(
name: "languages");
@@ -1279,9 +1347,6 @@ namespace Pf2eModel.Migrations
migrationBuilder.DropTable(
name: "backgrounds");
- migrationBuilder.DropTable(
- name: "trainings");
-
migrationBuilder.DropTable(
name: "deities");
@@ -1304,11 +1369,17 @@ namespace Pf2eModel.Migrations
name: "spells");
migrationBuilder.DropTable(
- name: "subclass_groups");
+ name: "subclasses");
+
+ migrationBuilder.DropTable(
+ name: "trainings");
migrationBuilder.DropTable(
name: "feats");
+ migrationBuilder.DropTable(
+ name: "subclass_groups");
+
migrationBuilder.DropTable(
name: "classes");
diff --git a/Pf2eModel/Migrations/Pf2eDbContextModelSnapshot.cs b/Pf2eModel/Migrations/Pf2eDbContextModelSnapshot.cs
index 15fd196..67456e4 100644
--- a/Pf2eModel/Migrations/Pf2eDbContextModelSnapshot.cs
+++ b/Pf2eModel/Migrations/Pf2eDbContextModelSnapshot.cs
@@ -414,8 +414,7 @@ namespace Pf2eModel.Migrations
b.Property("Name")
.IsRequired()
- .HasMaxLength(255)
- .HasColumnType("character varying(255)")
+ .HasColumnType("jsonb")
.HasColumnName("name")
.HasColumnOrder(2);
@@ -870,16 +869,10 @@ namespace Pf2eModel.Migrations
.HasColumnName("class_id")
.HasColumnOrder(2);
- b.Property("Name")
- .HasMaxLength(255)
- .HasColumnType("character varying(255)")
- .HasColumnName("name")
- .HasColumnOrder(4);
-
b.Property("Stage")
.HasColumnType("training_stage")
.HasColumnName("stage")
- .HasColumnOrder(5);
+ .HasColumnOrder(4);
b.Property("TrainingId")
.HasColumnType("integer")
@@ -898,6 +891,62 @@ namespace Pf2eModel.Migrations
b.ToTable("class_trainings", (string)null);
});
+ modelBuilder.Entity("Pf2eModel.Model.Structure.ClassRelation.SubclassProvidedEntities", b =>
+ {
+ b.Property("SubclassId")
+ .HasColumnType("integer")
+ .HasColumnName("subclass_id");
+
+ b.Property("EntityId")
+ .HasColumnType("integer")
+ .HasColumnName("entity_id");
+
+ b.HasKey("SubclassId", "EntityId")
+ .HasName("pk_subclass_provided_entities");
+
+ b.HasIndex("EntityId")
+ .HasDatabaseName("ix_subclass_provided_entities_entity_id");
+
+ b.ToTable("subclass_provided_entities", (string)null);
+ });
+
+ modelBuilder.Entity("Pf2eModel.Model.Structure.ClassRelation.SubclassTrainings", b =>
+ {
+ b.Property("Id")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("integer")
+ .HasColumnName("id")
+ .HasColumnOrder(1);
+
+ NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id"));
+
+ b.Property("Stage")
+ .HasColumnType("training_stage")
+ .HasColumnName("stage")
+ .HasColumnOrder(4);
+
+ b.Property("SubclassId")
+ .HasColumnType("integer")
+ .HasColumnName("subclass_id")
+ .HasColumnOrder(2);
+
+ b.Property("TrainingId")
+ .HasColumnType("integer")
+ .HasColumnName("training_id")
+ .HasColumnOrder(3);
+
+ b.HasKey("Id")
+ .HasName("pk_subclass_trainings");
+
+ b.HasIndex("SubclassId")
+ .HasDatabaseName("ix_subclass_trainings_subclass_id");
+
+ b.HasIndex("TrainingId")
+ .HasDatabaseName("ix_subclass_trainings_training_id");
+
+ b.ToTable("subclass_trainings", (string)null);
+ });
+
modelBuilder.Entity("Pf2eModel.Model.Structure.Condition", b =>
{
b.Property("Id")
@@ -1867,6 +1916,44 @@ namespace Pf2eModel.Migrations
b.Navigation("Training");
});
+ modelBuilder.Entity("Pf2eModel.Model.Structure.ClassRelation.SubclassProvidedEntities", b =>
+ {
+ b.HasOne("Pf2eModel.Model.Base.Entity", null)
+ .WithMany()
+ .HasForeignKey("EntityId")
+ .OnDelete(DeleteBehavior.Cascade)
+ .IsRequired()
+ .HasConstraintName("fk_subclass_provided_entities_entities_entity_id");
+
+ b.HasOne("Pf2eModel.Model.Structure.Subclass", null)
+ .WithMany()
+ .HasForeignKey("SubclassId")
+ .OnDelete(DeleteBehavior.Cascade)
+ .IsRequired()
+ .HasConstraintName("fk_subclass_provided_entities_subclasses_subclass_id");
+ });
+
+ modelBuilder.Entity("Pf2eModel.Model.Structure.ClassRelation.SubclassTrainings", b =>
+ {
+ b.HasOne("Pf2eModel.Model.Structure.Subclass", "Subclass")
+ .WithMany("Trainings")
+ .HasForeignKey("SubclassId")
+ .OnDelete(DeleteBehavior.Cascade)
+ .IsRequired()
+ .HasConstraintName("fk_subclass_trainings_subclasses_subclass_id");
+
+ b.HasOne("Pf2eModel.Model.Common.Training", "Training")
+ .WithMany()
+ .HasForeignKey("TrainingId")
+ .OnDelete(DeleteBehavior.Cascade)
+ .IsRequired()
+ .HasConstraintName("fk_subclass_trainings_trainings_training_id");
+
+ b.Navigation("Subclass");
+
+ b.Navigation("Training");
+ });
+
modelBuilder.Entity("Pf2eModel.Model.Structure.Condition", b =>
{
b.HasOne("Pf2eModel.Model.Base.Entity", "Entity")
@@ -2195,6 +2282,11 @@ namespace Pf2eModel.Migrations
b.Navigation("SpellRitual");
});
+ modelBuilder.Entity("Pf2eModel.Model.Structure.Subclass", b =>
+ {
+ b.Navigation("Trainings");
+ });
+
modelBuilder.Entity("Pf2eModel.Model.Structure.SubclassGroup", b =>
{
b.Navigation("Subclasses");
diff --git a/Pf2eModel/Model/Base/Targets/EntityExternal.cs b/Pf2eModel/Model/Base/Targets/EntityExternal.cs
index 2081ef2..0cbdc76 100644
--- a/Pf2eModel/Model/Base/Targets/EntityExternal.cs
+++ b/Pf2eModel/Model/Base/Targets/EntityExternal.cs
@@ -7,18 +7,24 @@ namespace Pf2eModel.Model.Base.Targets;
[PrimaryKey(nameof(EntityId), nameof(TargetId))]
public class EntityExternal
{
- [Column(Order = 0)]
+ [Column(Order = 1)]
public int EntityId { get; set; }
- [Column(Order = 1)]
+ [Column(Order = 2)]
public int TargetId { get; set; }
- [Column(Order = 2)]
+ /*
+ [Column(Order = 3)]
+ [MaxLength(255)]
+ public string ExternalId { get; set; } = "";
+ */
+
+ [Column(Order = 4)]
[MaxLength(255)]
[Comment("Часть URL до объекта. Для источников Foundry - полный UUID объекта")]
public string Suffix { get; set; } = "";
- [Column(Order = 3)]
+ [Column(Order = 5)]
[MaxLength(32)]
[Comment("Контроль версии объекта")]
public string Md5 { get; set; } = null!;
diff --git a/Pf2eModel/Model/Common/Training.cs b/Pf2eModel/Model/Common/Training.cs
index 6bb92da..f9244e6 100644
--- a/Pf2eModel/Model/Common/Training.cs
+++ b/Pf2eModel/Model/Common/Training.cs
@@ -1,5 +1,6 @@
using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;
+using Pf2eModel.Model.Common.I18n;
using Pf2eModel.Model.Enum;
namespace Pf2eModel.Model.Common;
@@ -12,8 +13,7 @@ public class Training
public int Id { get; set; }
[Column(Order = 2)]
- [MaxLength(Pf2eDbContext.NameLength)]
- public string Name { get; set; } = null!;
+ public LocaleString Name { get; set; } = [];
[Column(Order = 3)]
public TrainingType Type { get; set; }
diff --git a/Pf2eModel/Model/Enum/ActionEnum.cs b/Pf2eModel/Model/Enum/ActionEnum.cs
new file mode 100644
index 0000000..ca54d62
--- /dev/null
+++ b/Pf2eModel/Model/Enum/ActionEnum.cs
@@ -0,0 +1,69 @@
+using NpgsqlTypes;
+
+namespace Pf2eModel.Model.Enum;
+
+public enum ActionEnum
+{
+ [PgName("unknown")]
+ Unknown,
+
+ [PgName("1")]
+ SingleAction,
+
+ [PgName("2")]
+ TwoActions,
+
+ [PgName("3")]
+ ThreeActions,
+
+ [PgName("reaction")]
+ Reaction,
+
+ [PgName("free")]
+ FreeAction,
+
+ [PgName("passive")]
+ Passive,
+
+ [PgName("other")]
+ Other,
+
+ [PgName("1-3")]
+ SingleActionToThreeActions,
+
+ [PgName("1-2")]
+ SingleActionToTwoActions,
+
+ [PgName("2-3")]
+ TwoActionsToThreeActions,
+
+ [PgName("2/2 rounds")]
+ TwoActionsToTwoRounds,
+
+ [PgName("reaction/1")]
+ ReactionOrOneAction,
+
+ [PgName("reaction/2")]
+ ReactionOrTwoAction,
+
+ [PgName("reaction/3")]
+ ReactionOrThreeAction,
+
+ [PgName("free/1")]
+ FreeActionOrOneAction,
+
+ [PgName("1 minute")]
+ OneMinute,
+
+ [PgName("5 minutes")]
+ FiveMinutes,
+
+ [PgName("10 minutes")]
+ TenMinutes,
+
+ [PgName("30 minutes")]
+ ThirtyMinutes,
+
+ [PgName("1 hour")]
+ OneHour,
+}
diff --git a/Pf2eModel/Model/Enum/SpellAreaType.cs b/Pf2eModel/Model/Enum/SpellAreaType.cs
index f01b2aa..b0c266b 100644
--- a/Pf2eModel/Model/Enum/SpellAreaType.cs
+++ b/Pf2eModel/Model/Enum/SpellAreaType.cs
@@ -24,4 +24,16 @@ public enum SpellAreaType
[PgName("cylinder")]
Cylinder,
+
+ [PgName("varies")]
+ Varies,
+
+ [PgName("cuboid")]
+ Cuboid,
+
+ [PgName("circle")]
+ Circle,
+
+ [PgName("other")]
+ Other,
}
diff --git a/Pf2eModel/Model/Structure/Action.cs b/Pf2eModel/Model/Structure/Action.cs
index ff0bbbb..1da0baf 100644
--- a/Pf2eModel/Model/Structure/Action.cs
+++ b/Pf2eModel/Model/Structure/Action.cs
@@ -12,22 +12,10 @@ public class Action : IEntity
[Column(Order = 1)]
public int Id { get; set; }
+ [Column(Order = 2)]
+ public ActionEnum Actions { get; set; } = ActionEnum.Unknown;
+
[Column(Order = 3)]
- public int? Actions { get; set; } = null;
-
- [Column(Order = 4)]
- public int? MaxActions { get; set; } = null;
-
- [Column(Order = 5)]
- public bool IsReaction { get; set; } = false;
-
- [Column(Order = 6)]
- public bool IsFreeAction { get; set; } = false;
-
- [Column(Order = 6)]
- public bool IsPassive { get; set; } = false;
-
- [Column(Order = 6)]
// ReSharper disable once EntityFramework.ModelValidation.UnlimitedStringLength
public string? Extra { get; set; }
diff --git a/Pf2eModel/Model/Structure/ArchetypeRelation/ArchetypeFeats.cs b/Pf2eModel/Model/Structure/ArchetypeRelation/ArchetypeFeats.cs
index 23dbba2..2828a0b 100644
--- a/Pf2eModel/Model/Structure/ArchetypeRelation/ArchetypeFeats.cs
+++ b/Pf2eModel/Model/Structure/ArchetypeRelation/ArchetypeFeats.cs
@@ -3,7 +3,7 @@
namespace Pf2eModel.Model.Structure.ArchetypeRelation;
[PrimaryKey(nameof(ArchetypeId), nameof(FeatId))]
-internal class ArchetypeFeats
+public class ArchetypeFeats
{
public int ArchetypeId { get; set; }
diff --git a/Pf2eModel/Model/Structure/ClassRelation/ClassTraining.cs b/Pf2eModel/Model/Structure/ClassRelation/ClassTraining.cs
index 0cbde59..d7e66ac 100644
--- a/Pf2eModel/Model/Structure/ClassRelation/ClassTraining.cs
+++ b/Pf2eModel/Model/Structure/ClassRelation/ClassTraining.cs
@@ -20,10 +20,6 @@ public class ClassTraining
public int? TrainingId { get; set; }
[Column(Order = 4)]
- [MaxLength(Pf2eDbContext.NameLength)]
- public string? Name { get; set; }
-
- [Column(Order = 5)]
public TrainingStage Stage { get; set; }
[JsonIgnore]
diff --git a/Pf2eModel/Model/Structure/ClassRelation/SubclassProvidedEntities.cs b/Pf2eModel/Model/Structure/ClassRelation/SubclassProvidedEntities.cs
new file mode 100644
index 0000000..39d5869
--- /dev/null
+++ b/Pf2eModel/Model/Structure/ClassRelation/SubclassProvidedEntities.cs
@@ -0,0 +1,11 @@
+using Microsoft.EntityFrameworkCore;
+
+namespace Pf2eModel.Model.Structure.ClassRelation;
+
+[PrimaryKey(nameof(SubclassId), nameof(EntityId))]
+public class SubclassProvidedEntities
+{
+ public int SubclassId { get; set; }
+
+ public int EntityId { get; set; }
+}
diff --git a/Pf2eModel/Model/Structure/ClassRelation/SubclassTrainings.cs b/Pf2eModel/Model/Structure/ClassRelation/SubclassTrainings.cs
new file mode 100644
index 0000000..75ac908
--- /dev/null
+++ b/Pf2eModel/Model/Structure/ClassRelation/SubclassTrainings.cs
@@ -0,0 +1,27 @@
+using System.ComponentModel.DataAnnotations;
+using System.ComponentModel.DataAnnotations.Schema;
+using Pf2eModel.Model.Common;
+using Pf2eModel.Model.Enum;
+
+namespace Pf2eModel.Model.Structure.ClassRelation;
+
+public class SubclassTrainings
+{
+ [Key]
+ [DatabaseGenerated(DatabaseGeneratedOption.Identity)]
+ [Column(Order = 1)]
+ public int Id { get; set; }
+
+ [Column(Order = 2)]
+ public int SubclassId { get; set; }
+
+ [Column(Order = 3)]
+ public int TrainingId { get; set; }
+
+ [Column(Order = 4)]
+ public TrainingStage Stage { get; set; } = TrainingStage.Trained;
+
+ public Subclass Subclass { get; set; } = null!;
+
+ public Training Training { get; set; } = null!;
+}
diff --git a/Pf2eModel/Model/Structure/Spell.cs b/Pf2eModel/Model/Structure/Spell.cs
index b0c6637..a5d6bca 100644
--- a/Pf2eModel/Model/Structure/Spell.cs
+++ b/Pf2eModel/Model/Structure/Spell.cs
@@ -1,6 +1,7 @@
using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;
using Pf2eModel.Model.Base;
+using Pf2eModel.Model.Common.I18n;
using Pf2eModel.Model.Enum;
using Pf2eModel.Model.Structure.SpellRelation;
@@ -20,7 +21,12 @@ public class Spell : IEntity
public int Level { get; set; }
[Column(Order = 3)]
- public int Cost { get; set; }
+ public ActionEnum Actions { get; set; } = ActionEnum.Other;
+
+ [Column(Order = 4)]
+ public bool IsFocus { get; set; }
+
+ // ---
[Column(Order = 4)]
public bool Counteraction { get; set; }
@@ -51,7 +57,9 @@ public class Spell : IEntity
[Column(Order = 11)]
public bool CanHeightening { get; set; }
- public virtual SpellArea? SpellArea { get; set; }
+ // ---
+
+ public virtual ICollection SpellAreas { get; set; } = [];
public virtual SpellRitual? SpellRitual { get; set; }
diff --git a/Pf2eModel/Model/Structure/SpellRelation/SpellArea.cs b/Pf2eModel/Model/Structure/SpellRelation/SpellArea.cs
index ed9dae6..1480916 100644
--- a/Pf2eModel/Model/Structure/SpellRelation/SpellArea.cs
+++ b/Pf2eModel/Model/Structure/SpellRelation/SpellArea.cs
@@ -9,16 +9,19 @@ public class SpellArea
[Key]
[DatabaseGenerated(DatabaseGeneratedOption.None)]
[Column(Order = 1)]
- public int SpellId { get; set; }
+ public int Id { get; set; }
[Column(Order = 2)]
+ public int SpellId { get; set; }
+
+ [Column(Order = 3)]
[MaxLength(255)]
public string? Details { get; set; }
- [Column(Order = 3)]
+ [Column(Order = 4)]
public SpellAreaType Type { get; set; }
- [Column(Order = 4)]
+ [Column(Order = 5)]
public int Value { get; set; }
public virtual Spell Spell { get; set; } = null!;
diff --git a/Pf2eModel/Model/Structure/Subclass.cs b/Pf2eModel/Model/Structure/Subclass.cs
index 6e418ca..8b1e4e3 100644
--- a/Pf2eModel/Model/Structure/Subclass.cs
+++ b/Pf2eModel/Model/Structure/Subclass.cs
@@ -3,6 +3,7 @@ using System.ComponentModel.DataAnnotations.Schema;
using Pf2eModel.Model.Base;
using Pf2eModel.Model.Common.I18n;
using Pf2eModel.Model.Enum;
+using Pf2eModel.Model.Structure.ClassRelation;
namespace Pf2eModel.Model.Structure;
@@ -26,4 +27,8 @@ public class Subclass : IEntity
[Column(Order = 4)]
// ReSharper disable once EntityFramework.ModelValidation.UnlimitedStringLength
public string Extra { get; set; } = "{}";
+
+ public virtual ICollection Entities { get; set; } = [];
+
+ public virtual ICollection Trainings { get; set; } = [];
}
diff --git a/Pf2eModel/Pf2eDbContextModel.cs b/Pf2eModel/Pf2eDbContextModel.cs
index bffb505..da54736 100644
--- a/Pf2eModel/Pf2eDbContextModel.cs
+++ b/Pf2eModel/Pf2eDbContextModel.cs
@@ -159,7 +159,10 @@ public partial class Pf2eDbContext
modelBuilder.Entity(entity => { });
- modelBuilder.Entity(entity => { });
+ modelBuilder.Entity(entity =>
+ {
+ BindLocaleString(entity, t => t.Name);
+ });
}
private void DefineStructure(ModelBuilder modelBuilder)
@@ -331,6 +334,28 @@ public partial class Pf2eDbContext
.WithMany(g => g.Subclasses)
.HasForeignKey(s => s.GroupId)
.OnDelete(DeleteBehavior.Cascade);
+
+ entity
+ .HasMany(e => e.Entities)
+ .WithMany()
+ .UsingEntity(
+ l => l.HasOne().WithMany().HasForeignKey(se => se.EntityId),
+ r => r.HasOne().WithMany().HasForeignKey(se => se.SubclassId)
+ );
+
+ entity
+ .HasMany(e => e.Trainings)
+ .WithOne(t => t.Subclass)
+ .HasForeignKey(t => t.SubclassId)
+ .OnDelete(DeleteBehavior.Cascade);
+ });
+ modelBuilder.Entity(entity =>
+ {
+ entity
+ .HasOne(d => d.Subclass)
+ .WithMany(p => p.Trainings)
+ .HasForeignKey(d => d.SubclassId)
+ .OnDelete(DeleteBehavior.Cascade);
});
// Condition
@@ -413,11 +438,10 @@ public partial class Pf2eDbContext
BindEntity(entity);
entity
- .HasOne(e => e.SpellArea)
+ .HasMany(e => e.SpellAreas)
.WithOne(e => e.Spell)
- .HasForeignKey(e => e.SpellId)
- .OnDelete(DeleteBehavior.Cascade)
- .IsRequired(false);
+ .HasForeignKey(e => e.SpellId)
+ .OnDelete(DeleteBehavior.Cascade);
entity
.HasOne(e => e.SpellRitual)