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):
It is verified in the Model if there are compatible browsing properties. For example:
public virtual EntidadeEstrangeira EntidadeEstrangeira { get; set; }
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; }
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?
– Kelly Soares
@Kellysoares So, some constructions there are a little problematic. If it is your wish, I can comment them one by one.
– Leonel Sanches da Silva
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.
– Kelly Soares
@Kellysoares I updated the answer.
– Leonel Sanches da Silva