CG.Infrastructure.Entity 3.10.2

dotnet add package CG.Infrastructure.Entity --version 3.10.2
                    
NuGet\Install-Package CG.Infrastructure.Entity -Version 3.10.2
                    
This command is intended to be used within the Package Manager Console in Visual Studio, as it uses the NuGet module's version of Install-Package.
<PackageReference Include="CG.Infrastructure.Entity" Version="3.10.2" />
                    
For projects that support PackageReference, copy this XML node into the project file to reference the package.
<PackageVersion Include="CG.Infrastructure.Entity" Version="3.10.2" />
                    
Directory.Packages.props
<PackageReference Include="CG.Infrastructure.Entity" />
                    
Project file
For projects that support Central Package Management (CPM), copy this XML node into the solution Directory.Packages.props file to version the package.
paket add CG.Infrastructure.Entity --version 3.10.2
                    
#r "nuget: CG.Infrastructure.Entity, 3.10.2"
                    
#r directive can be used in F# Interactive and Polyglot Notebooks. Copy this into the interactive tool or source code of the script to reference the package.
#:package CG.Infrastructure.Entity@3.10.2
                    
#:package directive can be used in C# file-based apps starting in .NET 10 preview 4. Copy this into a .cs file before any lines of code to reference the package.
#addin nuget:?package=CG.Infrastructure.Entity&version=3.10.2
                    
Install as a Cake Addin
#tool nuget:?package=CG.Infrastructure.Entity&version=3.10.2
                    
Install as a Cake Tool

CG.Infrastructure.Entity

A lightweight .NET library providing a robust base entity class for domain-driven design and entity management in .NET applications.

Overview

CG.Infrastructure.Entity provides a foundation for building domain entities with built-in identity management, equality comparison, and hash code generation. This library is designed to work seamlessly with Entity Framework Core and other data access technologies while maintaining clean domain logic.

Features

  • Automatic GUID Generation: Automatically generates unique GUIDs for new entities
  • Identity Management: Built-in transient entity detection
  • Optimized Equality: Efficient equality comparison and hash code generation
  • Domain-Driven Design: Clean, focused base class for domain entities
  • Performance Optimized: Cached hash codes and efficient equality checks
  • Framework Agnostic: Works with any .NET data access technology

Requirements

  • .NET 9.0 or later
  • No external dependencies

Installation

dotnet add package CG.Infrastructure.Entity

Quick Start

Basic Usage

using Infrastructure.Entity.Entities;

public class Customer : BaseEntity
{
    public string Name { get; set; } = string.Empty;
    public string Email { get; set; } = string.Empty;
    public DateTime CreatedDate { get; set; }
    
    public Customer(string name, string email)
    {
        Name = name;
        Email = email;
        CreatedDate = DateTime.UtcNow;
    }
}

// Usage
var customer = new Customer("John Doe", "john@example.com");
Console.WriteLine($"Customer ID: {customer.Id}"); // Automatically generated GUID
Console.WriteLine($"Is Transient: {customer.IsTransient()}"); // false

Entity Equality

var customer1 = new Customer("John Doe", "john@example.com");
var customer2 = new Customer("John Doe", "john@example.com");

// Different instances with different IDs
Console.WriteLine(customer1.Equals(customer2)); // false

// Same instance
Console.WriteLine(customer1.Equals(customer1)); // true

// Same ID (after persistence)
customer2.Id = customer1.Id;
Console.WriteLine(customer1.Equals(customer2)); // true

Transient Entity Detection

var customer = new Customer("John Doe", "john@example.com");

// Before persistence
Console.WriteLine(customer.IsTransient()); // false (has generated ID)

// After clearing ID (simulating new entity)
customer.Id = default;
Console.WriteLine(customer.IsTransient()); // true

Core Functionality

BaseEntity Class

The BaseEntity class provides:

  • Id Property: Guid type identifier with protected setter
  • IsTransient(): Determines if the entity is new/unsaved
  • GetHashCode(): Optimized hash code generation with caching
  • Equals(): Comprehensive equality comparison

Identity Management

public abstract class BaseEntity
{
    public Guid Id { get; protected set; }
    
    protected BaseEntity()
    {
        Id = Id == default ? Guid.NewGuid() : Id;
    }
}
  • Automatically generates GUIDs for new entities
  • Preserves existing IDs when deserializing from database
  • Protected setter ensures identity immutability

Equality and Hash Code

public override bool Equals(object? obj)
{
    if (obj == null || obj is not BaseEntity)
        return false;
    
    if (ReferenceEquals(this, obj))
        return true;
    
    if (GetType() != obj.GetType())
        return false;
    
    BaseEntity item = (BaseEntity)obj;
    
    if (item.IsTransient() || IsTransient())
        return false;
    
    return item.Id.Equals(Id);
}
  • Reference equality for same instance
  • Type checking for different entity types
  • Transient entity handling
  • ID-based equality for persisted entities

Best Practices

1. Entity Design

public class Product : BaseEntity
{
    // Domain properties
    public string Name { get; private set; }
    public decimal Price { get; private set; }
    public int StockQuantity { get; private set; }
    
    // Domain methods
    public void UpdateStock(int quantity)
    {
        if (quantity < 0)
            throw new ArgumentException("Stock cannot be negative");
        
        StockQuantity = quantity;
    }
    
    public void AdjustPrice(decimal newPrice)
    {
        if (newPrice < 0)
            throw new ArgumentException("Price cannot be negative");
        
        Price = newPrice;
    }
}

2. Value Objects

public class Address : BaseEntity
{
    public string Street { get; set; } = string.Empty;
    public string City { get; set; } = string.Empty;
    public string PostalCode { get; set; } = string.Empty;
    public string Country { get; set; } = string.Empty;
    
    public override string ToString()
    {
        return $"{Street}, {City}, {PostalCode}, {Country}";
    }
}

3. Aggregate Roots

public class Order : BaseEntity
{
    private readonly List<OrderItem> _items = new();
    
    public string OrderNumber { get; private set; } = string.Empty;
    public DateTime OrderDate { get; private set; }
    public OrderStatus Status { get; private set; }
    public IReadOnlyCollection<OrderItem> Items => _items.AsReadOnly();
    
    public void AddItem(Product product, int quantity)
    {
        var item = new OrderItem(product.Id, quantity, product.Price);
        _items.Add(item);
    }
    
    public void MarkAsShipped()
    {
        if (Status != OrderStatus.Confirmed)
            throw new InvalidOperationException("Order must be confirmed before shipping");
        
        Status = OrderStatus.Shipped;
    }
}

Integration Examples

Entity Framework Core

public class ApplicationDbContext : DbContext
{
    public DbSet<Customer> Customers { get; set; } = null!;
    public DbSet<Product> Products { get; set; } = null!;
    public DbSet<Order> Orders { get; set; } = null!;
    
    protected override void OnModelCreating(ModelBuilder modelBuilder)
    {
        // Configure entities
        modelBuilder.Entity<Customer>(entity =>
        {
            entity.HasKey(e => e.Id);
            entity.Property(e => e.Name).IsRequired().HasMaxLength(100);
            entity.Property(e => e.Email).IsRequired().HasMaxLength(255);
        });
        
        modelBuilder.Entity<Product>(entity =>
        {
            entity.HasKey(e => e.Id);
            entity.Property(e => e.Name).IsRequired().HasMaxLength(200);
            entity.Property(e => e.Price).HasPrecision(18, 2);
        });
    }
}

Repository Pattern

public interface IRepository<T> where T : BaseEntity
{
    Task<T?> GetByIdAsync(Guid id);
    Task<IEnumerable<T>> GetAllAsync();
    Task<T> AddAsync(T entity);
    Task UpdateAsync(T entity);
    Task DeleteAsync(Guid id);
}

public class Repository<T> : IRepository<T> where T : BaseEntity
{
    private readonly ApplicationDbContext _context;
    
    public Repository(ApplicationDbContext context)
    {
        _context = context;
    }
    
    public async Task<T?> GetByIdAsync(Guid id)
    {
        return await _context.Set<T>().FindAsync(id);
    }
    
    public async Task<T> AddAsync(T entity)
    {
        // Entity ID is automatically generated
        var result = await _context.Set<T>().AddAsync(entity);
        await _context.SaveChangesAsync();
        return result.Entity;
    }
}

Performance Considerations

Hash Code Caching

The BaseEntity class caches hash codes to improve performance:

private int? _requestedHashCode;

public override int GetHashCode()
{
    if (!IsTransient())
    {
        if (!_requestedHashCode.HasValue)
        {
            _requestedHashCode = Id.GetHashCode() ^ 31;
        }
        return _requestedHashCode.Value;
    }
    return base.GetHashCode();
}

Equality Optimization

  • Early returns for null and reference equality
  • Type checking before expensive operations
  • Transient entity handling

Dependencies

This library has no external dependencies and is designed to be lightweight and focused.

Contributing

  1. Fork the repository
  2. Create a feature branch
  3. Make your changes
  4. Add tests for new functionality
  5. Ensure all tests pass
  6. Submit a pull request

License

This project is licensed under the MIT License - see the LICENSE file for details.

Version History

  • 3.10.0: Initial release with BaseEntity implementation

Support

For questions, issues, or contributions, please visit our GitHub repository or contact the development team.

  • CG.Infrastructure.Core - Core infrastructure services
  • CG.Infrastructure.Data - Data access and repository patterns
  • CG.Infrastructure.Configuration - Configuration management
Product Compatible and additional computed target framework versions.
.NET net9.0 is compatible.  net9.0-android was computed.  net9.0-browser was computed.  net9.0-ios was computed.  net9.0-maccatalyst was computed.  net9.0-macos was computed.  net9.0-tvos was computed.  net9.0-windows was computed.  net10.0 was computed.  net10.0-android was computed.  net10.0-browser was computed.  net10.0-ios was computed.  net10.0-maccatalyst was computed.  net10.0-macos was computed.  net10.0-tvos was computed.  net10.0-windows was computed. 
Compatible target framework(s)
Included target framework(s) (in package)
Learn more about Target Frameworks and .NET Standard.
  • net9.0

    • No dependencies.

NuGet packages (2)

Showing the top 2 NuGet packages that depend on CG.Infrastructure.Entity:

Package Downloads
CG.Infrastructure.Authentication

Infra Authentication library with AspNetCore.Identity setup, extensions and database contexts

CG.Infrastructure.Authorization

Infra Authorization library with Duende setup, extensions and database contexts

GitHub repositories

This package is not used by any popular GitHub repositories.

Version Downloads Last Updated
3.10.2 145 8/21/2025
3.10.1 147 8/10/2025
3.10.0 152 6/16/2025
3.9.0 137 12/10/2024
3.0.1 151 7/16/2024
3.0.0 147 2/26/2024
2.0.0 679 5/16/2023
1.0.0 794 5/26/2022