| name | entity-design |
| description | Design EF Core entities with navigation properties, value objects, Fluent API configuration, and audit fields. Use when creating new database entities, adding relationships, configuring owned types, designing a domain model for Entity Framework Core, or setting up table-per-hierarchy inheritance. |
Entity Design (EF Core)
Design and configure EF Core entities following project conventions.
Workflow
- Define the entity class with properties and base class inheritance
- Add navigation properties for relationships
- Create
IEntityTypeConfiguration<T> with Fluent API configuration
- Register in DbContext via
OnModelCreating or assembly scanning
- Generate and review migration to verify the resulting schema
Entity Structure
public class Invoice : EntityBase
{
public string InvoiceNumber { get; set; } = string.Empty;
public decimal Total { get; set; }
public InvoiceStatus Status { get; set; }
public Guid CustomerId { get; set; }
public Customer Customer { get; set; } = null!;
public ICollection<InvoiceLineItem> LineItems { get; set; } = new List<InvoiceLineItem>();
}
Configuration
public class InvoiceConfiguration : IEntityTypeConfiguration<Invoice>
{
public void Configure(EntityTypeBuilder<Invoice> builder)
{
builder.HasKey(x => x.Id);
builder.Property(x => x.InvoiceNumber).HasMaxLength(50).IsRequired();
builder.Property(x => x.Total).HasPrecision(18, 2);
builder.HasOne(x => x.Customer)
.WithMany(c => c.Invoices)
.HasForeignKey(x => x.CustomerId)
.OnDelete(DeleteBehavior.Restrict);
builder.HasMany(x => x.LineItems)
.WithOne(li => li.Invoice)
.HasForeignKey(li => li.InvoiceId)
.OnDelete(DeleteBehavior.Cascade);
builder.Property<byte[]>("RowVersion").IsRowVersion();
}
}
Best Practices
- Fluent API over data annotations for complex mappings — keeps entities clean
- Owned types for value objects (e.g.,
Address, Money) — builder.OwnsOne(x => x.Address)
- Shadow properties for audit fields (
CreatedAt, ModifiedAt) via SaveChanges override
- Explicit cascade delete — always configure
OnDelete() to avoid surprise cascades
- Concurrency tokens — add
[Timestamp] or IsRowVersion() for entities edited concurrently
Checklist