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....