Identifying the foreign key in the Codefirst Entity Framework

Asked

Viewed 2,229 times

1

The Entity Framework identifies the foreign key through properties that have Id as part of the name or by Data Annotation [Key]. My question is, how does it identify foreign keys and makes the relationship between another table?

public class Predio {
    public int Id { get; set; }
    public string Nome { get; set; }
    public Endereco Endereco { get; set; }
}

public class Construtora {
    public Construtora()
    {
        this.Predios = new List<Predio>();
    }
    public int Id { get; set; }
    public string Nome { get; set; }
    public string RegistroCivil { get; set; }
    public List<Predio> Predios { get; set; }
}

[ComplexType()]
public class Endereco {
    public string Logradouro { get; set; }
    public string Numero { get; set; }
    public string Bairro { get; set; }
    public string Cidade { get; set; }
    public string CEP { get; set; }
}

public class Contexto : DbContext
{
    public DbSet<Predio> Predios { get; set; }
    public DbSet<Construtora> Construtoras { get; set; }
}

1 answer

4


Objectively speaking, through a class called ForeignKeyPropertyDiscoveryConvention. The operation is explained here.

Roughly, the way the Entity Framework performs the discovery of the foreign key is as follows (consider that several of these steps use Reflection):

  1. It is verified in the Model if there are compatible browsing properties. For example:

    public virtual EntidadeEstrangeira EntidadeEstrangeira { get; set; }
    
  2. If yes, it is checked in Model if there is a candidate property to be the information component of that foreign key. For example:

    public int EntidadeEstrangeiraId { get; set; }
    

    2.1. This field may not be located. If it is not, the Entity Framework attempts to search for a property that is marked with the ForeignKeyAttribute. This Attribute can decorate both a navigation property and a data property. For example:

    [ForeignKey("EntidadeEstrangeira")]
    public int OutroNomeDeEntidadeEstrangeiraQualquerId { get; set; }
    

    or:

    [ForeignKey("EntidadeEstrangeiraId")]
    public virtual EntidadeEstrageira UmNomeQualquerDePropriedadeDeNavegacao { get; set; }
    
  3. Still, it is checked if there is any annotation of Fluent API in context. It is also possible to configure foreign keys.

I’m not going to go into details of how it works because it’s a lot, but in general, that’s it.


Your Case

I will analyze the entities one by one.

public class Predio {
    public int Id { get; set; }
    public string Nome { get; set; }
    public Endereco Endereco { get; set; }
}

This is a classic case that falls in the first step. Usually the pattern is virtual for browsing properties (I explained it here).

How did you not set the foreign key, if the object was not a complex type, the Entity Framework would define a foreign key for you in the table corresponding to the Model Predio. If I’m not mistaken, I’d stay Endereco_Id.

However, you have defined Endereco as a complex object. Since the relation is 1 to 1, at the bottom it is as if you were defining an extension of Predio. Notice how the schematic looked when generating the Migration:

    CreateTable(
            "dbo.Predios",
            c => new
                {
                    Id = c.Int(nullable: false, identity: true),
                    Nome = c.String(),
                    Endereco_Logradouro = c.String(),
                    Endereco_Numero = c.String(),
                    Endereco_Bairro = c.String(),
                    Endereco_Cidade = c.String(),
                    Endereco_CEP = c.String(),
                    Construtora_Id = c.Int(),
                })
            .PrimaryKey(t => t.Id)
            .ForeignKey("dbo.Construtoras", t => t.Construtora_Id)
            .Index(t => t.Construtora_Id);

Also note that you have not set a property to Construtora_Id, but performing the reading of Model Construtora, which has a ratio of 1 to N with Predio, Entity Framework concluded that a foreign key would be needed there, and defined it as Construtora_Id (rules 1 and 2, above).

Finally, this constructor has no use:

public Construtora()
{
    this.Predios = new List<Predio>();
}

Predios is defined in the data load of Construtora automatically. No need to initialize it.

  • Gypsy, in the example I posted I did not define as virtual and did not decorate anything in the entity Builder with Data Annotation [Foreignkey()], Fluent API was used in this context?

  • @Kellysoares So, some constructions there are a little problematic. If it is your wish, I can comment them one by one.

  • I would love to, because at first, I thought it was because of the builder of the Construction class who is passing a reference to the entity Buildings, I thought that’s what was doing the relationship between the entities.

  • @Kellysoares I updated the answer.

Browser other questions tagged

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