web-dev-qa-db-fra.com

Le type d'entité 'IdentityUserLogin <string>' nécessite la définition d'une clé primaire

j'utilise dotnet core 1.1 sur linux, et j'ai des problèmes lorsque je veux séparer le identityContext de mon dbContext normal, chaque fois que j'exécute la ligne suivante dans mon startup.cs -> configure:

//... some other services
using (var serviceScope = app.ApplicationServices.GetRequiredService<IServiceScopeFactory>().CreateScope())
{
    serviceScope.ServiceProvider.GetService<ApplicationDbContext>().Database.Migrate();
    //running other database.migrations here + seeding data. But it is the line above that causes problems

Cette ligne lève donc l'exception: le type d'entité 'IdentityUserLogin' nécessite la définition d'une clé primaire

Je ne comprends tout simplement pas cela, pourquoi est-ce mon travail de donner à IdentityUserLogin une clé primaire ??, c'est une classe tierce et je ne l'ai même pas touchée. J'ai la configuration simple suivante:

namespace EsportshubApi.Models
{
    public class ApplicationDbContext :  IdentityDbContext<ApplicationUser>
    {
        public ApplicationDbContext(DbContextOptions<ApplicationDbContext> options) : base(options)
        {
        }

        public ApplicationDbContext()
        {

        }

        protected override void OnModelCreating(ModelBuilder modelBuilder)
        {
            base.OnModelCreating(modelBuilder);


        }
    }
}

Et l'applicationUser:

namespace EsportshubApi.Models.Entities
{

    public class ApplicationUser : IdentityUser
    {
        public ApplicationUser() { }

        public static ApplicationUserBuilder Builder()
        {
            return new ApplicationUserBuilder(new ApplicationUser());
        }

        public int AccountId { get; set; }
        public Guid AccountGuid { get; set; }
        public string Salt { get; set; }
        public bool Verified { get; set; }
        public string Checksum { get; set; }
        public string Password { get; set; }
        public DateTime Created { get; set; }
        public DateTime Updated { get; set; }
    }

}

Dans ma startup, je configure le cadre d'identité de la manière suivante:

configureServices:

services.AddEntityFrameworkSqlServer().AddMySQL().AddDbContext<ApplicationDbContext>(options =>
                    options.UseMySQL(config["ConnectionStrings:DefaultConnection"]));

Et

Configurer:

 app.UseIdentity();

Mon projet est ouvert à: mon repo github

si cela aide.

J'ai essayé beaucoup de choses. Les deux plus prometteurs dérivaient toutes les classes utilisées dans cette émission générique et les transmettaient explicitement, essayaient de changer toutes leurs clés en entiers, etc. Et cela donnait exactement la même erreur juste avec int au lieu de chaîne. L'autre façon que j'ai essayé était de faire ce qui suit à l'intérieur de OnModelCreating pour donner à IdentityUserLogin une clé primaire en par exemple:

 modelBuilder.Entity<IdentityUserLogin<int>>()
            .Property(login => login.UserId)
            .ForMySQLHasColumnType("PK")
            .UseSqlServerIdentityColumn()
            .UseMySQLAutoIncrementColumn("AI");

Comme vous pouvez le voir, c'était à l'époque où j'avais UserId comme entier, mais je ne suis même pas sûr si UserId devrait être sa primaryKey. Je peux obtenir d'autres erreurs au lieu de celle-ci, cela dit

IdentityUserLogin fait partie d'une hiérarchie et n'a pas de valeurs discriminantes

Mais si j'avais des valeurs discriminantes, cela revient finalement à cette erreur. La partie la plus étrange que je pense est que j'ai la même implémentation EXACT que l'exemple de github UnicornStore, qui utilise également un peu le cadre d'identité .... Donc j'ai vraiment besoin de votre aide. Peut reproduire cette erreur en téléchargeant le projet, en copiant le default.appsettings.json en appsettings.json, mettez une chaîne de connexion valide, dotnet restore, courir avec dotnet run --environment Development.

J'ai même essayé de changer l'implémentation pour utiliser une base de données MSSQL au lieu de MySQL, mais cela a donné exactement la même erreur.

17
DenLilleMand

les clés des tables d'identité sont mappées dans la méthode OnModelCreating de IdentityDbContext et si cette méthode n'est pas appelée, vous finirez par obtenir l'erreur que vous avez obtenue.

Il vous suffit d'appeler.

protected override void OnModelCreating(ModelBuilder modelBuilder)
{
  base.OnModelCreating(modelBuilder);
}

La réponse originale (juste copiée pour la référence des autres juste au cas où) ici

62
immirza

D'accord. Je vais donc essayer de répondre à ma propre question, car je l'ai dépassée. Il est toujours possible de suivre le lien github dans l'OP et de voir le projet dans lequel j'ai eu l'erreur.

Surtout ce qui n'allait pas, c'est que j'ai eu cette erreur en essayant de migrer le ApplicationDbContext : IDentityContext mais en fait, l'erreur a été générée sur la base de mon autre dbContext dans l'application, lorsque j'ai essayé d'exécuter la migration sur celle-ci. Je ne sais toujours pas pourquoi l'autre DbContext a repris ces entités d'identité auxquelles je n'avais fait référence nulle part, je pense qu'il est étrange qu'un dbcontext semble savoir quelque chose sur des entités non mentionnées dans la méthode OnModelCreating. Quoi qu'il en soit - quand j'ai découvert que ce n'était pas le IdentityDbContext avec lequel quelque chose n'allait pas, j'ai simplement ajouté ce qui suit dans le OnModelCreating du contexte qui a jeté l'erreur:

 protected override void OnModelCreating(ModelBuilder modelBuilder)
        {
            base.OnModelCreating(modelBuilder);
            modelBuilder.Ignore <IdentityUserLogin<string>>();
            modelBuilder.Ignore <IdentityUserRole<string>>();
            modelBuilder.Ignore<IdentityUserClaim<string>>();
            modelBuilder.Ignore<IdentityUserToken<string>>();
            modelBuilder.Ignore<IdentityUser<string>>();
            modelBuilder.Ignore<ApplicationUser>();

Alors ... je me demande toujours pourquoi mon contexte reprend sur ces entités sans rien avoir à voir avec elles, et je suis assez inquiet que chaque fois que j'ajoute un contexte, je dois exclure des modèles au lieu de les inclure.

4
DenLilleMand

J'ai eu un problème similaire lié à votre problème initial où

Le type d'entité 'IdentityUserLogin' nécessite la définition d'une clé primaire.

Et même si je pense que votre solution pour ignorer les entités semble fonctionner, je voulais juste fournir une autre solution pour ceux qui souhaitent réellement attribuer une clé primaire à chaque entité. Le problème est que chaque fois que vous créez une entité, le DbContext voudra garder la trace de la clé primaire pour chacun - ainsi, vous devrez l'assigner.

Voir mon exemple ci-dessous, où Project et Target sont mes entités, et je leur ai attribué à chacune une propriété que je voudrais utiliser comme clé primaire pour chaque entité.

protected override void OnModelCreating(ModelBuilder builder)
{
    builder.Entity<Project>().HasKey(m => m.ProjectPath);
    builder.Entity<Target>().HasKey(m => m.Guid);
    base.OnModelCreating(builder);
} 

Une fois que vous avez identifié et attribué quelle propriété doit être désignée comme clé primaire pour cette entité, l'erreur disparaîtra.

4
susieloo_