-1

Given the following method-chain:

    modelBuilder
        .Entity<Student>()
        .HasOne<StudentAddress>(s => s.Address)
        .WithOne(ad => ad.Student);

How does HasOne know about the Student type (shown in lambda argument) provided by its previous method Entity<Student>?

Seems to me as if Entity<Student> somehow passes its designated type parameter Student to the next method via chaining (return value of Entity<Student> being the base object for next method HasOne).

chakmeshma
  • 246
  • 8
  • 27
  • 1
    "Seems to me as if Entity somehow passes its designated type parameter Student to the next method via chaining (return value of Entity being the base object for next method HasOne)." That's exactly what happens. – Sweeper Jul 28 '19 at 09:49
  • But how exactly, what is the syntax or part of the syntax that does it? – chakmeshma Jul 28 '19 at 09:52

1 Answers1

1

I'm guessing that you are calling this method:

public virtual EntityTypeBuilder<TEntity> Entity<TEntity>() where TEntity : class;

Look closely at the signature. The method takes a generic parameter called TEntity, and returns a EntityTypeBuilder<TEntity>, allowing you to chain any calls that can be called on EntityTypeBuilder<TEntity> at the end of a call to Entity<TEntity>() call.

In your case, you called Entity<Student>(), so the signature dictates that the result must be a EntityTypeBuilder<Student>. Then, you were able to call EntityTypeBuilder<Student>.HasOne:

public virtual ReferenceNavigationBuilder<TEntity,TRelatedEntity> HasOne<TRelatedEntity> (Expression<Func<TEntity,TRelatedEntity>> navigationExpression = null) where TRelatedEntity : class;

Look at what HasOne accepts - Expression<Func<TEntity,TRelatedEntity>>. Because you are calling EntityTypeBuilder<Student>.HasOne, TEntity is Student. The compiler sees your lambda expression and infers that s must be Student, because that's the only way that the lambda expression could be converted to Expression<Func<TEntity,TRelatedEntity>>.

Also note that HasOne returns a ReferenceNavigationBuilder<TEntity,TRelatedEntity>, which allows you to chain other calls, and that now you have passed two pieces of type information TEntity and TRelatedEntity.

In fact, you don't need to specify the generic parameter for HasOne, the compiler can infer those as well:

modelBuilder
    .Entity<Student>()
    .HasOne(s => s.Address)
    .WithOne(ad => ad.Student);
Sweeper
  • 213,210
  • 22
  • 193
  • 313