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
<PackageReference Include="CG.Infrastructure.Entity" Version="3.10.2" />
<PackageVersion Include="CG.Infrastructure.Entity" Version="3.10.2" />
<PackageReference Include="CG.Infrastructure.Entity" />
paket add CG.Infrastructure.Entity --version 3.10.2
#r "nuget: CG.Infrastructure.Entity, 3.10.2"
#:package CG.Infrastructure.Entity@3.10.2
#addin nuget:?package=CG.Infrastructure.Entity&version=3.10.2
#tool nuget:?package=CG.Infrastructure.Entity&version=3.10.2
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
- Fork the repository
- Create a feature branch
- Make your changes
- Add tests for new functionality
- Ensure all tests pass
- 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.
Related Packages
CG.Infrastructure.Core
- Core infrastructure servicesCG.Infrastructure.Data
- Data access and repository patternsCG.Infrastructure.Configuration
- Configuration management
Product | Versions 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. |
-
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.