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.