It's kinda Unit of Work, Repository things, done intuitively in EF AND EF Core.
It’s kinda Unit of Work, Repository things, done intuitively in EF AND EF Core.
You must setting up your DbContext class first, either by inheriting EfCoreDbContext (EF Core) or EfDbContext (EF):
public class MyDbContext : EfCoreDbContext // Inherit from EfDbContext if you are using EF6 or above
{
public DbSet<MyEntity> Entities { get; set; }
}
where MyEntity must inherit from IEntity or from base templating class BaseEntity<TEntity>:
public class MyEntity : BaseEntity<MyEntity>
{
[Key]
public int Id { get; set; }
public string Name { get; set; }
}
next, define your MyDto class for mapping from MyEntity. This MyDto class must inherit from IDto, or better from BaseDto<TDto, TValidator> class:
public class MyDto: BaseDto<MyDto, MyDtoFluentValidator>
{
public int Id { get; set; }
public string Name { get; set; }
}
don’t forget to define you MyDto validator class, by inheriting BaseFluentValidator<T> (using FluentValidator) or BaseValitValidator<T> (using Valit):
public class MyDtoFluentValidator: BaseFluentValidator<MyDto>
{
public MyDtoFluentValidator()
{
RuleFor(x => x.Id).NotEmpty();
RuleFor(x => x.Name).NotEmpty();
}
}
(BaseValitValidator<T> version):
public class MyDtoValitValidator : BaseValitValidator<MyDto>
{
public MyDtoValitValitator()
{
Valitator = ValitRules<MyDto>.Create()
.Ensure(x => x.Id, x => x.IsNonZero())
.Ensure(x => x.Name, x => x.Required())
.CreateValitator();
}
protected override IValitator<MyDto> Valitator { get; }
}
next, create you IMapperProfile derived class to maps MyEntity to MyDto and vice-versa:
public class MyMapperProfile : IMapperProfile
{
public Option<(Type Source, Type Destination)>[] GetBinds()
{
return new Option<(Type Source, Type Destination)>[]
{
(typeof(MyEntity), typeof(MyDto)),
(typeof(MyDto), typeof(MyEntity)),
};
}
}
And, lastly, at your startup class, inject the IMapperService like so:
// Use AutoMapper if you want to support Value-Object pattern
var mapperSvc = new AutoMapperService(); // Choose between AutoMapperService, BatMapMapperService, or MapsterMapperService
mapperSvc.Initialize<IMapperProfile>(new MyMapperProfile());
DslInjecterGetter.SetBaseMapperService(mapperSvc);
var uow = new EfCoreUnitOfWork(new MyDbContext()); // Or use EfUnitOfWork, if you are using EF6 or above.
DslInjecterGetter.SetBaseUnitOfWork(uow);
It’s quite daunting to setting it up huh? But wait, this is how you can utilize my charming library:
Option<CancellationToken> ctok = CancellationToken.None;
var dto = new MyDto();
var createResult = Create<MyEntity, MyDto, MyCreateInterceptor>.Handle(dto, ctok);
var deleteResult = Delete<MyEntity, MyDto, MyDeleteInterceptor>.Handle(dto, ctok);
var readLookupResult = ReadLookup<MyEntity, MyDto, MyReadLookupInterceptor>.Handle(false, ctok);
var readOneResult = ReadOne<MyEntity, MyDto, MyReadOneInterceptor>.Handle(dto, ctok);
var readPagedResult = ReadPaged<MyEntity, MyDto, MyReadPagedInterceptor>.Handle(1, 1, null, "Bla", ctok);
var updateResult = Update<MyEntity, MyDto, MyUpdateInterceptor>.Handle(dto, ctok);
And if you need transactional DB processing, you would do it like this:
using (var trx = uow.GetDbTransaction<MyDbContext>())
{
try
{
var createResult = Create<MyEntity, MyDto, MyCreateInterceptor>.Handle(dto, ctok);
var deleteResult = Delete<MyEntity, MyDto, MyDeleteInterceptor>.Handle(dto, ctok);
var readLookupResult = ReadLookup<MyEntity, MyDto, MyReadLookupInterceptor>.Handle(false, ctok);
var readOneResult = ReadOne<MyEntity, MyDto, MyReadOneInterceptor>.Handle(dto, ctok);
var readPagedResult = ReadPaged<MyEntity, MyDto, MyReadPagedInterceptor>.Handle(1, 1, null, "Bla", ctok);
var updateResult = Update<MyEntity, MyDto, MyUpdateInterceptor>.Handle(dto, ctok);
trx.Commit();
}
catch (Exception ex)
{
trx.Rollback();
}
}
Yes, of course, you will ask: what MyCreateInterceptor, MyDeleteInterceptor, MyReadLookupInterceptor,
MyReadOneInterceptor, MyReadOneInterceptor, MyReadPagedInterceptor, and MyUpdateInterceptor are all about. It’s your task to find what they are….