ef-core-entity-implementation

michaellperry's avatarfrom michaellperry

Use this skill when implementing domain entities and their properties in .NET.

0stars🔀0forks📁View on GitHub🕐Updated Jan 11, 2026

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.
nameef-core-entity-implementation
descriptionUse 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 required keyword: 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 Show with a relationship to Venue, add public ICollection<Show> Shows { get; set; } = new List<Show>(); to the Venue entity
  • 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:

  • TenantId property (inherited from base)
  • Tenant navigation 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.Empty for required, null for optional
  • Decimals: Use decimal for monetary values, prices
  • DateTimes: Use DateTime (UTC assumed), nullable for optional dates
  • Booleans: Default to false with clear semantic meaning
  • Enums: Create strongly-typed enums in Domain.Enums namespace
  • GUIDs: Use Guid type, 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:

  1. Public Constructor: Accepts navigation entities as parameters and initializes both the navigation property and its foreign key
  2. 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 required keyword 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 set to enforce initialization through constructor
ef-core-entity-implementation – AI Agent Skills | Claude Skills