Tengo que usar Enum Safe Pattern para persistir en la base de datos, solo el código de una enumeración. Cuando intento ejecutar la migración, aparece el error:
No se encontró un constructor adecuado para el tipo de entidad 'Regiao'. Los siguientes constructores tenían parámetros que no podían vincularse a las propiedades del tipo de entidad: no se puede unir 'codigo', 'nome' en 'Regiao (int codigo, string nome)'
Ya revisé el código, cambié el constructor de protegido a público, pero no tuvo ningún efecto.
Esta es la clase base.
public abstract class EnumBase<TEnum, TKey> :
IEquatable<EnumBase<TEnum, TKey>>,
IComparable<EnumBase<TEnum, TKey>>
where TEnum : EnumBase<TEnum, TKey>
where TKey : IEquatable<TKey>, IComparable<TKey>
{
private readonly TKey _codigo;
private readonly string _nome;
private static readonly List<TEnum> _listaDeEnums = new List<TEnum>();
private static bool _invoked;
public TKey Codigo => _codigo;
public string Nome => _nome;
public static IReadOnlyCollection<TEnum> ListaDeEnums
{
get
{
if (!_invoked)
{
_invoked = true;
typeof(TEnum).GetProperties(BindingFlags.Public | BindingFlags.Static).FirstOrDefault(p => p.PropertyType == typeof(TEnum))?.GetValue(null, null);
}
return _listaDeEnums;
}
}
protected EnumBase(TKey codigo, string nome)
{
_nome = nome;
_codigo = codigo;
TEnum item = this as TEnum;
_listaDeEnums.Add(item);
}
public static TEnum ObterPorNome(string nome)
{
return ListaDeEnums.SingleOrDefault(item => string.Equals(item.Nome, nome, StringComparison.OrdinalIgnoreCase));
}
public static TEnum ObterPorCodigo(TKey codigo)
{
// Can't use == to compare generics unless we constrain TValue to "class", which we don't want because then we couldn't use int.
return ListaDeEnums.SingleOrDefault(item => EqualityComparer<TKey>.Default.Equals(item.Codigo, codigo));
}
public override string ToString()
{
return _nome;
}
public virtual bool Equals(EnumBase<TEnum, TKey> other)
{
if (ReferenceEquals(null, other))
{
return false;
}
if (ReferenceEquals(this, other))
{
return true;
}
if (other.GetType() != GetType())
{
return false;
}
return _codigo.Equals(other._codigo);
}
public int CompareTo(EnumBase<TEnum, TKey> other)
{
return _codigo.CompareTo(other._codigo);
}
}
Esta es la clase que hereda de EnumBase
public class Regiao : EnumBase<Regiao, int>
{
public static Regiao Indefinida { get; } = new Regiao(0, "Indefinida");
public static Regiao CentroOeste { get; } = new Regiao(1, "Centro-Oeste");
public static Regiao Nordeste { get; } = new Regiao(2, "Nordeste");
public static Regiao Norte { get; } = new Regiao(3, "Norte");
public static Regiao Sudeste { get; } = new Regiao(4, "Sudeste");
public static Regiao Sul { get; } = new Regiao(5, "Sul");
public Regiao(int codigo, string nome) : base(codigo, nome) { }
}
Esta es la clase donde uso el Enum Regiao
public class Estado
{
public int ChaveEstadoDne { get; private set; }
public string SiglaPais2Pos { get; private set; }
public string Uf { get; private set; }
public string CodigoIbgeEstado { get; private set; }
public string NomeOficialEstado { get; private set; }
public string NomeAbreviadoEstado { get; private set; }
public Regiao Regiao { get; private set; }
public Guid PaisId { get; private set; }
protected Estado()
{
}
private Estado(Guid id, EntityStatus status, DateTime? dataCadastro, TipoProcesso rotina, int chaveEstadoDne, string siglaPais2Pos, string uf, string codigoIbge, string nomeOficial, string nomeAbreviado, Guid paisId) : base(id, chaveEstadoDne.ToString(), status, dataCadastro, rotina)
{
}
}
y finalmente el fragmento de código donde hago el mapeo
builder.Property(estado => estado.Regiao)
.HasColumnName("Regiao")
.HasConversion(
estado => estado.Codigo,
estado => Regiao.ObterPorCodigo(estado));
Esperaba que el campo Codigo fuera mapeado a la base de datos, y al leer el campo Código sería mapeado nuevamente al tipo Regiao. Pero recibo el mensaje:
System.InvalidOperationException HResult = 0x80131509 Mensaje = No se encontró un constructor adecuado para el tipo de entidad 'Regiao'. Los siguientes constructores tenían parámetros que no podían vincularse a las propiedades del tipo de entidad: no se puede unir 'codigo', 'nome' en 'Regiao (int codigo, string nome)'. .It. ModelBuilder.FinalizeModel () en System.Lazy 1.ViaFactory(LazyThreadSafetyMode mode) at System.Lazy
1.ExecutionAndPublication (LazyHelper executeAndPublication, Boolean useDefaultConstructor) en System.Lazy 1.CreateValue() at Microsoft.EntityFrameworkCore.Internal.DbContextServices.CreateModel() at Microsoft.EntityFrameworkCore.Internal.DbContextServices.get_Model() at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteRuntimeResolver.VisitFactory(FactoryCallSite factoryCallSite, ServiceProviderEngineScope scope) at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteVisitor
2.VisitCallSite (IServic eCallSite callSite, argumento TArgument) en Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteRuntimeResolver.VisitScoped (ScopedCallSite scopedCallSite, el alcance ServiceProviderEngineScope) en Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteVisitor 2.VisitCallSite(IServiceCallSite callSite, TArgument argument) at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteRuntimeResolver.VisitConstructor(ConstructorCallSite constructorCallSite, ServiceProviderEngineScope scope) at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteVisitor
2.VisitCallSite (IServiceCallSite callSite, argumento TArgument) en Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteRuntimeResolver.VisitScoped (ScopedCallSite scopedCallSite, Alcance ServiceProviderEngineScope) en Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteVisitor 2.VisitCallSite(IServiceCallSite callSite, TArgument argument) at Microsoft.Extensions.DependencyInjection.ServiceLookup.DynamicServiceProviderEngine.<>c__DisplayClass1_0.<RealizeService>b__0(ServiceProviderEngineScope scope) at Microsoft.Extensions.DependencyInjection.ServiceLookup.ServiceProviderEngine.GetService(Type serviceType, ServiceProviderEngineScope serviceProviderEngineScope) at Microsoft.Extensions.DependencyInjection.ServiceLookup.ServiceProviderEngineScope.GetService(Type serviceType) at Microsoft.Extensions.DependencyInjection.ServiceProviderServiceExtensions.GetRequiredService(IServiceProvider provider, Type serviceType) at Microsoft.Extensions.DependencyInjection.ServiceProviderServiceExtensions.GetRequiredService[T](IServiceProvider provider) at Microsoft.EntityFrameworkCore.DbContext.get_DbContextDependencies() at Microsoft.EntityFrameworkCore.DbContext.get_InternalServiceProvider() at Microsoft.EntityFrameworkCore.Internal.InternalAccessorExtensions.GetService[TService](IInfrastructure
1 accessor) en Microsoft.EntityFrameworkCore.Infrastructure.DatabaseFacade.get_DatabaseCreator () en Microsoft.EntityFrameworkCore.Infrastructure.DatabaseFacade.EnsureCreated () en Bigai.CepApi.Data.Initializers.CepApiInitializer.Initialize (Contexto CepApiContext) en D: \ Projects \ Dev \ Bigai \ CepApi \ src \ Bigai.AepApit.Inpi \\ .cs: línea 17 en Bigai.CepApi.Services.Api.Configurations.ApiConfiguration.UseApiConfiguration (aplicación IApplicationBuilder, contexto CepApiContext, proveedor IApiVersionDescriptionProvider) en D: \ Projects \ Dev \ Bigai \ CepApi \ src \ Bpii.SccA Bpii \ Configurations \ ApiConfiguration.cs: línea 48 en Bigai.CepApi.Services.Api.Startup.Configure (aplicación IApplicationBuilder, IHostingEnvironment env, contexto CepApiContext, proveedor IApiVersionDescriptionProvider) en D: \ Projects \ Dev \ Bigai \ CepApi \ sr CepApi.Services.Api \ Startup.cs: línea 74
¿Cómo arreglar esto, por favor?
Gracias @Christopher y @GPW.
Resolví el problema. De hecho, la solución estaba justo frente a mí, todo lo que tenía que hacer era crear un generador protegido necesario para nuestro amigo Entity Framework.
En mi clase base puse
protected EnumBase()
Y en la clase derivada:
protected Regiao() : base() { }
Estos dos cambios resolvieron el problema.