heitech.efXt
1.0.1
There is a newer version of this package available.
See the version list below for details.
See the version list below for details.
dotnet add package heitech.efXt --version 1.0.1
NuGet\Install-Package heitech.efXt -Version 1.0.1
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="heitech.efXt" Version="1.0.1" />
For projects that support PackageReference, copy this XML node into the project file to reference the package.
paket add heitech.efXt --version 1.0.1
The NuGet Team does not provide support for this client. Please contact its maintainers for support.
#r "nuget: heitech.efXt, 1.0.1"
#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.
// Install heitech.efXt as a Cake Addin #addin nuget:?package=heitech.efXt&version=1.0.1 // Install heitech.efXt as a Cake Tool #tool nuget:?package=heitech.efXt&version=1.0.1
The NuGet Team does not provide support for this client. Please contact its maintainers for support.
efXt
Aim of this library:
- Use Ef Core with common functionality so you dont have to implement it over and over again.
- IRepository<TEntity> interface
- Specification pattern for repeatable
- UnitOfWork and Rollback for better control of the ChangeTracking
- Make it easy to register the dbContext and setup code via the Microsoft.Extensions.DependencyInjection
- There is also an abstract class for the Repositories (GenericRepository<TEntity, TId>) which implements the most basic functions already
- All implementations of the IRepository<,> interface are also automatically added to the Dependency Injection (any assembly in the dependent ones of the executing assembly)
IUnitOfWork
/// <summary>
/// Represents all Commands to interact with the database and have a
/// Transaction scope in the Application before committing the changes to the database
/// </summary>
public interface IUnitOfWork : IAsyncDisposable
{
void Add<T>(T one)
where T : class;
void AddMany<T>(IEnumerable<T> many)
where T : class;
void Update<T>(T one)
where T : class;
void UpdateMany<T>(IEnumerable<T> many)
where T : class;
void Delete<T>(T one)
where T : class;
void DeleteMany<T>(IEnumerable<T> many)
where T : class;
///<summary>
/// Resets all changes on this entity, so it will not be commited to the database on Save
///</summary>
void RollbackOne<T>(T entity, Func<T, bool> predicate)
where T : class;
///<summary>
/// Resets all changes on all changed entities, so it will not be commited to the database on Save
///</summary>
void RollBackAll();
///<summary>
/// Commit all the changes made to any entities since the start of the UnitOfWork
///</summary>
Task SaveAsync();
}
IRepository<TEntity, TId>
///<summary>
/// Abstraction for DataAccess with generic and Specification methods
///</summary>
public interface IRepository<TEntity, TId>
where TEntity : class
{
/// <summary>
/// for special cases operate directly on the IQueryable
/// </summary>
IQueryable<TEntity> AsQueryable();
Task<TEntity> GetByIdAsync(TId id);
Task<TEntity> GetByIdAsync(ISpecification<TEntity> specification);
Task<IReadOnlyList<TEntity>> GetAllAsync();
Task<IReadOnlyList<TEntity>> GetAllBySpecificationAsync(ISpecification<TEntity> specification);
}
ISpecification<TEntity>
///<summary>
/// Provides Filtering capabilities for a Query on the Repository calls.
///</summary>
public interface ISpecification<TEntity>
where TEntity : class
{
Expression<Func<TEntity, bool>> Build();
}
GenericRepositry<TEntity, TId>
public abstract class GenericRepository<TEntity, TId> : IRepository<TEntity, TId>
where TEntity : class
{
protected DbContext Context { get; }
public GenericRepository(DbContext dbContext)
=> Context = dbContext;
public abstract Task<TEntity> GetByIdAsync(TId id);
public IQueryable<TEntity> AsQueryable() => Context.Set<TEntity>().AsQueryable();
public Task<TEntity> GetByIdAsync(ISpecification<TEntity> specification)
=> Context.Set<TEntity>().FirstOrDefaultAsync(specification.Build());
public async Task<IReadOnlyList<TEntity>> GetAllAsync()
=> await Context.Set<TEntity>().ToListAsync();
public async Task<IReadOnlyList<TEntity>> GetAllBySpecificationAsync(ISpecification<TEntity> specification)
=> await Context.Set<TEntity>().Where(specification.Build()).ToListAsync();
}
Examples
See some examples below. We assume Asp.Net Core for this Scenario. Else you´d need to use the static Factory class and manage the instances yourself. First Register it in the Startup of Asp.Net Core
// example with SqlServer, but any Action on DbContextOptionsBuilder are allowed.
services.RegisterEfAbstraction<MyDbContext>(options => options.UseSqlServer("connectionstring"));
Assume the following entities as the POCOS for EF Core
public class Entity
{
public int Id { get; set; }
public string Note { get; set; }
}
Example for all interfaces in some fictious usecases for our example Entity
public class EntityUseCases
{
private readonly IUnitOfWork _unitOfWork;
private readonly IRepository<Entity, int> _repository;
public EntityUseCases(IRepository<Entity, int> repository, IUnitOfWork unitOfWork)
{
_unitOfWork = unitOfWork;
_repository = repository;
}
public Task AddEntity(int id, string note)
{
_unitOfWork.Add(new Entity { Id = id, Note = note });
return _unitOfWork.SaveAsync();
}
public async Task UpdateNote(int id, string note)
{
Entity entity = await _repository.GetByIdAsync(id);
// change tracking on db context already marks the Entity as changed
// no need to call _unitOfOwrk.Update, only if an entity is not attached yet (e.g. when using AsNoTracking)
entity.Note = note;
await _unitOfWork.SaveAsync();
}
// it is also possible to provide multiple entities for each call to Add, Update or Delete with the Many Suffix
public async Task DeleteAllEntities()
{
IReadOnlyList<Entity> entities = await _repository.GetAllAsync();
_unitOfWork.DeleteMany(entities);
await _unitOfWork.SaveAsync();
}
// read use case with special filter (Specifications also work for )
public Task<IReadOnlyList<Entity>> GetEntitiesWithSpecificNote()
{
var specification = new NoteShorterThanThreeCharsSpecification();
return _repository.GetAllBySpecificationAsync(specification);
}
private class NoteShorterThanThreeCharsSpecification : ISpecification<Entity>
{
public Expression<Func<Entity, bool>> Build()
=> entity => entity.Note.Length <= 3;
}
}
Example for a specific Query you still want to be able to test without the dbContext
public interface IFirstTenEntitiesQuery
{
Task<IReadOnlyList<Entity>> ExecuteAsync();
}
public class Query : IFirstTenEntitiesQuery
{
private readonly IRepository<Entity, int> _repository;
public Query(DbContext repository)
=> _repository = repository;
public async Task<IReadOnlyList<Entity>> ExecuteAsync()
=> await _repository.AsQueryable()
.Take(10)
// may also use Include and other operators here.
.ToListAsync();
}
Product | Versions Compatible and additional computed target framework versions. |
---|---|
.NET | net6.0 is compatible. net6.0-android was computed. net6.0-ios was computed. net6.0-maccatalyst was computed. net6.0-macos was computed. net6.0-tvos was computed. net6.0-windows was computed. net7.0 was computed. net7.0-android was computed. net7.0-ios was computed. net7.0-maccatalyst was computed. net7.0-macos was computed. net7.0-tvos was computed. net7.0-windows was computed. net8.0 was computed. 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. |
Compatible target framework(s)
Included target framework(s) (in package)
Learn more about Target Frameworks and .NET Standard.
-
net6.0
- Microsoft.EntityFrameworkCore (>= 6.0.0)
- Scrutor (>= 3.3.0)
NuGet packages
This package is not used by any NuGet packages.
GitHub repositories
This package is not used by any popular GitHub repositories.
third release