← back to index

S8717 — Multiple "[Key]" attributes should not be used to define a composite key

Language: C#  |  Type: BUG  |  Severity: Blocker

Tags: entity-framework-core, entity-framework, orm, database

This rule raises an issue when an entity class declares more than one property annotated with the Key attribute in an attempt to define a composite primary key.

Why is this an issue?

Entity Framework Core does not interpret multiple Key attributes as a composite primary key. When an entity has two or more Key-decorated properties, EF Core throws an InvalidOperationException while building the model, the first time the DbContext is used.

What is the potential impact?

Because the model cannot be built, the application crashes the first time the DbContext is instantiated. This is not limited to the affected entity: nothing that depends on the context can run until the key is configured correctly.

How to fix it

Declare the composite key in a single place. Either apply the PrimaryKey attribute to the entity class, or configure the key with the Fluent API by overriding OnModelCreating and calling HasKey.

Code examples

Noncompliant code example

public class Student
{
    [Key]
    public string LastName { get; set; }   // Noncompliant
    [Key]
    public string FirstName { get; set; }
    public DateTime EnrollmentDate { get; set; }
}

Compliant solution

Apply the PrimaryKey attribute to the entity class:

[PrimaryKey(nameof(LastName), nameof(FirstName))]
public class Student
{
    public string LastName { get; set; }
    public string FirstName { get; set; }
    public DateTime EnrollmentDate { get; set; }
}

Alternatively, configure the key with the Fluent API in OnModelCreating:

public class Student
{
    public string LastName { get; set; }
    public string FirstName { get; set; }
    public DateTime EnrollmentDate { get; set; }
}

public class SchoolContext : DbContext
{
    protected override void OnModelCreating(ModelBuilder modelBuilder)
    {
        modelBuilder.Entity<Student>()
            .HasKey(s => new { s.LastName, s.FirstName });
    }
}

Going the extra mile

In larger projects, move each entity’s Fluent API configuration out of OnModelCreating into a dedicated class that implements EF Core’s IEntityTypeConfiguration<TEntity>. Its Configure(EntityTypeBuilder<TEntity> builder) method receives the same builder you would use inline, so the composite key is still declared with builder.HasKey(…​); you then register the class with modelBuilder.ApplyConfiguration(…​) in OnModelCreating. This keeps the entity free of mapping concerns and gathers its configuration in one focused place.

Resources

Documentation