# EasyCore.EFCoreRepository **Repository Path**: wzhy-0521/easy-core.-efcore-repository ## Basic Information - **Project Name**: EasyCore.EFCoreRepository - **Description**: EFCore仓储功能 - **Primary Language**: Unknown - **License**: MIT - **Default Branch**: master - **Homepage**: None - **GVP Project**: No ## Statistics - **Stars**: 1 - **Forks**: 1 - **Created**: 2025-06-05 - **Last Updated**: 2026-07-31 ## Categories & Tags **Categories**: Uncategorized **Tags**: EasyCore ## README # 🏗️ EasyCore.EFCoreRepository [English README](https://github.com/RockyWang0521/EasyCore.EFCoreRepository/blob/master/README.en-US.md) | [MongoDb English README](https://github.com/RockyWang0521/EasyCore.EFCoreRepository/blob/master/README.MongoDb.en-US.md) 📚 概述 Repository 是软件开发中的一个重要概念,尤其在 领域驱动设计(DDD) 🎯 和 数据访问层 中广泛使用。Repository 是一种 抽象数据访问层的设计模式 🏛️,它封装了数据访问逻辑,使上层业务逻辑与底层数据存储解耦。Repository 就像是数据仓库的接口 📦,用于管理实体对象的持久化(增删改查)操作。 ## 🚀 快速开始 ### 1. 📝 Program 注册 ``` 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(); // ✨ 使用 EasyCore EFCore Repository builder.Services.AddEasyCoreEFCoreRepository(); var app = builder.Build(); if (app.Environment.IsDevelopment()) { app.UseSwagger(); app.UseSwaggerUI(); } app.UseAuthorization(); app.MapControllers(); app.Run(); } } ``` ### 2. 🏷️ 实体继承 EasyCore.EFCoreRepository 提供了一个功能丰富的实体基类 EasyCoreEntity,包含: 🔄 并发标记 🗑️ 软删除 🏢 多租户 ID ``` // 💡 注意:EasyCoreEntity 中的泛型类型为表的主键类型 public class TestEntity : EasyCoreEntity { public string Name { get; set; } public int Age { get; set; } } ``` ### 3. 🔧 仓储类继承 EasyCore.EFCoreRepository 提供了完整的仓储抽象和实现: #### 仓储接口 📜 ``` public interface ITestEntityRepository : IRepository, ITransientDependencie { // 💡 ITransientDependencie 为 EasyCore.Dependencie 中的自动注入标记 } ``` #### 仓储实现 ⚙️ ``` public class TestEntityRepository : EfCoreRepository, ITestEntityRepository { public TestEntityRepository(TestDbContext dbContext, IServiceProvider serviceProvider) : base(dbContext, serviceProvider) { } } ``` ### 4.💡 使用仓储 #### 4.1 🎯 基础 CRUD 操作 ``` [Route("api/[controller]")] [ApiController] public class RepositoryController : ControllerBase { private readonly ITestEntityRepository _repository; public RepositoryController(ITestEntityRepository repository) => _repository = repository; // 🔍 查询 [HttpGet] public async Task Get() { return await _repository.GetFirstAsync(e => e.Name == "Test"); } // ➕ 新增 [HttpPost] public async Task Post() { await _repository.InsertAsync(new TestEntity { Name = "Test", Age = 10, Id = Guid.NewGuid() }, true); } // ✏️ 更新 [HttpPut] public async Task Put() { var entity = await _repository.GetFirstAsync(e => e.Name == "Test"); entity.Age = 20; await _repository.UpdateAsync(entity, true); } // 🗑️ 删除(软删除) [HttpDelete] public async Task Delete() { var entity = await _repository.GetFirstAsync(e => e.Age == 20); entity.IsDeleted = true; await _repository.UpdateAsync(entity, true); } } ``` #### 4.2 📋 完整的 API 列表 EasyCore.EFCoreRepository 提供了丰富的 API 方法: ##### 🔧 过滤器管理 ``` EfCoreRepository AddFilter(Type filterType); EfCoreRepository RemoveFilter(Type filterType); ``` ##### ➕ 插入操作 ``` Task InsertAsync(TEntity entity, bool autoSave = false, CancellationToken cancellationToken = default); TEntity Insert(TEntity entity, bool autoSave = false); Task InsertManyAsync(IEnumerable entities, bool autoSave = false, CancellationToken cancellationToken = default); void InsertMany(IEnumerable entities, bool autoSave = false); ``` ##### ✏️ 更新操作 ``` Task UpdateAsync(TEntity entity, bool autoSave = false, CancellationToken cancellationToken = default); TEntity Update(TEntity entity, bool autoSave = false); Task UpdateManyAsync(IEnumerable entities, bool autoSave = false, CancellationToken cancellationToken = default); void UpdateMany(IEnumerable entities, bool autoSave = false); ``` ##### 🗑️ 删除操作 ``` Task DeleteAsync(TEntity entity, bool autoSave = false, CancellationToken cancellationToken = default); void Delete(TEntity entity, bool autoSave = false); Task DeleteManyAsync(IEnumerable entities, bool autoSave = false, CancellationToken cancellationToken = default); void DeleteMany(IEnumerable entities, bool autoSave = false); ``` ##### 💾 保存操作 ``` Task SaveChangesAsync(CancellationToken cancellationToken = default); int SaveChanges(); ``` ##### 🔍 查询操作 ``` // 获取列表 Task> GetListAsync(CancellationToken cancellationToken = default); List GetList(); Task> GetListAsync(Expression> predicate, CancellationToken cancellationToken = default); List GetList(Expression> predicate); // 数量统计 Task GetCountAsync(CancellationToken cancellationToken = default); long GetCount(); Task GetCountAsync(Expression> predicate, CancellationToken cancellationToken = default); long GetCount(Expression> predicate); // 分页查询(可选排序) Task> GetPagedListAsync(int skipCount, int maxResultCount, CancellationToken cancellationToken = default); List GetPagedList(int skipCount, int maxResultCount); Task> GetPagedListAsync(int skipCount, int maxResultCount, Expression> orderBy, bool ascending = true, CancellationToken cancellationToken = default); List GetPagedList(int skipCount, int maxResultCount, Expression> orderBy, bool ascending = true); // 单实体查询(GetFirstAsync 未找到时抛出异常;GetFirst / GetFirstOrDefaultAsync 返回 null) Task GetFirstAsync(Expression> predicate, CancellationToken cancellationToken = default); Task GetFirstOrDefaultAsync(Expression> predicate, CancellationToken cancellationToken = default); TEntity? GetFirst(Expression> predicate); ``` ##### ⚡ 直接删除操作 ``` // DeleteDirect* 绕过软删除/租户过滤器,物理删除 Task DeleteDirectAsync(Expression> predicate, CancellationToken cancellationToken = default); void DeleteDirect(Expression> predicate); void DeleteManyDirect(IEnumerable entities, bool autoSave = false); Task DeleteManyDirectAsync(IEnumerable entities, bool autoSave = false, CancellationToken cancellationToken = default); ``` ### 5.🎛️ 高级功能 #### 🎯 WhereIf 支持 EasyCore.EFCoreRepository 提供了智能的条件查询支持: ``` IQueryable.WhereIf(xxx != null, x => x.xxx == xxx) ``` ✨ 特性:只有当 xxx != null 条件满足时,才会执行后面的过滤条件,否则继续执行后续代码。 ### 6. 🔍 数据过滤器 EasyCore.EFCoreRepository 内置了两个实用的数据过滤器: 🗑️ ISoftDeleteFilter - 软删除过滤器 🏢 ITenantFilter - 租户过滤器(有租户值时按 TenantId 过滤;无租户时只查 TenantId 为 null 的数据) 可通过 `ITenantProvider` 自定义租户来源(默认与 AspNetCore.Mvc `ICurrentTenant` 对齐:先 `HttpContext.Items["TenantId"]`,再请求头 `X-Tenant-Id`)。 #### 自定义过滤器示例 🎨: ``` public class CustomDataFilter : IDataFilter, ITransientDependencie { public IQueryable Apply(IQueryable query) where TEntity : class, IEntity { query = query.Where(e => ((e as TestEntity)!.Name == "Test")); return query; } } ``` #### 动态过滤器管理 ⚡: ``` _repository .RemoveFilter(typeof(ITenantFilter)) // 🗑️ 移除租户过滤器 .RemoveFilter(typeof(ISoftDeleteFilter)) // 🗑️ 移除软删除过滤器 .AddFilter(typeof(CustomDataFilter)) // ➕ 添加自定义过滤器 .Delete(e => e.Name == "Test1", true); // 🎯 执行操作 ``` # 🔄 EasyCore.UnitOfWork ## 🎯 工作单元模式 EasyCore.UnitOfWork 提供了 `[SaveChanges]` 特性,支持 **接口 / 类 / 方法 / 动态 API / Controller / 事件处理器**: - **服务 / 事件处理器**:Castle DynamicProxy(经 DI 接口代理调用生效) - **API 层**:`IFilterFactory` + 接口特性 Convention(EasyCoreAppService / Controller);Controller 不走 Castle 代理,避免双写 非 MVC 场景请把特性标在**实现类/方法**上,并通过接口解析服务。本包使用 Castle.Core.AsyncInterceptor。 `ControllerBase`(含 Dynamic API AppService)走 MVC Filter 路径。 ### 1. 📝 Program 注册 ``` 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(); // ✨ 使用 EasyCore EFCore Repository builder.Services.AddEasyCoreEFCoreRepository(); // 🔄 UnitOfWork:Castle DynamicProxy + MVC Filter builder.Services.AddEasyCoreUnitOfWork(); // RegisterSaveChangesFor / 程序集扫描已废弃(织入在编译期完成) var app = builder.Build(); if (app.Environment.IsDevelopment()) { app.UseSwagger(); app.UseSwaggerUI(); } app.UseAuthorization(); app.MapControllers(); app.Run(); } } ``` ### 2. 📜 抽象接口定义 ``` public interface IUnitOfWorkTest : ITransientDependencie { /// /// 🎯 测试实体工作单元 /// Task EntityUnitOfWork(); /// /// 💰 测试事务工作单元 /// Task Transaction(); } public interface IUnitOfWorkTest2 : ITransientDependencie { /// /// 🎯 测试实体工作单元 /// Task EntityUnitOfWork(); } ``` ### 3. 🏷️ SaveChangesAttribute 特性使用 #### 方法级别使用 🎯: ``` public class UnitOfWorkTest : IUnitOfWorkTest { private readonly ITestEntityRepository _repository; public UnitOfWorkTest(ITestEntityRepository repository) => _repository = repository; [SaveChanges(typeof(TestDbContext))] public Task EntityUnitOfWork() => _repository.InsertAsync(new TestEntity { Name = "Test", Age = 10, Id = Guid.NewGuid() }); [SaveChanges(true, typeof(TestDbContext))] // 💰 启用事务 public Task Transaction() => _repository.InsertAsync(new TestEntity { Name = "Test", Age = 10, Id = Guid.NewGuid() }); } ``` #### 类级别使用 🏛️: ``` [SaveChanges(typeof(TestDbContext))] public class UnitOfWorkTest2 : IUnitOfWorkTest2 { private readonly ITestEntityRepository _repository; public UnitOfWorkTest2(ITestEntityRepository repository) => _repository = repository; public Task EntityUnitOfWork() => _repository.InsertAsync(new TestEntity { Name = "Test", Age = 10, Id = Guid.NewGuid() }); } ``` #### 💡 特性参数说明: 第一个参数:是否为数据库事务,为 true 时执行事务保存 💰 第二个参数:指定要保存的数据库 DbContext 对象 # 🔍 EasyCore.EntityChange ## 📊 实体变更追踪 EasyCore.EntityChange 提供了强大的实体变更追踪能力!🕵️ ### 1. 📝 Program 注册 ``` // 1) 注册 EntityChange(默认扫描全部 Handler) builder.Services.AddEasyCoreEntityChange(); // 可选:关掉扫描,只精准注册 // builder.Services.AddEasyCoreEntityChange(enableAssemblyScanning: false) // .AddHandler(); // 2) 在每个需要追踪的 AddDbContext 里显式挂拦截器(多 DbContext 就分别写) builder.Services.AddDbContext((sp, options) => { options.UseEasyCoreEntityChange(sp); }); // builder.Services.AddDbContext((sp, options) => // { // options.UseSqlServer("..."); // options.UseEasyCoreEntityChange(sp); // 需要才挂 // }); builder.Services.AddEasyCoreEFCoreRepository(); ``` > 说明:推荐在 `AddDbContext((sp, options) => …)` 里调用 `UseEasyCoreEntityChange(sp)`,多个 DbContext 可按需分别启用。若漏写,与仓储联用时 `AddEasyCoreEFCoreRepository` / `AddEasyCoreMongoDbRepository` 仍会尝试自动挂上。软删除(`IsDeleted` 从 false→true)按 **Deleted** 派发。Handler 异常默认向上抛出(可用 `Configure(o => o.SuppressHandlerExceptions = true)` 改为吞掉)。 ### 2. 🎯 使用实体变更追踪 ``` public class EntityChange : IEntityUpdatedChangeHandler, IEntityDeletedChangeHandler, IEntityAddedChangeHandler { private readonly ILogger _logger; public EntityChange(ILogger logger) => _logger = logger; // ➕ 实体新增处理 public async Task OnAddedAsync(TestEntity entity) { _logger.LogInformation($"🆕 实体新增: Id:{entity.Id}; Name:{entity.Name}; Age:{entity.Age};"); await Task.CompletedTask; } // 🗑️ 实体删除处理 public async Task OnDeletedAsync(TestEntity entity) { _logger.LogInformation($"🗑️ 实体删除: Id:{entity.Id}; Name:{entity.Name}; Age:{entity.Age};"); await Task.CompletedTask; } // ✏️ 实体更新处理 public Task OnUpdatedAsync(TestEntity oldEntity, TestEntity currentEntity) { _logger.LogInformation($"✏️ 实体更新: " + $"Id:{oldEntity.Id} → {currentEntity.Id}; " + $"Name:{oldEntity.Name} → {currentEntity.Name}; " + $"Age:{oldEntity.Age} → {currentEntity.Age};"); return Task.CompletedTask; } } ``` #### 🎯 支持的变更接口: ``` IEntityAddedChangeHandler - 实体新增处理器 ➕ IEntityDeletedChangeHandler - 实体删除处理器 🗑️ IEntityUpdatedChangeHandler - 实体更新处理器 ✏️ ``` # 💎 Custom Entity 和 Custom Data Filter ## 1. 用户自定义数据库实体🦄 用户可根据自身项目进行自定义用户实体配置 ``` public class CustomEntity : EasyCoreEntity { public string CreateId{ get; set; } } public class TestCustomEntity : CustomEntity { } ``` CustomEntity为用户自定义实体对象,自定义实体中存在CreateId字段。保存时可用IEntityAddedChangeHandler 自动保存当前用户id。 ``` public class TestCustomEntityRepository : EfCoreRepository,ITestCustomEntityRepository,IEntityAddedChangeHandler { 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. 用户自定义数据过滤器🎁 用户可根据自身项目进行自定义数据过滤器配置 ``` public class TestEntityRepository : EfCoreRepository, ITestEntityRepository { public TestEntityRepository(TestDbContext dbContext, IServiceProvider serviceProvider) : base(dbContext, serviceProvider) { } /// /// Applies permanent data filters before persisting entities (Insert/Update/Delete). /// This method is called during the persistence pipeline to enforce global filters. /// /// The list of data filters that are currently scheduled for execution. /// The updated list of data filters after applying permanent filter rules. public override List OnApplyPersistingFilters(List dataFilters) { AddOnce(dataFilters, typeof(CustomDataFilter)); RemoveIfExistsFilter(dataFilters, typeof(CustomDataFilter)); return dataFilters; } } ``` 重写OnApplyPersistingFilters方法,添加或修改永久过滤器设置。 #### ✨ 特性:当实体完成增删改操作时,系统会自动调用对应的接口方法,实现无缝的变更追踪! # 🏷️CustomRepository 用户自定义仓储,由于每一个系统的实体字段都不相同。EasyCore不会对用户的实体字段和字段类型进行限制,比如添加人id等信息。类型可以是Guid也可以是long。 CustomEntityRepository 提供了三个重写方法:OnBeforeAdd (在添加前);OnBeforeUpdate (在修改前);OnBeforeDelete (在删除前); 这样我们在增删改的时候不需要手动的添加字段值。CustomRepository自动添加。 ``` public class CustomEntityRepository : EfCoreRepository where TDbContext : DbContext where TEntity : class, IEntity { public CustomEntityRepository(TDbContext dbContext, IServiceProvider serviceProvider) : base(dbContext, serviceProvider) { } /// /// Custom method to set the CreateId property of the entity before adding it to the database. /// /// public override void OnBeforeAdd(TEntity entity) { if (entity is CustomEntity customEntity) { customEntity.CreateId = "Test"; } } /// /// Custom method to set the UpdateId property of the entity before updating it in the database. /// /// public override void OnBeforeUpdate(TEntity entity) { // Do something entity before update } /// /// Custom method to set the DeleteId property of the entity before deleting it from the database. /// /// public override void OnBeforeDelete(TEntity entity) { // Do something entity before delete } ``` ``` public class TestCustomEntityRepository : CustomEntityRepository, ITestCustomEntityRepository { public TestCustomEntityRepository(TestDbContext dbContext, IServiceProvider serviceProvider) : base(dbContext, serviceProvider) { } } ``` 把选择权完全交由用户处理。 # 🎉 总结 EasyCore.EFCoreRepository 系列组件提供了: 🏗️ 完整的仓储模式实现 🔄 智能的工作单元管理 🔍 强大的实体变更追踪 🎯 丰富的查询和过滤功能 ⚡ 高性能的数据访问 让您的数据访问层更加 优雅、强大、易维护!✨