diff --git a/docs/02-Database.md b/docs/02-Database.md
index 87fef7c58..e7c5ede61 100644
--- a/docs/02-Database.md
+++ b/docs/02-Database.md
@@ -1,28 +1,74 @@
-### To change Database Provider
-
-1. Update provider and connection string in the `appsettings.json`:
+## To change Database Provider
+Update provider and connection string in the `appsettings.json`:
+#### SQLite
+``` json
+"Blogifier": {
+ "DbProvider": "Sqlite",
+ "ConnString": "Data Source=App_Data/blogifier.db",
+ ...
+}
```
+It is recommended to put the database file under the App_Data folder. The logs and local pictures in the project will be stored in this path for persistence.
+
+#### SqlServer
+``` json
"Blogifier": {
- "DbProvider": "SQLite",
- "ConnString": "Data Source=Blog.db",
+ "DbProvider": "SqlServer",
+ "ConnString": "Data Source=mssql; User Id=sa; Password=Password; Initial Catalog=blogifier;TrustServerCertificate=True",
...
}
```
-Valid providers: `SQLite`, `SqlServer`, `Postgres`, `MySql` (you'll need to supply valid connection string)
+In the latest version of sql server connection, SqlClient will perform a secure connection by default, and you need to add a server certificate to the system. The example adds TrustServerCertificate=True to ignore this requirement. You can also delete this ignore and enable a secure connection.
-2. Remove `Blogifier/Data/Migrations` folder with existing migrations
-3. In the Visual Studio, open `Package Manager Console`, set `Blogifier`
-as Default project and run these commands:
+#### MySql
+``` json
+"Blogifier": {
+ "DbProvider": "MySql",
+ "ConnString": "server=mysql;user=root;password=password;database=blogifier",
+ ...
+}
+```
+#### Postgres
+``` json
+"Blogifier": {
+ "DbProvider": "Postgres",
+ "ConnString": "Host=postgres;Username=postgres;Password=password;Database=blogifier;",
+ ...
+}
```
-Add-Migration Init -o Data\Migrations
-Update-Database
+In the above example, ConnString requires you to fill in the correct database host address username and password to connect normally
+
+
+## When a change to an entity field requires a database migration
+
+The database migration is stored in the src/Blogifier/Data/Migrations directory. The current project is still under development. When there is a modification, this directory may be deleted for quick migration. After the project is officially released, it is no longer recommended to delete the updated database migrate.
+
+The following is the way to generate a new migration or delete the previous migration command. Before executing the command, please configure the corresponding DbProvider and ConnString in appsettings.json and then execute the corresponding migration command
+``` shell
+# Revert Migration Tool
+dotnet tool restore
+
+# Jump to project directory
+cd src/Blogifier
+
+# Sqlite
+dotnet ef migrations add Init --context SqliteDbContext --output-dir Data/Migrations/Sqlite
+dotnet ef migrations remove --context SqliteDbContext
+
+# SqlServer
+dotnet ef migrations add Init --context SqlServerDbContext --output-dir Data/Migrations/SqlServer
+dotnet ef migrations remove --context SqlServerDbContext
+
+# MySql
+dotnet ef migrations add Init --context MySqlDbContext --output-dir Data/Migrations/MySql
+dotnet ef migrations remove --context MySqlDbContext
-# cil
-dotnet ef migrations Init -o Data\Migrations
-dotnet ef migrations remove
+# Postgres
+dotnet ef migrations add Init --context PostgresDbContext --output-dir Data/Migrations/Postgres
+dotnet ef migrations remove --context MySqlDbContext
```
-First command should re-generate provider specific code migrations and second will
-execute them and create database specified in the connection string.
+### Warn
+Do not add or delete database migration at will. After the application generates data, random migration may cause data loss. This project will automatically apply the migration when it starts.
diff --git a/src/Blogifier.Admin/Pages/Blogs/EditorView.razor b/src/Blogifier.Admin/Pages/Blogs/EditorView.razor
index 861dfe9b8..893a547f6 100644
--- a/src/Blogifier.Admin/Pages/Blogs/EditorView.razor
+++ b/src/Blogifier.Admin/Pages/Blogs/EditorView.razor
@@ -31,7 +31,7 @@
@_localizer["delete"]
-
+
diff --git a/src/Blogifier/Data/AppDbContext.cs b/src/Blogifier/Data/AppDbContext.cs
index 5dbd45791..e571ab06b 100644
--- a/src/Blogifier/Data/AppDbContext.cs
+++ b/src/Blogifier/Data/AppDbContext.cs
@@ -11,21 +11,18 @@ namespace Blogifier.Data;
public class AppDbContext : IdentityUserContext
{
- protected readonly DbContextOptions _options;
-
- public AppDbContext(DbContextOptions options) : base(options)
+ public AppDbContext(DbContextOptions options) : base(options)
{
- _options = options;
- }
+ }
public DbSet Options { get; set; } = default!;
public DbSet Posts { get; set; } = default!;
- public DbSet Storages { get; set; } = default!;
- public DbSet StorageReferences { get; set; } = default!;
public DbSet Categories { get; set; } = default!;
public DbSet PostCategories { get; set; } = default!;
- public DbSet Subscribers { get; set; } = default!;
public DbSet Newsletters { get; set; } = default!;
+ public DbSet Subscribers { get; set; } = default!;
+ public DbSet Storages { get; set; } = default!;
+ //public DbSet StorageReferences { get; set; } = default!;
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
@@ -36,6 +33,7 @@ protected override void OnModelCreating(ModelBuilder modelBuilder)
e.ToTable("User");
e.Property(p => p.Id).HasMaxLength(128);
e.Property(p => p.CreatedAt).HasColumnOrder(0);
+ e.Property(p => p.UpdatedAt).HasColumnOrder(1);
e.Property(p => p.PasswordHash).HasMaxLength(256);
e.Property(p => p.SecurityStamp).HasMaxLength(32);
e.Property(p => p.ConcurrencyStamp).HasMaxLength(64);
@@ -65,27 +63,22 @@ protected override void OnModelCreating(ModelBuilder modelBuilder)
e.HasIndex(b => b.Key).IsUnique();
});
- modelBuilder.Entity(e =>
+ modelBuilder.Entity(e =>
{
- e.ToTable("StorageReferences");
- e.HasKey(t => new { t.StorageId, t.EntityId, t.Type });
+ e.ToTable("Post");
+ e.HasIndex(b => b.Slug).IsUnique();
});
+ //modelBuilder.Entity(e =>
+ //{
+ // e.ToTable("StorageReferences");
+ // e.HasKey(t => new { t.StorageId, t.EntityId });
+ //});
+
modelBuilder.Entity(e =>
{
e.ToTable("PostCategories");
e.HasKey(t => new { t.PostId, t.CategoryId });
});
-
- modelBuilder.Entity(e =>
- {
- e.ToTable("Post");
- e.HasIndex(b => b.Slug).IsUnique();
-
- e.HasMany(e => e.StorageReferences)
- .WithOne(e => e.Post)
- .HasForeignKey(e => e.EntityId)
- .IsRequired();
- });
}
}
diff --git a/src/Blogifier/Data/Migrations/20230606095435_Storage.cs b/src/Blogifier/Data/Migrations/20230606095435_Storage.cs
deleted file mode 100644
index 8b561c8cc..000000000
--- a/src/Blogifier/Data/Migrations/20230606095435_Storage.cs
+++ /dev/null
@@ -1,241 +0,0 @@
-using Microsoft.EntityFrameworkCore.Metadata;
-using Microsoft.EntityFrameworkCore.Migrations;
-using System;
-
-#nullable disable
-
-namespace Blogifier.Data.Migrations
-{
- ///
- public partial class Storage : Migration
- {
- ///
- protected override void Up(MigrationBuilder migrationBuilder)
- {
- migrationBuilder.DropForeignKey(
- name: "FK_Newsletters_Posts_PostId",
- table: "Newsletters");
-
- migrationBuilder.DropForeignKey(
- name: "FK_PostCategories_Posts_PostId",
- table: "PostCategories");
-
- migrationBuilder.DropForeignKey(
- name: "FK_Posts_User_UserId",
- table: "Posts");
-
- migrationBuilder.DropPrimaryKey(
- name: "PK_Posts",
- table: "Posts");
-
- migrationBuilder.DropColumn(
- name: "AuthorId",
- table: "Storages");
-
- migrationBuilder.RenameTable(
- name: "Posts",
- newName: "Post");
-
- migrationBuilder.RenameColumn(
- name: "StorageType",
- table: "Storages",
- newName: "Type");
-
- migrationBuilder.RenameIndex(
- name: "IX_Posts_UserId",
- table: "Post",
- newName: "IX_Post_UserId");
-
- migrationBuilder.AddColumn(
- name: "Slug",
- table: "Storages",
- type: "varchar(2048)",
- maxLength: 2048,
- nullable: false,
- defaultValue: "")
- .Annotation("MySql:CharSet", "utf8mb4");
-
- migrationBuilder.AddColumn(
- name: "UserId",
- table: "Storages",
- type: "varchar(128)",
- nullable: false,
- defaultValue: "")
- .Annotation("MySql:CharSet", "utf8mb4");
-
- migrationBuilder.AddPrimaryKey(
- name: "PK_Post",
- table: "Post",
- column: "Id");
-
- migrationBuilder.CreateTable(
- name: "StorageReferences",
- columns: table => new
- {
- StorageId = table.Column(type: "int", nullable: false),
- EntityId = table.Column(type: "int", nullable: false),
- Type = table.Column(type: "int", nullable: false),
- CreatedAt = table.Column(type: "datetime(6)", nullable: false)
- .Annotation("MySql:ValueGenerationStrategy", MySqlValueGenerationStrategy.IdentityColumn)
- },
- constraints: table =>
- {
- table.PrimaryKey("PK_StorageReferences", x => new { x.StorageId, x.EntityId, x.Type });
- table.ForeignKey(
- name: "FK_StorageReferences_Post_EntityId",
- column: x => x.EntityId,
- principalTable: "Post",
- principalColumn: "Id",
- onDelete: ReferentialAction.Cascade);
- table.ForeignKey(
- name: "FK_StorageReferences_Storages_StorageId",
- column: x => x.StorageId,
- principalTable: "Storages",
- principalColumn: "Id",
- onDelete: ReferentialAction.Cascade);
- })
- .Annotation("MySql:CharSet", "utf8mb4");
-
- migrationBuilder.CreateIndex(
- name: "IX_Storages_UserId",
- table: "Storages",
- column: "UserId");
-
- migrationBuilder.CreateIndex(
- name: "IX_Post_Slug",
- table: "Post",
- column: "Slug",
- unique: true);
-
- migrationBuilder.CreateIndex(
- name: "IX_StorageReferences_EntityId",
- table: "StorageReferences",
- column: "EntityId");
-
- migrationBuilder.AddForeignKey(
- name: "FK_Newsletters_Post_PostId",
- table: "Newsletters",
- column: "PostId",
- principalTable: "Post",
- principalColumn: "Id",
- onDelete: ReferentialAction.Cascade);
-
- migrationBuilder.AddForeignKey(
- name: "FK_Post_User_UserId",
- table: "Post",
- column: "UserId",
- principalTable: "User",
- principalColumn: "Id",
- onDelete: ReferentialAction.Cascade);
-
- migrationBuilder.AddForeignKey(
- name: "FK_PostCategories_Post_PostId",
- table: "PostCategories",
- column: "PostId",
- principalTable: "Post",
- principalColumn: "Id",
- onDelete: ReferentialAction.Cascade);
-
- migrationBuilder.AddForeignKey(
- name: "FK_Storages_User_UserId",
- table: "Storages",
- column: "UserId",
- principalTable: "User",
- principalColumn: "Id",
- onDelete: ReferentialAction.Cascade);
- }
-
- ///
- protected override void Down(MigrationBuilder migrationBuilder)
- {
- migrationBuilder.DropForeignKey(
- name: "FK_Newsletters_Post_PostId",
- table: "Newsletters");
-
- migrationBuilder.DropForeignKey(
- name: "FK_Post_User_UserId",
- table: "Post");
-
- migrationBuilder.DropForeignKey(
- name: "FK_PostCategories_Post_PostId",
- table: "PostCategories");
-
- migrationBuilder.DropForeignKey(
- name: "FK_Storages_User_UserId",
- table: "Storages");
-
- migrationBuilder.DropTable(
- name: "StorageReferences");
-
- migrationBuilder.DropIndex(
- name: "IX_Storages_UserId",
- table: "Storages");
-
- migrationBuilder.DropPrimaryKey(
- name: "PK_Post",
- table: "Post");
-
- migrationBuilder.DropIndex(
- name: "IX_Post_Slug",
- table: "Post");
-
- migrationBuilder.DropColumn(
- name: "Slug",
- table: "Storages");
-
- migrationBuilder.DropColumn(
- name: "UserId",
- table: "Storages");
-
- migrationBuilder.RenameTable(
- name: "Post",
- newName: "Posts");
-
- migrationBuilder.RenameColumn(
- name: "Type",
- table: "Storages",
- newName: "StorageType");
-
- migrationBuilder.RenameIndex(
- name: "IX_Post_UserId",
- table: "Posts",
- newName: "IX_Posts_UserId");
-
- migrationBuilder.AddColumn(
- name: "AuthorId",
- table: "Storages",
- type: "int",
- nullable: false,
- defaultValue: 0);
-
- migrationBuilder.AddPrimaryKey(
- name: "PK_Posts",
- table: "Posts",
- column: "Id");
-
- migrationBuilder.AddForeignKey(
- name: "FK_Newsletters_Posts_PostId",
- table: "Newsletters",
- column: "PostId",
- principalTable: "Posts",
- principalColumn: "Id",
- onDelete: ReferentialAction.Cascade);
-
- migrationBuilder.AddForeignKey(
- name: "FK_PostCategories_Posts_PostId",
- table: "PostCategories",
- column: "PostId",
- principalTable: "Posts",
- principalColumn: "Id",
- onDelete: ReferentialAction.Cascade);
-
- migrationBuilder.AddForeignKey(
- name: "FK_Posts_User_UserId",
- table: "Posts",
- column: "UserId",
- principalTable: "User",
- principalColumn: "Id",
- onDelete: ReferentialAction.Cascade);
- }
- }
-}
diff --git a/src/Blogifier/Data/Migrations/20230606095435_Storage.Designer.cs b/src/Blogifier/Data/Migrations/MySql/20230608093107_Init.Designer.cs
similarity index 91%
rename from src/Blogifier/Data/Migrations/20230606095435_Storage.Designer.cs
rename to src/Blogifier/Data/Migrations/MySql/20230608093107_Init.Designer.cs
index 26459d812..2bd7fc94b 100644
--- a/src/Blogifier/Data/Migrations/20230606095435_Storage.Designer.cs
+++ b/src/Blogifier/Data/Migrations/MySql/20230608093107_Init.Designer.cs
@@ -8,11 +8,11 @@
#nullable disable
-namespace Blogifier.Data.Migrations
+namespace Blogifier.Data.Migrations.MySql
{
- [DbContext(typeof(AppDbContext))]
- [Migration("20230606095435_Storage")]
- partial class Storage
+ [DbContext(typeof(MySqlDbContext))]
+ [Migration("20230608093107_Init")]
+ partial class Init
{
///
protected override void BuildTargetModel(ModelBuilder modelBuilder)
@@ -103,6 +103,11 @@ protected override void BuildTargetModel(ModelBuilder modelBuilder)
b.Property("Type")
.HasColumnType("int");
+ b.Property("UpdatedAt")
+ .ValueGeneratedOnAddOrUpdate()
+ .HasColumnType("datetime(6)")
+ .HasColumnOrder(1);
+
b.Property("UserName")
.HasMaxLength(256)
.HasColumnType("varchar(256)");
@@ -369,28 +374,6 @@ protected override void BuildTargetModel(ModelBuilder modelBuilder)
b.ToTable("Storages");
});
- modelBuilder.Entity("Blogifier.Storages.StorageReference", b =>
- {
- b.Property("StorageId")
- .HasColumnType("int");
-
- b.Property("EntityId")
- .HasColumnType("int");
-
- b.Property("Type")
- .HasColumnType("int");
-
- b.Property("CreatedAt")
- .ValueGeneratedOnAdd()
- .HasColumnType("datetime(6)");
-
- b.HasKey("StorageId", "EntityId", "Type");
-
- b.HasIndex("EntityId");
-
- b.ToTable("StorageReferences", (string)null);
- });
-
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserClaim", b =>
{
b.Property("Id")
@@ -511,25 +494,6 @@ protected override void BuildTargetModel(ModelBuilder modelBuilder)
b.Navigation("User");
});
- modelBuilder.Entity("Blogifier.Storages.StorageReference", b =>
- {
- b.HasOne("Blogifier.Shared.Post", "Post")
- .WithMany("StorageReferences")
- .HasForeignKey("EntityId")
- .OnDelete(DeleteBehavior.Cascade)
- .IsRequired();
-
- b.HasOne("Blogifier.Storages.Storage", "Storage")
- .WithMany("StorageReferences")
- .HasForeignKey("StorageId")
- .OnDelete(DeleteBehavior.Cascade)
- .IsRequired();
-
- b.Navigation("Post");
-
- b.Navigation("Storage");
- });
-
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserClaim", b =>
{
b.HasOne("Blogifier.Identity.UserInfo", null)
@@ -565,13 +529,6 @@ protected override void BuildTargetModel(ModelBuilder modelBuilder)
modelBuilder.Entity("Blogifier.Shared.Post", b =>
{
b.Navigation("PostCategories");
-
- b.Navigation("StorageReferences");
- });
-
- modelBuilder.Entity("Blogifier.Storages.Storage", b =>
- {
- b.Navigation("StorageReferences");
});
#pragma warning restore 612, 618
}
diff --git a/src/Blogifier/Data/Migrations/20230602104208_Init.cs b/src/Blogifier/Data/Migrations/MySql/20230608093107_Init.cs
similarity index 91%
rename from src/Blogifier/Data/Migrations/20230602104208_Init.cs
rename to src/Blogifier/Data/Migrations/MySql/20230608093107_Init.cs
index e280ed4da..445fc0467 100644
--- a/src/Blogifier/Data/Migrations/20230602104208_Init.cs
+++ b/src/Blogifier/Data/Migrations/MySql/20230608093107_Init.cs
@@ -1,10 +1,10 @@
-using Microsoft.EntityFrameworkCore.Metadata;
-using Microsoft.EntityFrameworkCore.Migrations;
using System;
+using Microsoft.EntityFrameworkCore.Metadata;
+using Microsoft.EntityFrameworkCore.Migrations;
#nullable disable
-namespace Blogifier.Data.Migrations
+namespace Blogifier.Data.Migrations.MySql
{
///
public partial class Init : Migration
@@ -55,32 +55,6 @@ protected override void Up(MigrationBuilder migrationBuilder)
})
.Annotation("MySql:CharSet", "utf8mb4");
- migrationBuilder.CreateTable(
- name: "Storages",
- columns: table => new
- {
- Id = table.Column(type: "int", nullable: false)
- .Annotation("MySql:ValueGenerationStrategy", MySqlValueGenerationStrategy.IdentityColumn),
- AuthorId = table.Column(type: "int", nullable: false),
- CreatedAt = table.Column(type: "datetime(6)", nullable: false)
- .Annotation("MySql:ValueGenerationStrategy", MySqlValueGenerationStrategy.IdentityColumn),
- IsDeleted = table.Column(type: "tinyint(1)", nullable: false),
- DeletedAt = table.Column(type: "datetime(6)", nullable: true),
- Name = table.Column(type: "varchar(256)", maxLength: 256, nullable: false)
- .Annotation("MySql:CharSet", "utf8mb4"),
- Path = table.Column(type: "varchar(2048)", maxLength: 2048, nullable: false)
- .Annotation("MySql:CharSet", "utf8mb4"),
- Length = table.Column(type: "bigint", nullable: false),
- ContentType = table.Column(type: "varchar(128)", maxLength: 128, nullable: false)
- .Annotation("MySql:CharSet", "utf8mb4"),
- StorageType = table.Column(type: "int", nullable: false)
- },
- constraints: table =>
- {
- table.PrimaryKey("PK_Storages", x => x.Id);
- })
- .Annotation("MySql:CharSet", "utf8mb4");
-
migrationBuilder.CreateTable(
name: "Subscribers",
columns: table => new
@@ -112,6 +86,8 @@ protected override void Up(MigrationBuilder migrationBuilder)
{
CreatedAt = table.Column(type: "datetime(6)", nullable: false)
.Annotation("MySql:ValueGenerationStrategy", MySqlValueGenerationStrategy.IdentityColumn),
+ UpdatedAt = table.Column(type: "datetime(6)", nullable: false)
+ .Annotation("MySql:ValueGenerationStrategy", MySqlValueGenerationStrategy.ComputedColumn),
Id = table.Column(type: "varchar(128)", maxLength: 128, nullable: false)
.Annotation("MySql:CharSet", "utf8mb4"),
NickName = table.Column(type: "varchar(256)", maxLength: 256, nullable: false)
@@ -154,7 +130,7 @@ protected override void Up(MigrationBuilder migrationBuilder)
.Annotation("MySql:CharSet", "utf8mb4");
migrationBuilder.CreateTable(
- name: "Posts",
+ name: "Post",
columns: table => new
{
Id = table.Column(type: "int", nullable: false)
@@ -182,9 +158,44 @@ protected override void Up(MigrationBuilder migrationBuilder)
},
constraints: table =>
{
- table.PrimaryKey("PK_Posts", x => x.Id);
+ table.PrimaryKey("PK_Post", x => x.Id);
+ table.ForeignKey(
+ name: "FK_Post_User_UserId",
+ column: x => x.UserId,
+ principalTable: "User",
+ principalColumn: "Id",
+ onDelete: ReferentialAction.Cascade);
+ })
+ .Annotation("MySql:CharSet", "utf8mb4");
+
+ migrationBuilder.CreateTable(
+ name: "Storages",
+ columns: table => new
+ {
+ Id = table.Column(type: "int", nullable: false)
+ .Annotation("MySql:ValueGenerationStrategy", MySqlValueGenerationStrategy.IdentityColumn),
+ UserId = table.Column(type: "varchar(128)", nullable: false)
+ .Annotation("MySql:CharSet", "utf8mb4"),
+ CreatedAt = table.Column(type: "datetime(6)", nullable: false)
+ .Annotation("MySql:ValueGenerationStrategy", MySqlValueGenerationStrategy.IdentityColumn),
+ IsDeleted = table.Column(type: "tinyint(1)", nullable: false),
+ DeletedAt = table.Column(type: "datetime(6)", nullable: true),
+ Slug = table.Column(type: "varchar(2048)", maxLength: 2048, nullable: false)
+ .Annotation("MySql:CharSet", "utf8mb4"),
+ Name = table.Column(type: "varchar(256)", maxLength: 256, nullable: false)
+ .Annotation("MySql:CharSet", "utf8mb4"),
+ Path = table.Column(type: "varchar(2048)", maxLength: 2048, nullable: false)
+ .Annotation("MySql:CharSet", "utf8mb4"),
+ Length = table.Column(type: "bigint", nullable: false),
+ ContentType = table.Column(type: "varchar(128)", maxLength: 128, nullable: false)
+ .Annotation("MySql:CharSet", "utf8mb4"),
+ Type = table.Column(type: "int", nullable: false)
+ },
+ constraints: table =>
+ {
+ table.PrimaryKey("PK_Storages", x => x.Id);
table.ForeignKey(
- name: "FK_Posts_User_UserId",
+ name: "FK_Storages_User_UserId",
column: x => x.UserId,
principalTable: "User",
principalColumn: "Id",
@@ -284,9 +295,9 @@ protected override void Up(MigrationBuilder migrationBuilder)
{
table.PrimaryKey("PK_Newsletters", x => x.Id);
table.ForeignKey(
- name: "FK_Newsletters_Posts_PostId",
+ name: "FK_Newsletters_Post_PostId",
column: x => x.PostId,
- principalTable: "Posts",
+ principalTable: "Post",
principalColumn: "Id",
onDelete: ReferentialAction.Cascade);
})
@@ -309,9 +320,9 @@ protected override void Up(MigrationBuilder migrationBuilder)
principalColumn: "Id",
onDelete: ReferentialAction.Cascade);
table.ForeignKey(
- name: "FK_PostCategories_Posts_PostId",
+ name: "FK_PostCategories_Post_PostId",
column: x => x.PostId,
- principalTable: "Posts",
+ principalTable: "Post",
principalColumn: "Id",
onDelete: ReferentialAction.Cascade);
})
@@ -328,14 +339,25 @@ protected override void Up(MigrationBuilder migrationBuilder)
column: "Key",
unique: true);
+ migrationBuilder.CreateIndex(
+ name: "IX_Post_Slug",
+ table: "Post",
+ column: "Slug",
+ unique: true);
+
+ migrationBuilder.CreateIndex(
+ name: "IX_Post_UserId",
+ table: "Post",
+ column: "UserId");
+
migrationBuilder.CreateIndex(
name: "IX_PostCategories_CategoryId",
table: "PostCategories",
column: "CategoryId");
migrationBuilder.CreateIndex(
- name: "IX_Posts_UserId",
- table: "Posts",
+ name: "IX_Storages_UserId",
+ table: "Storages",
column: "UserId");
migrationBuilder.CreateIndex(
@@ -391,7 +413,7 @@ protected override void Down(MigrationBuilder migrationBuilder)
name: "Categories");
migrationBuilder.DropTable(
- name: "Posts");
+ name: "Post");
migrationBuilder.DropTable(
name: "User");
diff --git a/src/Blogifier/Data/Migrations/AppDbContextModelSnapshot.cs b/src/Blogifier/Data/Migrations/MySql/MySqlDbContextModelSnapshot.cs
similarity index 91%
rename from src/Blogifier/Data/Migrations/AppDbContextModelSnapshot.cs
rename to src/Blogifier/Data/Migrations/MySql/MySqlDbContextModelSnapshot.cs
index d8aeb9266..68b4308e9 100644
--- a/src/Blogifier/Data/Migrations/AppDbContextModelSnapshot.cs
+++ b/src/Blogifier/Data/Migrations/MySql/MySqlDbContextModelSnapshot.cs
@@ -7,10 +7,10 @@
#nullable disable
-namespace Blogifier.Data.Migrations
+namespace Blogifier.Data.Migrations.MySql
{
- [DbContext(typeof(AppDbContext))]
- partial class AppDbContextModelSnapshot : ModelSnapshot
+ [DbContext(typeof(MySqlDbContext))]
+ partial class MySqlDbContextModelSnapshot : ModelSnapshot
{
protected override void BuildModel(ModelBuilder modelBuilder)
{
@@ -100,6 +100,11 @@ protected override void BuildModel(ModelBuilder modelBuilder)
b.Property("Type")
.HasColumnType("int");
+ b.Property("UpdatedAt")
+ .ValueGeneratedOnAddOrUpdate()
+ .HasColumnType("datetime(6)")
+ .HasColumnOrder(1);
+
b.Property("UserName")
.HasMaxLength(256)
.HasColumnType("varchar(256)");
@@ -366,28 +371,6 @@ protected override void BuildModel(ModelBuilder modelBuilder)
b.ToTable("Storages");
});
- modelBuilder.Entity("Blogifier.Storages.StorageReference", b =>
- {
- b.Property("StorageId")
- .HasColumnType("int");
-
- b.Property("EntityId")
- .HasColumnType("int");
-
- b.Property("Type")
- .HasColumnType("int");
-
- b.Property("CreatedAt")
- .ValueGeneratedOnAdd()
- .HasColumnType("datetime(6)");
-
- b.HasKey("StorageId", "EntityId", "Type");
-
- b.HasIndex("EntityId");
-
- b.ToTable("StorageReferences", (string)null);
- });
-
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserClaim", b =>
{
b.Property("Id")
@@ -508,25 +491,6 @@ protected override void BuildModel(ModelBuilder modelBuilder)
b.Navigation("User");
});
- modelBuilder.Entity("Blogifier.Storages.StorageReference", b =>
- {
- b.HasOne("Blogifier.Shared.Post", "Post")
- .WithMany("StorageReferences")
- .HasForeignKey("EntityId")
- .OnDelete(DeleteBehavior.Cascade)
- .IsRequired();
-
- b.HasOne("Blogifier.Storages.Storage", "Storage")
- .WithMany("StorageReferences")
- .HasForeignKey("StorageId")
- .OnDelete(DeleteBehavior.Cascade)
- .IsRequired();
-
- b.Navigation("Post");
-
- b.Navigation("Storage");
- });
-
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserClaim", b =>
{
b.HasOne("Blogifier.Identity.UserInfo", null)
@@ -562,13 +526,6 @@ protected override void BuildModel(ModelBuilder modelBuilder)
modelBuilder.Entity("Blogifier.Shared.Post", b =>
{
b.Navigation("PostCategories");
-
- b.Navigation("StorageReferences");
- });
-
- modelBuilder.Entity("Blogifier.Storages.Storage", b =>
- {
- b.Navigation("StorageReferences");
});
#pragma warning restore 612, 618
}
diff --git a/src/Blogifier/Data/Migrations/Postgres/20230608094908_Init.Designer.cs b/src/Blogifier/Data/Migrations/Postgres/20230608094908_Init.Designer.cs
new file mode 100644
index 000000000..f3a45afcd
--- /dev/null
+++ b/src/Blogifier/Data/Migrations/Postgres/20230608094908_Init.Designer.cs
@@ -0,0 +1,555 @@
+//
+using System;
+using Blogifier.Data;
+using Microsoft.EntityFrameworkCore;
+using Microsoft.EntityFrameworkCore.Infrastructure;
+using Microsoft.EntityFrameworkCore.Migrations;
+using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
+using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata;
+
+#nullable disable
+
+namespace Blogifier.Data.Migrations.Postgres
+{
+ [DbContext(typeof(PostgresDbContext))]
+ [Migration("20230608094908_Init")]
+ partial class Init
+ {
+ ///
+ protected override void BuildTargetModel(ModelBuilder modelBuilder)
+ {
+#pragma warning disable 612, 618
+ modelBuilder
+ .HasAnnotation("ProductVersion", "7.0.5")
+ .HasAnnotation("Relational:MaxIdentifierLength", 63);
+
+ NpgsqlModelBuilderExtensions.UseIdentityByDefaultColumns(modelBuilder);
+
+ modelBuilder.Entity("Blogifier.Identity.UserInfo", b =>
+ {
+ b.Property("Id")
+ .HasMaxLength(128)
+ .HasColumnType("character varying(128)");
+
+ b.Property("AccessFailedCount")
+ .HasColumnType("integer");
+
+ b.Property("Avatar")
+ .HasMaxLength(1024)
+ .HasColumnType("character varying(1024)");
+
+ b.Property("Bio")
+ .HasMaxLength(2048)
+ .HasColumnType("character varying(2048)");
+
+ b.Property("ConcurrencyStamp")
+ .IsConcurrencyToken()
+ .HasMaxLength(64)
+ .HasColumnType("character varying(64)");
+
+ b.Property("CreatedAt")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("timestamp with time zone")
+ .HasColumnOrder(0)
+ .HasDefaultValueSql("now()");
+
+ b.Property("Email")
+ .HasMaxLength(256)
+ .HasColumnType("character varying(256)");
+
+ b.Property("EmailConfirmed")
+ .HasColumnType("boolean");
+
+ b.Property("Gender")
+ .HasMaxLength(32)
+ .HasColumnType("character varying(32)");
+
+ b.Property("LockoutEnabled")
+ .HasColumnType("boolean");
+
+ b.Property("LockoutEnd")
+ .HasColumnType("timestamp with time zone");
+
+ b.Property("NickName")
+ .IsRequired()
+ .HasMaxLength(256)
+ .HasColumnType("character varying(256)");
+
+ b.Property("NormalizedEmail")
+ .HasMaxLength(256)
+ .HasColumnType("character varying(256)");
+
+ b.Property("NormalizedUserName")
+ .HasMaxLength(256)
+ .HasColumnType("character varying(256)");
+
+ b.Property("PasswordHash")
+ .HasMaxLength(256)
+ .HasColumnType("character varying(256)");
+
+ b.Property("PhoneNumber")
+ .HasMaxLength(32)
+ .HasColumnType("character varying(32)");
+
+ b.Property("PhoneNumberConfirmed")
+ .HasColumnType("boolean");
+
+ b.Property("SecurityStamp")
+ .HasMaxLength(32)
+ .HasColumnType("character varying(32)");
+
+ b.Property("State")
+ .HasColumnType("integer");
+
+ b.Property("TwoFactorEnabled")
+ .HasColumnType("boolean");
+
+ b.Property("Type")
+ .HasColumnType("integer");
+
+ b.Property("UpdatedAt")
+ .HasColumnType("timestamp with time zone")
+ .HasColumnOrder(1);
+
+ b.Property("UserName")
+ .HasMaxLength(256)
+ .HasColumnType("character varying(256)");
+
+ b.HasKey("Id");
+
+ b.HasIndex("NormalizedEmail")
+ .HasDatabaseName("EmailIndex");
+
+ b.HasIndex("NormalizedUserName")
+ .IsUnique()
+ .HasDatabaseName("UserNameIndex");
+
+ b.ToTable("User", (string)null);
+ });
+
+ modelBuilder.Entity("Blogifier.Newsletters.Newsletter", b =>
+ {
+ b.Property("Id")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("integer");
+
+ NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id"));
+
+ b.Property("CreatedAt")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("timestamp with time zone")
+ .HasDefaultValueSql("now()");
+
+ b.Property("PostId")
+ .HasColumnType("integer");
+
+ b.Property("Success")
+ .HasColumnType("boolean");
+
+ b.Property("UpdatedAt")
+ .HasColumnType("timestamp with time zone");
+
+ b.HasKey("Id");
+
+ b.HasIndex("PostId");
+
+ b.ToTable("Newsletters");
+ });
+
+ modelBuilder.Entity("Blogifier.Newsletters.Subscriber", b =>
+ {
+ b.Property("Id")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("integer");
+
+ NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id"));
+
+ b.Property("Country")
+ .HasMaxLength(120)
+ .HasColumnType("character varying(120)");
+
+ b.Property("CreatedAt")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("timestamp with time zone")
+ .HasDefaultValueSql("now()");
+
+ b.Property("Email")
+ .IsRequired()
+ .HasMaxLength(160)
+ .HasColumnType("character varying(160)");
+
+ b.Property("Ip")
+ .HasMaxLength(80)
+ .HasColumnType("character varying(80)");
+
+ b.Property("Region")
+ .HasMaxLength(120)
+ .HasColumnType("character varying(120)");
+
+ b.Property("UpdatedAt")
+ .HasColumnType("timestamp with time zone");
+
+ b.HasKey("Id");
+
+ b.ToTable("Subscribers");
+ });
+
+ modelBuilder.Entity("Blogifier.Options.OptionInfo", b =>
+ {
+ b.Property("Id")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("integer");
+
+ NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id"));
+
+ b.Property("CreatedAt")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("timestamp with time zone")
+ .HasDefaultValueSql("now()");
+
+ b.Property("Key")
+ .IsRequired()
+ .HasMaxLength(256)
+ .HasColumnType("character varying(256)");
+
+ b.Property("UpdatedAt")
+ .HasColumnType("timestamp with time zone");
+
+ b.Property("Value")
+ .IsRequired()
+ .HasColumnType("text");
+
+ b.HasKey("Id");
+
+ b.HasIndex("Key")
+ .IsUnique();
+
+ b.ToTable("Options", (string)null);
+ });
+
+ modelBuilder.Entity("Blogifier.Shared.Category", b =>
+ {
+ b.Property("Id")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("integer");
+
+ NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id"));
+
+ b.Property("Content")
+ .IsRequired()
+ .HasMaxLength(120)
+ .HasColumnType("character varying(120)");
+
+ b.Property("CreatedAt")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("timestamp with time zone")
+ .HasDefaultValueSql("now()");
+
+ b.Property("Description")
+ .HasMaxLength(255)
+ .HasColumnType("character varying(255)");
+
+ b.HasKey("Id");
+
+ b.ToTable("Categories");
+ });
+
+ modelBuilder.Entity("Blogifier.Shared.Post", b =>
+ {
+ b.Property("Id")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("integer");
+
+ NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id"));
+
+ b.Property("Content")
+ .IsRequired()
+ .HasColumnType("text");
+
+ b.Property("Cover")
+ .HasMaxLength(160)
+ .HasColumnType("character varying(160)");
+
+ b.Property("CreatedAt")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("timestamp with time zone")
+ .HasDefaultValueSql("now()");
+
+ b.Property("Description")
+ .IsRequired()
+ .HasMaxLength(450)
+ .HasColumnType("character varying(450)");
+
+ b.Property("PostType")
+ .HasColumnType("integer");
+
+ b.Property("PublishedAt")
+ .HasColumnType("timestamp with time zone");
+
+ b.Property("Slug")
+ .IsRequired()
+ .HasMaxLength(160)
+ .HasColumnType("character varying(160)");
+
+ b.Property("State")
+ .HasColumnType("integer");
+
+ b.Property("Title")
+ .IsRequired()
+ .HasMaxLength(160)
+ .HasColumnType("character varying(160)");
+
+ b.Property("UpdatedAt")
+ .HasColumnType("timestamp with time zone");
+
+ b.Property("UserId")
+ .IsRequired()
+ .HasMaxLength(128)
+ .HasColumnType("character varying(128)");
+
+ b.Property("Views")
+ .HasColumnType("integer");
+
+ b.HasKey("Id");
+
+ b.HasIndex("Slug")
+ .IsUnique();
+
+ b.HasIndex("UserId");
+
+ b.ToTable("Post", (string)null);
+ });
+
+ modelBuilder.Entity("Blogifier.Shared.PostCategory", b =>
+ {
+ b.Property("PostId")
+ .HasColumnType("integer");
+
+ b.Property("CategoryId")
+ .HasColumnType("integer");
+
+ b.HasKey("PostId", "CategoryId");
+
+ b.HasIndex("CategoryId");
+
+ b.ToTable("PostCategories", (string)null);
+ });
+
+ modelBuilder.Entity("Blogifier.Storages.Storage", b =>
+ {
+ b.Property("Id")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("integer");
+
+ NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id"));
+
+ b.Property("ContentType")
+ .IsRequired()
+ .HasMaxLength(128)
+ .HasColumnType("character varying(128)");
+
+ b.Property("CreatedAt")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("timestamp with time zone")
+ .HasDefaultValueSql("now()");
+
+ b.Property("DeletedAt")
+ .HasColumnType("timestamp with time zone");
+
+ b.Property("IsDeleted")
+ .HasColumnType("boolean");
+
+ b.Property("Length")
+ .HasColumnType("bigint");
+
+ b.Property("Name")
+ .IsRequired()
+ .HasMaxLength(256)
+ .HasColumnType("character varying(256)");
+
+ b.Property("Path")
+ .IsRequired()
+ .HasMaxLength(2048)
+ .HasColumnType("character varying(2048)");
+
+ b.Property("Slug")
+ .IsRequired()
+ .HasMaxLength(2048)
+ .HasColumnType("character varying(2048)");
+
+ b.Property("Type")
+ .HasColumnType("integer");
+
+ b.Property("UserId")
+ .IsRequired()
+ .HasColumnType("character varying(128)");
+
+ b.HasKey("Id");
+
+ b.HasIndex("UserId");
+
+ b.ToTable("Storages");
+ });
+
+ modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserClaim", b =>
+ {
+ b.Property("Id")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("integer");
+
+ NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id"));
+
+ b.Property("ClaimType")
+ .HasMaxLength(16)
+ .HasColumnType("character varying(16)");
+
+ b.Property("ClaimValue")
+ .HasMaxLength(256)
+ .HasColumnType("character varying(256)");
+
+ b.Property("UserId")
+ .IsRequired()
+ .HasColumnType("character varying(128)");
+
+ b.HasKey("Id");
+
+ b.HasIndex("UserId");
+
+ b.ToTable("UserClaim", (string)null);
+ });
+
+ modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserLogin", b =>
+ {
+ b.Property("LoginProvider")
+ .HasColumnType("text");
+
+ b.Property("ProviderKey")
+ .HasColumnType("text");
+
+ b.Property("ProviderDisplayName")
+ .HasMaxLength(128)
+ .HasColumnType("character varying(128)");
+
+ b.Property("UserId")
+ .IsRequired()
+ .HasColumnType("character varying(128)");
+
+ b.HasKey("LoginProvider", "ProviderKey");
+
+ b.HasIndex("UserId");
+
+ b.ToTable("UserLogin", (string)null);
+ });
+
+ modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserToken", b =>
+ {
+ b.Property("UserId")
+ .HasColumnType("character varying(128)");
+
+ b.Property("LoginProvider")
+ .HasColumnType("text");
+
+ b.Property("Name")
+ .HasColumnType("text");
+
+ b.Property("Value")
+ .HasMaxLength(1024)
+ .HasColumnType("character varying(1024)");
+
+ b.HasKey("UserId", "LoginProvider", "Name");
+
+ b.ToTable("UserToken", (string)null);
+ });
+
+ modelBuilder.Entity("Blogifier.Newsletters.Newsletter", b =>
+ {
+ b.HasOne("Blogifier.Shared.Post", "Post")
+ .WithMany()
+ .HasForeignKey("PostId")
+ .OnDelete(DeleteBehavior.Cascade)
+ .IsRequired();
+
+ b.Navigation("Post");
+ });
+
+ modelBuilder.Entity("Blogifier.Shared.Post", b =>
+ {
+ b.HasOne("Blogifier.Identity.UserInfo", "User")
+ .WithMany()
+ .HasForeignKey("UserId")
+ .OnDelete(DeleteBehavior.Cascade)
+ .IsRequired();
+
+ b.Navigation("User");
+ });
+
+ modelBuilder.Entity("Blogifier.Shared.PostCategory", b =>
+ {
+ b.HasOne("Blogifier.Shared.Category", "Category")
+ .WithMany("PostCategories")
+ .HasForeignKey("CategoryId")
+ .OnDelete(DeleteBehavior.Cascade)
+ .IsRequired();
+
+ b.HasOne("Blogifier.Shared.Post", "Post")
+ .WithMany("PostCategories")
+ .HasForeignKey("PostId")
+ .OnDelete(DeleteBehavior.Cascade)
+ .IsRequired();
+
+ b.Navigation("Category");
+
+ b.Navigation("Post");
+ });
+
+ modelBuilder.Entity("Blogifier.Storages.Storage", b =>
+ {
+ b.HasOne("Blogifier.Identity.UserInfo", "User")
+ .WithMany()
+ .HasForeignKey("UserId")
+ .OnDelete(DeleteBehavior.Cascade)
+ .IsRequired();
+
+ b.Navigation("User");
+ });
+
+ modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserClaim", b =>
+ {
+ b.HasOne("Blogifier.Identity.UserInfo", null)
+ .WithMany()
+ .HasForeignKey("UserId")
+ .OnDelete(DeleteBehavior.Cascade)
+ .IsRequired();
+ });
+
+ modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserLogin", b =>
+ {
+ b.HasOne("Blogifier.Identity.UserInfo", null)
+ .WithMany()
+ .HasForeignKey("UserId")
+ .OnDelete(DeleteBehavior.Cascade)
+ .IsRequired();
+ });
+
+ modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserToken", b =>
+ {
+ b.HasOne("Blogifier.Identity.UserInfo", null)
+ .WithMany()
+ .HasForeignKey("UserId")
+ .OnDelete(DeleteBehavior.Cascade)
+ .IsRequired();
+ });
+
+ modelBuilder.Entity("Blogifier.Shared.Category", b =>
+ {
+ b.Navigation("PostCategories");
+ });
+
+ modelBuilder.Entity("Blogifier.Shared.Post", b =>
+ {
+ b.Navigation("PostCategories");
+ });
+#pragma warning restore 612, 618
+ }
+ }
+}
diff --git a/src/Blogifier/Data/Migrations/Postgres/20230608094908_Init.cs b/src/Blogifier/Data/Migrations/Postgres/20230608094908_Init.cs
new file mode 100644
index 000000000..42ac2abb5
--- /dev/null
+++ b/src/Blogifier/Data/Migrations/Postgres/20230608094908_Init.cs
@@ -0,0 +1,353 @@
+using System;
+using Microsoft.EntityFrameworkCore.Migrations;
+using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata;
+
+#nullable disable
+
+namespace Blogifier.Data.Migrations.Postgres
+{
+ ///
+ public partial class Init : Migration
+ {
+ ///
+ protected override void Up(MigrationBuilder migrationBuilder)
+ {
+ migrationBuilder.CreateTable(
+ name: "Categories",
+ columns: table => new
+ {
+ Id = table.Column(type: "integer", nullable: false)
+ .Annotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn),
+ CreatedAt = table.Column(type: "timestamp with time zone", nullable: false, defaultValueSql: "now()"),
+ Content = table.Column(type: "character varying(120)", maxLength: 120, nullable: false),
+ Description = table.Column(type: "character varying(255)", maxLength: 255, nullable: true)
+ },
+ constraints: table =>
+ {
+ table.PrimaryKey("PK_Categories", x => x.Id);
+ });
+
+ migrationBuilder.CreateTable(
+ name: "Options",
+ columns: table => new
+ {
+ Id = table.Column(type: "integer", nullable: false)
+ .Annotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn),
+ CreatedAt = table.Column(type: "timestamp with time zone", nullable: false, defaultValueSql: "now()"),
+ UpdatedAt = table.Column(type: "timestamp with time zone", nullable: false),
+ Key = table.Column(type: "character varying(256)", maxLength: 256, nullable: false),
+ Value = table.Column(type: "text", nullable: false)
+ },
+ constraints: table =>
+ {
+ table.PrimaryKey("PK_Options", x => x.Id);
+ });
+
+ migrationBuilder.CreateTable(
+ name: "Subscribers",
+ columns: table => new
+ {
+ Id = table.Column(type: "integer", nullable: false)
+ .Annotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn),
+ CreatedAt = table.Column(type: "timestamp with time zone", nullable: false, defaultValueSql: "now()"),
+ UpdatedAt = table.Column(type: "timestamp with time zone", nullable: false),
+ Email = table.Column(type: "character varying(160)", maxLength: 160, nullable: false),
+ Ip = table.Column(type: "character varying(80)", maxLength: 80, nullable: true),
+ Country = table.Column(type: "character varying(120)", maxLength: 120, nullable: true),
+ Region = table.Column(type: "character varying(120)", maxLength: 120, nullable: true)
+ },
+ constraints: table =>
+ {
+ table.PrimaryKey("PK_Subscribers", x => x.Id);
+ });
+
+ migrationBuilder.CreateTable(
+ name: "User",
+ columns: table => new
+ {
+ CreatedAt = table.Column(type: "timestamp with time zone", nullable: false, defaultValueSql: "now()"),
+ UpdatedAt = table.Column(type: "timestamp with time zone", nullable: false),
+ Id = table.Column(type: "character varying(128)", maxLength: 128, nullable: false),
+ NickName = table.Column(type: "character varying(256)", maxLength: 256, nullable: false),
+ Avatar = table.Column(type: "character varying(1024)", maxLength: 1024, nullable: true),
+ Bio = table.Column(type: "character varying(2048)", maxLength: 2048, nullable: true),
+ Gender = table.Column(type: "character varying(32)", maxLength: 32, nullable: true),
+ Type = table.Column(type: "integer", nullable: false),
+ State = table.Column(type: "integer", nullable: false),
+ UserName = table.Column(type: "character varying(256)", maxLength: 256, nullable: true),
+ NormalizedUserName = table.Column(type: "character varying(256)", maxLength: 256, nullable: true),
+ Email = table.Column(type: "character varying(256)", maxLength: 256, nullable: true),
+ NormalizedEmail = table.Column(type: "character varying(256)", maxLength: 256, nullable: true),
+ EmailConfirmed = table.Column(type: "boolean", nullable: false),
+ PasswordHash = table.Column(type: "character varying(256)", maxLength: 256, nullable: true),
+ SecurityStamp = table.Column(type: "character varying(32)", maxLength: 32, nullable: true),
+ ConcurrencyStamp = table.Column(type: "character varying(64)", maxLength: 64, nullable: true),
+ PhoneNumber = table.Column(type: "character varying(32)", maxLength: 32, nullable: true),
+ PhoneNumberConfirmed = table.Column(type: "boolean", nullable: false),
+ TwoFactorEnabled = table.Column(type: "boolean", nullable: false),
+ LockoutEnd = table.Column(type: "timestamp with time zone", nullable: true),
+ LockoutEnabled = table.Column(type: "boolean", nullable: false),
+ AccessFailedCount = table.Column(type: "integer", nullable: false)
+ },
+ constraints: table =>
+ {
+ table.PrimaryKey("PK_User", x => x.Id);
+ });
+
+ migrationBuilder.CreateTable(
+ name: "Post",
+ columns: table => new
+ {
+ Id = table.Column(type: "integer", nullable: false)
+ .Annotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn),
+ CreatedAt = table.Column(type: "timestamp with time zone", nullable: false, defaultValueSql: "now()"),
+ UpdatedAt = table.Column(type: "timestamp with time zone", nullable: false),
+ UserId = table.Column(type: "character varying(128)", maxLength: 128, nullable: false),
+ Title = table.Column(type: "character varying(160)", maxLength: 160, nullable: false),
+ Slug = table.Column(type: "character varying(160)", maxLength: 160, nullable: false),
+ Description = table.Column(type: "character varying(450)", maxLength: 450, nullable: false),
+ Content = table.Column(type: "text", nullable: false),
+ Cover = table.Column(type: "character varying(160)", maxLength: 160, nullable: true),
+ Views = table.Column(type: "integer", nullable: false),
+ PublishedAt = table.Column(type: "timestamp with time zone", nullable: true),
+ PostType = table.Column(type: "integer", nullable: false),
+ State = table.Column(type: "integer", nullable: false)
+ },
+ constraints: table =>
+ {
+ table.PrimaryKey("PK_Post", x => x.Id);
+ table.ForeignKey(
+ name: "FK_Post_User_UserId",
+ column: x => x.UserId,
+ principalTable: "User",
+ principalColumn: "Id",
+ onDelete: ReferentialAction.Cascade);
+ });
+
+ migrationBuilder.CreateTable(
+ name: "Storages",
+ columns: table => new
+ {
+ Id = table.Column(type: "integer", nullable: false)
+ .Annotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn),
+ UserId = table.Column(type: "character varying(128)", nullable: false),
+ CreatedAt = table.Column(type: "timestamp with time zone", nullable: false, defaultValueSql: "now()"),
+ IsDeleted = table.Column(type: "boolean", nullable: false),
+ DeletedAt = table.Column(type: "timestamp with time zone", nullable: true),
+ Slug = table.Column(type: "character varying(2048)", maxLength: 2048, nullable: false),
+ Name = table.Column(type: "character varying(256)", maxLength: 256, nullable: false),
+ Path = table.Column(type: "character varying(2048)", maxLength: 2048, nullable: false),
+ Length = table.Column(type: "bigint", nullable: false),
+ ContentType = table.Column(type: "character varying(128)", maxLength: 128, nullable: false),
+ Type = table.Column(type: "integer", nullable: false)
+ },
+ constraints: table =>
+ {
+ table.PrimaryKey("PK_Storages", x => x.Id);
+ table.ForeignKey(
+ name: "FK_Storages_User_UserId",
+ column: x => x.UserId,
+ principalTable: "User",
+ principalColumn: "Id",
+ onDelete: ReferentialAction.Cascade);
+ });
+
+ migrationBuilder.CreateTable(
+ name: "UserClaim",
+ columns: table => new
+ {
+ Id = table.Column(type: "integer", nullable: false)
+ .Annotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn),
+ UserId = table.Column(type: "character varying(128)", nullable: false),
+ ClaimType = table.Column(type: "character varying(16)", maxLength: 16, nullable: true),
+ ClaimValue = table.Column(type: "character varying(256)", maxLength: 256, nullable: true)
+ },
+ constraints: table =>
+ {
+ table.PrimaryKey("PK_UserClaim", x => x.Id);
+ table.ForeignKey(
+ name: "FK_UserClaim_User_UserId",
+ column: x => x.UserId,
+ principalTable: "User",
+ principalColumn: "Id",
+ onDelete: ReferentialAction.Cascade);
+ });
+
+ migrationBuilder.CreateTable(
+ name: "UserLogin",
+ columns: table => new
+ {
+ LoginProvider = table.Column(type: "text", nullable: false),
+ ProviderKey = table.Column(type: "text", nullable: false),
+ ProviderDisplayName = table.Column(type: "character varying(128)", maxLength: 128, nullable: true),
+ UserId = table.Column(type: "character varying(128)", nullable: false)
+ },
+ constraints: table =>
+ {
+ table.PrimaryKey("PK_UserLogin", x => new { x.LoginProvider, x.ProviderKey });
+ table.ForeignKey(
+ name: "FK_UserLogin_User_UserId",
+ column: x => x.UserId,
+ principalTable: "User",
+ principalColumn: "Id",
+ onDelete: ReferentialAction.Cascade);
+ });
+
+ migrationBuilder.CreateTable(
+ name: "UserToken",
+ columns: table => new
+ {
+ UserId = table.Column(type: "character varying(128)", nullable: false),
+ LoginProvider = table.Column(type: "text", nullable: false),
+ Name = table.Column(type: "text", nullable: false),
+ Value = table.Column(type: "character varying(1024)", maxLength: 1024, nullable: true)
+ },
+ constraints: table =>
+ {
+ table.PrimaryKey("PK_UserToken", x => new { x.UserId, x.LoginProvider, x.Name });
+ table.ForeignKey(
+ name: "FK_UserToken_User_UserId",
+ column: x => x.UserId,
+ principalTable: "User",
+ principalColumn: "Id",
+ onDelete: ReferentialAction.Cascade);
+ });
+
+ migrationBuilder.CreateTable(
+ name: "Newsletters",
+ columns: table => new
+ {
+ Id = table.Column(type: "integer", nullable: false)
+ .Annotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn),
+ CreatedAt = table.Column(type: "timestamp with time zone", nullable: false, defaultValueSql: "now()"),
+ UpdatedAt = table.Column(type: "timestamp with time zone", nullable: false),
+ PostId = table.Column(type: "integer", nullable: false),
+ Success = table.Column(type: "boolean", nullable: false)
+ },
+ constraints: table =>
+ {
+ table.PrimaryKey("PK_Newsletters", x => x.Id);
+ table.ForeignKey(
+ name: "FK_Newsletters_Post_PostId",
+ column: x => x.PostId,
+ principalTable: "Post",
+ principalColumn: "Id",
+ onDelete: ReferentialAction.Cascade);
+ });
+
+ migrationBuilder.CreateTable(
+ name: "PostCategories",
+ columns: table => new
+ {
+ PostId = table.Column(type: "integer", nullable: false),
+ CategoryId = table.Column(type: "integer", nullable: false)
+ },
+ constraints: table =>
+ {
+ table.PrimaryKey("PK_PostCategories", x => new { x.PostId, x.CategoryId });
+ table.ForeignKey(
+ name: "FK_PostCategories_Categories_CategoryId",
+ column: x => x.CategoryId,
+ principalTable: "Categories",
+ principalColumn: "Id",
+ onDelete: ReferentialAction.Cascade);
+ table.ForeignKey(
+ name: "FK_PostCategories_Post_PostId",
+ column: x => x.PostId,
+ principalTable: "Post",
+ principalColumn: "Id",
+ onDelete: ReferentialAction.Cascade);
+ });
+
+ migrationBuilder.CreateIndex(
+ name: "IX_Newsletters_PostId",
+ table: "Newsletters",
+ column: "PostId");
+
+ migrationBuilder.CreateIndex(
+ name: "IX_Options_Key",
+ table: "Options",
+ column: "Key",
+ unique: true);
+
+ migrationBuilder.CreateIndex(
+ name: "IX_Post_Slug",
+ table: "Post",
+ column: "Slug",
+ unique: true);
+
+ migrationBuilder.CreateIndex(
+ name: "IX_Post_UserId",
+ table: "Post",
+ column: "UserId");
+
+ migrationBuilder.CreateIndex(
+ name: "IX_PostCategories_CategoryId",
+ table: "PostCategories",
+ column: "CategoryId");
+
+ migrationBuilder.CreateIndex(
+ name: "IX_Storages_UserId",
+ table: "Storages",
+ column: "UserId");
+
+ migrationBuilder.CreateIndex(
+ name: "EmailIndex",
+ table: "User",
+ column: "NormalizedEmail");
+
+ migrationBuilder.CreateIndex(
+ name: "UserNameIndex",
+ table: "User",
+ column: "NormalizedUserName",
+ unique: true);
+
+ migrationBuilder.CreateIndex(
+ name: "IX_UserClaim_UserId",
+ table: "UserClaim",
+ column: "UserId");
+
+ migrationBuilder.CreateIndex(
+ name: "IX_UserLogin_UserId",
+ table: "UserLogin",
+ column: "UserId");
+ }
+
+ ///
+ protected override void Down(MigrationBuilder migrationBuilder)
+ {
+ migrationBuilder.DropTable(
+ name: "Newsletters");
+
+ migrationBuilder.DropTable(
+ name: "Options");
+
+ migrationBuilder.DropTable(
+ name: "PostCategories");
+
+ migrationBuilder.DropTable(
+ name: "Storages");
+
+ migrationBuilder.DropTable(
+ name: "Subscribers");
+
+ migrationBuilder.DropTable(
+ name: "UserClaim");
+
+ migrationBuilder.DropTable(
+ name: "UserLogin");
+
+ migrationBuilder.DropTable(
+ name: "UserToken");
+
+ migrationBuilder.DropTable(
+ name: "Categories");
+
+ migrationBuilder.DropTable(
+ name: "Post");
+
+ migrationBuilder.DropTable(
+ name: "User");
+ }
+ }
+}
diff --git a/src/Blogifier/Data/Migrations/Postgres/PostgresDbContextModelSnapshot.cs b/src/Blogifier/Data/Migrations/Postgres/PostgresDbContextModelSnapshot.cs
new file mode 100644
index 000000000..324b7c149
--- /dev/null
+++ b/src/Blogifier/Data/Migrations/Postgres/PostgresDbContextModelSnapshot.cs
@@ -0,0 +1,552 @@
+//
+using System;
+using Blogifier.Data;
+using Microsoft.EntityFrameworkCore;
+using Microsoft.EntityFrameworkCore.Infrastructure;
+using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
+using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata;
+
+#nullable disable
+
+namespace Blogifier.Data.Migrations.Postgres
+{
+ [DbContext(typeof(PostgresDbContext))]
+ partial class PostgresDbContextModelSnapshot : ModelSnapshot
+ {
+ protected override void BuildModel(ModelBuilder modelBuilder)
+ {
+#pragma warning disable 612, 618
+ modelBuilder
+ .HasAnnotation("ProductVersion", "7.0.5")
+ .HasAnnotation("Relational:MaxIdentifierLength", 63);
+
+ NpgsqlModelBuilderExtensions.UseIdentityByDefaultColumns(modelBuilder);
+
+ modelBuilder.Entity("Blogifier.Identity.UserInfo", b =>
+ {
+ b.Property("Id")
+ .HasMaxLength(128)
+ .HasColumnType("character varying(128)");
+
+ b.Property("AccessFailedCount")
+ .HasColumnType("integer");
+
+ b.Property("Avatar")
+ .HasMaxLength(1024)
+ .HasColumnType("character varying(1024)");
+
+ b.Property("Bio")
+ .HasMaxLength(2048)
+ .HasColumnType("character varying(2048)");
+
+ b.Property