Тип сущности ModeratedUser требует определения первичного ключа - PullRequest
0 голосов
/ 24 апреля 2019

Я испытываю ошибку с AspNetCore.Identity.EntityFrameworkCore 2.1.6 при использовании миграции базы данных с первым кодом.Ошибка:

Для типа объекта ModeratedUser требуется определить первичный ключ.

Меня смущает, поскольку у меня есть первичный ключ, определенный для всех сущностей, использующих Fluent Api.Я провел исследование по этой конкретной проблеме, и все посты, на которые я натолкнулся, касаются разных проблем (обратите внимание, что для определения моих отношений «многие ко многим» я следовал следующему: https://www.learnentityframeworkcore.com/configuration/many-to-many-relationship-configuration)

Вотсущности и конфигурации типов сущностей:

public class ModeratedUser
{
    public Guid ModeratedId { get; set; }

    public virtual List<ModeratorModerated> ModeratorModerated { get; set; }
}

public class ModeratorUser
{
    public Guid ModeratorId { get; set; }

    public virtual List<ModeratorModerated> ModeratorModerated { get; set; }
}

//explicit class to outline many to many between moderated and moderators
public class ModeratorModerated
{
    public Guid ModeratorId { get; set; }
    public Guid ModeratedId { get; set; }
    public ModeratedUser Moderated { get; set; }
    public ModeratorUser Moderator { get; set; }
}

Вот конфигурации типов сущностей:

public abstract class ModeratedConfiguration : EntityMappingConfiguration<ModeratedUser>
{
    public override void MapToConfig(EntityTypeBuilder<ModeratedUser> builder)
    {
        builder.HasKey(x => x.ModeratedId);

        builder.ToTable("ModeratedUsers", "Mod");
    }
}

public abstract class ModeratorsConfiguration : EntityMappingConfiguration<ModeratorUser>
{
    public override void MapToConfig(EntityTypeBuilder<ModeratorUser> builder)
    {
        builder.HasKey(x => x.ModeratorId);
        builder.ToTable("ModeratorUsers", "Mod");
    }
}

public abstract class ModeratorModeratedConfiguration : EntityMappingConfiguration<ModeratorModerated>
{
    public override void MapToConfig(EntityTypeBuilder<ModeratorModerated> builder)
    {
        builder.HasKey(x => new { x.ModeratedId, x.ModeratorId });

        builder.HasOne(x => x.Moderated)
            .WithMany(x => x.ModeratorModerated)
            .HasForeignKey(x => x.ModeratedId);

        builder.HasOne(x => x.Moderator)
            .WithMany(x => x.ModeratorModerated)
            .HasForeignKey(x => x.ModeratorId);

        builder.ToTable("ModeratorModerated", "Mod");
    }
}

Как видите, я установил ключ .HasKey для обоих ModeratorUser.cs.и ModeratedUser.cs и установили CompositeKey для класса конфигурации ModeratorModerated.cs.

Вот мой класс Context:

public class DbContext : IdentityDbContext<ApplicationUser>
{
    public DbContext(DbContextOptions<DbContext> options) : base(options)
    {
    }

    public DbSet<CatalogItem> CatalogItems { get; set; }
    public DbSet<ModeratedUser> ModeratedUsers { get; set; }
    public DbSet<ModeratorUser> ModeratorUsers { get; set; }

    protected override void OnModelCreating(ModelBuilder builder)
    {
        builder.HasDefaultSchema("UDC");

        builder.AddEntityConfigurationsFromAssembly(GetType().Assembly);

        base.OnModelCreating(builder);
    }
}

А вот мой класс ModelBuilderExtensions.cs, который я использую для создания экземпляраthe EntityMappingConfigurations ...

public interface IEntityMappingConfiguration
{
    void MapToConfig(ModelBuilder b);
}

public interface IEntityMappingConfiguration<T> : IEntityMappingConfiguration where T : class
{
    void MapToConfig(EntityTypeBuilder<T> builder);
}

public abstract class EntityMappingConfiguration<T> : IEntityMappingConfiguration<T> where T : class
{
    public abstract void MapToConfig(EntityTypeBuilder<T> b);

    public void MapToConfig(ModelBuilder b)
    {
        MapToConfig(b.Entity<T>());
    }
}

public static class ModelBuilderExtenions
{
    private static IEnumerable<Type> GetMappingTypes(this Assembly assembly, Type mappingInterface)
    {
        return assembly.GetTypes().Where(x => !x.IsAbstract && x.GetInterfaces().Any(y => y.GetTypeInfo().IsGenericType && y.GetGenericTypeDefinition() == mappingInterface));
    }

    public static void AddEntityConfigurationsFromAssembly(this ModelBuilder modelBuilder, Assembly assembly)
    {
        var mappingTypes = assembly.GetMappingTypes(typeof(IEntityMappingConfiguration<>));
        foreach (var config in mappingTypes.Select(Activator.CreateInstance).Cast<IEntityMappingConfiguration>())
        {
            config.MapToConfig(modelBuilder);
        }
    }
}

Ошибка из окна PackageManagerConsole в VS2017:

System.InvalidOperationException: тип сущности 'ModeratedUser' требует, чтобы первичный ключ былопределены.

Как вы можете видеть, небольшое приложение, но я не могу пройти мой первый мм, используя EFCore.в EF6.2 было не так сложно.Что мне здесь не хватает?

1 Ответ

1 голос
/ 24 апреля 2019

Попробуйте это изменения

public class ModeratedConfiguration : IEntityTypeConfiguration<ModeratedUser>
{
    public void Configure(EntityTypeBuilder<ModeratedUser> builder)
    {
        builder.ToTable("ModeratedUsers", "Mod");
        builder.HasKey(x => x.ModeratedId);
    }
}

public class ModeratorsConfiguration : IEntityTypeConfiguration<ModeratorUser>
{
    public void Configure(EntityTypeBuilder<ModeratorUser> builder)
    {
        builder.ToTable("ModeratorUsers", "Mod");
        builder.HasKey(x => x.ModeratorId);
    }
}

public class ModeratorModeratedConfiguration : IEntityTypeConfiguration<ModeratorModerated>
{
    public void Configure(EntityTypeBuilder<ModeratorModerated> builder)
    {
        builder.ToTable("ModeratorModerated", "Mod");
        builder.HasKey(x => new { x.ModeratedId, x.ModeratorId });

        builder.HasOne(x => x.Moderated)
            .WithMany(x => x.ModeratorModerated)
            .HasForeignKey(x => x.ModeratedId);

        builder.HasOne(x => x.Moderator)
            .WithMany(x => x.ModeratorModerated)
            .HasForeignKey(x => x.ModeratorId);

    }
}

Ваш DbContext должен быть

public class DbContext : IdentityDbContext<ApplicationUser>
{

    public DbContext(DbContextOptions<DbContext> options) : base(options)
    {
    }

    public DbSet<CatalogItem> CatalogItems { get; set; }
    public DbSet<ModeratedUser> ModeratedUsers { get; set; }
    public DbSet<ModeratorUser> ModeratorUsers { get; set; }

    protected override void OnModelCreating(ModelBuilder builder)
    {
        builder.HasDefaultSchema("UDC");

        builder.ApplyConfiguration<ModeratedUser>(new ModeratedUser());
        builder.ApplyConfiguration<ModeratedUser>(new ModeratorsConfiguration());
        builder.ApplyConfiguration<ModeratorModerated>(new ModeratorModeratedConfiguration());
        base.OnModelCreating(builder);
    }
}
...