How to do the mapping (Entitytypeconfiguration) of this complex type?

Asked

Viewed 677 times

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 to EnumeradorAbstrato<T>.

  • Okay, you’ve been included.

1 answer

2


You declare a mapping to a.TipoAtividade.Identificador, where TipoAtividade is the type ETipoAtividade.

ETipoAtividade does not contain a member Identificador. Seria Id?

That seems to be the mistake. Maybe yours EnumeradorAbstrato<T> own the member Identificador, but the code is not posted.

----EDIT----

The estate Identificador does not have Setter... The EntityFramework pracisa both of get when of set to work.

----EDIT----

Regarding the error of absence of constructor without parameters:

The Entity framework requires entities to have a constructor without parameters. The values are collected in the databank, but it is still necessary to create, or instantiate, the objects. For this, it is necessary to have a constructor.

Create an empty constructor, and it will be solved.

  • Includes the code of the Enumerator class. I cannot use ID because it is a nullable type, unlike the Identifier which is an INT.

  • 1

    I edited, I think I found the problem.

  • Great! It really didn’t cause any exceptions. I will validate the rest. Beforehand +1.

  • You made an exception when I tried to find an object. I edited the question.

  • How did the Setter of Identificador

  • Very simple: set { _id = value; }

  • I edited once more.

  • I believe it worked. I had other problems, but not related to this one. Thank you.

Show 3 more comments

Browser other questions tagged

You are not signed in. Login or sign up in order to post.