🔑 Keys in EF Core
✅ 1. Primary Key (PK)
Definition: Uniquely identifies each entity. Default Convention: Property namedId or <EntityName>Id.
Explicit Definition:
Data Annotation:
[Key]
public int ProductId { get; set; }
Fluent API:
modelBuilder.Entity<Product>()
.HasKey(p => p.ProductId);
✅ 2. Composite Key
modelBuilder.Entity<OrderDetail>()
.HasKey(od => new { od.OrderId, od.ProductId });
⚠️ Must be defined using Fluent API (Data Annotations don’t support composite keys).
✅ 3. Alternate Key
modelBuilder.Entity<Product>()
.HasAlternateKey(p => p.Sku);
✅ Primary Key vs Alternate Key
| Feature | Primary Key | Alternate Key |
|---|---|---|
| Uniquely identifies? | ✅ Yes | ✅ Yes |
| Required? | ✅ Yes | ❌ Optional |
| Can be used as FK? | ✅ Yes | ✅ Yes (with .HasPrincipalKey) |
✅ 4. Foreign Key (FK)
modelBuilder.Entity<Employee>()
.HasOne(e => e.Department)
.WithMany(d => d.Employees)
.HasForeignKey(e => e.DepartmentId);
✅ 5. Composite Foreign Key
modelBuilder.Entity<OrderDetail>()
.HasOne(od => od.Product)
.WithMany()
.HasForeignKey(od => new { od.ProductId, od.SupplierId });
✅ 6. Shadow Properties & Shadow Foreign Keys
Shadow Property:modelBuilder.Entity<Order>()
.Property<int>("ShadowCustomerId");
Shadow FK:
modelBuilder.Entity<Order>()
.HasOne(typeof(Customer))
.WithMany()
.HasForeignKey("ShadowCustomerId");
✅ 7. Alternate Key as Principal in FK
modelBuilder.Entity<Product>()
.HasAlternateKey(p => p.Sku);
modelBuilder.Entity<OrderDetail>()
.HasOne(od => od.Product)
.WithMany()
.HasForeignKey(od => od.ProductSku)
.HasPrincipalKey(p => p.Sku);
✅ 8. Keyless Entities
modelBuilder.Entity<MyView>().HasNoKey();
- Cannot be updated, inserted, or deleted.
- Cannot participate in relationships.
✅ 9. Unique Constraints Across Multiple Columns
modelBuilder.Entity<User>()
.HasAlternateKey(u => new { u.Email, u.Username });
Or using Index:
modelBuilder.Entity<User>()
.HasIndex(u => u.Email)
.IsUnique();
👉
.HasIndex() creates an index (performance), .HasAlternateKey() enforces uniqueness in EF model.✅ 10. Common Errors and Gotchas
| Situation | Outcome/Error |
|---|---|
| No PK defined | ❌ Runtime error |
| Changing PK in migration | ❌ Drops table → risk of data loss |
Nullable FK with .OnDelete(SetNull) | ❌ Error if FK is non-nullable |
| FK type mismatch | ❌ Runtime exception |
| Optional FK in composite key | ❌ Not allowed |
| Required navigation with optional FK | ❌ Invalid – must match nullability |
✅ 11. Key Usage in Change Tracking
For composite keys, all values must match for EF Core to treat two entities as the same in the ChangeTracker.
✅ 12. Fluent API vs Data Annotations
| Feature | Fluent API | Data Annotations |
|---|---|---|
| Flexibility | ✅ High | ❌ Limited |
| Composite Keys | ✅ Yes | ❌ Not supported |
| Precedence | ✅ Overrides Data Annotations | ❌ Can be overridden |
✅ 13. GUID as Primary Key
- Pros: Globally unique, useful in distributed systems.
- Cons: Poor for clustered indexes (fragmentation). Use
NEWSEQUENTIALID()for better performance.
modelBuilder.Entity<User>()
.Property(u => u.UserId)
.HasDefaultValueSql("NEWSEQUENTIALID()");
✅ 14. Renaming Foreign Key Constraint
modelBuilder.Entity<Employee>()
.HasOne(e => e.Department)
.WithMany()
.HasForeignKey(e => e.DepartmentId)
.HasConstraintName("FK_Employee_Department");
✅ 15. Default Key Generation Strategies
modelBuilder.Entity<Product>()
.Property(p => p.ProductId)
.ValueGeneratedOnAdd();
.ValueGeneratedOnAdd()→ Auto-increment/identity..ValueGeneratedNever()→ Must be set manually..ValueGeneratedOnAddOrUpdate()→ For computed columns.
✅ 16. Owned Entities and Keys
modelBuilder.Entity<Order>()
.OwnsOne(o => o.ShippingAddress);
Owned types share the same PK as the owner.
✅ 17. Summary Table
| Concept | Description | Example |
|---|---|---|
| Primary Key | Unique identity | .HasKey(x => x.Id) |
| Composite Key | Multiple properties as PK | .HasKey(x => new { x.A, x.B }) |
| Alternate Key | Additional unique constraint | .HasAlternateKey(x => x.Email) |
| Foreign Key | Connects entities | .HasForeignKey() |
| Shadow Property | Not in class but in EF model | .Property<string>("Code") |
| Shadow FK | FK property not in class | .HasForeignKey("CustomerId") |
| Keyless Entity | No primary key | .HasNoKey() |
| Rename FK | Custom FK name | .HasConstraintName("FK_Custom") |
| GUID as PK | Unique but fragmented index | Use NEWSEQUENTIALID() |
| Default Key Strategy | Configure key generation | .ValueGeneratedOnAdd() |
| Owned Entity Key | Shares owner’s PK | .OwnsOne(...) |
✅ 18. Final Tip
👉 Best Practice: Define keys clearly in your model from the beginning.
Avoid changing PK/AK definitions after production to prevent migration issues and data loss.
Comments
Post a Comment