diff --git a/Server/DB/Documents/Account.cs b/Server/DB/Documents/Account.cs
index 20c8bc0..80ede30 100644
--- a/Server/DB/Documents/Account.cs
+++ b/Server/DB/Documents/Account.cs
@@ -20,7 +20,10 @@ public class Account
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public Guid Id { get; set; }
- [Column(TypeName = "varchar(20)")] public string Username { get; set; }
+ [Column(TypeName = "varchar(20)")]
+ [MaxLength(20)]
+ public string Username { get; set; }
+
[Column(TypeName = "bytea")] public byte[] Password { get; set; }
[EmailAddress] public string Email { get; set; }
diff --git a/Server/DB/Documents/Character.cs b/Server/DB/Documents/Character.cs
index c286fff..16e18e6 100644
--- a/Server/DB/Documents/Character.cs
+++ b/Server/DB/Documents/Character.cs
@@ -1,10 +1,12 @@
using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;
+using Microsoft.EntityFrameworkCore;
using Wonderking.Game.Data.Character;
using Wonderking.Packets.Outgoing.Data;
namespace Server.DB.Documents;
+[Index(nameof(Name), IsUnique = true), Index(nameof(Id), IsUnique = true)]
public class Character
{
public virtual Account Account { get; set; }
@@ -14,7 +16,11 @@ public class Character
public Guid Id { get; set; }
public ushort MapId { get; set; }
+
+ [Column(TypeName = "varchar(20)")]
+ [MaxLength(20)]
public string Name { get; set; }
+
public short LastXCoordinate { get; set; }
public short LastYCoordinate { get; set; }
public PvPLevel PvPLevel { get; set; }
diff --git a/Server/DB/Documents/GuildMember.cs b/Server/DB/Documents/GuildMember.cs
index 557aa2d..07e0edd 100644
--- a/Server/DB/Documents/GuildMember.cs
+++ b/Server/DB/Documents/GuildMember.cs
@@ -9,7 +9,7 @@ public class GuildMember
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public Guid Id { get; set; }
- public Character Character { get; set; }
- public Guild Guild { get; set; }
+ public virtual Character Character { get; set; }
+ public virtual Guild Guild { get; set; }
public GuildRank Rank { get; set; }
}
diff --git a/Server/DB/Documents/InventoryItem.cs b/Server/DB/Documents/InventoryItem.cs
index 08f5078..57754f0 100644
--- a/Server/DB/Documents/InventoryItem.cs
+++ b/Server/DB/Documents/InventoryItem.cs
@@ -3,7 +3,7 @@ namespace Server.DB.Documents;
public class InventoryItem
{
public Guid CharacterId { get; set; }
- public Character Character { get; set; }
+ public virtual Character Character { get; set; }
public Guid Id { get; set; }
public ushort ItemId { get; set; }
public ushort Count { get; set; }
diff --git a/Server/DB/Migrations/20231116110504_DBPoolingAndLazyLoadingSupport.Designer.cs b/Server/DB/Migrations/20231116110504_DBPoolingAndLazyLoadingSupport.Designer.cs
new file mode 100644
index 0000000..932bf0b
--- /dev/null
+++ b/Server/DB/Migrations/20231116110504_DBPoolingAndLazyLoadingSupport.Designer.cs
@@ -0,0 +1,333 @@
+//
+using System;
+using Microsoft.EntityFrameworkCore;
+using Microsoft.EntityFrameworkCore.Infrastructure;
+using Microsoft.EntityFrameworkCore.Migrations;
+using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
+using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata;
+using Server.DB;
+
+#nullable disable
+
+namespace Server.DB.Migrations
+{
+ [DbContext(typeof(WonderkingContext))]
+ [Migration("20231116110504_DBPoolingAndLazyLoadingSupport")]
+ partial class DBPoolingAndLazyLoadingSupport
+ {
+ ///
+ protected override void BuildTargetModel(ModelBuilder modelBuilder)
+ {
+#pragma warning disable 612, 618
+ modelBuilder
+ .HasAnnotation("ProductVersion", "8.0.0")
+ .HasAnnotation("Proxies:ChangeTracking", false)
+ .HasAnnotation("Proxies:CheckEquality", false)
+ .HasAnnotation("Proxies:LazyLoading", true)
+ .HasAnnotation("Relational:MaxIdentifierLength", 63);
+
+ NpgsqlModelBuilderExtensions.UseIdentityByDefaultColumns(modelBuilder);
+
+ modelBuilder.Entity("Server.DB.Documents.Account", b =>
+ {
+ b.Property("Id")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("uuid");
+
+ b.Property("Email")
+ .HasColumnType("text");
+
+ b.Property("Password")
+ .HasColumnType("bytea");
+
+ b.Property("PermissionLevel")
+ .HasColumnType("smallint");
+
+ b.Property("Salt")
+ .HasColumnType("bytea");
+
+ b.Property("Username")
+ .HasMaxLength(20)
+ .HasColumnType("varchar(20)");
+
+ b.HasKey("Id");
+
+ b.HasIndex("Id")
+ .IsUnique();
+
+ b.HasIndex("Username")
+ .IsUnique();
+
+ b.ToTable("Accounts");
+ });
+
+ modelBuilder.Entity("Server.DB.Documents.Character", b =>
+ {
+ b.Property("Id")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("uuid");
+
+ b.Property("AccountId")
+ .HasColumnType("uuid");
+
+ b.Property("Experience")
+ .HasColumnType("bigint");
+
+ b.Property("Gender")
+ .HasColumnType("smallint");
+
+ b.Property("GuildId")
+ .HasColumnType("uuid");
+
+ b.Property("Health")
+ .HasColumnType("integer");
+
+ b.Property("LastXCoordinate")
+ .HasColumnType("smallint");
+
+ b.Property("LastYCoordinate")
+ .HasColumnType("smallint");
+
+ b.Property("Level")
+ .HasColumnType("smallint");
+
+ b.Property("Mana")
+ .HasColumnType("integer");
+
+ b.Property("MapId")
+ .HasColumnType("integer");
+
+ b.Property("Name")
+ .HasMaxLength(20)
+ .HasColumnType("varchar(20)");
+
+ b.Property("PvPLevel")
+ .HasColumnType("smallint");
+
+ b.HasKey("Id");
+
+ b.HasIndex("AccountId");
+
+ b.HasIndex("GuildId");
+
+ b.HasIndex("Id")
+ .IsUnique();
+
+ b.HasIndex("Name")
+ .IsUnique();
+
+ b.ToTable("Characters");
+ });
+
+ modelBuilder.Entity("Server.DB.Documents.Guild", b =>
+ {
+ b.Property("Id")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("uuid");
+
+ b.Property("Name")
+ .HasColumnType("text");
+
+ b.Property("Notice")
+ .HasColumnType("text");
+
+ b.HasKey("Id");
+
+ b.ToTable("Guild");
+ });
+
+ modelBuilder.Entity("Server.DB.Documents.GuildMember", b =>
+ {
+ b.Property("Id")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("uuid");
+
+ b.Property("CharacterId")
+ .HasColumnType("uuid");
+
+ b.Property("GuildId")
+ .HasColumnType("uuid");
+
+ b.Property("Rank")
+ .HasColumnType("smallint");
+
+ b.HasKey("Id");
+
+ b.HasIndex("CharacterId");
+
+ b.HasIndex("GuildId");
+
+ b.ToTable("GuildMember");
+ });
+
+ modelBuilder.Entity("Server.DB.Documents.InventoryItem", b =>
+ {
+ b.Property("Id")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("uuid");
+
+ b.Property("AddOption")
+ .HasColumnType("smallint");
+
+ b.Property("AddOption2")
+ .HasColumnType("smallint");
+
+ b.Property("AddOption3")
+ .HasColumnType("smallint");
+
+ b.Property("CharacterId")
+ .HasColumnType("uuid");
+
+ b.Property("Count")
+ .HasColumnType("integer");
+
+ b.Property("InventoryTab")
+ .HasColumnType("smallint");
+
+ b.Property("ItemId")
+ .HasColumnType("integer");
+
+ b.Property("Level")
+ .HasColumnType("smallint");
+
+ b.Property("Option")
+ .HasColumnType("smallint");
+
+ b.Property("Option2")
+ .HasColumnType("smallint");
+
+ b.Property("Option3")
+ .HasColumnType("smallint");
+
+ b.Property("Rarity")
+ .HasColumnType("smallint");
+
+ b.Property("Slot")
+ .HasColumnType("smallint");
+
+ b.HasKey("Id");
+
+ b.HasIndex("CharacterId");
+
+ b.ToTable("InventoryItem");
+ });
+
+ modelBuilder.Entity("Server.DB.Documents.Character", b =>
+ {
+ b.HasOne("Server.DB.Documents.Account", "Account")
+ .WithMany("Characters")
+ .HasForeignKey("AccountId");
+
+ b.HasOne("Server.DB.Documents.Guild", "Guild")
+ .WithMany()
+ .HasForeignKey("GuildId");
+
+ b.OwnsOne("Wonderking.Packets.Outgoing.Data.BaseStats", "BaseStats", b1 =>
+ {
+ b1.Property("CharacterId")
+ .HasColumnType("uuid");
+
+ b1.Property("Dexterity")
+ .HasColumnType("smallint");
+
+ b1.Property("Intelligence")
+ .HasColumnType("smallint");
+
+ b1.Property("Luck")
+ .HasColumnType("smallint");
+
+ b1.Property("Strength")
+ .HasColumnType("smallint");
+
+ b1.Property("Vitality")
+ .HasColumnType("smallint");
+
+ b1.Property("Wisdom")
+ .HasColumnType("smallint");
+
+ b1.HasKey("CharacterId");
+
+ b1.ToTable("Characters");
+
+ b1.WithOwner()
+ .HasForeignKey("CharacterId");
+ });
+
+ b.OwnsOne("Wonderking.Packets.Outgoing.Data.JobData", "JobData", b1 =>
+ {
+ b1.Property("CharacterId")
+ .HasColumnType("uuid");
+
+ b1.Property("FirstJob")
+ .HasColumnType("smallint");
+
+ b1.Property("FourthJob")
+ .HasColumnType("smallint");
+
+ b1.Property("SecondJob")
+ .HasColumnType("smallint");
+
+ b1.Property("ThirdJob")
+ .HasColumnType("smallint");
+
+ b1.HasKey("CharacterId");
+
+ b1.ToTable("Characters");
+
+ b1.WithOwner()
+ .HasForeignKey("CharacterId");
+ });
+
+ b.Navigation("Account");
+
+ b.Navigation("BaseStats");
+
+ b.Navigation("Guild");
+
+ b.Navigation("JobData");
+ });
+
+ modelBuilder.Entity("Server.DB.Documents.GuildMember", b =>
+ {
+ b.HasOne("Server.DB.Documents.Character", "Character")
+ .WithMany()
+ .HasForeignKey("CharacterId");
+
+ b.HasOne("Server.DB.Documents.Guild", "Guild")
+ .WithMany("GuildMembers")
+ .HasForeignKey("GuildId");
+
+ b.Navigation("Character");
+
+ b.Navigation("Guild");
+ });
+
+ modelBuilder.Entity("Server.DB.Documents.InventoryItem", b =>
+ {
+ b.HasOne("Server.DB.Documents.Character", "Character")
+ .WithMany("InventoryItems")
+ .HasForeignKey("CharacterId")
+ .OnDelete(DeleteBehavior.Cascade)
+ .IsRequired();
+
+ b.Navigation("Character");
+ });
+
+ modelBuilder.Entity("Server.DB.Documents.Account", b =>
+ {
+ b.Navigation("Characters");
+ });
+
+ modelBuilder.Entity("Server.DB.Documents.Character", b =>
+ {
+ b.Navigation("InventoryItems");
+ });
+
+ modelBuilder.Entity("Server.DB.Documents.Guild", b =>
+ {
+ b.Navigation("GuildMembers");
+ });
+#pragma warning restore 612, 618
+ }
+ }
+}
diff --git a/Server/DB/Migrations/20231116110504_DBPoolingAndLazyLoadingSupport.cs b/Server/DB/Migrations/20231116110504_DBPoolingAndLazyLoadingSupport.cs
new file mode 100644
index 0000000..9b9cb8c
--- /dev/null
+++ b/Server/DB/Migrations/20231116110504_DBPoolingAndLazyLoadingSupport.cs
@@ -0,0 +1,57 @@
+using Microsoft.EntityFrameworkCore.Migrations;
+
+#nullable disable
+
+namespace Server.DB.Migrations;
+
+///
+public partial class DBPoolingAndLazyLoadingSupport : Migration
+{
+ ///
+ protected override void Up(MigrationBuilder migrationBuilder)
+ {
+ migrationBuilder.AlterColumn(
+ name: "Name",
+ table: "Characters",
+ type: "varchar(20)",
+ maxLength: 20,
+ nullable: true,
+ oldClrType: typeof(string),
+ oldType: "text",
+ oldNullable: true);
+
+ migrationBuilder.CreateIndex(
+ name: "IX_Characters_Id",
+ table: "Characters",
+ column: "Id",
+ unique: true);
+
+ migrationBuilder.CreateIndex(
+ name: "IX_Characters_Name",
+ table: "Characters",
+ column: "Name",
+ unique: true);
+ }
+
+ ///
+ protected override void Down(MigrationBuilder migrationBuilder)
+ {
+ migrationBuilder.DropIndex(
+ name: "IX_Characters_Id",
+ table: "Characters");
+
+ migrationBuilder.DropIndex(
+ name: "IX_Characters_Name",
+ table: "Characters");
+
+ migrationBuilder.AlterColumn(
+ name: "Name",
+ table: "Characters",
+ type: "text",
+ nullable: true,
+ oldClrType: typeof(string),
+ oldType: "varchar(20)",
+ oldMaxLength: 20,
+ oldNullable: true);
+ }
+}
diff --git a/Server/DB/Migrations/WonderkingContextModelSnapshot.cs b/Server/DB/Migrations/WonderkingContextModelSnapshot.cs
index 28aea68..8e5308f 100644
--- a/Server/DB/Migrations/WonderkingContextModelSnapshot.cs
+++ b/Server/DB/Migrations/WonderkingContextModelSnapshot.cs
@@ -18,6 +18,9 @@ namespace Server.DB.Migrations
#pragma warning disable 612, 618
modelBuilder
.HasAnnotation("ProductVersion", "8.0.0")
+ .HasAnnotation("Proxies:ChangeTracking", false)
+ .HasAnnotation("Proxies:CheckEquality", false)
+ .HasAnnotation("Proxies:LazyLoading", true)
.HasAnnotation("Relational:MaxIdentifierLength", 63);
NpgsqlModelBuilderExtensions.UseIdentityByDefaultColumns(modelBuilder);
@@ -41,6 +44,7 @@ namespace Server.DB.Migrations
.HasColumnType("bytea");
b.Property("Username")
+ .HasMaxLength(20)
.HasColumnType("varchar(20)");
b.HasKey("Id");
@@ -91,7 +95,8 @@ namespace Server.DB.Migrations
.HasColumnType("integer");
b.Property("Name")
- .HasColumnType("text");
+ .HasMaxLength(20)
+ .HasColumnType("varchar(20)");
b.Property("PvPLevel")
.HasColumnType("smallint");
@@ -102,6 +107,12 @@ namespace Server.DB.Migrations
b.HasIndex("GuildId");
+ b.HasIndex("Id")
+ .IsUnique();
+
+ b.HasIndex("Name")
+ .IsUnique();
+
b.ToTable("Characters");
});
diff --git a/Server/DB/WonderkingContext.cs b/Server/DB/WonderkingContext.cs
index 8ec7cf6..8251da3 100644
--- a/Server/DB/WonderkingContext.cs
+++ b/Server/DB/WonderkingContext.cs
@@ -1,27 +1,16 @@
+using JetBrains.Annotations;
+
namespace Server.DB;
using Documents;
using Microsoft.EntityFrameworkCore;
-using Microsoft.Extensions.Configuration;
-using Microsoft.Extensions.Logging;
public class WonderkingContext : DbContext
{
- private readonly IConfiguration _configuration;
- private readonly ILoggerFactory _loggerFactory;
-
- public WonderkingContext(ILoggerFactory loggerFactory, IConfiguration configuration)
+ public WonderkingContext([NotNull] DbContextOptions options) : base(options)
{
- this._loggerFactory = loggerFactory;
- this._configuration = configuration;
}
public DbSet Accounts { get; set; }
public DbSet Characters { get; set; }
-
- protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder) =>
- optionsBuilder
- .UseNpgsql(
- $"Host={this._configuration["DB:Host"]};Username={this._configuration["DB:Username"]};Password={this._configuration["DB:Password"]};Database={this._configuration["DB:Database"]};Port={this._configuration["DB:Port"]}")
- .EnableSensitiveDataLogging().UseLoggerFactory(this._loggerFactory);
}
diff --git a/Server/Program.cs b/Server/Program.cs
index a092fe9..3a3659d 100644
--- a/Server/Program.cs
+++ b/Server/Program.cs
@@ -17,10 +17,21 @@ builder.Configuration.AddJsonFile("settings.json", true, true)
.AddJsonFile($"settings.{builder.Environment.EnvironmentName}.json", true)
.AddEnvironmentVariables().Build();
builder.Services.AddLogging();
-builder.Logging.AddFile("Logs/Server-{Date}.log", LogLevel.Trace);
-builder.Logging.AddFile("Logs/Server-{Date}.json.log", LogLevel.Trace, isJson: true);
+var loggerFactory = LoggerFactory.Create(loggingBuilder =>
+{
+ loggingBuilder.AddFile("Logs/Server-{Date}.log", LogLevel.Trace);
+ loggingBuilder.AddFile("Logs/Server-{Date}.json.log", LogLevel.Trace, isJson: true);
+ loggingBuilder.AddConsole();
+});
builder.Services.AddEntityFrameworkNpgsql();
-builder.Services.AddDbContext();
+builder.Services.AddDbContextPool(o =>
+{
+ using var configuration = builder.Configuration;
+ o.UseNpgsql(
+ $"Host={configuration["DB:Host"]};Username={configuration["DB:Username"]};Password={configuration["DB:Password"]};Database={configuration["DB:Database"]};Port={configuration["DB:Port"]}")
+ .EnableSensitiveDataLogging().UseLazyLoadingProxies().UseLoggerFactory(loggerFactory);
+});
+builder.Services.AddSingleton(loggerFactory);
builder.Services.AddSingleton();
builder.Services.AddSingleton();
builder.Services.AddHostedService();
diff --git a/Server/Server.csproj b/Server/Server.csproj
index 8342b6d..5745021 100644
--- a/Server/Server.csproj
+++ b/Server/Server.csproj
@@ -66,6 +66,7 @@
+
all
runtime; build; native; contentfiles; analyzers; buildtransitive