dotnet / EntityFramework.Docs

Documentation for Entity Framework Core and Entity Framework 6
https://docs.microsoft.com/ef/
Creative Commons Attribution 4.0 International
1.62k stars 1.96k forks source link

"Entity types with constructors" documentation doesn't explain how the framework prioritizes constructors for instantiation. #3636

Open ErroneousFatality opened 2 years ago

ErroneousFatality commented 2 years ago

"Entity types with constructors" documentation doesn't explain how the framework prioritizes constructors for instantiation.

The ambiguous text in question:

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.

Does the framework look for the constructor that has the greatest number of parameters matching properties? Is it possible to define which constructor for a given entity should be used? Or to set the global method of choosing?

In my case, I've got a private default constructor I always leave for EF Core. I have another internal constructor my domain services use to create the entity, and that constructor can have some heavy validation or other type of logic inside itself. If I create another private constructor that accepts parameters for all the properties, will that one be prioritized over the one mentioned above?

What if I already have a constructor that accepts parameters for all properties and does some logic I wouldn't want to run on EFCore's entity instantiation? How could I solve that, given that I can't create two constructors with the same parameter signature?

EDIT: I've tested it out on EFCore 6.0.1. The framework prioritizes the constructor with minimal parameter count (including 0) where all parameters correspond to a property. If this was made clear in the documentation I wouldn't have had to waste time on testing it out!


Document Details

Do not edit this section. It is required for docs.microsoft.com ➟ GitHub issue linking.

ajcvickers commented 2 years ago

@ErroneousFatality This is related to #2571, #1847, and #746. I agree this documentation could be better.

EF always uses a parameterless constructor if one is present. This avoids breaking from earlier versions of EF that would only use parameterless constructors. Configuration for the constructor to use is tracked by https://github.com/dotnet/efcore/issues/10789.

ErroneousFatality commented 2 years ago

Thanks for the info. The biggest issue I'm having, due to the way it currently works, is that when using the nullable reference type enabled configuration, I'd like to have a constructor for EF that covers all the non-nullable types that need to have values on construction, but often I can't because my "domain" constructor has equal or less parameters. So I end up with some monstrosity like private Entity(string property1) {Property1 = property1; Property2 = default!; Property3 = default!;}