From c6b05c12e501f31b731fd32f6c47cf20fd18a0e0 Mon Sep 17 00:00:00 2001
From: lq1405 <2769838458@qq.com>
Date: Sat, 23 May 2026 11:03:51 +0800
Subject: [PATCH] =?UTF-8?q?fix(web):=20=E6=81=A2=E5=A4=8D=E8=A7=86?=
=?UTF-8?q?=E9=A2=91=E7=BB=A7=E7=BB=AD=E6=92=AD=E6=94=BE=E5=92=8C=E8=BF=9B?=
=?UTF-8?q?=E5=BA=A6=E4=BF=9D=E5=AD=98?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
- 将播放器收敛为单个共享实例,避免列表/网格内多个 video ref 导致进度保存失效
- 恢复视频播放器上方的继续播放提示
- 在播放、暂停、拖动、结束、切换页面和离开页面时保存播放位置
- 保留文件浏览分页和排序参数的前端调用
---
AGENTS.md | 4 +
FileShare-EFCore/Database/AppDataContext.cs | 1 +
...0_AutoMigration_20260523103531.Designer.cs | 455 +++++++++++++++++
...0523023700_AutoMigration_20260523103531.cs | 38 ++
.../MySQL/MySqlAppDataContextModelSnapshot.cs | 7 +
...3_AutoMigration_20260523103531.Designer.cs | 470 ++++++++++++++++++
...0523023643_AutoMigration_20260523103531.cs | 38 ++
.../PostgreSqlAppDataContextModelSnapshot.cs | 7 +
...7_AutoMigration_20260523103531.Designer.cs | 453 +++++++++++++++++
...0523023607_AutoMigration_20260523103531.cs | 38 ++
.../SqliteAppDataContextModelSnapshot.cs | 7 +
...5_AutoMigration_20260523103531.Designer.cs | 470 ++++++++++++++++++
...0523023625_AutoMigration_20260523103531.cs | 38 ++
.../SqlServerAppDataContextModelSnapshot.cs | 7 +
FileShare-EFCore/Models/ManagedFileRecord.cs | 4 +
FileShare-Services/Endpoints/AppEndpoints.cs | 8 +-
.../FileLibrary/FileLibraryContracts.cs | 20 +-
.../FileLibrary/FileLibraryEndpointService.cs | 7 +-
.../FileLibrary/FileLibraryService.cs | 103 +++-
FileShare-Web-VUE/src/api/index.ts | 11 +-
FileShare-Web-VUE/src/assets/main.css | 35 ++
.../src/components/ClientPage.vue | 393 +++++++++------
22 files changed, 2449 insertions(+), 165 deletions(-)
create mode 100644 AGENTS.md
create mode 100644 FileShare-EFCore/Migrations/MySQL/20260523023700_AutoMigration_20260523103531.Designer.cs
create mode 100644 FileShare-EFCore/Migrations/MySQL/20260523023700_AutoMigration_20260523103531.cs
create mode 100644 FileShare-EFCore/Migrations/PostgreSQL/20260523023643_AutoMigration_20260523103531.Designer.cs
create mode 100644 FileShare-EFCore/Migrations/PostgreSQL/20260523023643_AutoMigration_20260523103531.cs
create mode 100644 FileShare-EFCore/Migrations/SQLite/20260523023607_AutoMigration_20260523103531.Designer.cs
create mode 100644 FileShare-EFCore/Migrations/SQLite/20260523023607_AutoMigration_20260523103531.cs
create mode 100644 FileShare-EFCore/Migrations/SqlServer/20260523023625_AutoMigration_20260523103531.Designer.cs
create mode 100644 FileShare-EFCore/Migrations/SqlServer/20260523023625_AutoMigration_20260523103531.cs
diff --git a/AGENTS.md b/AGENTS.md
new file mode 100644
index 0000000..f234b07
--- /dev/null
+++ b/AGENTS.md
@@ -0,0 +1,4 @@
+# Codex Rules
+
+- Do not manually edit files under `FileShare-EFCore/Migrations/**`. These files are generated by EF scripts.
+- When database schema changes are needed, update the EF model/configuration only and ask the user to generate migrations with the project scripts.
diff --git a/FileShare-EFCore/Database/AppDataContext.cs b/FileShare-EFCore/Database/AppDataContext.cs
index 9b10a90..68ac116 100644
--- a/FileShare-EFCore/Database/AppDataContext.cs
+++ b/FileShare-EFCore/Database/AppDataContext.cs
@@ -73,6 +73,7 @@ namespace FileShare_EFCore.Database
entity.HasIndex(e => e.AbsolutePath).IsUnique().HasDatabaseName("idx-managed-file-record-absolute-path");
entity.HasIndex(e => new { e.MediaType, e.Exists }).HasDatabaseName("idx-managed-file-record-media-type-exists");
entity.HasIndex(e => e.LastPlayedAt).HasDatabaseName("idx-managed-file-record-last-played-at");
+ entity.HasIndex(e => e.FileCreationTimeUtc).HasDatabaseName("idx-managed-file-record-file-creation-time");
entity.Property(e => e.FileName).HasMaxLength(260);
entity.Property(e => e.RelativePath).HasMaxLength(1024);
entity.Property(e => e.AbsolutePath).HasMaxLength(2048);
diff --git a/FileShare-EFCore/Migrations/MySQL/20260523023700_AutoMigration_20260523103531.Designer.cs b/FileShare-EFCore/Migrations/MySQL/20260523023700_AutoMigration_20260523103531.Designer.cs
new file mode 100644
index 0000000..1f643d7
--- /dev/null
+++ b/FileShare-EFCore/Migrations/MySQL/20260523023700_AutoMigration_20260523103531.Designer.cs
@@ -0,0 +1,455 @@
+//
+using System;
+using FileShare_EFCore.Database;
+using Microsoft.EntityFrameworkCore;
+using Microsoft.EntityFrameworkCore.Infrastructure;
+using Microsoft.EntityFrameworkCore.Migrations;
+using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
+
+#nullable disable
+
+namespace FileShare_EFCore.Migrations.MySQL
+{
+ [DbContext(typeof(MySqlAppDataContext))]
+ [Migration("20260523023700_AutoMigration_20260523103531")]
+ partial class AutoMigration_20260523103531
+ {
+ ///
+ protected override void BuildTargetModel(ModelBuilder modelBuilder)
+ {
+#pragma warning disable 612, 618
+ modelBuilder
+ .HasAnnotation("ProductVersion", "10.0.7")
+ .HasAnnotation("Relational:MaxIdentifierLength", 64);
+
+ modelBuilder.Entity("FileShare_EFCore.Models.ApiRefreshTokenEntity", b =>
+ {
+ b.Property("Id")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("bigint")
+ .HasColumnName("id");
+
+ b.Property("CreatedAt")
+ .HasColumnType("datetime(6)")
+ .HasColumnName("created-at");
+
+ b.Property("Device")
+ .HasMaxLength(200)
+ .HasColumnType("varchar(200)")
+ .HasColumnName("device");
+
+ b.Property("ExpiresAt")
+ .HasColumnType("datetime(6)")
+ .HasColumnName("expires-at");
+
+ b.Property("IpAddress")
+ .HasMaxLength(64)
+ .HasColumnType("varchar(64)")
+ .HasColumnName("ip-address");
+
+ b.Property("ReplacedByTokenHash")
+ .HasMaxLength(128)
+ .HasColumnType("varchar(128)")
+ .HasColumnName("replaced-by-token-hash");
+
+ b.Property("RevokedAt")
+ .HasColumnType("datetime(6)")
+ .HasColumnName("revoked-at");
+
+ b.Property("TokenHash")
+ .IsRequired()
+ .HasMaxLength(128)
+ .HasColumnType("varchar(128)")
+ .HasColumnName("token-hash");
+
+ b.Property("UserId")
+ .HasColumnType("int")
+ .HasColumnName("user-id");
+
+ b.HasKey("Id")
+ .HasName("pk-api-refresh-token");
+
+ b.HasIndex("TokenHash")
+ .IsUnique()
+ .HasDatabaseName("idx-api-refresh-token-hash");
+
+ b.HasIndex("UserId")
+ .HasDatabaseName("idx-api-refresh-token-user-id");
+
+ b.ToTable("api-refresh-token", t =>
+ {
+ t.HasComment("API refresh token");
+ });
+ });
+
+ modelBuilder.Entity("FileShare_EFCore.Models.ManagedFileRecord", b =>
+ {
+ b.Property("Id")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("int")
+ .HasColumnName("id");
+
+ b.Property("AbsolutePath")
+ .IsRequired()
+ .HasMaxLength(2048)
+ .HasColumnType("varchar(2048)")
+ .HasColumnName("absolute-path");
+
+ b.Property("ContentType")
+ .IsRequired()
+ .HasMaxLength(100)
+ .HasColumnType("varchar(100)")
+ .HasColumnName("content-type");
+
+ b.Property("CreatedAt")
+ .HasColumnType("datetime(6)")
+ .HasColumnName("created-at");
+
+ b.Property("Exists")
+ .HasColumnType("tinyint(1)")
+ .HasColumnName("exists");
+
+ b.Property("Extension")
+ .IsRequired()
+ .HasMaxLength(32)
+ .HasColumnType("varchar(32)")
+ .HasColumnName("extension");
+
+ b.Property("FileCreationTimeUtc")
+ .HasColumnType("datetime(6)")
+ .HasColumnName("file-creation-time-utc");
+
+ b.Property("FileName")
+ .IsRequired()
+ .HasMaxLength(260)
+ .HasColumnType("varchar(260)")
+ .HasColumnName("file-name");
+
+ b.Property("LastPlayedAt")
+ .HasColumnType("datetime(6)")
+ .HasColumnName("last-played-at");
+
+ b.Property("LastSeenAt")
+ .HasColumnType("datetime(6)")
+ .HasColumnName("last-seen-at");
+
+ b.Property("LastWriteTimeUtc")
+ .HasColumnType("datetime(6)")
+ .HasColumnName("last-write-time-utc");
+
+ b.Property("LibraryRootId")
+ .HasColumnType("int")
+ .HasColumnName("library-root-id");
+
+ b.Property("MediaType")
+ .IsRequired()
+ .HasMaxLength(20)
+ .HasColumnType("varchar(20)")
+ .HasColumnName("media-type");
+
+ b.Property("PlaybackPosition")
+ .HasColumnType("double")
+ .HasColumnName("playback-position");
+
+ b.Property("RelativePath")
+ .IsRequired()
+ .HasMaxLength(1024)
+ .HasColumnType("varchar(1024)")
+ .HasColumnName("relative-path");
+
+ b.Property("SizeBytes")
+ .HasColumnType("bigint")
+ .HasColumnName("size-bytes");
+
+ b.Property("ThumbnailId")
+ .HasColumnType("int")
+ .HasColumnName("thumbnail-id");
+
+ b.Property("UpdatedAt")
+ .HasColumnType("datetime(6)")
+ .HasColumnName("updated-at");
+
+ b.Property("VideoDuration")
+ .HasColumnType("double")
+ .HasColumnName("video-duration");
+
+ b.HasKey("Id")
+ .HasName("pk-managed-file-record");
+
+ b.HasIndex("AbsolutePath")
+ .IsUnique()
+ .HasDatabaseName("idx-managed-file-record-absolute-path");
+
+ b.HasIndex("FileCreationTimeUtc")
+ .HasDatabaseName("idx-managed-file-record-file-creation-time");
+
+ b.HasIndex("LastPlayedAt")
+ .HasDatabaseName("idx-managed-file-record-last-played-at");
+
+ b.HasIndex("LibraryRootId")
+ .HasDatabaseName("idx-managed-file-record-root-id");
+
+ b.HasIndex("ThumbnailId")
+ .HasDatabaseName("idx-managed-file-record-thumbnail-id");
+
+ b.HasIndex("MediaType", "Exists")
+ .HasDatabaseName("idx-managed-file-record-media-type-exists");
+
+ b.ToTable("managed-file-record", t =>
+ {
+ t.HasComment("文件库文件记录");
+ });
+ });
+
+ modelBuilder.Entity("FileShare_EFCore.Models.ManagedLibraryRoot", b =>
+ {
+ b.Property("Id")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("int")
+ .HasColumnName("id");
+
+ b.Property("CreatedAt")
+ .HasColumnType("datetime(6)")
+ .HasColumnName("created-at");
+
+ b.Property("DisplayName")
+ .IsRequired()
+ .HasMaxLength(200)
+ .HasColumnType("varchar(200)")
+ .HasColumnName("display-name");
+
+ b.Property("IsAvailable")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("tinyint(1)")
+ .HasDefaultValue(true)
+ .HasColumnName("is-available");
+
+ b.Property("IsEnabled")
+ .HasColumnType("tinyint(1)")
+ .HasColumnName("is-enabled");
+
+ b.Property("LastScanCompletedAt")
+ .HasColumnType("datetime(6)")
+ .HasColumnName("last-scan-completed-at");
+
+ b.Property("LastScanError")
+ .HasMaxLength(2000)
+ .HasColumnType("varchar(2000)")
+ .HasColumnName("last-scan-error");
+
+ b.Property("LastScanStartedAt")
+ .HasColumnType("datetime(6)")
+ .HasColumnName("last-scan-started-at");
+
+ b.Property("Path")
+ .IsRequired()
+ .HasMaxLength(1024)
+ .HasColumnType("varchar(1024)")
+ .HasColumnName("path");
+
+ b.Property("ScanIntervalMinutes")
+ .HasColumnType("int")
+ .HasColumnName("scan-interval-minutes");
+
+ b.Property("UpdatedAt")
+ .HasColumnType("datetime(6)")
+ .HasColumnName("updated-at");
+
+ b.HasKey("Id")
+ .HasName("pk-managed-library-root");
+
+ b.HasIndex("Path")
+ .IsUnique()
+ .HasDatabaseName("idx-managed-library-root-path");
+
+ b.ToTable("managed-library-root", t =>
+ {
+ t.HasComment("文件库根目录");
+ });
+ });
+
+ modelBuilder.Entity("FileShare_EFCore.Models.ManagedThumbnailMap", b =>
+ {
+ b.Property("Id")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("int")
+ .HasColumnName("id");
+
+ b.Property("ContentType")
+ .IsRequired()
+ .HasMaxLength(100)
+ .HasColumnType("varchar(100)")
+ .HasColumnName("content-type");
+
+ b.Property("CreatedAt")
+ .HasColumnType("datetime(6)")
+ .HasColumnName("created-at");
+
+ b.Property("LibraryRootId")
+ .HasColumnType("int")
+ .HasColumnName("library-root-id");
+
+ b.Property("RelativePath")
+ .IsRequired()
+ .HasMaxLength(1024)
+ .HasColumnType("varchar(1024)")
+ .HasColumnName("relative-path");
+
+ b.Property("UpdatedAt")
+ .HasColumnType("datetime(6)")
+ .HasColumnName("updated-at");
+
+ b.HasKey("Id")
+ .HasName("pk-managed-thumbnail-map");
+
+ b.HasIndex("LibraryRootId")
+ .HasDatabaseName("idx-managed-thumbnail-map-root-id");
+
+ b.HasIndex("RelativePath")
+ .IsUnique()
+ .HasDatabaseName("idx-managed-thumbnail-map-relative-path");
+
+ b.ToTable("managed-thumbnail-map", t =>
+ {
+ t.HasComment("文件缩略图映射记录");
+ });
+ });
+
+ modelBuilder.Entity("FileShare_EFCore.Models.UserEntity", b =>
+ {
+ b.Property("Id")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("int")
+ .HasColumnName("id")
+ .HasComment("用户主键");
+
+ b.Property("CreatedAt")
+ .HasColumnType("datetime(6)")
+ .HasColumnName("created-at")
+ .HasComment("创建时间");
+
+ b.Property("Email")
+ .HasMaxLength(200)
+ .HasColumnType("varchar(200)")
+ .HasColumnName("email")
+ .HasComment("用户邮箱");
+
+ b.Property("Name")
+ .HasMaxLength(100)
+ .HasColumnType("varchar(100)")
+ .HasColumnName("name")
+ .HasComment("用户名称");
+
+ b.Property("PasswordHash")
+ .HasMaxLength(200)
+ .HasColumnType("varchar(200)")
+ .HasColumnName("password-hash")
+ .HasComment("密码哈希值");
+
+ b.Property("PhoneNumber")
+ .HasMaxLength(50)
+ .HasColumnType("varchar(50)")
+ .HasColumnName("phone-number")
+ .HasComment("电话号码");
+
+ b.Property("UpdatedAt")
+ .HasColumnType("datetime(6)")
+ .HasColumnName("updated-at")
+ .HasComment("更新时间");
+
+ b.HasKey("Id")
+ .HasName("pk-user");
+
+ b.ToTable("user", t =>
+ {
+ t.HasComment("用户实体,演示数据库 CRUD 操作");
+ });
+ });
+
+ modelBuilder.Entity("FileShare_EFCore.Models.WeatherForecastEntity", b =>
+ {
+ b.Property("Id")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("int")
+ .HasColumnName("id")
+ .HasComment("天气预报主键");
+
+ b.Property("CreatedAt")
+ .HasColumnType("datetime(6)")
+ .HasColumnName("created-at")
+ .HasComment("创建时间");
+
+ b.Property("Date")
+ .HasColumnType("date")
+ .HasColumnName("date")
+ .HasComment("预报日期");
+
+ b.Property("Summary")
+ .HasMaxLength(200)
+ .HasColumnType("varchar(200)")
+ .HasColumnName("summary")
+ .HasComment("天气摘要");
+
+ b.Property("TemperatureC")
+ .HasColumnType("int")
+ .HasColumnName("temperature-c")
+ .HasComment("摄氏温度");
+
+ b.Property("UpdatedAt")
+ .HasColumnType("datetime(6)")
+ .HasColumnName("updated-at")
+ .HasComment("更新时间");
+
+ b.HasKey("Id")
+ .HasName("pk-weather-forecast");
+
+ b.ToTable("weather-forecast", t =>
+ {
+ t.HasComment("天气预报数据实体");
+ });
+ });
+
+ modelBuilder.Entity("FileShare_EFCore.Models.ManagedFileRecord", b =>
+ {
+ b.HasOne("FileShare_EFCore.Models.ManagedLibraryRoot", "LibraryRoot")
+ .WithMany("Files")
+ .HasForeignKey("LibraryRootId")
+ .OnDelete(DeleteBehavior.Cascade)
+ .IsRequired();
+
+ b.HasOne("FileShare_EFCore.Models.ManagedThumbnailMap", "Thumbnail")
+ .WithMany("Files")
+ .HasForeignKey("ThumbnailId")
+ .OnDelete(DeleteBehavior.SetNull);
+
+ b.Navigation("LibraryRoot");
+
+ b.Navigation("Thumbnail");
+ });
+
+ modelBuilder.Entity("FileShare_EFCore.Models.ManagedThumbnailMap", b =>
+ {
+ b.HasOne("FileShare_EFCore.Models.ManagedLibraryRoot", "LibraryRoot")
+ .WithMany("Thumbnails")
+ .HasForeignKey("LibraryRootId")
+ .OnDelete(DeleteBehavior.Cascade)
+ .IsRequired();
+
+ b.Navigation("LibraryRoot");
+ });
+
+ modelBuilder.Entity("FileShare_EFCore.Models.ManagedLibraryRoot", b =>
+ {
+ b.Navigation("Files");
+
+ b.Navigation("Thumbnails");
+ });
+
+ modelBuilder.Entity("FileShare_EFCore.Models.ManagedThumbnailMap", b =>
+ {
+ b.Navigation("Files");
+ });
+#pragma warning restore 612, 618
+ }
+ }
+}
diff --git a/FileShare-EFCore/Migrations/MySQL/20260523023700_AutoMigration_20260523103531.cs b/FileShare-EFCore/Migrations/MySQL/20260523023700_AutoMigration_20260523103531.cs
new file mode 100644
index 0000000..1521a77
--- /dev/null
+++ b/FileShare-EFCore/Migrations/MySQL/20260523023700_AutoMigration_20260523103531.cs
@@ -0,0 +1,38 @@
+using System;
+using Microsoft.EntityFrameworkCore.Migrations;
+
+#nullable disable
+
+namespace FileShare_EFCore.Migrations.MySQL
+{
+ ///
+ public partial class AutoMigration_20260523103531 : Migration
+ {
+ ///
+ protected override void Up(MigrationBuilder migrationBuilder)
+ {
+ migrationBuilder.AddColumn(
+ name: "file-creation-time-utc",
+ table: "managed-file-record",
+ type: "datetime(6)",
+ nullable: true);
+
+ migrationBuilder.CreateIndex(
+ name: "idx-managed-file-record-file-creation-time",
+ table: "managed-file-record",
+ column: "file-creation-time-utc");
+ }
+
+ ///
+ protected override void Down(MigrationBuilder migrationBuilder)
+ {
+ migrationBuilder.DropIndex(
+ name: "idx-managed-file-record-file-creation-time",
+ table: "managed-file-record");
+
+ migrationBuilder.DropColumn(
+ name: "file-creation-time-utc",
+ table: "managed-file-record");
+ }
+ }
+}
diff --git a/FileShare-EFCore/Migrations/MySQL/MySqlAppDataContextModelSnapshot.cs b/FileShare-EFCore/Migrations/MySQL/MySqlAppDataContextModelSnapshot.cs
index add6e0d..55c038d 100644
--- a/FileShare-EFCore/Migrations/MySQL/MySqlAppDataContextModelSnapshot.cs
+++ b/FileShare-EFCore/Migrations/MySQL/MySqlAppDataContextModelSnapshot.cs
@@ -112,6 +112,10 @@ namespace FileShare_EFCore.Migrations.MySQL
.HasColumnType("varchar(32)")
.HasColumnName("extension");
+ b.Property("FileCreationTimeUtc")
+ .HasColumnType("datetime(6)")
+ .HasColumnName("file-creation-time-utc");
+
b.Property("FileName")
.IsRequired()
.HasMaxLength(260)
@@ -173,6 +177,9 @@ namespace FileShare_EFCore.Migrations.MySQL
.IsUnique()
.HasDatabaseName("idx-managed-file-record-absolute-path");
+ b.HasIndex("FileCreationTimeUtc")
+ .HasDatabaseName("idx-managed-file-record-file-creation-time");
+
b.HasIndex("LastPlayedAt")
.HasDatabaseName("idx-managed-file-record-last-played-at");
diff --git a/FileShare-EFCore/Migrations/PostgreSQL/20260523023643_AutoMigration_20260523103531.Designer.cs b/FileShare-EFCore/Migrations/PostgreSQL/20260523023643_AutoMigration_20260523103531.Designer.cs
new file mode 100644
index 0000000..90bdaa3
--- /dev/null
+++ b/FileShare-EFCore/Migrations/PostgreSQL/20260523023643_AutoMigration_20260523103531.Designer.cs
@@ -0,0 +1,470 @@
+//
+using System;
+using FileShare_EFCore.Database;
+using Microsoft.EntityFrameworkCore;
+using Microsoft.EntityFrameworkCore.Infrastructure;
+using Microsoft.EntityFrameworkCore.Migrations;
+using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
+using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata;
+
+#nullable disable
+
+namespace FileShare_EFCore.Migrations.PostgreSQL
+{
+ [DbContext(typeof(PostgreSqlAppDataContext))]
+ [Migration("20260523023643_AutoMigration_20260523103531")]
+ partial class AutoMigration_20260523103531
+ {
+ ///
+ protected override void BuildTargetModel(ModelBuilder modelBuilder)
+ {
+#pragma warning disable 612, 618
+ modelBuilder
+ .HasAnnotation("ProductVersion", "10.0.7")
+ .HasAnnotation("Relational:MaxIdentifierLength", 63);
+
+ NpgsqlModelBuilderExtensions.UseIdentityByDefaultColumns(modelBuilder);
+
+ modelBuilder.Entity("FileShare_EFCore.Models.ApiRefreshTokenEntity", b =>
+ {
+ b.Property("Id")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("bigint")
+ .HasColumnName("id");
+
+ NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id"));
+
+ b.Property("CreatedAt")
+ .HasColumnType("timestamp with time zone")
+ .HasColumnName("created-at");
+
+ b.Property("Device")
+ .HasMaxLength(200)
+ .HasColumnType("character varying(200)")
+ .HasColumnName("device");
+
+ b.Property("ExpiresAt")
+ .HasColumnType("timestamp with time zone")
+ .HasColumnName("expires-at");
+
+ b.Property("IpAddress")
+ .HasMaxLength(64)
+ .HasColumnType("character varying(64)")
+ .HasColumnName("ip-address");
+
+ b.Property("ReplacedByTokenHash")
+ .HasMaxLength(128)
+ .HasColumnType("character varying(128)")
+ .HasColumnName("replaced-by-token-hash");
+
+ b.Property("RevokedAt")
+ .HasColumnType("timestamp with time zone")
+ .HasColumnName("revoked-at");
+
+ b.Property("TokenHash")
+ .IsRequired()
+ .HasMaxLength(128)
+ .HasColumnType("character varying(128)")
+ .HasColumnName("token-hash");
+
+ b.Property("UserId")
+ .HasColumnType("integer")
+ .HasColumnName("user-id");
+
+ b.HasKey("Id")
+ .HasName("pk-api-refresh-token");
+
+ b.HasIndex("TokenHash")
+ .IsUnique()
+ .HasDatabaseName("idx-api-refresh-token-hash");
+
+ b.HasIndex("UserId")
+ .HasDatabaseName("idx-api-refresh-token-user-id");
+
+ b.ToTable("api-refresh-token", t =>
+ {
+ t.HasComment("API refresh token");
+ });
+ });
+
+ modelBuilder.Entity("FileShare_EFCore.Models.ManagedFileRecord", b =>
+ {
+ b.Property("Id")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("integer")
+ .HasColumnName("id");
+
+ NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id"));
+
+ b.Property("AbsolutePath")
+ .IsRequired()
+ .HasMaxLength(2048)
+ .HasColumnType("character varying(2048)")
+ .HasColumnName("absolute-path");
+
+ b.Property("ContentType")
+ .IsRequired()
+ .HasMaxLength(100)
+ .HasColumnType("character varying(100)")
+ .HasColumnName("content-type");
+
+ b.Property("CreatedAt")
+ .HasColumnType("timestamp with time zone")
+ .HasColumnName("created-at");
+
+ b.Property("Exists")
+ .HasColumnType("boolean")
+ .HasColumnName("exists");
+
+ b.Property("Extension")
+ .IsRequired()
+ .HasMaxLength(32)
+ .HasColumnType("character varying(32)")
+ .HasColumnName("extension");
+
+ b.Property("FileCreationTimeUtc")
+ .HasColumnType("timestamp with time zone")
+ .HasColumnName("file-creation-time-utc");
+
+ b.Property("FileName")
+ .IsRequired()
+ .HasMaxLength(260)
+ .HasColumnType("character varying(260)")
+ .HasColumnName("file-name");
+
+ b.Property("LastPlayedAt")
+ .HasColumnType("timestamp with time zone")
+ .HasColumnName("last-played-at");
+
+ b.Property("LastSeenAt")
+ .HasColumnType("timestamp with time zone")
+ .HasColumnName("last-seen-at");
+
+ b.Property("LastWriteTimeUtc")
+ .HasColumnType("timestamp with time zone")
+ .HasColumnName("last-write-time-utc");
+
+ b.Property("LibraryRootId")
+ .HasColumnType("integer")
+ .HasColumnName("library-root-id");
+
+ b.Property("MediaType")
+ .IsRequired()
+ .HasMaxLength(20)
+ .HasColumnType("character varying(20)")
+ .HasColumnName("media-type");
+
+ b.Property("PlaybackPosition")
+ .HasColumnType("double precision")
+ .HasColumnName("playback-position");
+
+ b.Property("RelativePath")
+ .IsRequired()
+ .HasMaxLength(1024)
+ .HasColumnType("character varying(1024)")
+ .HasColumnName("relative-path");
+
+ b.Property("SizeBytes")
+ .HasColumnType("bigint")
+ .HasColumnName("size-bytes");
+
+ b.Property("ThumbnailId")
+ .HasColumnType("integer")
+ .HasColumnName("thumbnail-id");
+
+ b.Property("UpdatedAt")
+ .HasColumnType("timestamp with time zone")
+ .HasColumnName("updated-at");
+
+ b.Property("VideoDuration")
+ .HasColumnType("double precision")
+ .HasColumnName("video-duration");
+
+ b.HasKey("Id")
+ .HasName("pk-managed-file-record");
+
+ b.HasIndex("AbsolutePath")
+ .IsUnique()
+ .HasDatabaseName("idx-managed-file-record-absolute-path");
+
+ b.HasIndex("FileCreationTimeUtc")
+ .HasDatabaseName("idx-managed-file-record-file-creation-time");
+
+ b.HasIndex("LastPlayedAt")
+ .HasDatabaseName("idx-managed-file-record-last-played-at");
+
+ b.HasIndex("LibraryRootId")
+ .HasDatabaseName("idx-managed-file-record-root-id");
+
+ b.HasIndex("ThumbnailId")
+ .HasDatabaseName("idx-managed-file-record-thumbnail-id");
+
+ b.HasIndex("MediaType", "Exists")
+ .HasDatabaseName("idx-managed-file-record-media-type-exists");
+
+ b.ToTable("managed-file-record", t =>
+ {
+ t.HasComment("文件库文件记录");
+ });
+ });
+
+ modelBuilder.Entity("FileShare_EFCore.Models.ManagedLibraryRoot", b =>
+ {
+ b.Property("Id")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("integer")
+ .HasColumnName("id");
+
+ NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id"));
+
+ b.Property("CreatedAt")
+ .HasColumnType("timestamp with time zone")
+ .HasColumnName("created-at");
+
+ b.Property("DisplayName")
+ .IsRequired()
+ .HasMaxLength(200)
+ .HasColumnType("character varying(200)")
+ .HasColumnName("display-name");
+
+ b.Property("IsAvailable")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("boolean")
+ .HasDefaultValue(true)
+ .HasColumnName("is-available");
+
+ b.Property("IsEnabled")
+ .HasColumnType("boolean")
+ .HasColumnName("is-enabled");
+
+ b.Property("LastScanCompletedAt")
+ .HasColumnType("timestamp with time zone")
+ .HasColumnName("last-scan-completed-at");
+
+ b.Property("LastScanError")
+ .HasMaxLength(2000)
+ .HasColumnType("character varying(2000)")
+ .HasColumnName("last-scan-error");
+
+ b.Property("LastScanStartedAt")
+ .HasColumnType("timestamp with time zone")
+ .HasColumnName("last-scan-started-at");
+
+ b.Property("Path")
+ .IsRequired()
+ .HasMaxLength(1024)
+ .HasColumnType("character varying(1024)")
+ .HasColumnName("path");
+
+ b.Property("ScanIntervalMinutes")
+ .HasColumnType("integer")
+ .HasColumnName("scan-interval-minutes");
+
+ b.Property("UpdatedAt")
+ .HasColumnType("timestamp with time zone")
+ .HasColumnName("updated-at");
+
+ b.HasKey("Id")
+ .HasName("pk-managed-library-root");
+
+ b.HasIndex("Path")
+ .IsUnique()
+ .HasDatabaseName("idx-managed-library-root-path");
+
+ b.ToTable("managed-library-root", t =>
+ {
+ t.HasComment("文件库根目录");
+ });
+ });
+
+ modelBuilder.Entity("FileShare_EFCore.Models.ManagedThumbnailMap", b =>
+ {
+ b.Property("Id")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("integer")
+ .HasColumnName("id");
+
+ NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id"));
+
+ b.Property("ContentType")
+ .IsRequired()
+ .HasMaxLength(100)
+ .HasColumnType("character varying(100)")
+ .HasColumnName("content-type");
+
+ b.Property("CreatedAt")
+ .HasColumnType("timestamp with time zone")
+ .HasColumnName("created-at");
+
+ b.Property("LibraryRootId")
+ .HasColumnType("integer")
+ .HasColumnName("library-root-id");
+
+ b.Property("RelativePath")
+ .IsRequired()
+ .HasMaxLength(1024)
+ .HasColumnType("character varying(1024)")
+ .HasColumnName("relative-path");
+
+ b.Property("UpdatedAt")
+ .HasColumnType("timestamp with time zone")
+ .HasColumnName("updated-at");
+
+ b.HasKey("Id")
+ .HasName("pk-managed-thumbnail-map");
+
+ b.HasIndex("LibraryRootId")
+ .HasDatabaseName("idx-managed-thumbnail-map-root-id");
+
+ b.HasIndex("RelativePath")
+ .IsUnique()
+ .HasDatabaseName("idx-managed-thumbnail-map-relative-path");
+
+ b.ToTable("managed-thumbnail-map", t =>
+ {
+ t.HasComment("文件缩略图映射记录");
+ });
+ });
+
+ modelBuilder.Entity("FileShare_EFCore.Models.UserEntity", b =>
+ {
+ b.Property("Id")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("integer")
+ .HasColumnName("id")
+ .HasComment("用户主键");
+
+ NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id"));
+
+ b.Property("CreatedAt")
+ .HasColumnType("timestamp with time zone")
+ .HasColumnName("created-at")
+ .HasComment("创建时间");
+
+ b.Property("Email")
+ .HasMaxLength(200)
+ .HasColumnType("character varying(200)")
+ .HasColumnName("email")
+ .HasComment("用户邮箱");
+
+ b.Property("Name")
+ .HasMaxLength(100)
+ .HasColumnType("character varying(100)")
+ .HasColumnName("name")
+ .HasComment("用户名称");
+
+ b.Property("PasswordHash")
+ .HasMaxLength(200)
+ .HasColumnType("character varying(200)")
+ .HasColumnName("password-hash")
+ .HasComment("密码哈希值");
+
+ b.Property("PhoneNumber")
+ .HasMaxLength(50)
+ .HasColumnType("character varying(50)")
+ .HasColumnName("phone-number")
+ .HasComment("电话号码");
+
+ b.Property("UpdatedAt")
+ .HasColumnType("timestamp with time zone")
+ .HasColumnName("updated-at")
+ .HasComment("更新时间");
+
+ b.HasKey("Id")
+ .HasName("pk-user");
+
+ b.ToTable("user", t =>
+ {
+ t.HasComment("用户实体,演示数据库 CRUD 操作");
+ });
+ });
+
+ modelBuilder.Entity("FileShare_EFCore.Models.WeatherForecastEntity", b =>
+ {
+ b.Property("Id")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("integer")
+ .HasColumnName("id")
+ .HasComment("天气预报主键");
+
+ NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id"));
+
+ b.Property("CreatedAt")
+ .HasColumnType("timestamp with time zone")
+ .HasColumnName("created-at")
+ .HasComment("创建时间");
+
+ b.Property("Date")
+ .HasColumnType("date")
+ .HasColumnName("date")
+ .HasComment("预报日期");
+
+ b.Property("Summary")
+ .HasMaxLength(200)
+ .HasColumnType("character varying(200)")
+ .HasColumnName("summary")
+ .HasComment("天气摘要");
+
+ b.Property("TemperatureC")
+ .HasColumnType("integer")
+ .HasColumnName("temperature-c")
+ .HasComment("摄氏温度");
+
+ b.Property("UpdatedAt")
+ .HasColumnType("timestamp with time zone")
+ .HasColumnName("updated-at")
+ .HasComment("更新时间");
+
+ b.HasKey("Id")
+ .HasName("pk-weather-forecast");
+
+ b.ToTable("weather-forecast", t =>
+ {
+ t.HasComment("天气预报数据实体");
+ });
+ });
+
+ modelBuilder.Entity("FileShare_EFCore.Models.ManagedFileRecord", b =>
+ {
+ b.HasOne("FileShare_EFCore.Models.ManagedLibraryRoot", "LibraryRoot")
+ .WithMany("Files")
+ .HasForeignKey("LibraryRootId")
+ .OnDelete(DeleteBehavior.Cascade)
+ .IsRequired();
+
+ b.HasOne("FileShare_EFCore.Models.ManagedThumbnailMap", "Thumbnail")
+ .WithMany("Files")
+ .HasForeignKey("ThumbnailId")
+ .OnDelete(DeleteBehavior.SetNull);
+
+ b.Navigation("LibraryRoot");
+
+ b.Navigation("Thumbnail");
+ });
+
+ modelBuilder.Entity("FileShare_EFCore.Models.ManagedThumbnailMap", b =>
+ {
+ b.HasOne("FileShare_EFCore.Models.ManagedLibraryRoot", "LibraryRoot")
+ .WithMany("Thumbnails")
+ .HasForeignKey("LibraryRootId")
+ .OnDelete(DeleteBehavior.Cascade)
+ .IsRequired();
+
+ b.Navigation("LibraryRoot");
+ });
+
+ modelBuilder.Entity("FileShare_EFCore.Models.ManagedLibraryRoot", b =>
+ {
+ b.Navigation("Files");
+
+ b.Navigation("Thumbnails");
+ });
+
+ modelBuilder.Entity("FileShare_EFCore.Models.ManagedThumbnailMap", b =>
+ {
+ b.Navigation("Files");
+ });
+#pragma warning restore 612, 618
+ }
+ }
+}
diff --git a/FileShare-EFCore/Migrations/PostgreSQL/20260523023643_AutoMigration_20260523103531.cs b/FileShare-EFCore/Migrations/PostgreSQL/20260523023643_AutoMigration_20260523103531.cs
new file mode 100644
index 0000000..e63ff72
--- /dev/null
+++ b/FileShare-EFCore/Migrations/PostgreSQL/20260523023643_AutoMigration_20260523103531.cs
@@ -0,0 +1,38 @@
+using System;
+using Microsoft.EntityFrameworkCore.Migrations;
+
+#nullable disable
+
+namespace FileShare_EFCore.Migrations.PostgreSQL
+{
+ ///
+ public partial class AutoMigration_20260523103531 : Migration
+ {
+ ///
+ protected override void Up(MigrationBuilder migrationBuilder)
+ {
+ migrationBuilder.AddColumn(
+ name: "file-creation-time-utc",
+ table: "managed-file-record",
+ type: "timestamp with time zone",
+ nullable: true);
+
+ migrationBuilder.CreateIndex(
+ name: "idx-managed-file-record-file-creation-time",
+ table: "managed-file-record",
+ column: "file-creation-time-utc");
+ }
+
+ ///
+ protected override void Down(MigrationBuilder migrationBuilder)
+ {
+ migrationBuilder.DropIndex(
+ name: "idx-managed-file-record-file-creation-time",
+ table: "managed-file-record");
+
+ migrationBuilder.DropColumn(
+ name: "file-creation-time-utc",
+ table: "managed-file-record");
+ }
+ }
+}
diff --git a/FileShare-EFCore/Migrations/PostgreSQL/PostgreSqlAppDataContextModelSnapshot.cs b/FileShare-EFCore/Migrations/PostgreSQL/PostgreSqlAppDataContextModelSnapshot.cs
index f84c2a0..5534954 100644
--- a/FileShare-EFCore/Migrations/PostgreSQL/PostgreSqlAppDataContextModelSnapshot.cs
+++ b/FileShare-EFCore/Migrations/PostgreSQL/PostgreSqlAppDataContextModelSnapshot.cs
@@ -119,6 +119,10 @@ namespace FileShare_EFCore.Migrations.PostgreSQL
.HasColumnType("character varying(32)")
.HasColumnName("extension");
+ b.Property("FileCreationTimeUtc")
+ .HasColumnType("timestamp with time zone")
+ .HasColumnName("file-creation-time-utc");
+
b.Property("FileName")
.IsRequired()
.HasMaxLength(260)
@@ -180,6 +184,9 @@ namespace FileShare_EFCore.Migrations.PostgreSQL
.IsUnique()
.HasDatabaseName("idx-managed-file-record-absolute-path");
+ b.HasIndex("FileCreationTimeUtc")
+ .HasDatabaseName("idx-managed-file-record-file-creation-time");
+
b.HasIndex("LastPlayedAt")
.HasDatabaseName("idx-managed-file-record-last-played-at");
diff --git a/FileShare-EFCore/Migrations/SQLite/20260523023607_AutoMigration_20260523103531.Designer.cs b/FileShare-EFCore/Migrations/SQLite/20260523023607_AutoMigration_20260523103531.Designer.cs
new file mode 100644
index 0000000..5fe6daf
--- /dev/null
+++ b/FileShare-EFCore/Migrations/SQLite/20260523023607_AutoMigration_20260523103531.Designer.cs
@@ -0,0 +1,453 @@
+//
+using System;
+using FileShare_EFCore.Database;
+using Microsoft.EntityFrameworkCore;
+using Microsoft.EntityFrameworkCore.Infrastructure;
+using Microsoft.EntityFrameworkCore.Migrations;
+using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
+
+#nullable disable
+
+namespace FileShare_EFCore.Migrations.SQLite
+{
+ [DbContext(typeof(SqliteAppDataContext))]
+ [Migration("20260523023607_AutoMigration_20260523103531")]
+ partial class AutoMigration_20260523103531
+ {
+ ///
+ protected override void BuildTargetModel(ModelBuilder modelBuilder)
+ {
+#pragma warning disable 612, 618
+ modelBuilder.HasAnnotation("ProductVersion", "10.0.7");
+
+ modelBuilder.Entity("FileShare_EFCore.Models.ApiRefreshTokenEntity", b =>
+ {
+ b.Property("Id")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("INTEGER")
+ .HasColumnName("id");
+
+ b.Property("CreatedAt")
+ .HasColumnType("TEXT")
+ .HasColumnName("created-at");
+
+ b.Property("Device")
+ .HasMaxLength(200)
+ .HasColumnType("TEXT")
+ .HasColumnName("device");
+
+ b.Property("ExpiresAt")
+ .HasColumnType("TEXT")
+ .HasColumnName("expires-at");
+
+ b.Property("IpAddress")
+ .HasMaxLength(64)
+ .HasColumnType("TEXT")
+ .HasColumnName("ip-address");
+
+ b.Property("ReplacedByTokenHash")
+ .HasMaxLength(128)
+ .HasColumnType("TEXT")
+ .HasColumnName("replaced-by-token-hash");
+
+ b.Property("RevokedAt")
+ .HasColumnType("TEXT")
+ .HasColumnName("revoked-at");
+
+ b.Property("TokenHash")
+ .IsRequired()
+ .HasMaxLength(128)
+ .HasColumnType("TEXT")
+ .HasColumnName("token-hash");
+
+ b.Property("UserId")
+ .HasColumnType("INTEGER")
+ .HasColumnName("user-id");
+
+ b.HasKey("Id")
+ .HasName("pk-api-refresh-token");
+
+ b.HasIndex("TokenHash")
+ .IsUnique()
+ .HasDatabaseName("idx-api-refresh-token-hash");
+
+ b.HasIndex("UserId")
+ .HasDatabaseName("idx-api-refresh-token-user-id");
+
+ b.ToTable("api-refresh-token", t =>
+ {
+ t.HasComment("API refresh token");
+ });
+ });
+
+ modelBuilder.Entity("FileShare_EFCore.Models.ManagedFileRecord", b =>
+ {
+ b.Property("Id")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("INTEGER")
+ .HasColumnName("id");
+
+ b.Property("AbsolutePath")
+ .IsRequired()
+ .HasMaxLength(2048)
+ .HasColumnType("TEXT")
+ .HasColumnName("absolute-path");
+
+ b.Property("ContentType")
+ .IsRequired()
+ .HasMaxLength(100)
+ .HasColumnType("TEXT")
+ .HasColumnName("content-type");
+
+ b.Property("CreatedAt")
+ .HasColumnType("TEXT")
+ .HasColumnName("created-at");
+
+ b.Property("Exists")
+ .HasColumnType("INTEGER")
+ .HasColumnName("exists");
+
+ b.Property("Extension")
+ .IsRequired()
+ .HasMaxLength(32)
+ .HasColumnType("TEXT")
+ .HasColumnName("extension");
+
+ b.Property("FileCreationTimeUtc")
+ .HasColumnType("TEXT")
+ .HasColumnName("file-creation-time-utc");
+
+ b.Property("FileName")
+ .IsRequired()
+ .HasMaxLength(260)
+ .HasColumnType("TEXT")
+ .HasColumnName("file-name");
+
+ b.Property("LastPlayedAt")
+ .HasColumnType("TEXT")
+ .HasColumnName("last-played-at");
+
+ b.Property("LastSeenAt")
+ .HasColumnType("TEXT")
+ .HasColumnName("last-seen-at");
+
+ b.Property("LastWriteTimeUtc")
+ .HasColumnType("TEXT")
+ .HasColumnName("last-write-time-utc");
+
+ b.Property("LibraryRootId")
+ .HasColumnType("INTEGER")
+ .HasColumnName("library-root-id");
+
+ b.Property("MediaType")
+ .IsRequired()
+ .HasMaxLength(20)
+ .HasColumnType("TEXT")
+ .HasColumnName("media-type");
+
+ b.Property("PlaybackPosition")
+ .HasColumnType("REAL")
+ .HasColumnName("playback-position");
+
+ b.Property("RelativePath")
+ .IsRequired()
+ .HasMaxLength(1024)
+ .HasColumnType("TEXT")
+ .HasColumnName("relative-path");
+
+ b.Property("SizeBytes")
+ .HasColumnType("INTEGER")
+ .HasColumnName("size-bytes");
+
+ b.Property("ThumbnailId")
+ .HasColumnType("INTEGER")
+ .HasColumnName("thumbnail-id");
+
+ b.Property("UpdatedAt")
+ .HasColumnType("TEXT")
+ .HasColumnName("updated-at");
+
+ b.Property("VideoDuration")
+ .HasColumnType("REAL")
+ .HasColumnName("video-duration");
+
+ b.HasKey("Id")
+ .HasName("pk-managed-file-record");
+
+ b.HasIndex("AbsolutePath")
+ .IsUnique()
+ .HasDatabaseName("idx-managed-file-record-absolute-path");
+
+ b.HasIndex("FileCreationTimeUtc")
+ .HasDatabaseName("idx-managed-file-record-file-creation-time");
+
+ b.HasIndex("LastPlayedAt")
+ .HasDatabaseName("idx-managed-file-record-last-played-at");
+
+ b.HasIndex("LibraryRootId")
+ .HasDatabaseName("idx-managed-file-record-root-id");
+
+ b.HasIndex("ThumbnailId")
+ .HasDatabaseName("idx-managed-file-record-thumbnail-id");
+
+ b.HasIndex("MediaType", "Exists")
+ .HasDatabaseName("idx-managed-file-record-media-type-exists");
+
+ b.ToTable("managed-file-record", t =>
+ {
+ t.HasComment("文件库文件记录");
+ });
+ });
+
+ modelBuilder.Entity("FileShare_EFCore.Models.ManagedLibraryRoot", b =>
+ {
+ b.Property("Id")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("INTEGER")
+ .HasColumnName("id");
+
+ b.Property("CreatedAt")
+ .HasColumnType("TEXT")
+ .HasColumnName("created-at");
+
+ b.Property("DisplayName")
+ .IsRequired()
+ .HasMaxLength(200)
+ .HasColumnType("TEXT")
+ .HasColumnName("display-name");
+
+ b.Property("IsAvailable")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("INTEGER")
+ .HasDefaultValue(true)
+ .HasColumnName("is-available");
+
+ b.Property("IsEnabled")
+ .HasColumnType("INTEGER")
+ .HasColumnName("is-enabled");
+
+ b.Property("LastScanCompletedAt")
+ .HasColumnType("TEXT")
+ .HasColumnName("last-scan-completed-at");
+
+ b.Property("LastScanError")
+ .HasMaxLength(2000)
+ .HasColumnType("TEXT")
+ .HasColumnName("last-scan-error");
+
+ b.Property("LastScanStartedAt")
+ .HasColumnType("TEXT")
+ .HasColumnName("last-scan-started-at");
+
+ b.Property("Path")
+ .IsRequired()
+ .HasMaxLength(1024)
+ .HasColumnType("TEXT")
+ .HasColumnName("path");
+
+ b.Property("ScanIntervalMinutes")
+ .HasColumnType("INTEGER")
+ .HasColumnName("scan-interval-minutes");
+
+ b.Property("UpdatedAt")
+ .HasColumnType("TEXT")
+ .HasColumnName("updated-at");
+
+ b.HasKey("Id")
+ .HasName("pk-managed-library-root");
+
+ b.HasIndex("Path")
+ .IsUnique()
+ .HasDatabaseName("idx-managed-library-root-path");
+
+ b.ToTable("managed-library-root", t =>
+ {
+ t.HasComment("文件库根目录");
+ });
+ });
+
+ modelBuilder.Entity("FileShare_EFCore.Models.ManagedThumbnailMap", b =>
+ {
+ b.Property("Id")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("INTEGER")
+ .HasColumnName("id");
+
+ b.Property("ContentType")
+ .IsRequired()
+ .HasMaxLength(100)
+ .HasColumnType("TEXT")
+ .HasColumnName("content-type");
+
+ b.Property("CreatedAt")
+ .HasColumnType("TEXT")
+ .HasColumnName("created-at");
+
+ b.Property("LibraryRootId")
+ .HasColumnType("INTEGER")
+ .HasColumnName("library-root-id");
+
+ b.Property("RelativePath")
+ .IsRequired()
+ .HasMaxLength(1024)
+ .HasColumnType("TEXT")
+ .HasColumnName("relative-path");
+
+ b.Property("UpdatedAt")
+ .HasColumnType("TEXT")
+ .HasColumnName("updated-at");
+
+ b.HasKey("Id")
+ .HasName("pk-managed-thumbnail-map");
+
+ b.HasIndex("LibraryRootId")
+ .HasDatabaseName("idx-managed-thumbnail-map-root-id");
+
+ b.HasIndex("RelativePath")
+ .IsUnique()
+ .HasDatabaseName("idx-managed-thumbnail-map-relative-path");
+
+ b.ToTable("managed-thumbnail-map", t =>
+ {
+ t.HasComment("文件缩略图映射记录");
+ });
+ });
+
+ modelBuilder.Entity("FileShare_EFCore.Models.UserEntity", b =>
+ {
+ b.Property("Id")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("INTEGER")
+ .HasColumnName("id")
+ .HasComment("用户主键");
+
+ b.Property("CreatedAt")
+ .HasColumnType("TEXT")
+ .HasColumnName("created-at")
+ .HasComment("创建时间");
+
+ b.Property("Email")
+ .HasMaxLength(200)
+ .HasColumnType("TEXT")
+ .HasColumnName("email")
+ .HasComment("用户邮箱");
+
+ b.Property("Name")
+ .HasMaxLength(100)
+ .HasColumnType("TEXT")
+ .HasColumnName("name")
+ .HasComment("用户名称");
+
+ b.Property("PasswordHash")
+ .HasMaxLength(200)
+ .HasColumnType("TEXT")
+ .HasColumnName("password-hash")
+ .HasComment("密码哈希值");
+
+ b.Property("PhoneNumber")
+ .HasMaxLength(50)
+ .HasColumnType("TEXT")
+ .HasColumnName("phone-number")
+ .HasComment("电话号码");
+
+ b.Property("UpdatedAt")
+ .HasColumnType("TEXT")
+ .HasColumnName("updated-at")
+ .HasComment("更新时间");
+
+ b.HasKey("Id")
+ .HasName("pk-user");
+
+ b.ToTable("user", t =>
+ {
+ t.HasComment("用户实体,演示数据库 CRUD 操作");
+ });
+ });
+
+ modelBuilder.Entity("FileShare_EFCore.Models.WeatherForecastEntity", b =>
+ {
+ b.Property("Id")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("INTEGER")
+ .HasColumnName("id")
+ .HasComment("天气预报主键");
+
+ b.Property("CreatedAt")
+ .HasColumnType("TEXT")
+ .HasColumnName("created-at")
+ .HasComment("创建时间");
+
+ b.Property("Date")
+ .HasColumnType("TEXT")
+ .HasColumnName("date")
+ .HasComment("预报日期");
+
+ b.Property("Summary")
+ .HasMaxLength(200)
+ .HasColumnType("TEXT")
+ .HasColumnName("summary")
+ .HasComment("天气摘要");
+
+ b.Property("TemperatureC")
+ .HasColumnType("INTEGER")
+ .HasColumnName("temperature-c")
+ .HasComment("摄氏温度");
+
+ b.Property("UpdatedAt")
+ .HasColumnType("TEXT")
+ .HasColumnName("updated-at")
+ .HasComment("更新时间");
+
+ b.HasKey("Id")
+ .HasName("pk-weather-forecast");
+
+ b.ToTable("weather-forecast", t =>
+ {
+ t.HasComment("天气预报数据实体");
+ });
+ });
+
+ modelBuilder.Entity("FileShare_EFCore.Models.ManagedFileRecord", b =>
+ {
+ b.HasOne("FileShare_EFCore.Models.ManagedLibraryRoot", "LibraryRoot")
+ .WithMany("Files")
+ .HasForeignKey("LibraryRootId")
+ .OnDelete(DeleteBehavior.Cascade)
+ .IsRequired();
+
+ b.HasOne("FileShare_EFCore.Models.ManagedThumbnailMap", "Thumbnail")
+ .WithMany("Files")
+ .HasForeignKey("ThumbnailId")
+ .OnDelete(DeleteBehavior.SetNull);
+
+ b.Navigation("LibraryRoot");
+
+ b.Navigation("Thumbnail");
+ });
+
+ modelBuilder.Entity("FileShare_EFCore.Models.ManagedThumbnailMap", b =>
+ {
+ b.HasOne("FileShare_EFCore.Models.ManagedLibraryRoot", "LibraryRoot")
+ .WithMany("Thumbnails")
+ .HasForeignKey("LibraryRootId")
+ .OnDelete(DeleteBehavior.Cascade)
+ .IsRequired();
+
+ b.Navigation("LibraryRoot");
+ });
+
+ modelBuilder.Entity("FileShare_EFCore.Models.ManagedLibraryRoot", b =>
+ {
+ b.Navigation("Files");
+
+ b.Navigation("Thumbnails");
+ });
+
+ modelBuilder.Entity("FileShare_EFCore.Models.ManagedThumbnailMap", b =>
+ {
+ b.Navigation("Files");
+ });
+#pragma warning restore 612, 618
+ }
+ }
+}
diff --git a/FileShare-EFCore/Migrations/SQLite/20260523023607_AutoMigration_20260523103531.cs b/FileShare-EFCore/Migrations/SQLite/20260523023607_AutoMigration_20260523103531.cs
new file mode 100644
index 0000000..d0cfa99
--- /dev/null
+++ b/FileShare-EFCore/Migrations/SQLite/20260523023607_AutoMigration_20260523103531.cs
@@ -0,0 +1,38 @@
+using System;
+using Microsoft.EntityFrameworkCore.Migrations;
+
+#nullable disable
+
+namespace FileShare_EFCore.Migrations.SQLite
+{
+ ///
+ public partial class AutoMigration_20260523103531 : Migration
+ {
+ ///
+ protected override void Up(MigrationBuilder migrationBuilder)
+ {
+ migrationBuilder.AddColumn(
+ name: "file-creation-time-utc",
+ table: "managed-file-record",
+ type: "TEXT",
+ nullable: true);
+
+ migrationBuilder.CreateIndex(
+ name: "idx-managed-file-record-file-creation-time",
+ table: "managed-file-record",
+ column: "file-creation-time-utc");
+ }
+
+ ///
+ protected override void Down(MigrationBuilder migrationBuilder)
+ {
+ migrationBuilder.DropIndex(
+ name: "idx-managed-file-record-file-creation-time",
+ table: "managed-file-record");
+
+ migrationBuilder.DropColumn(
+ name: "file-creation-time-utc",
+ table: "managed-file-record");
+ }
+ }
+}
diff --git a/FileShare-EFCore/Migrations/SQLite/SqliteAppDataContextModelSnapshot.cs b/FileShare-EFCore/Migrations/SQLite/SqliteAppDataContextModelSnapshot.cs
index b71579a..0cbc4bb 100644
--- a/FileShare-EFCore/Migrations/SQLite/SqliteAppDataContextModelSnapshot.cs
+++ b/FileShare-EFCore/Migrations/SQLite/SqliteAppDataContextModelSnapshot.cs
@@ -110,6 +110,10 @@ namespace FileShare_EFCore.Migrations.SQLite
.HasColumnType("TEXT")
.HasColumnName("extension");
+ b.Property("FileCreationTimeUtc")
+ .HasColumnType("TEXT")
+ .HasColumnName("file-creation-time-utc");
+
b.Property("FileName")
.IsRequired()
.HasMaxLength(260)
@@ -171,6 +175,9 @@ namespace FileShare_EFCore.Migrations.SQLite
.IsUnique()
.HasDatabaseName("idx-managed-file-record-absolute-path");
+ b.HasIndex("FileCreationTimeUtc")
+ .HasDatabaseName("idx-managed-file-record-file-creation-time");
+
b.HasIndex("LastPlayedAt")
.HasDatabaseName("idx-managed-file-record-last-played-at");
diff --git a/FileShare-EFCore/Migrations/SqlServer/20260523023625_AutoMigration_20260523103531.Designer.cs b/FileShare-EFCore/Migrations/SqlServer/20260523023625_AutoMigration_20260523103531.Designer.cs
new file mode 100644
index 0000000..c30264c
--- /dev/null
+++ b/FileShare-EFCore/Migrations/SqlServer/20260523023625_AutoMigration_20260523103531.Designer.cs
@@ -0,0 +1,470 @@
+//
+using System;
+using FileShare_EFCore.Database;
+using Microsoft.EntityFrameworkCore;
+using Microsoft.EntityFrameworkCore.Infrastructure;
+using Microsoft.EntityFrameworkCore.Metadata;
+using Microsoft.EntityFrameworkCore.Migrations;
+using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
+
+#nullable disable
+
+namespace FileShare_EFCore.Migrations.SqlServer
+{
+ [DbContext(typeof(SqlServerAppDataContext))]
+ [Migration("20260523023625_AutoMigration_20260523103531")]
+ partial class AutoMigration_20260523103531
+ {
+ ///
+ protected override void BuildTargetModel(ModelBuilder modelBuilder)
+ {
+#pragma warning disable 612, 618
+ modelBuilder
+ .HasAnnotation("ProductVersion", "10.0.7")
+ .HasAnnotation("Relational:MaxIdentifierLength", 128);
+
+ SqlServerModelBuilderExtensions.UseIdentityColumns(modelBuilder);
+
+ modelBuilder.Entity("FileShare_EFCore.Models.ApiRefreshTokenEntity", b =>
+ {
+ b.Property("Id")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("bigint")
+ .HasColumnName("id");
+
+ SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id"));
+
+ b.Property("CreatedAt")
+ .HasColumnType("datetime2")
+ .HasColumnName("created-at");
+
+ b.Property("Device")
+ .HasMaxLength(200)
+ .HasColumnType("nvarchar(200)")
+ .HasColumnName("device");
+
+ b.Property("ExpiresAt")
+ .HasColumnType("datetime2")
+ .HasColumnName("expires-at");
+
+ b.Property("IpAddress")
+ .HasMaxLength(64)
+ .HasColumnType("nvarchar(64)")
+ .HasColumnName("ip-address");
+
+ b.Property("ReplacedByTokenHash")
+ .HasMaxLength(128)
+ .HasColumnType("nvarchar(128)")
+ .HasColumnName("replaced-by-token-hash");
+
+ b.Property("RevokedAt")
+ .HasColumnType("datetime2")
+ .HasColumnName("revoked-at");
+
+ b.Property("TokenHash")
+ .IsRequired()
+ .HasMaxLength(128)
+ .HasColumnType("nvarchar(128)")
+ .HasColumnName("token-hash");
+
+ b.Property("UserId")
+ .HasColumnType("int")
+ .HasColumnName("user-id");
+
+ b.HasKey("Id")
+ .HasName("pk-api-refresh-token");
+
+ b.HasIndex("TokenHash")
+ .IsUnique()
+ .HasDatabaseName("idx-api-refresh-token-hash");
+
+ b.HasIndex("UserId")
+ .HasDatabaseName("idx-api-refresh-token-user-id");
+
+ b.ToTable("api-refresh-token", t =>
+ {
+ t.HasComment("API refresh token");
+ });
+ });
+
+ modelBuilder.Entity("FileShare_EFCore.Models.ManagedFileRecord", b =>
+ {
+ b.Property("Id")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("int")
+ .HasColumnName("id");
+
+ SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id"));
+
+ b.Property("AbsolutePath")
+ .IsRequired()
+ .HasMaxLength(2048)
+ .HasColumnType("nvarchar(2048)")
+ .HasColumnName("absolute-path");
+
+ b.Property("ContentType")
+ .IsRequired()
+ .HasMaxLength(100)
+ .HasColumnType("nvarchar(100)")
+ .HasColumnName("content-type");
+
+ b.Property("CreatedAt")
+ .HasColumnType("datetime2")
+ .HasColumnName("created-at");
+
+ b.Property("Exists")
+ .HasColumnType("bit")
+ .HasColumnName("exists");
+
+ b.Property("Extension")
+ .IsRequired()
+ .HasMaxLength(32)
+ .HasColumnType("nvarchar(32)")
+ .HasColumnName("extension");
+
+ b.Property("FileCreationTimeUtc")
+ .HasColumnType("datetime2")
+ .HasColumnName("file-creation-time-utc");
+
+ b.Property("FileName")
+ .IsRequired()
+ .HasMaxLength(260)
+ .HasColumnType("nvarchar(260)")
+ .HasColumnName("file-name");
+
+ b.Property("LastPlayedAt")
+ .HasColumnType("datetime2")
+ .HasColumnName("last-played-at");
+
+ b.Property("LastSeenAt")
+ .HasColumnType("datetime2")
+ .HasColumnName("last-seen-at");
+
+ b.Property("LastWriteTimeUtc")
+ .HasColumnType("datetime2")
+ .HasColumnName("last-write-time-utc");
+
+ b.Property("LibraryRootId")
+ .HasColumnType("int")
+ .HasColumnName("library-root-id");
+
+ b.Property("MediaType")
+ .IsRequired()
+ .HasMaxLength(20)
+ .HasColumnType("nvarchar(20)")
+ .HasColumnName("media-type");
+
+ b.Property("PlaybackPosition")
+ .HasColumnType("float")
+ .HasColumnName("playback-position");
+
+ b.Property("RelativePath")
+ .IsRequired()
+ .HasMaxLength(1024)
+ .HasColumnType("nvarchar(1024)")
+ .HasColumnName("relative-path");
+
+ b.Property("SizeBytes")
+ .HasColumnType("bigint")
+ .HasColumnName("size-bytes");
+
+ b.Property("ThumbnailId")
+ .HasColumnType("int")
+ .HasColumnName("thumbnail-id");
+
+ b.Property("UpdatedAt")
+ .HasColumnType("datetime2")
+ .HasColumnName("updated-at");
+
+ b.Property("VideoDuration")
+ .HasColumnType("float")
+ .HasColumnName("video-duration");
+
+ b.HasKey("Id")
+ .HasName("pk-managed-file-record");
+
+ b.HasIndex("AbsolutePath")
+ .IsUnique()
+ .HasDatabaseName("idx-managed-file-record-absolute-path");
+
+ b.HasIndex("FileCreationTimeUtc")
+ .HasDatabaseName("idx-managed-file-record-file-creation-time");
+
+ b.HasIndex("LastPlayedAt")
+ .HasDatabaseName("idx-managed-file-record-last-played-at");
+
+ b.HasIndex("LibraryRootId")
+ .HasDatabaseName("idx-managed-file-record-root-id");
+
+ b.HasIndex("ThumbnailId")
+ .HasDatabaseName("idx-managed-file-record-thumbnail-id");
+
+ b.HasIndex("MediaType", "Exists")
+ .HasDatabaseName("idx-managed-file-record-media-type-exists");
+
+ b.ToTable("managed-file-record", t =>
+ {
+ t.HasComment("文件库文件记录");
+ });
+ });
+
+ modelBuilder.Entity("FileShare_EFCore.Models.ManagedLibraryRoot", b =>
+ {
+ b.Property("Id")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("int")
+ .HasColumnName("id");
+
+ SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id"));
+
+ b.Property("CreatedAt")
+ .HasColumnType("datetime2")
+ .HasColumnName("created-at");
+
+ b.Property("DisplayName")
+ .IsRequired()
+ .HasMaxLength(200)
+ .HasColumnType("nvarchar(200)")
+ .HasColumnName("display-name");
+
+ b.Property("IsAvailable")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("bit")
+ .HasDefaultValue(true)
+ .HasColumnName("is-available");
+
+ b.Property("IsEnabled")
+ .HasColumnType("bit")
+ .HasColumnName("is-enabled");
+
+ b.Property("LastScanCompletedAt")
+ .HasColumnType("datetime2")
+ .HasColumnName("last-scan-completed-at");
+
+ b.Property("LastScanError")
+ .HasMaxLength(2000)
+ .HasColumnType("nvarchar(2000)")
+ .HasColumnName("last-scan-error");
+
+ b.Property("LastScanStartedAt")
+ .HasColumnType("datetime2")
+ .HasColumnName("last-scan-started-at");
+
+ b.Property("Path")
+ .IsRequired()
+ .HasMaxLength(1024)
+ .HasColumnType("nvarchar(1024)")
+ .HasColumnName("path");
+
+ b.Property("ScanIntervalMinutes")
+ .HasColumnType("int")
+ .HasColumnName("scan-interval-minutes");
+
+ b.Property("UpdatedAt")
+ .HasColumnType("datetime2")
+ .HasColumnName("updated-at");
+
+ b.HasKey("Id")
+ .HasName("pk-managed-library-root");
+
+ b.HasIndex("Path")
+ .IsUnique()
+ .HasDatabaseName("idx-managed-library-root-path");
+
+ b.ToTable("managed-library-root", t =>
+ {
+ t.HasComment("文件库根目录");
+ });
+ });
+
+ modelBuilder.Entity("FileShare_EFCore.Models.ManagedThumbnailMap", b =>
+ {
+ b.Property("Id")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("int")
+ .HasColumnName("id");
+
+ SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id"));
+
+ b.Property("ContentType")
+ .IsRequired()
+ .HasMaxLength(100)
+ .HasColumnType("nvarchar(100)")
+ .HasColumnName("content-type");
+
+ b.Property("CreatedAt")
+ .HasColumnType("datetime2")
+ .HasColumnName("created-at");
+
+ b.Property("LibraryRootId")
+ .HasColumnType("int")
+ .HasColumnName("library-root-id");
+
+ b.Property("RelativePath")
+ .IsRequired()
+ .HasMaxLength(1024)
+ .HasColumnType("nvarchar(1024)")
+ .HasColumnName("relative-path");
+
+ b.Property("UpdatedAt")
+ .HasColumnType("datetime2")
+ .HasColumnName("updated-at");
+
+ b.HasKey("Id")
+ .HasName("pk-managed-thumbnail-map");
+
+ b.HasIndex("LibraryRootId")
+ .HasDatabaseName("idx-managed-thumbnail-map-root-id");
+
+ b.HasIndex("RelativePath")
+ .IsUnique()
+ .HasDatabaseName("idx-managed-thumbnail-map-relative-path");
+
+ b.ToTable("managed-thumbnail-map", t =>
+ {
+ t.HasComment("文件缩略图映射记录");
+ });
+ });
+
+ modelBuilder.Entity("FileShare_EFCore.Models.UserEntity", b =>
+ {
+ b.Property("Id")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("int")
+ .HasColumnName("id")
+ .HasComment("用户主键");
+
+ SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id"));
+
+ b.Property("CreatedAt")
+ .HasColumnType("datetime2")
+ .HasColumnName("created-at")
+ .HasComment("创建时间");
+
+ b.Property("Email")
+ .HasMaxLength(200)
+ .HasColumnType("nvarchar(200)")
+ .HasColumnName("email")
+ .HasComment("用户邮箱");
+
+ b.Property("Name")
+ .HasMaxLength(100)
+ .HasColumnType("nvarchar(100)")
+ .HasColumnName("name")
+ .HasComment("用户名称");
+
+ b.Property("PasswordHash")
+ .HasMaxLength(200)
+ .HasColumnType("nvarchar(200)")
+ .HasColumnName("password-hash")
+ .HasComment("密码哈希值");
+
+ b.Property("PhoneNumber")
+ .HasMaxLength(50)
+ .HasColumnType("nvarchar(50)")
+ .HasColumnName("phone-number")
+ .HasComment("电话号码");
+
+ b.Property("UpdatedAt")
+ .HasColumnType("datetime2")
+ .HasColumnName("updated-at")
+ .HasComment("更新时间");
+
+ b.HasKey("Id")
+ .HasName("pk-user");
+
+ b.ToTable("user", t =>
+ {
+ t.HasComment("用户实体,演示数据库 CRUD 操作");
+ });
+ });
+
+ modelBuilder.Entity("FileShare_EFCore.Models.WeatherForecastEntity", b =>
+ {
+ b.Property("Id")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("int")
+ .HasColumnName("id")
+ .HasComment("天气预报主键");
+
+ SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id"));
+
+ b.Property("CreatedAt")
+ .HasColumnType("datetime2")
+ .HasColumnName("created-at")
+ .HasComment("创建时间");
+
+ b.Property("Date")
+ .HasColumnType("date")
+ .HasColumnName("date")
+ .HasComment("预报日期");
+
+ b.Property("Summary")
+ .HasMaxLength(200)
+ .HasColumnType("nvarchar(200)")
+ .HasColumnName("summary")
+ .HasComment("天气摘要");
+
+ b.Property("TemperatureC")
+ .HasColumnType("int")
+ .HasColumnName("temperature-c")
+ .HasComment("摄氏温度");
+
+ b.Property("UpdatedAt")
+ .HasColumnType("datetime2")
+ .HasColumnName("updated-at")
+ .HasComment("更新时间");
+
+ b.HasKey("Id")
+ .HasName("pk-weather-forecast");
+
+ b.ToTable("weather-forecast", t =>
+ {
+ t.HasComment("天气预报数据实体");
+ });
+ });
+
+ modelBuilder.Entity("FileShare_EFCore.Models.ManagedFileRecord", b =>
+ {
+ b.HasOne("FileShare_EFCore.Models.ManagedLibraryRoot", "LibraryRoot")
+ .WithMany("Files")
+ .HasForeignKey("LibraryRootId")
+ .OnDelete(DeleteBehavior.Cascade)
+ .IsRequired();
+
+ b.HasOne("FileShare_EFCore.Models.ManagedThumbnailMap", "Thumbnail")
+ .WithMany("Files")
+ .HasForeignKey("ThumbnailId")
+ .OnDelete(DeleteBehavior.SetNull);
+
+ b.Navigation("LibraryRoot");
+
+ b.Navigation("Thumbnail");
+ });
+
+ modelBuilder.Entity("FileShare_EFCore.Models.ManagedThumbnailMap", b =>
+ {
+ b.HasOne("FileShare_EFCore.Models.ManagedLibraryRoot", "LibraryRoot")
+ .WithMany("Thumbnails")
+ .HasForeignKey("LibraryRootId")
+ .OnDelete(DeleteBehavior.Cascade)
+ .IsRequired();
+
+ b.Navigation("LibraryRoot");
+ });
+
+ modelBuilder.Entity("FileShare_EFCore.Models.ManagedLibraryRoot", b =>
+ {
+ b.Navigation("Files");
+
+ b.Navigation("Thumbnails");
+ });
+
+ modelBuilder.Entity("FileShare_EFCore.Models.ManagedThumbnailMap", b =>
+ {
+ b.Navigation("Files");
+ });
+#pragma warning restore 612, 618
+ }
+ }
+}
diff --git a/FileShare-EFCore/Migrations/SqlServer/20260523023625_AutoMigration_20260523103531.cs b/FileShare-EFCore/Migrations/SqlServer/20260523023625_AutoMigration_20260523103531.cs
new file mode 100644
index 0000000..4a7bfa3
--- /dev/null
+++ b/FileShare-EFCore/Migrations/SqlServer/20260523023625_AutoMigration_20260523103531.cs
@@ -0,0 +1,38 @@
+using System;
+using Microsoft.EntityFrameworkCore.Migrations;
+
+#nullable disable
+
+namespace FileShare_EFCore.Migrations.SqlServer
+{
+ ///
+ public partial class AutoMigration_20260523103531 : Migration
+ {
+ ///
+ protected override void Up(MigrationBuilder migrationBuilder)
+ {
+ migrationBuilder.AddColumn(
+ name: "file-creation-time-utc",
+ table: "managed-file-record",
+ type: "datetime2",
+ nullable: true);
+
+ migrationBuilder.CreateIndex(
+ name: "idx-managed-file-record-file-creation-time",
+ table: "managed-file-record",
+ column: "file-creation-time-utc");
+ }
+
+ ///