web-dev-qa-db-fra.com

Entity Framework Core "Le type d'entité 'XXX' nécessite la définition d'une clé primaire."

J'essaie donc actuellement de créer une première migration de code avec Entity Framework Core pour un tableau qui affiche les conférences terminées par l'utilisateur de l'application. Mon modèle ressemble à ceci:

public class LectureCompletion
{
    [Key,  Column(Order = 0)]
    [ForeignKey("Lecture")]
    public Lecture LectureId { get; set; }

    [Key,  Column(Order = 1)]
    [ForeignKey("User")]
    public ApplicationUser UserId{ get; set; }

    public bool Completed { get; set; }
}

Je veux utiliser le UserId et le LectureId comme clé composite unique. Cependant, j'obtiens cette erreur:

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

Je ne comprends pas pourquoi cela se produit car j'ai clairement mes attributs clés dans les positions correctes? Puis-je utiliser ApplicationUser comme clé étrangère/primaire?

Voici mon modèle Lecture:

public class Lecture
{
    [Key]
    public int LectureId { get; set; }

    public string ModuleName { get; set; }
    public string LectureName { get; set; }
}

Et mon ApplicationDBContext.cs:

public class ApplicationDbContext : IdentityDbContext<ApplicationUser>
{
    public DbSet<Lecture> Lectures { get; set; }
    public DbSet<LectureCompletion> LectureCompletion { get; set; }

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

    protected override void OnModelCreating(ModelBuilder builder)
    {
        base.OnModelCreating(builder);
        // Customize the ASP.NET Identity model and override the defaults if needed.
        // For example, you can rename the ASP.NET Identity table names and more.
        // Add your customizations after calling base.OnModelCreating(builder);
    }
}
11
Josh L

Vous ne pouvez pas définir une clé compoiste avec une annotation de données uniquement. Vous devez utiliser à la place l'API Fluent.

public class LectureCompletion
{
    // which is your case.
    [ForeignKey(nameof(Lecture))] 
    public int LectureId { get;set; }
    public Lecture Lecture { get; set; }
    [ForeignKey(nameof(ApplicationUser))]
    public int UserId {get;set;}
    public ApplicationUser ApplicationUser { get; set; }
    public bool Completed { get; set; }
}


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

     // Define composite key.
     builder.Entity<LectureCompletion>()
         .HasKey(lc => new { lc.LectureId, lc.UserId });
}

https://docs.Microsoft.com/en-us/ef/core/modeling/keys

17
anserk

Votre classe LectureCompletion a besoin d'une clé primaire pour être définie correctement .[Key] est l'annotation de clé primaire pour indiquer explicitement à EntityFramework de la définir comme clé primaire, sinon la convention prendra le relais.

Autrement dit, les propriétés nommées soit ID ou suffixées avec ID, par exemple PokemonID pour la table Pokemon. ID ou Id n'est pas sensible à la casse dans ce cas.

L'attribut de clé étrangère n'est utilisé que si vous souhaitez que le nom de votre propriété de clé étrangère dans la classe LectureCompletion soit nommé différemment de votre classe référencée. Par exemple, si la clé primaire de votre classe ApplicationUser est ApplicationUserId, mais dans la classe LectureCompletion vous voulez qu'elle soit UserId, vous pouvez ajouter l'attribut.

Fais-le comme ça

public class LectureCompletion
{
    [Key] // Defined only once
    public LectureCompletionId { get;set; }

    // Not needed if Lecture class has the primary key property of LectureId,
    // which is your case.
    [ForeignKey("Lecture")] // Name of your navigation property below.
    public int LectureId { get;set; }

    public Lecture Lecture { get; set; }

    [ForeignKey("ApplicationUser")]
    public int UserId {get;set;}

    public ApplicationUser ApplicationUser { get; set; }

    public bool Completed { get; set; }
}

En ce qui concerne EntityFramework Core, le ColumnOrder ne semble pas avoir d'effet pour l'instant.

3
IvanJazz