ef-core-entity-implementation
Use this skill when implementing domain entities and their properties in .NET.
When & Why to Use This Skill
This Claude skill automates the implementation of .NET domain entities and Entity Framework Core (EF Core) models. It enforces standardized patterns for property definitions, complex navigation relationships, multi-tenancy, and constructor logic, ensuring high-quality, maintainable, and database-compliant code following Clean Architecture principles.
Use Cases
- Defining new domain entities with standardized XML documentation and C# 'required' property patterns to ensure data integrity.
- Setting up complex one-to-many or many-to-one relationships with correctly linked navigation properties and foreign keys to prevent EF Core mapping errors.
- Implementing multi-tenant domain models that automatically inherit required audit and tenant metadata without manual property duplication.
- Generating EF Core-compatible constructors that handle non-nullable navigation properties and private parameterless requirements for proper object materialization.
- Integrating specialized data types like Geospatial (NetTopologySuite) or Value Objects into the domain layer with consistent patterns.
| name | ef-core-entity-implementation |
|---|---|
| description | Use this skill when implementing domain entities and their properties in .NET. |
Entity Class Construction Rules
Base Structure
namespace GloboTicket.Domain.Entities;
/// <summary>
/// [Clear, concise description of the entity's business purpose]
/// </summary>
public class EntityName : [Entity | MultiTenantEntity]
{
// Properties defined here
}
Property Patterns
Required Properties
- Use
requiredkeyword:public required string Name { get; set; } - Include XML doc comment explaining the property's purpose
- Provide default value in initializer if sensible:
= string.Empty;
Optional Properties
- Make nullable:
public string? Description { get; set; } - Include XML doc comment
- Default to
null(implicit)
Navigation Properties (Collections)
/// <summary>
/// The collection of related entities.
/// </summary>
public ICollection<RelatedEntity> RelatedEntities { get; set; } = new List<RelatedEntity>();
IMPORTANT: When creating a new relationship, ALWAYS add the collection navigation property to the parent (one) side:
- If you're creating a child entity (many side), you MUST also add the collection property to the parent entity
- Example: When creating
Showwith a relationship toVenue, addpublic ICollection<Show> Shows { get; set; } = new List<Show>();to theVenueentity - Use the
WithMany(parent => parent.Collection)pattern in the configuration on the many side
Navigation Properties (Single - Optional)
/// <summary>
/// The parent entity.
/// </summary>
public ParentEntity? Parent { get; set; }
/// <summary>
/// Foreign key for the parent entity.
/// </summary>
public int? ParentId { get; set; }
Navigation Properties (Single - Required)
/// <summary>
/// The parent entity.
/// </summary>
public ParentEntity Parent { get; private set; }
/// <summary>
/// Foreign key for the parent entity.
/// </summary>
public int ParentId { get; private set; }
Important Notes on Required Navigation Properties:
- Required navigation properties should be non-nullable
- Both foreign key and navigation properties should have
private set - Use null assertion assignment (
= null!;) in constructors to avoid compiler warnings - Required navigation properties are initialized via constructor parameters
- A private parameterless constructor must be provided for Entity Framework Core
Complex Types (Value Objects)
/// <summary>
/// The billing address for this entity.
/// </summary>
public required Address BillingAddress { get; set; }
/// <summary>
/// Optional shipping address.
/// </summary>
public Address? ShippingAddress { get; set; }
Geospatial Properties
using NetTopologySuite.Geometries;
/// <summary>
/// Geographic location (latitude/longitude).
/// </summary>
public Point? Location { get; set; }
Multi-Tenant Entity Additional Requirements
When inheriting from MultiTenantEntity, DO NOT manually add:
TenantIdproperty (inherited from base)Tenantnavigation property (inherited from base)Id,CreatedAt,UpdatedAt(inherited through base chain)
These are automatically provided by the inheritance hierarchy.
Common Property Types
- Strings: Default to
string.Emptyfor required,nullfor optional - Decimals: Use
decimalfor monetary values, prices - DateTimes: Use
DateTime(UTC assumed), nullable for optional dates - Booleans: Default to
falsewith clear semantic meaning - Enums: Create strongly-typed enums in
Domain.Enumsnamespace - GUIDs: Use
Guidtype, typically optional except for unique identifiers
Constructor Patterns
For Entities with Required Navigation Properties
Entities that have required navigation properties (non-nullable relationships) must have:
- Public Constructor: Accepts navigation entities as parameters and initializes both the navigation property and its foreign key
- Private Parameterless Constructor: For Entity Framework Core to use during materialization
public class Show : Entity
{
/// <summary>
/// Initializes a new instance of the <see cref="Show"/> class.
/// </summary>
/// <param name="act">The Act that is performing in this show.</param>
/// <param name="venue">The Venue where this show is held.</param>
/// <exception cref="ArgumentNullException">Thrown when act or venue is null.</exception>
public Show(Act act, Venue venue)
{
ArgumentNullException.ThrowIfNull(act);
ArgumentNullException.ThrowIfNull(venue);
Act = act;
ActId = act.Id;
Venue = venue;
VenueId = venue.Id;
}
/// <summary>
/// Private parameterless constructor for Entity Framework Core.
/// </summary>
private Show()
{
Act = null!;
Venue = null!;
}
/// <summary>
/// Gets or sets the start time of the show in UTC.
/// </summary>
public required DateTime StartTime { get; set; }
/// <summary>
/// Gets the foreign key for the Act performing in this show.
/// </summary>
public int ActId { get; private set; }
/// <summary>
/// Gets the Act that is performing in this show.
/// </summary>
public Act Act { get; private set; }
/// <summary>
/// Gets the foreign key for the Venue where this show is held.
/// </summary>
public int VenueId { get; private set; }
/// <summary>
/// Gets the Venue where this show is held.
/// </summary>
public Venue Venue { get; private set; }
}
Key Constructor Rules
- Constructor parameters should ONLY be used for navigation properties, not value properties
- Value properties should use the
requiredkeyword instead - Public constructor validates navigation properties are not null using
ArgumentNullException.ThrowIfNull() - Public constructor sets both the navigation property and its foreign key from the passed entity's Id
- Private parameterless constructor initializes navigation properties with
null!to suppress compiler warnings - Foreign keys and navigation properties have
private setto enforce initialization through constructor