Merge pull request #5623 from barronpm/ef-cleanup2

EF Core Cleanup 2
This commit is contained in:
Bill Thornton
2021-05-04 23:59:15 -04:00
committed by GitHub
47 changed files with 1056 additions and 271 deletions

View File

@@ -149,21 +149,77 @@ namespace Jellyfin.Server.Implementations
modelBuilder.HasDefaultSchema("jellyfin");
// Collations
modelBuilder.Entity<User>()
.Property(user => user.Username)
.UseCollation("NOCASE");
// Delete behavior
modelBuilder.Entity<User>()
.HasOne(u => u.ProfileImage)
.WithOne()
.OnDelete(DeleteBehavior.Cascade);
modelBuilder.Entity<User>()
.HasMany(u => u.Permissions)
.WithOne()
.HasForeignKey(p => p.UserId)
.OnDelete(DeleteBehavior.Cascade);
modelBuilder.Entity<User>()
.HasMany(u => u.Preferences)
.WithOne()
.HasForeignKey(p => p.UserId)
.OnDelete(DeleteBehavior.Cascade);
modelBuilder.Entity<User>()
.HasMany(u => u.AccessSchedules)
.WithOne()
.OnDelete(DeleteBehavior.Cascade);
modelBuilder.Entity<User>()
.HasMany(u => u.DisplayPreferences)
.WithOne()
.OnDelete(DeleteBehavior.Cascade);
modelBuilder.Entity<User>()
.HasMany(u => u.ItemDisplayPreferences)
.WithOne()
.OnDelete(DeleteBehavior.Cascade);
modelBuilder.Entity<DisplayPreferences>()
.HasIndex(entity => entity.UserId)
.IsUnique(false);
.HasMany(d => d.HomeSections)
.WithOne()
.OnDelete(DeleteBehavior.Cascade);
// Indexes
modelBuilder.Entity<User>()
.HasIndex(entity => entity.Username)
.IsUnique();
modelBuilder.Entity<DisplayPreferences>()
.HasIndex(entity => new { entity.UserId, entity.ItemId, entity.Client })
.IsUnique();
modelBuilder.Entity<CustomItemDisplayPreferences>()
.HasIndex(entity => entity.UserId)
.IsUnique(false);
modelBuilder.Entity<CustomItemDisplayPreferences>()
.HasIndex(entity => new { entity.UserId, entity.ItemId, entity.Client, entity.Key })
.IsUnique();
// Used to get a user's permissions or a specific permission for a user.
// Also prevents multiple values being created for a user.
// Filtered over non-null user ids for when other entities (groups, API keys) get permissions
modelBuilder.Entity<Permission>()
.HasIndex(p => new { p.UserId, p.Kind })
.HasFilter("[UserId] IS NOT NULL")
.IsUnique();
modelBuilder.Entity<Preference>()
.HasIndex(p => new { p.UserId, p.Kind })
.HasFilter("[UserId] IS NOT NULL")
.IsUnique();
}
}
}

View File

@@ -0,0 +1,535 @@
#pragma warning disable CS1591
// <auto-generated />
using System;
using Jellyfin.Server.Implementations;
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Infrastructure;
using Microsoft.EntityFrameworkCore.Migrations;
using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
namespace Jellyfin.Server.Implementations.Migrations
{
[DbContext(typeof(JellyfinDb))]
[Migration("20210320181425_AddIndexesAndCollations")]
partial class AddIndexesAndCollations
{
protected override void BuildTargetModel(ModelBuilder modelBuilder)
{
#pragma warning disable 612, 618
modelBuilder
.HasDefaultSchema("jellyfin")
.HasAnnotation("ProductVersion", "5.0.3");
modelBuilder.Entity("Jellyfin.Data.Entities.AccessSchedule", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("INTEGER");
b.Property<int>("DayOfWeek")
.HasColumnType("INTEGER");
b.Property<double>("EndHour")
.HasColumnType("REAL");
b.Property<double>("StartHour")
.HasColumnType("REAL");
b.Property<Guid>("UserId")
.HasColumnType("TEXT");
b.HasKey("Id");
b.HasIndex("UserId");
b.ToTable("AccessSchedules");
});
modelBuilder.Entity("Jellyfin.Data.Entities.ActivityLog", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("INTEGER");
b.Property<DateTime>("DateCreated")
.HasColumnType("TEXT");
b.Property<string>("ItemId")
.HasMaxLength(256)
.HasColumnType("TEXT");
b.Property<int>("LogSeverity")
.HasColumnType("INTEGER");
b.Property<string>("Name")
.IsRequired()
.HasMaxLength(512)
.HasColumnType("TEXT");
b.Property<string>("Overview")
.HasMaxLength(512)
.HasColumnType("TEXT");
b.Property<uint>("RowVersion")
.IsConcurrencyToken()
.HasColumnType("INTEGER");
b.Property<string>("ShortOverview")
.HasMaxLength(512)
.HasColumnType("TEXT");
b.Property<string>("Type")
.IsRequired()
.HasMaxLength(256)
.HasColumnType("TEXT");
b.Property<Guid>("UserId")
.HasColumnType("TEXT");
b.HasKey("Id");
b.ToTable("ActivityLogs");
});
modelBuilder.Entity("Jellyfin.Data.Entities.CustomItemDisplayPreferences", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("INTEGER");
b.Property<string>("Client")
.IsRequired()
.HasMaxLength(32)
.HasColumnType("TEXT");
b.Property<Guid>("ItemId")
.HasColumnType("TEXT");
b.Property<string>("Key")
.IsRequired()
.HasColumnType("TEXT");
b.Property<Guid>("UserId")
.HasColumnType("TEXT");
b.Property<string>("Value")
.IsRequired()
.HasColumnType("TEXT");
b.HasKey("Id");
b.HasIndex("UserId", "ItemId", "Client", "Key")
.IsUnique();
b.ToTable("CustomItemDisplayPreferences");
});
modelBuilder.Entity("Jellyfin.Data.Entities.DisplayPreferences", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("INTEGER");
b.Property<int>("ChromecastVersion")
.HasColumnType("INTEGER");
b.Property<string>("Client")
.IsRequired()
.HasMaxLength(32)
.HasColumnType("TEXT");
b.Property<string>("DashboardTheme")
.HasMaxLength(32)
.HasColumnType("TEXT");
b.Property<bool>("EnableNextVideoInfoOverlay")
.HasColumnType("INTEGER");
b.Property<int?>("IndexBy")
.HasColumnType("INTEGER");
b.Property<Guid>("ItemId")
.HasColumnType("TEXT");
b.Property<int>("ScrollDirection")
.HasColumnType("INTEGER");
b.Property<bool>("ShowBackdrop")
.HasColumnType("INTEGER");
b.Property<bool>("ShowSidebar")
.HasColumnType("INTEGER");
b.Property<int>("SkipBackwardLength")
.HasColumnType("INTEGER");
b.Property<int>("SkipForwardLength")
.HasColumnType("INTEGER");
b.Property<string>("TvHome")
.HasMaxLength(32)
.HasColumnType("TEXT");
b.Property<Guid>("UserId")
.HasColumnType("TEXT");
b.HasKey("Id");
b.HasIndex("UserId", "ItemId", "Client")
.IsUnique();
b.ToTable("DisplayPreferences");
});
modelBuilder.Entity("Jellyfin.Data.Entities.HomeSection", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("INTEGER");
b.Property<int>("DisplayPreferencesId")
.HasColumnType("INTEGER");
b.Property<int>("Order")
.HasColumnType("INTEGER");
b.Property<int>("Type")
.HasColumnType("INTEGER");
b.HasKey("Id");
b.HasIndex("DisplayPreferencesId");
b.ToTable("HomeSection");
});
modelBuilder.Entity("Jellyfin.Data.Entities.ImageInfo", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("INTEGER");
b.Property<DateTime>("LastModified")
.HasColumnType("TEXT");
b.Property<string>("Path")
.IsRequired()
.HasMaxLength(512)
.HasColumnType("TEXT");
b.Property<Guid?>("UserId")
.HasColumnType("TEXT");
b.HasKey("Id");
b.HasIndex("UserId")
.IsUnique();
b.ToTable("ImageInfos");
});
modelBuilder.Entity("Jellyfin.Data.Entities.ItemDisplayPreferences", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("INTEGER");
b.Property<string>("Client")
.IsRequired()
.HasMaxLength(32)
.HasColumnType("TEXT");
b.Property<int?>("IndexBy")
.HasColumnType("INTEGER");
b.Property<Guid>("ItemId")
.HasColumnType("TEXT");
b.Property<bool>("RememberIndexing")
.HasColumnType("INTEGER");
b.Property<bool>("RememberSorting")
.HasColumnType("INTEGER");
b.Property<string>("SortBy")
.IsRequired()
.HasMaxLength(64)
.HasColumnType("TEXT");
b.Property<int>("SortOrder")
.HasColumnType("INTEGER");
b.Property<Guid>("UserId")
.HasColumnType("TEXT");
b.Property<int>("ViewType")
.HasColumnType("INTEGER");
b.HasKey("Id");
b.HasIndex("UserId");
b.ToTable("ItemDisplayPreferences");
});
modelBuilder.Entity("Jellyfin.Data.Entities.Permission", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("INTEGER");
b.Property<int>("Kind")
.HasColumnType("INTEGER");
b.Property<Guid?>("Permission_Permissions_Guid")
.HasColumnType("TEXT");
b.Property<uint>("RowVersion")
.IsConcurrencyToken()
.HasColumnType("INTEGER");
b.Property<Guid?>("UserId")
.HasColumnType("TEXT");
b.Property<bool>("Value")
.HasColumnType("INTEGER");
b.HasKey("Id");
b.HasIndex("UserId", "Kind")
.IsUnique()
.HasFilter("[UserId] IS NOT NULL");
b.ToTable("Permissions");
});
modelBuilder.Entity("Jellyfin.Data.Entities.Preference", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("INTEGER");
b.Property<int>("Kind")
.HasColumnType("INTEGER");
b.Property<Guid?>("Preference_Preferences_Guid")
.HasColumnType("TEXT");
b.Property<uint>("RowVersion")
.IsConcurrencyToken()
.HasColumnType("INTEGER");
b.Property<Guid?>("UserId")
.HasColumnType("TEXT");
b.Property<string>("Value")
.IsRequired()
.HasMaxLength(65535)
.HasColumnType("TEXT");
b.HasKey("Id");
b.HasIndex("UserId", "Kind")
.IsUnique()
.HasFilter("[UserId] IS NOT NULL");
b.ToTable("Preferences");
});
modelBuilder.Entity("Jellyfin.Data.Entities.User", b =>
{
b.Property<Guid>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("TEXT");
b.Property<string>("AudioLanguagePreference")
.HasMaxLength(255)
.HasColumnType("TEXT");
b.Property<string>("AuthenticationProviderId")
.IsRequired()
.HasMaxLength(255)
.HasColumnType("TEXT");
b.Property<bool>("DisplayCollectionsView")
.HasColumnType("INTEGER");
b.Property<bool>("DisplayMissingEpisodes")
.HasColumnType("INTEGER");
b.Property<string>("EasyPassword")
.HasMaxLength(65535)
.HasColumnType("TEXT");
b.Property<bool>("EnableAutoLogin")
.HasColumnType("INTEGER");
b.Property<bool>("EnableLocalPassword")
.HasColumnType("INTEGER");
b.Property<bool>("EnableNextEpisodeAutoPlay")
.HasColumnType("INTEGER");
b.Property<bool>("EnableUserPreferenceAccess")
.HasColumnType("INTEGER");
b.Property<bool>("HidePlayedInLatest")
.HasColumnType("INTEGER");
b.Property<long>("InternalId")
.HasColumnType("INTEGER");
b.Property<int>("InvalidLoginAttemptCount")
.HasColumnType("INTEGER");
b.Property<DateTime?>("LastActivityDate")
.HasColumnType("TEXT");
b.Property<DateTime?>("LastLoginDate")
.HasColumnType("TEXT");
b.Property<int?>("LoginAttemptsBeforeLockout")
.HasColumnType("INTEGER");
b.Property<int>("MaxActiveSessions")
.HasColumnType("INTEGER");
b.Property<int?>("MaxParentalAgeRating")
.HasColumnType("INTEGER");
b.Property<bool>("MustUpdatePassword")
.HasColumnType("INTEGER");
b.Property<string>("Password")
.HasMaxLength(65535)
.HasColumnType("TEXT");
b.Property<string>("PasswordResetProviderId")
.IsRequired()
.HasMaxLength(255)
.HasColumnType("TEXT");
b.Property<bool>("PlayDefaultAudioTrack")
.HasColumnType("INTEGER");
b.Property<bool>("RememberAudioSelections")
.HasColumnType("INTEGER");
b.Property<bool>("RememberSubtitleSelections")
.HasColumnType("INTEGER");
b.Property<int?>("RemoteClientBitrateLimit")
.HasColumnType("INTEGER");
b.Property<uint>("RowVersion")
.IsConcurrencyToken()
.HasColumnType("INTEGER");
b.Property<string>("SubtitleLanguagePreference")
.HasMaxLength(255)
.HasColumnType("TEXT");
b.Property<int>("SubtitleMode")
.HasColumnType("INTEGER");
b.Property<int>("SyncPlayAccess")
.HasColumnType("INTEGER");
b.Property<string>("Username")
.IsRequired()
.HasMaxLength(255)
.HasColumnType("TEXT")
.UseCollation("NOCASE");
b.HasKey("Id");
b.HasIndex("Username")
.IsUnique();
b.ToTable("Users");
});
modelBuilder.Entity("Jellyfin.Data.Entities.AccessSchedule", b =>
{
b.HasOne("Jellyfin.Data.Entities.User", null)
.WithMany("AccessSchedules")
.HasForeignKey("UserId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
});
modelBuilder.Entity("Jellyfin.Data.Entities.DisplayPreferences", b =>
{
b.HasOne("Jellyfin.Data.Entities.User", null)
.WithMany("DisplayPreferences")
.HasForeignKey("UserId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
});
modelBuilder.Entity("Jellyfin.Data.Entities.HomeSection", b =>
{
b.HasOne("Jellyfin.Data.Entities.DisplayPreferences", null)
.WithMany("HomeSections")
.HasForeignKey("DisplayPreferencesId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
});
modelBuilder.Entity("Jellyfin.Data.Entities.ImageInfo", b =>
{
b.HasOne("Jellyfin.Data.Entities.User", null)
.WithOne("ProfileImage")
.HasForeignKey("Jellyfin.Data.Entities.ImageInfo", "UserId")
.OnDelete(DeleteBehavior.Cascade);
});
modelBuilder.Entity("Jellyfin.Data.Entities.ItemDisplayPreferences", b =>
{
b.HasOne("Jellyfin.Data.Entities.User", null)
.WithMany("ItemDisplayPreferences")
.HasForeignKey("UserId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
});
modelBuilder.Entity("Jellyfin.Data.Entities.Permission", b =>
{
b.HasOne("Jellyfin.Data.Entities.User", null)
.WithMany("Permissions")
.HasForeignKey("UserId")
.OnDelete(DeleteBehavior.Cascade);
});
modelBuilder.Entity("Jellyfin.Data.Entities.Preference", b =>
{
b.HasOne("Jellyfin.Data.Entities.User", null)
.WithMany("Preferences")
.HasForeignKey("UserId")
.OnDelete(DeleteBehavior.Cascade);
});
modelBuilder.Entity("Jellyfin.Data.Entities.DisplayPreferences", b =>
{
b.Navigation("HomeSections");
});
modelBuilder.Entity("Jellyfin.Data.Entities.User", b =>
{
b.Navigation("AccessSchedules");
b.Navigation("DisplayPreferences");
b.Navigation("ItemDisplayPreferences");
b.Navigation("Permissions");
b.Navigation("Preferences");
b.Navigation("ProfileImage");
});
#pragma warning restore 612, 618
}
}
}

View File

@@ -0,0 +1,240 @@
#pragma warning disable CS1591
#pragma warning disable SA1601
using System;
using Microsoft.EntityFrameworkCore.Migrations;
namespace Jellyfin.Server.Implementations.Migrations
{
public partial class AddIndexesAndCollations : Migration
{
protected override void Up(MigrationBuilder migrationBuilder)
{
migrationBuilder.DropForeignKey(
name: "FK_ImageInfos_Users_UserId",
schema: "jellyfin",
table: "ImageInfos");
migrationBuilder.DropForeignKey(
name: "FK_Permissions_Users_Permission_Permissions_Guid",
schema: "jellyfin",
table: "Permissions");
migrationBuilder.DropForeignKey(
name: "FK_Preferences_Users_Preference_Preferences_Guid",
schema: "jellyfin",
table: "Preferences");
migrationBuilder.DropIndex(
name: "IX_Preferences_Preference_Preferences_Guid",
schema: "jellyfin",
table: "Preferences");
migrationBuilder.DropIndex(
name: "IX_Permissions_Permission_Permissions_Guid",
schema: "jellyfin",
table: "Permissions");
migrationBuilder.DropIndex(
name: "IX_DisplayPreferences_UserId",
schema: "jellyfin",
table: "DisplayPreferences");
migrationBuilder.DropIndex(
name: "IX_CustomItemDisplayPreferences_UserId",
schema: "jellyfin",
table: "CustomItemDisplayPreferences");
migrationBuilder.AlterColumn<string>(
name: "Username",
schema: "jellyfin",
table: "Users",
type: "TEXT",
maxLength: 255,
nullable: false,
collation: "NOCASE",
oldClrType: typeof(string),
oldType: "TEXT",
oldMaxLength: 255);
migrationBuilder.AddColumn<Guid>(
name: "UserId",
schema: "jellyfin",
table: "Preferences",
type: "TEXT",
nullable: true);
migrationBuilder.AddColumn<Guid>(
name: "UserId",
schema: "jellyfin",
table: "Permissions",
type: "TEXT",
nullable: true);
migrationBuilder.Sql("UPDATE Preferences SET UserId = Preference_Preferences_Guid");
migrationBuilder.Sql("UPDATE Permissions SET UserId = Permission_Permissions_Guid");
migrationBuilder.CreateIndex(
name: "IX_Users_Username",
schema: "jellyfin",
table: "Users",
column: "Username",
unique: true);
migrationBuilder.CreateIndex(
name: "IX_Preferences_UserId_Kind",
schema: "jellyfin",
table: "Preferences",
columns: new[] { "UserId", "Kind" },
unique: true,
filter: "[UserId] IS NOT NULL");
migrationBuilder.CreateIndex(
name: "IX_Permissions_UserId_Kind",
schema: "jellyfin",
table: "Permissions",
columns: new[] { "UserId", "Kind" },
unique: true,
filter: "[UserId] IS NOT NULL");
migrationBuilder.AddForeignKey(
name: "FK_ImageInfos_Users_UserId",
schema: "jellyfin",
table: "ImageInfos",
column: "UserId",
principalSchema: "jellyfin",
principalTable: "Users",
principalColumn: "Id",
onDelete: ReferentialAction.Cascade);
migrationBuilder.AddForeignKey(
name: "FK_Permissions_Users_UserId",
schema: "jellyfin",
table: "Permissions",
column: "UserId",
principalSchema: "jellyfin",
principalTable: "Users",
principalColumn: "Id",
onDelete: ReferentialAction.Cascade);
migrationBuilder.AddForeignKey(
name: "FK_Preferences_Users_UserId",
schema: "jellyfin",
table: "Preferences",
column: "UserId",
principalSchema: "jellyfin",
principalTable: "Users",
principalColumn: "Id",
onDelete: ReferentialAction.Cascade);
}
protected override void Down(MigrationBuilder migrationBuilder)
{
migrationBuilder.DropForeignKey(
name: "FK_ImageInfos_Users_UserId",
schema: "jellyfin",
table: "ImageInfos");
migrationBuilder.DropForeignKey(
name: "FK_Permissions_Users_UserId",
schema: "jellyfin",
table: "Permissions");
migrationBuilder.DropForeignKey(
name: "FK_Preferences_Users_UserId",
schema: "jellyfin",
table: "Preferences");
migrationBuilder.DropIndex(
name: "IX_Users_Username",
schema: "jellyfin",
table: "Users");
migrationBuilder.DropIndex(
name: "IX_Preferences_UserId_Kind",
schema: "jellyfin",
table: "Preferences");
migrationBuilder.DropIndex(
name: "IX_Permissions_UserId_Kind",
schema: "jellyfin",
table: "Permissions");
migrationBuilder.DropColumn(
name: "UserId",
schema: "jellyfin",
table: "Preferences");
migrationBuilder.DropColumn(
name: "UserId",
schema: "jellyfin",
table: "Permissions");
migrationBuilder.AlterColumn<string>(
name: "Username",
schema: "jellyfin",
table: "Users",
type: "TEXT",
maxLength: 255,
nullable: false,
oldClrType: typeof(string),
oldType: "TEXT",
oldMaxLength: 255,
oldCollation: "NOCASE");
migrationBuilder.CreateIndex(
name: "IX_Preferences_Preference_Preferences_Guid",
schema: "jellyfin",
table: "Preferences",
column: "Preference_Preferences_Guid");
migrationBuilder.CreateIndex(
name: "IX_Permissions_Permission_Permissions_Guid",
schema: "jellyfin",
table: "Permissions",
column: "Permission_Permissions_Guid");
migrationBuilder.CreateIndex(
name: "IX_DisplayPreferences_UserId",
schema: "jellyfin",
table: "DisplayPreferences",
column: "UserId");
migrationBuilder.CreateIndex(
name: "IX_CustomItemDisplayPreferences_UserId",
schema: "jellyfin",
table: "CustomItemDisplayPreferences",
column: "UserId");
migrationBuilder.AddForeignKey(
name: "FK_ImageInfos_Users_UserId",
schema: "jellyfin",
table: "ImageInfos",
column: "UserId",
principalSchema: "jellyfin",
principalTable: "Users",
principalColumn: "Id",
onDelete: ReferentialAction.Restrict);
migrationBuilder.AddForeignKey(
name: "FK_Permissions_Users_Permission_Permissions_Guid",
schema: "jellyfin",
table: "Permissions",
column: "Permission_Permissions_Guid",
principalSchema: "jellyfin",
principalTable: "Users",
principalColumn: "Id",
onDelete: ReferentialAction.Restrict);
migrationBuilder.AddForeignKey(
name: "FK_Preferences_Users_Preference_Preferences_Guid",
schema: "jellyfin",
table: "Preferences",
column: "Preference_Preferences_Guid",
principalSchema: "jellyfin",
principalTable: "Users",
principalColumn: "Id",
onDelete: ReferentialAction.Restrict);
}
}
}

View File

@@ -114,8 +114,6 @@ namespace Jellyfin.Server.Implementations.Migrations
b.HasKey("Id");
b.HasIndex("UserId");
b.HasIndex("UserId", "ItemId", "Client", "Key")
.IsUnique();
@@ -173,8 +171,6 @@ namespace Jellyfin.Server.Implementations.Migrations
b.HasKey("Id");
b.HasIndex("UserId");
b.HasIndex("UserId", "ItemId", "Client")
.IsUnique();
@@ -288,12 +284,17 @@ namespace Jellyfin.Server.Implementations.Migrations
.IsConcurrencyToken()
.HasColumnType("INTEGER");
b.Property<Guid?>("UserId")
.HasColumnType("TEXT");
b.Property<bool>("Value")
.HasColumnType("INTEGER");
b.HasKey("Id");
b.HasIndex("Permission_Permissions_Guid");
b.HasIndex("UserId", "Kind")
.IsUnique()
.HasFilter("[UserId] IS NOT NULL");
b.ToTable("Permissions");
});
@@ -314,6 +315,9 @@ namespace Jellyfin.Server.Implementations.Migrations
.IsConcurrencyToken()
.HasColumnType("INTEGER");
b.Property<Guid?>("UserId")
.HasColumnType("TEXT");
b.Property<string>("Value")
.IsRequired()
.HasMaxLength(65535)
@@ -321,7 +325,9 @@ namespace Jellyfin.Server.Implementations.Migrations
b.HasKey("Id");
b.HasIndex("Preference_Preferences_Guid");
b.HasIndex("UserId", "Kind")
.IsUnique()
.HasFilter("[UserId] IS NOT NULL");
b.ToTable("Preferences");
});
@@ -428,10 +434,14 @@ namespace Jellyfin.Server.Implementations.Migrations
b.Property<string>("Username")
.IsRequired()
.HasMaxLength(255)
.HasColumnType("TEXT");
.HasColumnType("TEXT")
.UseCollation("NOCASE");
b.HasKey("Id");
b.HasIndex("Username")
.IsUnique();
b.ToTable("Users");
});
@@ -466,7 +476,8 @@ namespace Jellyfin.Server.Implementations.Migrations
{
b.HasOne("Jellyfin.Data.Entities.User", null)
.WithOne("ProfileImage")
.HasForeignKey("Jellyfin.Data.Entities.ImageInfo", "UserId");
.HasForeignKey("Jellyfin.Data.Entities.ImageInfo", "UserId")
.OnDelete(DeleteBehavior.Cascade);
});
modelBuilder.Entity("Jellyfin.Data.Entities.ItemDisplayPreferences", b =>
@@ -482,14 +493,16 @@ namespace Jellyfin.Server.Implementations.Migrations
{
b.HasOne("Jellyfin.Data.Entities.User", null)
.WithMany("Permissions")
.HasForeignKey("Permission_Permissions_Guid");
.HasForeignKey("UserId")
.OnDelete(DeleteBehavior.Cascade);
});
modelBuilder.Entity("Jellyfin.Data.Entities.Preference", b =>
{
b.HasOne("Jellyfin.Data.Entities.User", null)
.WithMany("Preferences")
.HasForeignKey("Preference_Preferences_Guid");
.HasForeignKey("UserId")
.OnDelete(DeleteBehavior.Cascade);
});
modelBuilder.Entity("Jellyfin.Data.Entities.DisplayPreferences", b =>

View File

@@ -144,7 +144,13 @@ namespace Jellyfin.Server.Implementations.Users
throw new ArgumentException("The new and old names must be different.");
}
if (Users.Any(u => u.Id != user.Id && u.Username.Equals(newName, StringComparison.OrdinalIgnoreCase)))
await using var dbContext = _dbProvider.CreateContext();
if (await dbContext.Users
.AsQueryable()
.Where(u => u.Username == newName && u.Id != user.Id)
.AnyAsync()
.ConfigureAwait(false))
{
throw new ArgumentException(string.Format(
CultureInfo.InvariantCulture,
@@ -251,16 +257,6 @@ namespace Jellyfin.Server.Implementations.Users
}
await using var dbContext = _dbProvider.CreateContext();
// Clear all entities related to the user from the database.
if (user.ProfileImage != null)
{
dbContext.Remove(user.ProfileImage);
}
dbContext.RemoveRange(user.Permissions);
dbContext.RemoveRange(user.Preferences);
dbContext.RemoveRange(user.AccessSchedules);
dbContext.Users.Remove(user);
await dbContext.SaveChangesAsync().ConfigureAwait(false);
_users.Remove(userId);