Search code examples
.net-coreef-core-3.1entity-framework-core-3.1

why ef core FisrtOrDefault() will call the entity parameter constructor?


sorry,i am not very good at english!!

i am using ef core 3.1.4,i just don't understand

  • why the 【IQueryable.FirstOrDefault() 】 method will call the entity paramter constructor?
  • what is the mapping rule?

the result and code is here:

Program.cs Result

enter image description here

Program.cs

using System;
using System.Linq;
using System.Text.Json;
using IdentityClient.Data;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.DependencyInjection;

namespace IdentityClient
{
    class Program
    {
        static void Main(string[] args) {
            var services = new ServiceCollection();
            services.AddDbContext<MyDbContext>(x => x.UseInMemoryDatabase("db"));
            var provider = services.BuildServiceProvider();

            var writeContext = provider.CreateScope().ServiceProvider.GetRequiredService<MyDbContext>();
            var admin = new UserEntity("admin", "admin123");
            Console.WriteLine(JsonSerializer.Serialize(admin));
            writeContext.User.Add(admin);
            writeContext.SaveChanges();

            var readContext = provider.CreateScope().ServiceProvider.GetRequiredService<MyDbContext>();
            var user = readContext.User.FirstOrDefault();
            Console.WriteLine(user == null ? "" : JsonSerializer.Serialize(user));

            Console.ReadLine();
        }
    }
}

MyDbContext.cs

using Microsoft.EntityFrameworkCore;

namespace IdentityClient.Data
{
    public class MyDbContext:DbContext
    {
        public MyDbContext(DbContextOptions<MyDbContext> options):base(options)
        {

        }

        public DbSet<UserEntity> User { get; set; }
    }
}

UserEntity.cs

using System;

namespace IdentityClient.Data
{
    public class UserEntity
    {
        //1.why query will call the constructor?
        public UserEntity(string name, string password) {
            Id=Guid.NewGuid();
            Name = name;
            Salt = Guid.NewGuid().ToString();
            //2.why [Password] is different,what is the rule
            Password = Salt;
        }
        public Guid Id { get; set; }
        public string Name { get; set; }
        public string Password { get; set; }
        public string Salt { get; set; }
    }
}


Solution

  • 1. Why query will call the constructor?

    Starting with EF Core 2.1, it is now possible to define a constructor with parameters and have EF Core call this constructor when creating an instance of the entity. The constructor parameters can be bound to mapped properties, or to various kinds of services to facilitate behaviors like lazy-loading.

    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.

    https://learn.microsoft.com/en-us/ef/core/modeling/constructors

    2. Why [Password] is different, what is the rule?

    Based on the Microsoft documentation you can map query results to entity properties by this convention:

    The parameter types and names must match property types and names, except that properties can be Pascal-cased while the parameters are camel-cased.

    If you don't accept the parameter for a specific property it will map implicitly. so Salt fills from query and Password fills in the constructor.

    Postscript: Being set property by another property in the constructor is not a good practice. because the order of declaration or statements could impact the final result. for example In your case when you change lines 19,20 with each other in this example you will get the expected result, and it's a bad smell in your code.

    enter image description here