...
Bloco de código | ||||||||
---|---|---|---|---|---|---|---|---|
| ||||||||
using Tnf.Reflection.Extensions; using Tnf.App.EntityFrameworkCore; using Tnf.Architecture.Domain; using Tnf.Modules; [DependsOn( typeof(DomainModule), typeof(TnfAppEntityFrameworkCoreModule))] public class EntityFrameworkModule : TnfModule { public override void Initialize() { IocManager.RegisterAssemblyByConvention(typeof(EntityFrameworkModule).GetAssembly(Assembly)); } } |
Podemos perceber em nosso módulo definido acima no atributo "DependsOn" fazendo referencia ao TnfAppEntityFrameworkCoreModule. Essa dependência comporta toda a estrutura necessária para a utilização do Entity Framework Core.
...
Bloco de código | ||||||||
---|---|---|---|---|---|---|---|---|
| ||||||||
using System.ComponentModel.DataAnnotations; using System.ComponentModel.DataAnnotations.Schema; using Tnf.Architecture.Dto; using Tnf.AutoMapper; using Tnf.Domain.Entities; [AutoMap(typeof(CountryDto))] [Table("Countries")] public class Country : Entity { public const int MaxNameLength = 256; [Required] [MaxLength(MaxNameLength)] public string Name { get; set; } public Country() { } public Country(int id, string name) { Id = id; Name = name; } } |
...
Bloco de código | ||||||||
---|---|---|---|---|---|---|---|---|
| ||||||||
public interface ICountryRepository : IRepository<Country> { } |
Essa interface está dentro do projeto de Domain para que ele não precise conhecer o projeto de Arquitetura.
Como instalamos o pacote Tnf.App.EntityFrameworkCore e configuramos a dependência do módulo TnfAppEntityFrameworkCoreModule, ao utilizar o tipo ICountryRepository para a entidade "Country", nosso mecanismo de injeção de dependência está injetando o repositório padrão EfCoreRepositoryBasepadrão AppEfCoreRepositoryBase com suporte a métodos para realizar operações de CRUD e queries mais complexas.
...
Bloco de código | ||||||||
---|---|---|---|---|---|---|---|---|
| ||||||||
public class CustomCountryRepository : EfCoreRepositoryBase<ArchitectureDbContextAppEfCoreRepositoryBase<ArchitectureDbContext, Country, int>, ICountryRepository { public ProfessionalRepository(IDbContextProvider<ArchitectureDbContext> dbContextProvider) : base(dbContextProvider) { } public override Professional Get(decimal id) { return base.Get(id); } } |
...
Abaixo temos um exemplo de uma tabela "Professional" representada pela classe ProfessionalPoco (PKs: ProfessionalId, Code):
Bloco de código | ||||||||
---|---|---|---|---|---|---|---|---|
| ||||||||
using System; using System.Collections.Generic; using Tnf.Architecture.Dto.Registration; using Tnf.AutoMapper; using Tnf.Domain.Entities; namespace Tnf.Architecture.EntityFrameworkCore.Entities { [AutoMap(typeof(ProfessionalDto))] public class ProfessionalPoco public class ProfessionalPoco : Entity { public ProfessionalPoco() { } public decimal ProfessionalId { get; set; } public string Name { get; set; } public Guid Code { get; set; } public string Address { get; set; } public string AddressNumber { get; set; } public string AddressComplement { get; set; } public string ZipCode { get; set; } public string Phone { get; set; } public string Email { get; set; } public List<ProfessionalSpecialtiesPoco> ProfessionalSpecialties { get; set; } } } |
Tendo a definição de nossa entidade vamos agora configura-la em nosso Configuração do contexto:
Bloco de código | ||||||||
---|---|---|---|---|---|---|---|---|
| ||||||||
using Microsoft.EntityFrameworkCore; using Tnf.EntityFrameworkCore; using Tnf.Architecture.EntityFrameworkCore.Entities; namespace Tnf.Architecture.EntityFrameworkCore { public class LegacyDbContext : TnfDbContext { public DbSet<ProfessionalPoco> Professionals { get; set; } public DbSet<ProfessionalSpecialtiesPoco> ProfessionalSpecialties { get; set; } public DbSet<SpecialtyPoco> Specialties { get; set; } public LegacyDbContext(DbContextOptions<LegacyDbContext> options) : base(options) { } protected override void OnModelCreating(ModelBuilder modelBuilder) { modelBuilder.Entity<ProfessionalPoco>(m => { // PKs m.Ignore(i => i.Id); m.HasKey(i => new { i.ProfessionalId, i.Code }); // Configure PKs auto generated m.Property(i => i.Code).ValueGeneratedOnAdd().HasColumnName("SYS009_PROFESSIONAL_CODE"); // Hack pois o método ValueGeneratedOnAdd do EF Core ainda não aceita propriedades decimal m.Property(i => i.ProfessionalId).HasDefaultValueSql("SELECT ISNULL(MAX(SYS009_PROFESSIONAL_ID), 1) FROM SYS009_PROFESSIONAL").HasColumnName("SYS009_PROFESSIONAL_ID"); m.Property(p => p.Name).HasColumnName("SYS009_NAME").HasMaxLength(50).IsRequired(); m.Property(p => p.Address).HasColumnName("SYS009_ADDRESS").HasMaxLength(50).IsRequired(); m.Property(p => p.AddressComplement).HasColumnName("SYS009_ADDRESS_COMPLEMENT").HasMaxLength(100).IsRequired(); m.Property(p => p.AddressNumber).HasColumnName("SYS009_ADDRESS_NUMBER").HasMaxLength(9).IsRequired(); m.Property(p => p.Email).HasColumnName("SYS009_EMAIL").HasMaxLength(50).IsRequired(); m.Property(p => p.Email).HasColumnName("SYS009_EMAIL").HasMaxLength(50).IsRequired(); m.Property(p => p.Phone).HasColumnName("SYS009_PHONE").HasMaxLength(50).IsRequired(); m.Property(p => p.ZipCode).HasColumnName("SYS009_ZIP_CODE").HasMaxLength(15).IsRequired(); m.ToTable("SYS009_PROFESSIONAL"); }); modelBuilder.Entity<SpecialtyPoco>(m => { // PKs m.HasKey(i => i.Id); // Configure PKs auto generated m.Property(i => i.Id).ValueGeneratedOnAdd().HasColumnName("SYS011_SPECIALTIES_ID"); m.Property(p => p.Description).HasColumnName("SYS011_SPECIALTIES_DESCRIPTION").HasMaxLength(100).IsRequired(); m.ToTable("SYS011_SPECIALTIES"); }); modelBuilder.Entity<ProfessionalSpecialtiesPoco>(m => { // PKs m.Ignore(i => i.Id); m.HasKey(i => new { i.ProfessionalId, i.Code, i.SpecialtyId }); m.Property(i => i.ProfessionalId).HasColumnName("SYS009_PROFESSIONAL_ID"); m.Property(i => i.Code).HasColumnName("SYS009_PROFESSIONAL_CODE"); m.Property(i => i.SpecialtyId).HasColumnName("SYS011_SPECIALTIES_ID"); m.HasOne(o => o.Professional) .WithMany(w => w.ProfessionalSpecialties) .HasPrincipalKey(k => new { k.ProfessionalId, k.Code }) .HasForeignKey(k => new { k.ProfessionalId, k.Code }); m.HasOne(o => o.Specialty) .WithMany(w => w.ProfessionalSpecialties) .HasPrincipalKey(k => k.Id) .HasForeignKey(k => k.SpecialtyId); m.ToTable("SYS010_PROFESSIONAL_SPECIALTIES"); }); } } } |
Note que no contexto acima temos a configuração de nossa entidade Professional (SYS009_PROFESSIONAL) com um relacionamento de N para N (SYS010_PROFESSIONAL_SPECIALTIES) com a entidade Specialty (SYS011_SPECIALTIES) que representa as especialidades de um profissional.
Como o repositório por default exige uma chave primaria essa é ignorada por ser do tipo Int pela , nossa entidade comporta apenas uma chave. Dessa forma devemos ignora-la na hora de representar a tabela em nosso contexto utilizando a configuração m.Ignore(i => i.Id).
...
Como em muitos casos temos que criar chaves auto incremento podemos utilizar o método chamado ValueGeneratedOnAdd que irá configurar a chave como Identity.
Obs: Existem alguns tipos de dados ainda no Entity Framework Core que não estão funcionando com valores auto incremento como decimal. Para esses valores podemos contornar o problema usando o método HasDefaultValueSql, onde é passada uma instrução SQL que irá recuperar o valor do campo na hora de usar o seu auto incremento (Esse problema já está previsto para ser resolvido em futuras releases do Entity Framework Core)).
Note que além das chaves auto incremento configuramos também nomes das colunas, relacionamentos N para N e nomes das tabelas.
...
Bloco de código | ||||||||
---|---|---|---|---|---|---|---|---|
| ||||||||
using Tnf.Architecture.Domain.Interfaces.RepositoriesSystem; using TnfSystem.EntityFrameworkCoreCollections.RepositoriesGeneric; using Tnf.EntityFrameworkCore; using Tnf.Architecture.EntityFrameworkCore.EntitiesApp.Dto.Request; using Tnf.Architecture.Dto; using System.Collections.Generic; using System.Linq; using Tnf.AutoMapperCommon.ValueObjects; using Tnf.Architecture.DtoDomain.Registration; using MicrosoftTnf.Domain.EntityFrameworkCoreRepositories; using System; namespace Tnf.Architecture.EntityFrameworkCoreDomain.Interfaces.Repositories { public classinterface ProfessionalRepositoryIProfessionalRepository : EfCoreRepositoryBase<LegacyDbContext, ProfessionalPoco>, IProfessionalRepositoryIRepository { publicProfessional ProfessionalRepository(IDbContextProvider<LegacyDbContext> dbContextProvider)GetProfessional(IRequestDto<ComposeKey<Guid, decimal>> requestDto); ComposeKey<Guid, decimal> : base(dbContextProvider)CreateProfessional(Professional entity); { void } UpdateProfessional(Professional entity); public bool DeleteProfessional(ProfessionalKeysDtoComposeKey<Guid, decimal> keys); void AddOrRemoveSpecialties(ComposeKey<Guid, decimal> keys, IList<Specialty> specialties); bool ExistsProfessional(ComposeKey<Guid, decimal> keys); } } |
Bloco de código | ||||||||
---|---|---|---|---|---|---|---|---|
| ||||||||
using Microsoft.EntityFrameworkCore; using System; using System.Collections.Generic; using System.Linq; using System.Transactions; using Tnf.App.AutoMapper; using Tnf.App.Dto.Request; using Tnf.App.EntityFrameworkCore; using Tnf.App.EntityFrameworkCore.Repositories; using Tnf.Architecture.Common.ValueObjects; using Tnf.Architecture.Domain.Interfaces.Repositories; using Tnf.Architecture.Domain.Registration; using Tnf.Architecture.Dto.Registration; using Tnf.Architecture.EntityFrameworkCore.Contexts; using Tnf.Architecture.EntityFrameworkCore.Entities; using Tnf.Domain.Uow; using Tnf.EntityFrameworkCore; namespace Tnf.Architecture.EntityFrameworkCore.Repositories { public class ProfessionalRepository : AppEfCoreRepositoryBase<LegacyDbContext, ProfessionalPoco>, IProfessionalRepository { private readonly IUnitOfWorkManager _unitOfWorkManager; public ProfessionalRepository(IDbContextProvider<LegacyDbContext> dbContextProvider, IUnitOfWorkManager unitOfWorkManager) : base(dbContextProvider) { _unitOfWorkManager = unitOfWorkManager; } public bool DeleteProfessional(ComposeKey<Guid, decimal> keys) { { var dbEntity = Context.Professionals .Include(i => i.ProfessionalSpecialties) .SingleOrDefault(s => s.ProfessionalId == keys.ProfessionalIdSecundaryKey && s.Code == keys.CodePrimaryKey); if (dbEntity !== null) { return false; dbEntity.ProfessionalSpecialties.ForEach(w => Context.ProfessionalSpecialties.Remove(w)); Context.Professionals.Remove(dbEntity); } return dbEntity != nulltrue; } private ProfessionalPoco GetProfessionalPoco(ProfessionalKeysDto keysIRequestDto<ComposeKey<Guid, decimal>> requestDto) { var dbEntity = Context.Professionals .Include(i => i.ProfessionalSpecialties) .ThenInclude(i => i.Specialty .IncludeByRequestDto(requestDto) .SingleOrDefaultWhere(w => w.ProfessionalId == keys.ProfessionalIdrequestDto.GetId().SecundaryKey && w.Code == keys.Code); requestDto.GetId().PrimaryKey) return dbEntity; } public ProfessionalDto GetProfessional(ProfessionalKeysDto keys) .SelectFieldsByRequestDto(requestDto) { var dbEntity = GetProfessionalPoco(keys.SingleOrDefault(); return dbEntity != null ? dbEntity.MapTo<ProfessionalDto>() : null; } public ProfessionalDtoProfessional CreateProfessional(ProfessionalDto entityGetProfessional(IRequestDto<ComposeKey<Guid, decimal>> requestDto) { var dbEntity = entity.MapTo<ProfessionalPoco>GetProfessionalPoco(requestDto); Context.Professionals.Addif (dbEntity == null) return null; Context.SaveChangesvar dto = dbEntity.MapTo<Professional>(); return dbEntity.MapTo<ProfessionalDto>()dto; } public ComposeKey<Guid, ProfessionalDtodecimal> UpdateProfessionalCreateProfessional(ProfessionalDtoProfessional entity) { var mappedEntitydbEntity = GetProfessionalPoco(new ProfessionalKeysDto(entity.ProfessionalId, entity.Code))MapTo<ProfessionalPoco>(); entity.MapTo(mappedEntitydbEntity.ProfessionalId = GetNextKeyProfessional(); Context.Professionals.UpdateAdd(mappedEntitydbEntity); Context.SaveChanges(); return mappedEntity.MapTo<ProfessionalDto>( new ComposeKey<Guid, decimal>(dbEntity.Code, dbEntity.ProfessionalId); } publicprivate PagingResponseDto<ProfessionalDto>decimal GetAllProfessionalsGetNextKeyProfessional(GetAllProfessionalsDto request) { using (var responseuow = new PagingResponseDto<ProfessionalDto>();_unitOfWorkManager.Begin(TransactionScopeOption.RequiresNew)) var{ dbBaseQuery = Context.Professionals var lastKey = Context.IncludeProfessionals.Select(is => i.ProfessionalSpecialties)s.ProfessionalId).DefaultIfEmpty(0).Max(); .Include("ProfessionalSpecialties.Specialty")return (lastKey + 1); } } .Where(w => request.Name ==public null || w.Name.Contains(request.Name)); void UpdateProfessional(Professional entity) { var dbQuery = dbBaseQuery var mappedEntity = GetProfessionalPoco(new RequestDto<ComposeKey<Guid, decimal>>(new ComposeKey<Guid, .Skip(request.Offset) decimal>(entity.Code, entity.ProfessionalId))); entity.TakeMapTo(request.PageSizemappedEntity); .ToArray(Context.Professionals.Update(mappedEntity); response.Total = base.CountContext.SaveChanges(); } response.Data = dbQuery.MapTo<List<ProfessionalDto>>(); public void AddOrRemoveSpecialties(ComposeKey<Guid, decimal> keys, IList<Specialty> specialties) return response; { } var publicrequest void= AddOrRemoveSpecialties(ProfessionalKeysDtonew keysRequestDto<ComposeKey<Guid, List<SpecialtyDto> dto) {decimal>>(keys) { Expand = new ProfessionalDto().Expandables[0] }; var dbProfessional = GetProfessionalPoco(keysrequest); if (dbProfessional !== null) { return; var idsToAdd = dtospecialties.Select(s => s.Id).ToArray(); if (dbProfessional.ProfessionalSpecialties == null) dbProfessional.ProfessionalSpecialties = new List<ProfessionalSpecialtiesPoco>(); dbProfessional.ProfessionalSpecialties.RemoveAll(w => !idsToAdd.Contains(w.SpecialtyId)); foreach (var specialty dto.ForEach(w =>in specialties) { var dbProfessionalSpecialties = dbProfessional.ProfessionalSpecialties .FirstOrDefault(s => s.SpecialtyId == wspecialty.Id); if (dbProfessionalSpecialties == null) { dbProfessional.ProfessionalSpecialties.Add(new ProfessionalSpecialtiesPoco() { ProfessionalId = dbProfessional.ProfessionalId, Code = dbProfessional.Code, SpecialtyId = wspecialty.Id }); } }); } } public bool ExistsProfessional(ProfessionalKeysDtoComposeKey<Guid, decimal> keys) { var dbEntity = Context.Professionals .SingleOrDefault(s => s.ProfessionalId == keys.ProfessionalIdSecundaryKey && s.Code == keys.CodePrimaryKey); return dbEntity != null; } } } |
...