Senne Verhaegen
Senne Verhaegen

Reputation: 1046

How does EF Core instantiate and initialize entities?

How does EF Core instantiate and initialize objects that are retrieved from a database? In the following example, the Person class has a default constructor and a parameterized constructor. Neither of these constructors is called when my program retrieves the Person object from the database.

public class Person
{
    public int Id { get; set; }
    public string FirstName { get; set; }
    public string LastName { get; set; }
    
    public Person()
    {
        Console.WriteLine("Default ctor accessed");
    }
    
    public Person(string firstName, string lastName)
    {
        Console.WriteLine("Parameterized ctor accessed");
        FirstName = firstName;
        LastName = lastName;
    }
}

// Program.cs
// Other code omitted for brevity
var personRead = context.Persons.First(p => p.FirstName.Equals("MyName"));
Console.WriteLine($"Firstname: {personRead.FirstName}");

This conflicts with the microsoft documentation:

When EF Core creates instances of these types, such as for the results of a query, it will first call the default parameterless constructor and then set each property to the value from the database. However, if EF Core finds a parameterized constructor with parameter names and types that match those of mapped properties, then it will instead call the parameterized constructor with values for those properties and will not set each property explicitly

The article was written on 14/10/2020 so it might be out of date. However my question still remains. How does EF core instantiate and initialize these objects? I'm using Microsoft.EntityFrameworkCore version 6.0.8

Upvotes: 2

Views: 760

Answers (1)

Ivan Stoev
Ivan Stoev

Reputation: 205929

Neither of these constructors is called when my program retrieves the Person object from the database

This can't be true except you have another constructor(s) not shown here.

EF Core definitely uses class constructor for instantiating entities, so the documentation is correct, however it's unclear which one in case there are multiple. All it says is:

Note

Currently, all constructor binding is by convention. Configuration of specific constructors to use is planned for a future release.

The answer is hidden inside the implementation of the ConstructorBindingFactory class which is responsible for selecting the constructor to be used, and more specifically the following comment inside GetBindings method:

Trying to find the constructor with the most service properties followed by the least scalar property parameters

Service properties are explained in Injecting services section, and scalar property parameters refer to primitive type constructor arguments explained in Binding to mapped properties.

In your example, there is no constructor with service type arguments, so the one with the least scalar property parameters will be chosen, which in this case is the parameterless constructor (parameters count is 0)

public Person()
{
    Console.WriteLine("Default ctor accessed");
}

Again, if you have other constructors, check if some of them is "better". But as it looks, if you have parameterless constructor (doesn't matter if public, protected, internal, private etc.) and no constructors with service type arguments, then EF Core will always use the parameterless one.

If you want, you can check the entity instantiation info using the metadata API, e.g.

var entityType = dbContext.Model.FindEntityType(typeof(Person));
var info = entityType.ConstructorBinding;

ConstructorBinding property returns instance of abstract type InstantiationBinding class. ParameterBindings property returns information about parameters and corresponding properties, and CreateConstructorExpression method which

Creates an expression tree that represents creating an entity instance from the given binding information. For example, this might be a NewExpression to call a constructor, or a MethodCallExpression to call a factory method.

Currently there are two implementations of aforementioned abstract type - ConstructorBinding class for instantiation using constructor, and FactoryMethodBinding class for instantiation via factory method.

So, currently by convention EF Core uses constructor instantiation, but factory method instantiation might be added in the future (it might even be used currently by proxies extension, but it uses/requires parameterless constructor in the class they are inheriting).

Upvotes: 5

Related Questions