EasyCore.EFCoreRepository
8.0.7
dotnet add package EasyCore.EFCoreRepository --version 8.0.7
NuGet\Install-Package EasyCore.EFCoreRepository -Version 8.0.7
<PackageReference Include="EasyCore.EFCoreRepository" Version="8.0.7" />
<PackageVersion Include="EasyCore.EFCoreRepository" Version="8.0.7" />
<PackageReference Include="EasyCore.EFCoreRepository" />
paket add EasyCore.EFCoreRepository --version 8.0.7
#r "nuget: EasyCore.EFCoreRepository, 8.0.7"
#:package EasyCore.EFCoreRepository@8.0.7
#addin nuget:?package=EasyCore.EFCoreRepository&version=8.0.7
#tool nuget:?package=EasyCore.EFCoreRepository&version=8.0.7
ποΈ 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!
π·οΈCustomRepository
A user-defined repository. Since the entity fields vary across different systems, EasyCore does not restrict the entity fields or field types used by users. For example, fields like "creator ID" can be either Guid or long.
CustomEntityRepository provides three overridable methods: OnBeforeAdd (before adding), OnBeforeUpdate (before updating), and OnBeforeDelete (before deleting).
This allows us to automatically set field values during create, update, and delete operations without manual intervention. CustomRepository handles this automatically.
public class CustomEntityRepository<TDbContext, TEntity> : EfCoreRepository<TDbContext, TEntity>
where TDbContext : DbContext
where TEntity : class, IEntity
{
public CustomEntityRepository(TDbContext dbContext, IServiceProvider serviceProvider) : base(dbContext, serviceProvider)
{
}
/// <summary>
/// Custom method to set the CreateId property of the entity before adding it to the database.
/// </summary>
/// <param name="entity"></param>
public override void OnBeforeAdd(TEntity entity)
{
if (entity is CustomEntity customEntity)
{
customEntity.CreateId = "Test";
}
}
/// <summary>
/// Custom method to set the UpdateId property of the entity before updating it in the database.
/// </summary>
/// <param name="entity"></param>
public override void OnBeforeUpdate(TEntity entity)
{
// Do something entity before update
}
/// <summary>
/// Custom method to set the DeleteId property of the entity before deleting it from the database.
/// </summary>
/// <param name="entity"></param>
public override void OnBeforeDelete(TEntity entity)
{
// Do something entity before delete
}
public class TestCustomEntityRepository : CustomEntityRepository<TestDbContext, TestCustomEntity>, ITestCustomEntityRepository
{
public TestCustomEntityRepository(TestDbContext dbContext, IServiceProvider serviceProvider) : base(dbContext, serviceProvider)
{
}
}
Full control is given to the user.
π 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 | Versions 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. |
-
net8.0
- EasyCore.EntityChange (>= 8.0.3)
- Microsoft.AspNetCore.Mvc (>= 2.1.3)
- Microsoft.EntityFrameworkCore (>= 8.0.0)
- Microsoft.Extensions.DependencyInjection.Abstractions (>= 8.0.0)
NuGet packages
This package is not used by any NuGet packages.
GitHub repositories
This package is not used by any popular GitHub repositories.