No Multiple Key Attributes

ID

csharp.no_multiple_key_attributes

Severity

critical

Remediation Complexity

trivial

Remediation Risk

low

Remediation Effort

low

Resource

Reliability

Language

CSharp

Tags

data-annotations, orm, reliability, startup-failure

Description

Reports an entity type that puts [Key] on two or more of its properties or fields. The attribute names the primary key, singular; it does not compose into a composite key. Entity Framework Core rejects such a model with an InvalidOperationException while building it, which happens the first time the DbContext is used.

Rationale

[Key] carries no ordering and no notion of being one part of something larger, so a mapper reading two of them sees two candidate keys and no way to choose. Rather than pick one, Entity Framework Core refuses to build the model at all. The consequence is not subtly wrong data — it is an application that cannot touch its database, failing on the first query with an exception raised deep inside model building.

The intent behind two [Key] attributes is nearly always a composite key, and that is configuration rather than annotation: it belongs in OnModelCreating, via HasKey. An entity configured that way carries no [Key] at all.

public class OrderLine                     // FLAW — two keys, no composite key
{
    [Key]
    public int OrderId { get; set; }

    [Key]
    public int ProductId { get; set; }
}

public class Customer                      // OK — exactly one key
{
    [Key]
    public int Id { get; set; }

    public string Name { get; set; }
}

public class Payment                       // OK — the composite key is configured, not annotated
{
    public int OrderId { get; set; }
    public int Sequence { get; set; }
}

public class BillingContext : DbContext
{
    protected override void OnModelCreating(ModelBuilder modelBuilder)
    {
        modelBuilder.Entity<Payment>().HasKey(p => new { p.OrderId, p.Sequence });
    }
}

Remediation

If the entity really has a composite key, remove every [Key] from it and declare the key once in OnModelCreating with modelBuilder.Entity<T>().HasKey(…​), listing the members in the order the key requires. If only one member is the key, remove the attribute from the others.