Class Mapping with FluentAPI and Entityframework C #

0

Parent, State, City Table

A country can have several states and a state can have only 1 country;

  

State-> Country: 1: N

A city can have only one state and one state can have several cities.

  

City | State 1: N

     

I would like to know how I should build this relationship in my C # class. Like the data collection and the FK relationship part, I'm kind of confused how this is accomplished.

public class Pais : EntityBase
{
    public Pais()
    {
        Estados = new List<Estado>();
    }

    public override long Handle { get; set; }
    public string Descricao { get; set; }
    public string Sigla { get; set; }
    public virtual ICollection<Estado> Estados { get; set; }
}

public class PaisMap : EntityTypeConfiguration<Pais>
{
    public PaisMap()
    {
        ToTable("Pais");            
        HasKey(x => x.Handle);
        Property(x => x.Descricao).HasMaxLength(150).IsRequired();
        Property(x => x.Sigla).HasMaxLength(3).IsRequired();
        HasMany(x => x.Estados);
    }
}

public class Estado : EntityBase
{
    public Estado()
    {
        Pais = new Pais();
        Cidades = new List<Cidade>();
    }

    public override long Handle { get; set; }
    public string Descricao { get; set; }
    public string Sigla { get; set; }
    public long PaisHandle { get; set; }
    public virtual Pais Pais { get; set; }
    public virtual ICollection<Cidade> Cidades { get; set; }
}

public class EstadoMap : EntityTypeConfiguration<Estado>
{
    public EstadoMap()
    {
        ToTable("Estado");            
        HasKey(x => x.Handle);
        Property(x => x.Descricao).HasMaxLength(150).IsRequired();
        Property(x => x.Sigla).HasMaxLength(2).IsRequired();

        HasRequired(x => x.Pais)
            .WithMany(x => x.Estados)
            .HasForeignKey(x => x.PaisHandle);

        HasMany(x => x.Cidades);
    }
}

public class Cidade : EntityBase
{
    public Cidade()
    {
        Pais = new Pais();
        Estado = new Estado();
    }

    public override long Handle { get; set; }
    public string Descricao { get; set; }
    public string Sigla { get; set; }
    public long PaisHandle { get; set; }
    public virtual Pais Pais { get; set; }
    public long EstadoHandle { get; set; }
    public virtual Estado Estado { get; set; }
}

public class CidadeMap : EntityTypeConfiguration<Cidade>
{
    public CidadeMap()
    {  
        ToTable("Cidade");            
        HasKey(x => x.Handle);
        Property(x => x.Descricao).HasMaxLength(150).IsRequired();
        Property(x => x.Sigla).HasMaxLength(2).IsRequired();

        HasRequired(x => x.Estado)
            .WithMany(x => x.Cidades)
            .HasForeignKey(x => x.EstadoHandle);            
    }
}
    
asked by anonymous 22.06.2017 / 17:24

1 answer

1

Look, avoid using FluentAPI for the most basic cases, in this case it is best to use DataAnnotations :

Below an implementation, note that in EntityBase I'm using EntityFramework.Triggers to automate the update of some fields.

// Não esqueça do abstract
public abstract class EntityBase
{
    // Acredite, colocar o ID na classe base não é uma boa.
    // Como você faria com uma entidade com chave multipla
    // public Guid EntityID { get; set; }


    public Guid UsuarioCriacaoID { get; set; }
    public Guid UsuarioAtualizacaoID { get; set; }
    public DateTime DataCriacao { get; set; }
    public DateTime DataAtualizacao { get; set; }
    public bool IsDeleted { get; set; }


    [ForeignKey("UsuarioCriacaoID")]
    public virtual Pais UsuarioCriacao { get; set; }
    [ForeignKey("UsuarioAtualizacaoID")]
    public virtual Pais UsuarioAtualizacao { get; set; }    

    static EntityBase()
    {
        Triggers<EntityBase>.Inserting += entry =>
        {                
            var contexto = entry.Context as MyContext;
            entry.Entity.DataCriacao = DateTime.Now;
            entry.Entity.DataAtualizacao = DateTime.Now;
            entry.Entity.UsuarioCriacaoID = contexto.UsuarioID;
            entry.Entity.UsuarioAtualizacaoID = contexto.UsuarioID;
            entry.Entity.IsDeleted = false;
        };
        Triggers<EntityBase>.Updating += entry =>
        {
            var contexto = entry.Context as MyContext;
            entry.Entity.DataCriacao = DateTime.Now;
            entry.Entity.DataAtualizacao = DateTime.Now;
            entry.Entity.UsuarioCriacaoID = contexto.UsuarioID;
            entry.Entity.UsuarioAtualizacaoID = contexto.UsuarioID;
            entry.Entity.IsDeleted = false;
        };
        Triggers<EntityBase>.Deleting += entry =>
        {
            var contexto = entry.Context as Contexto;
            entry.Entity.IsDeleted = true;
            entry.Cancel = true;
        };
    }
}

[Table("Usuarios")]
public class Usuario
{
    [Key]
    public Guid UsuarioID { get; set; }

    [Required]
    [Index(IsUnique=true)]
    [MaxLength(50)]
    public string Logon { get; set; }

    [Required]
    [MaxLength(64)]
    public byte[] Senha { get; set; }

    [Required]
    [MaxLength(16)]
    public byte[] Salt { get; set; }
}

[Table("Paises")]
public class Pais : EntityBase
{
    [Key]
    public Guid PaisID { get; set; }

    [Required]
    [MaxLength(150)]
    public string Descricao { get; set; }

    [Required]
    [MaxLength(3)]
    public string Sigla { get; set; }

    public virtual ICollection<Estado> Estados { get; set; } = new List<Estado>();
}

[Table("Estados")]
public class Estado : EntityBase
{
    [Key]
    public Guid EstadoID { get; set; }
    public Guid PaisID { get; set; }

    [Required]
    [MaxLength(150)]
    public string Descricao { get; set; }
    public string Sigla { get; set; }

    [Required]
    [MaxLength(2)]
    public long PaisHandle { get; set; }

    // Utilize o Atributo ForeignKey apenas se a propriedade usada configurar o relacionamento tenha um nome diferente da Key da Entidade Referenciada.
    // [ForeignKey("PaisID")]
    public virtual Pais Pais { get; set; }

    public virtual ICollection<Cidade> Cidades { get; set; } new List<Cidade>();
}

[Table("Cidades")]
public class Cidade : EntityBase
{
    public Cidade()
    {
        Pais = new Pais();
        Estado = new Estado();
    }

    [Key]
    public Guid CidadeID { get; set; }
    public Guid EstadoID { get; set; }

    [Required]
    [MaxLength(150)]
    public string Descricao { get; set; }

    [Required]
    [MaxLength(2)]
    public string Sigla { get; set; }

    // Utilize o Atributo ForeignKey apenas se a propriedade usada configurar o relacionamento tenha um nome diferente da Key da Entidade Referenciada.
    // [ForeignKey("EstadoID")]
    public virtual Estado Estado { get; set; }
}

public class MyContext : DbContext 
{ 
    public Guid UsuarioID { get; private set; }
    public MyContext(Guid usuarioID)
    {
        this.UsuarioID = usuarioID;
    }

    public DbSet<Usuario> Usuarios { get; set; } 
    public DbSet<Pais> Paises { get; set; } 
    public DbSet<Estado> Estados { get; set; } 
    public DbSet<Cidade> Cidades { get; set; } 

    protected override void OnModelCreating(DbModelBuilder modelBuilder) 
    { 
        modelBuilder.Filter("IsDeleted", (EntityBase d) => d.IsDeleted, false);
        // Faça aqui os mapeamentos que não conseguir fazer por DataAnnotations, como por exemplo algo especifico para o SGBD.
    } 
}

Finally, if you decide to use Soft Delete as in the example above, it will be interesting to use some global filter scheme, such as EntityFramework.DynamicFilters

EDIT - About the Fluent API

Let's look at just the following snippet of code:

public class EstadoMap : EntityTypeConfiguration<Estado>
{
    public EstadoMap()
    {
        ...
        HasMany(x => x.Cidades);
    }
}

public class CidadeMap : EntityTypeConfiguration<Cidade>
{
    public CidadeMap()
    {  
        ...
        HasRequired(x => x.Estado)
            .WithMany(x => x.Cidades)
            .HasForeignKey(x => x.EstadoHandle);            
    }
}

When doing HasRequired(x => x.Estado).WithMany(x => x.Cidades).HasForeignKey(x => x.EstadoHandle) on CidadeMap you are already mapping the two sides of the relationship, so calling HasMany(x => x.Cidades) on EstadoMap is unnecessary, just remove this type of mapping.

public class PaisMap : EntityTypeConfiguration<Pais>
{
    public PaisMap()
    {
        ToTable("Pais");            
        HasKey(x => x.Handle);
        Property(x => x.Descricao).HasMaxLength(150).IsRequired();
        Property(x => x.Sigla).HasMaxLength(3).IsRequired();
    }
}

public class EstadoMap : EntityTypeConfiguration<Estado>
{
    public EstadoMap()
    {
        ToTable("Estado");            
        HasKey(x => x.Handle);
        Property(x => x.Descricao).HasMaxLength(150).IsRequired();
        Property(x => x.Sigla).HasMaxLength(2).IsRequired();
        HasRequired(x => x.Pais).WithMany(x => x.Estados).HasForeignKey(x => x.PaisHandle);
    }
}

public class CidadeMap : EntityTypeConfiguration<Cidade>
{
    public CidadeMap()
    {  
        ToTable("Cidade");            
        HasKey(x => x.Handle);
        Property(x => x.Descricao).HasMaxLength(150).IsRequired();
        Property(x => x.Sigla).HasMaxLength(2).IsRequired();
        HasRequired(x => x.Estado).WithMany(x => x.Cidades).HasForeignKey(x => x.EstadoHandle);            
    }
}
    
22.06.2017 / 21:33