Índice
Em grande parte de nosso sistema, muitas telas precisam contém conter apenas uma lógica de CRUD básica (Create, Read, Update e Delete).
Visando uma maior produtividade, o TNF contém trás classes que agilizam essa criação de serviços de forma automática.
Para utilizar essas funcionalidades instale via nuget o pacote Tnf Tnf.App.EntityFrameworkCore disponível em nosso package source: https://www.myget.org/F/tnf/api/v3/index.json
Primeiro vamos criar nossa interface para o serviço de aplicação definindo sua herança para a interface IAsyncCrudAppService<CountryDto> IAppApplicationService<PersonDto, GetAllPeopleDto> informando qual o Dto que será usado para o mapeamento da entidade, e qual o Dto para métodos de GetAll:
Bloco de código | ||||||||
---|---|---|---|---|---|---|---|---|
| ||||||||
public interface ICountryAppServiceIPersonAppService : IAsyncCrudAppService<CountryDto>IAppApplicationService<PersonDto, GetAllPeopleDto> { } |
...
...
No exemplo acima criamos um serviço para trabalhar com o objeto CountryDto representando a entidade persistida com Entity Framework Core.Dto:
Bloco de código | ||||||||
---|---|---|---|---|---|---|---|---|
| ||||||||
public class CountryDtoPersonDto : CustomValidateDtoBase { public static PersonDto NullInstance = new PersonDto().AsNullable(); public string Name { get; set; } public override void AddValidationErrors(CustomValidationContext context)enum Error { if (string.IsNullOrWhiteSpace(Name)) GetAllPeople = 1, { GetPerson = 2, PostPerson = 3, context.Results.Add(new ValidationResult("Name is required")); PutPerson = 4, DeletePerson = }5 } } |
Acima temos a definição de nosso DTO usando a herança de uma classe chamada CustomValidate. Essa classe realiza a validação do objeto DTO ao criar o serviço automático. Nela podem ser adicionadas regras de validação personalizadas.
...
Entidade
...
Para a tabela "Countries" temos a seguinte definição:
Bloco de código | ||||||||
---|---|---|---|---|---|---|---|---|
| ||||||||
[AutoMap(typeof(CountryDto))] [Table("Countries")] public class CountryPerson : Entity { public const int MaxNameLength = 256; [Required] [MaxLength(MaxNameLength)] public string Name { get; set; } public CountryPerson() { } public CountryPerson(int id, string name) { Id = id; Name = name; } public enum Error { PersonNameMustHaveValue = 1 } } |
Até este ponto temos nossa definição de serviço (interface), DTO Dto criado e Entidade no Entity Framework Core representada.
Note o atributo AutoMap esta sendo usado na entidade.
Essa especificação garante que ao utilizar o serviço de CRUD irá usar o Mapper automático das propriedades pra classe de infraestrutura e DTO Dto.
Para utilizar o AutoMapper consulte o tópico de Mapeamento Automático de Entidades.
...
...
Agora vamos implementar a nossa classe de serviço:
Bloco de código | ||||||||
---|---|---|---|---|---|---|---|---|
| ||||||||
public class CountryAppService : AsyncCrudAppService<Country, CountryDto>, ICountryAppService { public CountryAppService(IRepository<Country> repository) PersonAppService : AppApplicationService, IPersonAppService { private readonly IAppDomainService<Person> _service; public PersonAppService(IAppDomainService<Person> service) { _service = service; } public IListDto<PersonDto, int> GetAll(GetAllPeopleDto request) => _service.GetAll<PersonDto>(request, p => request.Name.IsNullOrEmpty() || p.Name.Contains(request.Name)); public PersonDto Get(IRequestDto<int> id) { ValidateRequestDto(id, nameof(id)); if (Notification.HasNotification()) return PersonDto.NullInstance; var entity = _service.Get(id); return entity.MapTo<PersonDto>(); } public PersonDto Create(PersonDto person) { ValidateDto(person, nameof(person)); if (Notification.HasNotification()) return PersonDto.NullInstance; var personBuilder = new PersonBuilder(Notification) .WithId(person.Id) .WithName(person.Name); person.Id = _service.InsertAndGetId(personBuilder); return person; } public PersonDto Update(int id, PersonDto person) { ValidateDtoAndId(person, id, nameof(person), nameof(id)); if (Notification.HasNotification()) return PersonDto.NullInstance; var personBuilder = new PersonBuilder(Notification) .WithId(id) .WithName(person.Name); _service.Update(personBuilder); : base(repositoryperson.Id = id; return person; } public void Delete(int id) { ValidateId(id, nameof(id)); if (Notification.HasNotification()) return; _service.Delete(id); } } |
Note que a definição do serviço se da pela herança da classe AsyncCrudAppService< Entity, Dto> IAppDomainService<Person> onde é passado a entidade Entidade do Entity Framework Core e a sua classe de DTO criada.
Como parâmetro em seu construtor o serviço recebe um tipo IRepository<Entity> definindo o repositório que será usado pelo serviço automático na hora de realizar as operações.
Após a definição acima o serviço de aplicação pode ser usado normalmente em sua aplicação.
A herança da classe AsyncCrudAppService< Entity, Dto> expõe o interface IAppApplicationService<PersonDto, GetAllPeopleDto> expõe os métodos de CRUD no formato assíncronosíncrono. Também existe a versão síncrona assíncrona do serviço de CRUD usando a herança CrudAppService< Entity, Dto>interface IAppAsyncApplicationService<PersonDto, GetAllPeopleDto>.