Map Many to Many in the Entity Framework

6

I have a problem mapping with the Entity Framework.

I have two models, "project" and "company", where in the "company" there can be several "projects".

 public class Projeto
 {
    [Key]
    public int Id { get; set; }
    public string Nome { get; set; }
    public string Descricao { get; set; }
    public byte[] Versao { get; set; }
 }


public class Empresa
{
    [Key]
    public Int32   Id                              { get;set; }  
    public String  Nome                            { get;set; } 
    public String  Fone                            { get;set; } 
    public String  Contato                         { get;set; } 
    public String  Email                           { get;set; } 
    public virtual ICollection<Projeto>  Projetos  { get;set; } 
}

When I run the% cos of% visual studio Package Manager Console , for it to create the database migration file, it generates a column in the project table, to reference the company.

Then seen this, and this answer here in So-PT I created another class to do a many- to-many

public class EmpresaProjeto
{
    [Key]
    public Int32 Id { get; set; }
    public virtual Empresa Empresa {get;set;}
    public virtual Projeto Projeto { get; set; }
}

And register the class type in the context

public DbSet<Projeto> Projeto { get; set; }
public DbSet<Empresa> Empresa { get; set; }
public DbSet<EmpresaProjeto> EmpresaProjeto { get; set; }

But it happens that now in my "Company", "Projects" is always empty, how can I do that in my entity already bring the "Projects" together?

Can anyone with more EF experience help me?

    
asked by anonymous 18.04.2017 / 14:28

3 answers

2

By the description of your question, it seems to me that you want to set up a relationship of 1:N , where a Empresa can have N Projeto if a Projeto can only have 1 Empresa then you could have the following mapping.:

public class Projeto
{
    [Key]
    public int ProjetoId { get; set; }
    public string Nome { get; set; }
    public string Descricao { get; set; }
    public byte[] Versao { get; set; }
    public int EmpresaId { get; set; }

    [ForeignKey("EmpresaId")]
    public virtual Empresa Empresa { get;set; } 
}


public class Empresa
{
    [Key]
    public Int32 EmpresaId { get;set; }  
    public String Nome { get;set; } 
    public String Fone { get;set; } 
    public String Contato { get;set; } 
    public String Email { get;set; } 
    public virtual ICollection<Projeto>  Projetos  { get;set; } 
}

You can omit the EmpresaId column in Projeto as follows, but I do not recommend it.

public class Projeto
{
    [Key]
    public int ProjetoId { get; set; }
    public string Nome { get; set; }
    public string Descricao { get; set; }
    public byte[] Versao { get; set; }
    public virtual Empresa Empresa { get;set; } 
}


public class Empresa
{
    [Key]
    public Int32 EmpresaId { get;set; }  
    public String Nome { get;set; } 
    public String Fone { get;set; } 
    public String Contato { get;set; } 
    public String Email { get;set; } 
    public virtual ICollection<Projeto>  Projetos  { get;set; } 
}

I do not recommend the following fact: If you have EmpresaId of Empresa and want to update Projeto , you'll have to load Empresa into Contexto , or Attach incomplete or searching with Find .

// Attach do objeto incompleto
var empresa = new Empresa { EmpresaId = empresaId };
context.Empresas.Attach(empresa); 
context.Entry(empresa).State = EntityState.Unchanged; 

projeto.Empresa = empresa;
context.SaveChanges();

// Consultar Objeto
var empresa = context.Empresas.Find(empresaId); 
projeto.Empresa = empresa;
context.SaveChanges();

// Setar o EmpresaId no Projeto
projeto.EmpresaId = empresaId;
context.SaveChanges();

But if you really need a N:M relationship, you are not forced to create an extra Entity.

public class Projeto
{
    [Key]
    public int ProjetoId { get; set; }
    public string Nome { get; set; }
    public string Descricao { get; set; }
    public byte[] Versao { get; set; }
    public virtual ICollection<Empresa> Empresas { get;set; } 
}

public class Empresa
{
    [Key]
    public Int32 EmpresaId { get;set; }  
    public String Nome { get;set; } 
    public String Fone { get;set; } 
    public String Contato { get;set; } 
    public String Email { get;set; } 
    public virtual ICollection<Projeto> Projetos { get;set; } 
}

In the example above, the EF will create the ProjetoEmpresa table in the Database, having a composite key with ProjetoId and EmpresaId .

However, if the connection between Projeto and Empresa adds some information, such as the Contract number, in this case it is interpresante to add a new entity.

public class Projeto
{
    [Key]
    public int ProjetoId { get; set; }
    public string Nome { get; set; }
    public string Descricao { get; set; }
    public byte[] Versao { get; set; }
    public virtual ICollection<ProjetoEmpresa> Empresas { get;set; } 
}

public class Empresa
{
    [Key]
    public Int32 EmpresaId { get;set; }  
    public String Nome { get;set; } 
    public String Fone { get;set; } 
    public String Contato { get;set; } 
    public String Email { get;set; } 
    public virtual ICollection<ProjetoEmpresa> Projetos { get;set; } 
}

public class ProjetoEmpresa
{
    [Key, Column(Order = 1)]
    public int ProjetoId { get; set; }
    [Key, Column(Order = 2)]
    public int EmpresaId { get; set; }
    public string Contrato { get; set; }        

    [ForeignKey("ProjetoId")]
    public virtual Projeto Projeto { get;set; }     
    [ForeignKey("EmpresaId")]
    public virtual Empresa Empresa { get;set; } 
}

Again, you may omit the fields EmpresaId and ProjetoId in ProjetoEmpresa , but do not recommend.

Finally, I do not see a gain in having Chave Simples Auto Incremental in the ProjetoEmpresa table, remember, it will usually only be used as a bridge between Projeto and Empresa so it's interesting to have a compound key that enforces this integrity.

If you choose to have a Chave Simples Auto Incremental , do not forget to create a Índice Único as suggested by @CiganoMorrisonMendez.

    
18.05.2017 / 16:10
4

Hello,

In your mapping class try specifying the properties that will be the foreign keys:

  • These properties should retain the type and naming of the parent object.

    public class EmpresaProjeto
    {
        [Key]
        public Int32 Id { get; set; }
        public int EmpresaId {get;set;}
        public virtual Empresa Empresa {get;set;}
        public int ProjetoId { get; set; }
        public virtual Projeto Projeto { get; set; }
    }
    
  • Or use Data Annotations:

    public class EmpresaProjeto
    {
       [Key]
       public Int32 Id { get; set; }
       [ForeignKey("EmpresaId")]
       public virtual Empresa Empresa {get;set;}
       [ForeignKey("ProjetoId")]
       public virtual Projeto Projeto { get; set; }
    }
    

I think I can solve it.

    
17.05.2017 / 21:41
2

Some things are missing:

public class EmpresaProjeto
{
    [Key]
    public Int32 Id { get; set; }
    [Index("IUQ_EmpresaProjeto_EmpresaId_ProjetoId", IsUnique = true, Order = 1)]
    public int EmpresaId { get; set; }
    [Index("IUQ_EmpresaProjeto_EmpresaId_ProjetoId", IsUnique = true, Order = 2)]
    public int ProjetoId { get; set; }

    public virtual Empresa Empresa {get;set;}
    public virtual Projeto Projeto { get; set; }
}

The reverse relationships were also missing:

 public class Projeto
 {
    [Key]
    public int Id { get; set; }
    public string Nome { get; set; }
    public string Descricao { get; set; }
    public byte[] Versao { get; set; }

    // Faltou
    public virtual ICollection<EmpresaProjeto> ProjetoEmpresas { get; set; }
 }


public class Empresa
{
    [Key]
    public Int32   Id                              { get;set; }  
    public String  Nome                            { get;set; } 
    public String  Fone                            { get;set; } 
    public String  Contato                         { get;set; } 
    public String  Email                           { get;set; } 
    // Não é mais 1:N, então essa propriedade sai.
    // public virtual ICollection<Projeto>  Projetos  { get;set; } 

    // Entra esta no lugar.
    public virtual ICollection<EmpresaProjeto> EmpresaProjetos { get; set; }
}
    
17.05.2017 / 21:48