Class mapping with Fluentapi and Entityframework C#

Asked

Viewed 392 times

0

Table Parents, State, City;

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

State->Parents : 1:N

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

City|State 1:N

I’d like to know how I’m supposed to build this relationship in my C class. Like the data collection and the relationship part of FK, 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);            
    }
}
  • I do not understand the need for city is directly linked with the country. For through a given state is already bound to the country anyway.

  • @Cleidson_eng, apart from this relationship that was not so correct, I would like to know how I do the mapping, because I’m doing it the way it is in the code and not the right way, I would like the correct way to do mapping using Codefirst and Fluentapi

  • See This Link Has an example that can help you: Part 1 Part 2

1 answer

1

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

Below is an implementation, note that in Entitybase I am using the EntityFramework.Triggers to automate updating 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 above example, it will be interesting to use some global filter scheme, such as EntityFramework.DynamicFilters

EDIT - About the Fluent API

Let’s just look at the following excerpt 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);            
    }
}

in making HasRequired(x => x.Estado).WithMany(x => x.Cidades).HasForeignKey(x => x.EstadoHandle) in the CidadeMap you are already mapping the two sides of the relationship, so call HasMany(x => x.Cidades) in the 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);            
    }
}
  • I totally understood your tip, only that these classes I took just example to show here, there are many tables, and from what I studied and heard enough, it is that it is important and a great practice, to leave the Entity totally without business rule, I mean, using the Fluent API to accomplish this, I’m trying to do here more is giving error in Migrations. I will open another topic to see if anyone can help me in the problem. Thank you for the Solution where it really was the relationships of the tables

  • @Nicolabogar saw no business rules in the above model, only rules inherent in Modeling, so we are not hurting this principle..

  • Correct, but in this case up there that you yourself passed, you could give me an example using Fluentapi?

  • @Nicolabogar ready.

Browser other questions tagged

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