EasyCore.EntityChange 8.0.4

dotnet add package EasyCore.EntityChange --version 8.0.4
                    
NuGet\Install-Package EasyCore.EntityChange -Version 8.0.4
                    
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="EasyCore.EntityChange" Version="8.0.4" />
                    
For projects that support PackageReference, copy this XML node into the project file to reference the package.
<PackageVersion Include="EasyCore.EntityChange" Version="8.0.4" />
                    
Directory.Packages.props
<PackageReference Include="EasyCore.EntityChange" />
                    
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 EasyCore.EntityChange --version 8.0.4
                    
#r "nuget: EasyCore.EntityChange, 8.0.4"
                    
#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 EasyCore.EntityChange@8.0.4
                    
#: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=EasyCore.EntityChange&version=8.0.4
                    
Install as a Cake Addin
#tool nuget:?package=EasyCore.EntityChange&version=8.0.4
                    
Install as a Cake Tool

πŸ—οΈ EasyCore.EFCoreRepository

δΈ­ζ–‡ README | MongoDb δΈ­ζ–‡ README

πŸ“š Overview Repository is a crucial concept in software development, widely used especially in Domain-Driven Design (DDD) 🎯 and the Data Access Layer. Repository is a design pattern πŸ›οΈ that abstracts the data access layer, encapsulating data access logic and decoupling upper-level business logic from underlying data storage. Repository acts like an interface πŸ“¦ to the data warehouse, managing persistence operations (CRUD) for entity objects.

πŸš€ Quick Start

1. πŸ“ Program Registration

public class Program
{
    public static void Main(string[] args)
    {
        var builder = WebApplication.CreateBuilder(args);

        builder.Services.AddControllers();
        builder.Services.AddEndpointsApiExplorer();
        builder.Services.AddSwaggerGen();
        builder.Services.EasyCoreDependencie();

        builder.Services.AddDbContext<TestDbContext>();

        // ✨ Use EasyCore EFCore Repository
        builder.Services.EasyCoreEFCoreRepository();

        var app = builder.Build();

        if (app.Environment.IsDevelopment())
        {
            app.UseSwagger();
            app.UseSwaggerUI();
        }

        app.UseAuthorization();
        app.MapControllers();
        app.Run();
    }
}

2. 🏷️ Entity Inheritance

EasyCore.EFCoreRepository provides a feature-rich entity base class EasyCoreEntity, including:

πŸ”„ Concurrency Token

πŸ—‘οΈ Soft Delete

🏒 Multi-Tenant ID

// πŸ’‘ Note: The generic type in `EasyCoreEntity<TKey>` is the primary key type of the table
public class TestEntity : EasyCoreEntity<Guid>
{
    public string Name { get; set; }
    public int Age { get; set; }
}

3. πŸ”§ Repository Class Inheritance

EasyCore.EFCoreRepository provides complete repository abstraction and implementation:

Repository Interface πŸ“œ

public interface ITestEntityRepository : IRepository<TestDbContext, TestEntity>, ITransientDependencie
{
    // πŸ’‘ ITransientDependencie is the auto-injection marker from EasyCore.Dependencie
}

Repository Implementation βš™οΈ

public class TestEntityRepository : EfCoreRepository<TestDbContext, TestEntity>, ITestEntityRepository
{
    public TestEntityRepository(TestDbContext dbContext, IServiceProvider serviceProvider) 
        : base(dbContext, serviceProvider)
    {
    }
}

4.πŸ’‘ Using the Repository

4.1 🎯 Basic CRUD Operations
[Route("api/[controller]")]
[ApiController]
public class RepositoryController : ControllerBase
{
    private readonly ITestEntityRepository _repository;

    public RepositoryController(ITestEntityRepository repository) => _repository = repository;

    // πŸ” Query
    [HttpGet]
    public async Task<TestEntity> Get()
    {
        return await _repository.GetAsync(e => e.Name == "Test");
    }

    // βž• Insert
    [HttpPost]
    public async Task Post()
    {
        await _repository.InsertAsync(new TestEntity { 
            Name = "Test", 
            Age = 10, 
            Id = Guid.NewGuid() 
        }, true);
    }

    // ✏️ Update
    [HttpPut]
    public async Task Put()
    {
        var entity = await _repository.GetAsync(e => e.Name == "Test");
        entity.Age = 20;
        await _repository.UpdateAsync(entity, true);
    }

    // πŸ—‘οΈ Delete (Soft Delete)
    [HttpDelete]
    public async Task Delete()
    {
        var entity = await _repository.GetAsync(e => e.Age == 20);
        entity.IsDeleted = true;
        await _repository.UpdateAsync(entity, true);
    }
}
4.2 πŸ“‹ Complete API List

EasyCore.EFCoreRepository provides a rich set of API methods:

πŸ”§ Filter Management
EfCoreRepository<TDbContext, TEntity> AddFilter(Type filterType);

EfCoreRepository<TDbContext, TEntity> RemoveFilter(Type filterType);
βž• Insert Operations
Task<TEntity> InsertAsync(TEntity entity, bool autoSave = false, CancellationToken cancellationToken = default);

TEntity Insert(TEntity entity, bool autoSave = false);

Task InsertManyAsync(IEnumerable<TEntity> entities, bool autoSave = false, CancellationToken cancellationToken = default);

void InsertMany(IEnumerable<TEntity> entities, bool autoSave = false);
✏️ Update Operations
Task<TEntity> UpdateAsync(TEntity entity, bool autoSave = false, CancellationToken cancellationToken = default);

TEntity Update(TEntity entity, bool autoSave = false);

Task UpdateManyAsync(IEnumerable<TEntity> entities, bool autoSave = false, CancellationToken cancellationToken = default);

void UpdateMany(IEnumerable<TEntity> entities, bool autoSave = false);
πŸ—‘οΈ Delete Operations
Task DeleteAsync(TEntity entity, bool autoSave = false, CancellationToken cancellationToken = default);

void Delete(TEntity entity, bool autoSave = false);

Task DeleteManyAsync(IEnumerable<TEntity> entities, bool autoSave = false, CancellationToken cancellationToken = default);

void DeleteMany(IEnumerable<TEntity> entities, bool autoSave = false);
πŸ’Ύ Save Operations
Task<int> SaveChangesAsync(CancellationToken cancellationToken = default);

int SaveChanges();
πŸ” Query Operations
// Get List
Task<List<TEntity>> GetListAsync(bool includeDetails = false, CancellationToken cancellationToken = default);

List<TEntity> GetList(bool includeDetails = false);

// Count
Task<long> GetCountAsync(CancellationToken cancellationToken = default);

long GetCount();

Task<long> GetCountAsync(Expression<Func<TEntity, bool>> predicate, CancellationToken cancellationToken = default);

long GetCount(Expression<Func<TEntity, bool>> predicate);

// Paged Query
Task<List<TEntity>> GetPagedListAsync(int skipCount, int maxResultCount, string? sorting = null, bool includeDetails = false, CancellationToken cancellationToken = default);

List<TEntity> GetPagedList(int skipCount, int maxResultCount, string? sorting = null, bool includeDetails = false);

// Conditional Query
Task<List<TEntity>> GetListAsync(Expression<Func<TEntity, bool>> predicate, bool includeDetails = false, CancellationToken cancellationToken = default);

List<TEntity> GetList(Expression<Func<TEntity, bool>> predicate, bool includeDetails = false);

// Single Entity Query
Task<TEntity> GetAsync(Expression<Func<TEntity, bool>> predicate, bool includeDetails = false, CancellationToken cancellationToken = default);

TEntity? Get(Expression<Func<TEntity, bool>> predicate, bool includeDetails = false);
⚑ Direct Delete Operations
Task DeleteDirectAsync(Expression<Func<TEntity, bool>> predicate, CancellationToken cancellationToken = default);

void DeleteDirect(Expression<Func<TEntity, bool>> predicate);

void DeleteManyDirect(IEnumerable<TEntity> entities, bool autoSave = false);

Task DeleteManyDirectAsync(IEnumerable<TEntity> entities, bool autoSave = false, CancellationToken cancellationToken = default);

5.πŸŽ›οΈ Advanced Features

🎯 WhereIf Support

EasyCore.EFCoreRepository provides intelligent conditional query support:

IQueryable<T>.WhereIf(xxx != null, x => x.xxx == xxx)

✨ Feature: The subsequent filter condition is only executed when the xxx != null condition is met; otherwise, the code continues execution.

6. πŸ” Data Filters

EasyCore.EFCoreRepository includes two practical built-in data filters:

πŸ—‘οΈ ISoftDeleteFilter - Soft Delete Filter

🏒 ITenantFilter - Tenant Filter

Custom Filter Example 🎨:
public class CustomDataFilter : IDataFilter, ITransientDependencie
{
    public IQueryable<TEntity> Apply<TEntity>(IQueryable<TEntity> query) where TEntity : class, IEntity
    {
        query = query.Where(e => ((e as TestEntity)!.Name == "Test"));
        return query;
    }
}
Dynamic Filter Management ⚑:
_repository
    .RemoveFilter(typeof(ITenantFilter))      // πŸ—‘οΈ Remove Tenant Filter
    .RemoveFilter(typeof(ISoftDeleteFilter))  // πŸ—‘οΈ Remove Soft Delete Filter  
    .AddFilter(typeof(CustomDataFilter))      // βž• Add Custom Filter
    .Delete(e => e.Name == "Test1", true);    // 🎯 Execute Operation

πŸ”„ EasyCore.UnitOfWork

🎯 Unit of Work Pattern

EasyCore.UnitOfWork provides the SaveChangesAttribute feature, making data persistence simple and efficient! ✨

1. πŸ“ Program Registration

public class Program
{
    public static void Main(string[] args)
    {
        var builder = WebApplication.CreateBuilder(args);

        builder.Services.AddControllers();
        builder.Services.AddEndpointsApiExplorer();
        builder.Services.AddSwaggerGen();
        builder.Services.EasyCoreDependencie();
        builder.Services.AddDbContext<TestDbContext>();

        // ✨ Use EasyCore EFCore Repository
        builder.Services.EasyCoreEFCoreRepository();
        // πŸ”„ Use EasyCore UnitOfWork
        builder.Services.EasyCoreUnitOfWork();

        var app = builder.Build();

        if (app.Environment.IsDevelopment())
        {
            app.UseSwagger();
            app.UseSwaggerUI();
        }

        app.UseAuthorization();
        app.MapControllers();
        app.Run();
    }
}

2. πŸ“œ Abstract Interface Definition

public interface IUnitOfWorkTest : ITransientDependencie
{
    /// <summary>
    /// 🎯 Test Entity Unit of Work
    /// </summary>
    Task<TestEntity> EntityUnitOfWork();

    /// <summary>
    /// πŸ’° Test Transaction Unit of Work  
    /// </summary>
    Task<TestEntity> Transaction();
}

public interface IUnitOfWorkTest2 : ITransientDependencie
{
    /// <summary>
    /// 🎯 Test Entity Unit of Work
    /// </summary>
    Task<TestEntity> EntityUnitOfWork();
}

3. 🏷️ Using the SaveChangesAttribute

Method Level Usage 🎯:
public class UnitOfWorkTest : IUnitOfWorkTest
{
    private readonly ITestEntityRepository _repository;

    public UnitOfWorkTest(ITestEntityRepository repository) => _repository = repository;

    [SaveChanges(typeof(TestDbContext))]
    public Task<TestEntity> EntityUnitOfWork() 
        => _repository.InsertAsync(new TestEntity { Name = "Test", Age = 10, Id = Guid.NewGuid() });

    [SaveChanges(true, typeof(TestDbContext))]  // πŸ’° Enable Transaction
    public Task<TestEntity> Transaction() 
        => _repository.InsertAsync(new TestEntity { Name = "Test", Age = 10, Id = Guid.NewGuid() });
}
Class Level Usage πŸ›οΈ:
[SaveChanges(typeof(TestDbContext))]
public class UnitOfWorkTest2 : IUnitOfWorkTest2
{
    private readonly ITestEntityRepository _repository;

    public UnitOfWorkTest2(ITestEntityRepository repository) => _repository = repository;

    public Task<TestEntity> EntityUnitOfWork() 
        => _repository.InsertAsync(new TestEntity { Name = "Test", Age = 10, Id = Guid.NewGuid() });
}
πŸ’‘ Attribute Parameter Description:

First parameter: Whether it is a database transaction; when true, performs a transactional save πŸ’°

Second parameter: Specifies the database DbContext object to save

πŸ” EasyCore.EntityChange

πŸ“Š Entity Change Tracking

EasyCore.EFCoreEntityChange provides powerful entity change tracking capabilities! πŸ•΅οΈ

1. πŸ“ Program Registration

builder.Services.AddDbContext<TestDbContext>(op =>
{
    op.UseEasyCoreEntityChange(builder.Services); // ✨ Use EasyCore EFCore Entity Change Tracking
});

builder.Services.AddDbContext<Test2DbContext>(op =>
{
    op.UseEasyCoreEntityChange(builder.Services); // ✨ Use EasyCore EFCore Entity Change Tracking
});

// πŸ”§ Enable EasyCore Entity Change Service
builder.Services.EasyCoreEntityChange();

2. 🎯 Using Entity Change Tracking

public class EntityChange : 
    IEntityUpdatedChangeHandler<TestEntity>, 
    IEntityDeletedChangeHandler<TestEntity>, 
    IEntityAddedChangeHandler<TestEntity>
{
    private readonly ILogger<EntityChange> _logger;

    public EntityChange(ILogger<EntityChange> logger) => _logger = logger;

    // βž• Entity Added Handler
    public async Task OnAddedAsync(TestEntity entity)
    {
        _logger.LogInformation($"πŸ†• Entity Added: Id:{entity.Id}; Name:{entity.Name}; Age:{entity.Age};");
        await Task.CompletedTask;
    }

    // πŸ—‘οΈ Entity Deleted Handler  
    public async Task OnDeletedAsync(TestEntity entity)
    {
        _logger.LogInformation($"πŸ—‘οΈ Entity Deleted: Id:{entity.Id}; Name:{entity.Name}; Age:{entity.Age};");
        await Task.CompletedTask;
    }

    // ✏️ Entity Updated Handler
    public Task OnUpdatedAsync(TestEntity oldEntity, TestEntity currentEntity)
    {
        _logger.LogInformation($"✏️ Entity Updated: " +
            $"Id:{oldEntity.Id} β†’ {currentEntity.Id}; " +
            $"Name:{oldEntity.Name} β†’ {currentEntity.Name}; " +
            $"Age:{oldEntity.Age} β†’ {currentEntity.Age};");
        return Task.CompletedTask;
    }
}
🎯 Supported Change Interfaces:
IEntityAddedChangeHandler<TEntity> - Entity Added Handler βž•

IEntityDeletedChangeHandler<TEntity> - Entity Deleted Handler πŸ—‘οΈ

IEntityUpdatedChangeHandler<TEntity> - Entity Updated Handler ✏️

πŸ’Ž Custom Entity And Custom Data Filter

1. User-Defined Database EntityπŸ¦„

Users can configure custom user entities based on their specific project requirements.

    public class CustomEntity : EasyCoreEntity<Guid>
    {
        public string CreateId{ get; set; }
    }

    public class TestCustomEntity : CustomEntity
    {

    }

The CustomEntity represents a user-defined entity object. This custom entity contains a CreateId field. During the save operation, the IEntityAddedChangeHandler<TEntity> interface can be utilized to automatically save the current user's ID.

    public class TestCustomEntityRepository : EfCoreRepository<TestDbContext, TestCustomEntity>,ITestCustomEntityRepository,IEntityAddedChangeHandler<TestCustomEntity>
    {
        public TestCustomEntityRepository(TestDbContext dbContext, IServiceProvider serviceProvider) : base(dbContext, serviceProvider)
        {

        }

        public async Task OnAddedAsync(TestCustomEntity entity)
        {
            if (entity is CustomEntity customEntity)
            {
                customEntity.CreateId = "Test";
            }

            await Task.CompletedTask;
        }
    }

2. User-defined Data Filters🎁

Users can configure custom data filters based on their specific project requirements.

    public class TestEntityRepository :
        EfCoreRepository<TestDbContext, TestEntity>,
        ITestEntityRepository
    {
        public TestEntityRepository(TestDbContext dbContext, IServiceProvider serviceProvider) : base(dbContext, serviceProvider)
        {

        }

        /// <summary>
        /// Applies permanent data filters before persisting entities (Insert/Update/Delete).
        /// This method is called during the persistence pipeline to enforce global filters.
        /// </summary>
        /// <param name="dataFilters">The list of data filters that are currently scheduled for execution.</param>
        /// <returns>The updated list of data filters after applying permanent filter rules.</returns>
        public override List<IDataFilter> OnApplyPersistingFilters(List<IDataFilter> dataFilters)
        {
            AddOnce(dataFilters, typeof(CustomDataFilter));

            RemoveIfExistsFilter(dataFilters, typeof(CustomDataFilter));

            return dataFilters;
        }
    }

Override the OnApplyPersistingFilters method to add or modify persistent filter settings.

✨ Feature: When entity add, delete, or update operations are completed, the system automatically calls the corresponding interface methods, enabling seamless change tracking!

πŸŽ‰ Summary

The EasyCore.EFCoreRepository series of components provides:

πŸ—οΈ Complete Repository Pattern Implementation

πŸ”„ Smart Unit of Work Management

πŸ” Powerful Entity Change Tracking

🎯 Rich Querying and Filtering Capabilities

⚑ High-Performance Data Access

Making your data access layer more elegant, powerful, and maintainable! ✨

Product Compatible and additional computed target framework versions.
.NET net8.0 is compatible.  net8.0-android was computed.  net8.0-browser was computed.  net8.0-ios was computed.  net8.0-maccatalyst was computed.  net8.0-macos was computed.  net8.0-tvos was computed.  net8.0-windows was computed.  net9.0 was computed.  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.

NuGet packages (1)

Showing the top 1 NuGet packages that depend on EasyCore.EntityChange:

Package Downloads
EasyCore.EFCoreRepository

.net core repository.

GitHub repositories

This package is not used by any popular GitHub repositories.

Version Downloads Last Updated
8.0.4 280 11/30/2025
8.0.2 172 11/23/2025