2
My application Numerators follow the 'secure enumerator' design pattern, where I have the enumerator statement as static members, and the Numerators instance following a contract (Ienumeradorseguro interface).
This is the standard interface of all Enumerators:
public interface IEnumeradorSeguro
{
object Id { get; }
String Descricao { get; }
}
An example of an enumerator:
public class ETipoAtividade : EnumeradorAbstrato<ETipoAtividade>
{
public ETipoAtividade(object id, string descricao) : base(id, descricao)
{}
public ETipoAtividade(object id) : base(id)
{}
public static ETipoAtividade NovaImplementacao
{
get { return new ETipoAtividade((short)1, "Nova implementação"); }
}
public static ETipoAtividade Melhoria
{
get { return new ETipoAtividade((short)2, "Melhoria"); }
}
public static ETipoAtividade CorrecaoDeBug
{
get { return new ETipoAtividade((short)3, "Correção de bug"); }
}
public static ETipoAtividade Reengenharia
{
get { return new ETipoAtividade((short)4, "Reengenharia"); }
}
}
Use of the enumerator:
public class Atividade : ObjetoPersistente
{
public Atividade()
{
Projeto = new Projeto();
StatusAtividade = EStatusAtividade.NaoIniciado;
TipoAtividade = ETipoAtividade.NovaImplementacao;
Usuario = new Usuario();
}
public DateTime DataHoraFim { get; set; }
public DateTime DataHoraInicio { get; set; }
public string DescricaoAtividade { get; set; }
public string EstimativaInicialAtividade { get; set; }
public Projeto Projeto { get; set; }
public long CodigoProjeto {
get
{
if(Projeto == null) Projeto = new Projeto();
return Projeto.Codigo;
}
set
{
Projeto.Codigo = value;
}
}
public string NomeProjeto
{
get { return Projeto.Nome; }
}
public Usuario Usuario { get; set; }
public string LoginUsuario
{
get { return Usuario.Login; }
}
public long CodigoUsuario {
get
{
if(Usuario == null) Usuario = new Usuario();
return Usuario.Codigo;
}
set
{
Usuario.Codigo = value;
}
}
public EStatusAtividade StatusAtividade { get; set; }
public string DescricaoStatusAtividade
{
get { return StatusAtividade.Descricao; }
}
public string DescricaoTipoAtividade
{
get { return TipoAtividade.Descricao; }
}
public ETipoAtividade TipoAtividade { get; set; }
public string TituloAtividade { get; set; }
public override bool Equals(object obj)
{
return (obj is Atividade) && (obj as Atividade).Codigo.Equals(Codigo);
}
public override int GetHashCode()
{
return Codigo.GetHashCode();
}
}
How I am mapping via Fluent-api:
public class AtividadeMap : EntityTypeConfiguration<Atividade>
{
public AtividadeMap()
{
HasKey(a => a.Codigo);
ToTable("tb_atividade");
Property(a => a.TituloAtividade).HasColumnName("titulo_atividade");
Property(a => a.DescricaoAtividade).HasColumnName("descricao_atividade");
Property(a => a.DataHoraInicio).HasColumnName("data_hora_inicio");
Property(a => a.DataHoraFim).HasColumnName("data_hora_fim");
Property(a => a.Codigo).HasColumnName("pk_atividade");
Property(a => a.StatusAtividade.Identificador).HasColumnName("status_atividade");
Property(a => a.EstimativaInicialAtividade).HasColumnName("estimativa_inicial_atividade");
Property(a => a.TipoAtividade.Identificador).HasColumnName("tipo_atividade");
HasRequired(a => a.Usuario);
HasRequired(a => a.Projeto);
}
}
I have identified that the two Enumerators (Etipoatividade and Statusativity) are complex types, but even so, an exception is triggered when Dbcontext invokes the model’s construction method:
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
base.OnModelCreating(modelBuilder);
modelBuilder.Configurations.Add(new ProjetoMap());
modelBuilder.ComplexType<EStatusAtividade>();
modelBuilder.ComplexType<ETipoAtividade>();
modelBuilder.Configurations.Add(new AtividadeMap());
modelBuilder.Configurations.Add(new UsuarioMap());
}
Exception:
An exception of type 'System.InvalidOperationException' occurred in EntityFramework.dll but was not handled in user code
Additional information: The property 'Identificador' is not a declared property on type 'EStatusAtividade'. Verify that the property has not been explicitly excluded from the model by using the Ignore method or NotMappedAttribute data annotation. Make sure that it is a valid primitive property.
Edit:
How do I get the enumerator instance from what’s in the database:
atividade.StatusAtividade = EStatusAtividade.ObtenhaItem((short)1);
Edit2: Enumerator Code
[Serializable]
public abstract class EnumeradorAbstrato<T> : IEnumeradorSeguro where T : IEnumeradorSeguro
{
/// <summary>
/// Neste construtor são passados como parametros o Id e Descricao
/// </summary>
/// <param name="id"></param>
/// <param name="descricao"></param>
protected EnumeradorAbstrato(object id, String descricao)
{
_id = id;
_descricao = descricao;
}
/// <summary>
/// Neste construtor são passados como parametros o Id
/// </summary>
/// <param name="id"></param>
protected EnumeradorAbstrato(object id)
{
_id = id;
_descricao = id.ToString();
}
#region IEnumeradorSeguro Members
private object _id; //declarando o id do enumerador
private String _descricao; //declarando a descrição do enumerador
/// <summary>
/// Este metodo retorna o Id do enumerador
/// </summary>
public virtual object Id
{
get
{
return _id;
}
}
static bool IsNumeric(string inputString)
{
return Regex.IsMatch(inputString, "^[0-9]+$");
}
/// <summary>
/// Identificador para usar nos switch-case
/// Só funciona quando o Id for números inteiros.
/// </summary>
public int Identificador
{
get
{
Func<string,int> funcId;
funcId = idx => {
if (IsNumeric(idx))
return int.Parse(idx);
throw new Exception("Id não numérico!");};
return funcId(Id.ToString());
}
}
/// <summary>
/// Este metodo retorna a descrição do enumerador
/// </summary>
public string Descricao
{
get
{
return _descricao;
}
}
#endregion
/// <summary>
/// neste metodo retorna a descrição de enumerador
/// </summary>
/// <returns></returns>
public override string ToString()
{
return Descricao;
}
public static bool IsNull(T valor)
{
try
{
return String.IsNullOrEmpty(valor.ToString());
}
catch (Exception)
{
return true;
}
}
// override object.Equals
public override bool Equals(object obj)
{
if (obj == null || !(obj is EnumeradorAbstrato<T>))
{
return false;
}
return _id.Equals(((EnumeradorAbstrato<T>)obj)._id);
}
public static bool operator ==(EnumeradorAbstrato<T> obj1, object obj2)
{
if(!(obj2 is EnumeradorAbstrato<T>))
{
return false;
}
var tmpObj2 = (EnumeradorAbstrato<T>) obj2;
if(tmpObj2.Equals(obj1 ))
{
return true;
}
return false;
}
public static bool operator !=(EnumeradorAbstrato<T> obj1, object obj2)
{
return !(obj1 == obj2);
}
/// <summary>
/// Este metodo retorna o Id do enumerador
/// </summary>
/// <returns></returns>
public override int GetHashCode()
{
return Id.GetHashCode();
}
public static T ObtenhaItem(object id)
{
return ObtenhaItem(typeof(T), id);
}
public static T ObtenhaItem(string descricao)
{
return ObtenhaItem(typeof (T), descricao);
}
public static IList<T> ObtenhaTodos()
{
return ObtenhaTodos(typeof(T));
}
/// <summary>
/// Obtem lista de short com identificadores dos enumeradores de uma lista.
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="enumeradores"></param>
/// <returns></returns>
public static List<short> ObtenhaIdentificadoresDeListaDeEnumeradores<T>(List<T> enumeradores)
where T : IEnumeradorSeguro
{
var lista = new List<short>();
foreach (var enumerador in enumeradores)
{
lista.Add((short)enumerador.Id);
}
return lista;
}
/// <summary>
/// Obtem lista de enumeradores a partir de lista contendo identificadores.
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="identificadores"></param>
/// <returns></returns>
public static List<T> ObtenhaListaDeEnumeradoresPorIdentificadores<T>(List<short> identificadores) where T: IEnumeradorSeguro
{
var lista = new List<T>();
foreach (var identificador in identificadores)
{
var enumerador = EnumeradorAbstrato<T>.ObtenhaItem(typeof(T), identificador);
lista.Add(enumerador);
}
return lista;
}
/// <summary>
/// Este metodo retorna a lista do enumerador passado
/// </summary>
/// <param name="tipoDoEnumerador"></param>
/// <returns></returns>
protected static IList<T> ObtenhaTodos(Type tipoDoEnumerador)
{
List<T> lista = new List<T>();
foreach (var campo in tipoDoEnumerador.GetProperties())
{
if (campo.PropertyType.IsPublic && (campo.PropertyType.Name.Equals(typeof(T).Name) || campo.PropertyType.IsSubclassOf(typeof(T))))
{
T obj = default(T);
obj = (T)campo.GetValue(obj, BindingFlags.GetProperty | BindingFlags.Static, null, null,
CultureInfo.CurrentCulture);
lista.Add(obj);
}
}
return lista;
}
/// <summary>
/// Passa o tipo do enumerador e o Id
/// </summary>
/// <param name="tipoDoEnumerador"></param>
/// <param name="Id"></param>
/// <returns></returns>
protected static T ObtenhaItem(Type tipoDoEnumerador, object Id)
{
return ObtenhaItem(tipoDoEnumerador, Id, "Id");
}
/// <summary>
/// Passa o tipo do enumerador e um valor string que pode ser o Id ou Descricao
/// </summary>
/// <param name="tipoDoEnumerador"></param>
/// <param name="valor"></param>
/// <returns></returns>
protected static T ObtenhaItem(Type tipoDoEnumerador, string valor)
{
var item = ObtenhaItem(tipoDoEnumerador, valor, "Descricao");
if (item == null) item = ObtenhaItem(tipoDoEnumerador, valor, "Id");
return item;
}
/// <summary>
/// "varre" para ver se encontra o tipo de numerador informado e o Id
/// </summary>
/// <param name="tipoDoEnumerador"></param>
/// <param name="valor"></param>
/// <param name="nomeDaPropriedade"></param>
/// <returns></returns>
protected static T ObtenhaItem(Type tipoDoEnumerador, object valor, string nomeDaPropriedade)
{
foreach (T item in ObtenhaTodos(tipoDoEnumerador))
{//se encontrado retorna o item
//if (item.GetType().GetField(NomeDaPropriedade).GetValue(item).Equals(Valor))
// return item;
if (item.GetType().GetProperty(nomeDaPropriedade).GetValue(item, null).Equals(valor))
return item;
}
return default(T); //É o mesmo que return null;
}
}
Edit2: Code of Statuvity
public class EStatusAtividade : EnumeradorAbstrato<EStatusAtividade>
{
public EStatusAtividade(object id, string descricao) : base(id, descricao)
{}
public EStatusAtividade(object id) : base(id)
{}
public static EStatusAtividade NaoIniciado
{
get{ return new EStatusAtividade((short)1, "Não iniciado");}
}
public static EStatusAtividade Iniciado
{
get { return new EStatusAtividade((short)2, "Iniciado"); }
}
public static EStatusAtividade EmTestes
{
get { return new EStatusAtividade((short)3, "Em testes"); }
}
public static EStatusAtividade Concluido
{
get { return new EStatusAtividade((short)4, "Concluído"); }
}
}
Edit 3: After inclusion of the set in the Identifier property, I had this exception:
{"The class 'SabreControleDesenvolvimento.PrototipoCriador.Uteis.Enumeradores.EStatusAtividade' has no parameterless constructor."}
The RU would not be recovering the value of that property in the bank?
The codes are missing for
EStatusAtividade
and toEnumeradorAbstrato<T>
.– RSinohara
Okay, you’ve been included.
– Joaquim Magalhães