EF Core 如何确定使用哪个参数化实体构造函数?

问题描述 投票:0回答:1

我使用 EF Core 7.0 中的功能,允许使用带有参数化构造函数的实体,如here所述。

但是,在选择要使用的构造函数时,我不了解 EF Core 的某些行为。

例如,我有这个实体,带有只读 ID,因此有一个创建构造函数,它生成 id 和一个以 Id 作为参数的重构构造函数。

public class Poll
{
    public Guid Id { get; }
    public string Name {get;set;}
    public DateTime ExpirationDate { get; set; }
    public List<Vote> Votes { get; set; }
    public List<DateTime> dates {get;set;} = new List<DateTime>();

    public Poll(string name, List<DateTime> dates) : this(
        Guid.NewGuid(), 
        name,
        new List<Vote>(), 
        dates, 
        DateTime.UtcNow.AddMonths(2)
        )
    {
    }

    public Poll(Guid id, string name, List<DateTime> dates, DateTime expirationDate)
    {
        Name = name;
        Id = id;
        Dates = dates;
        ExpirationDate = expirationDate;
    }





}

与以下模型绑定:

       modelBuilder.Entity<Poll>(entity =>
        {
            entity.HasKey(poll => poll.Id);
            entity
                .Property(poll => poll.Id)
                .ValueGeneratedNever();
            entity.Property(poll => poll.Name);
            entity.Property(poll => poll.Dates);
            entity.Property(poll => poll.ExpirationDate);
        });

查询此实体时,EF Core 将调用第一个(创建)构造函数,而我希望(根据文档,我认为这是合乎逻辑的)它宁愿使用第二个(重构)构造函数。 为什么它没有按照文档使用带有每个映射属性参数的构造函数:

但是,如果 EF Core 找到一个参数化构造函数,其参数名称和类型与映射属性匹配,那么它将使用这些属性的值调用参数化构造函数,并且不会显式设置每个属性。

编辑:通过删除第一个构造函数进行实验,它抛出一个异常,指出

votes
参数无法绑定到属性。删除它时它起作用了。但是,当添加回我的第一个构造函数时,EF 仍然返回使用它而不是另一个,所以问题仍然存在。

c# .net-core entity-framework-core
1个回答
1
投票

GitHub 上的源代码显示使用了标量参数最少的构造函数 - 你没有服务,只有标量属性参数.

来自

ConstructorBindingFactory
参与构造函数选择的源码:

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

源代码中的单元测试演示了这种行为。
在下面的示例中,将选择具有 2 个参数的构造函数。

public void Binds_to_least_parameters_if_no_services()
{
    var constructorBinding = GetBinding<BlogSeveral>();

    Assert.NotNull(constructorBinding);

    var parameters = constructorBinding.Constructor.GetParameters();
    var bindings = constructorBinding.ParameterBindings;

    Assert.Equal(2, parameters.Length);
    Assert.Equal(2, bindings.Count);

    Assert.Equal("title", parameters[0].Name);
    Assert.Equal("id", parameters[1].Name);

    Assert.Equal("Title", bindings[0].ConsumedProperties.First().Name);
    Assert.Equal("Id", bindings[1].ConsumedProperties.First().Name);
}

private class BlogSeveral : Blog
{
    public BlogSeveral(string title, int id)
    { }

    public BlogSeveral(string title, Guid? shadow, int id)
    { }

    public BlogSeveral(string title, Guid? shadow, bool dummy, int id)
    { }
}
© www.soinside.com 2019 - 2024. All rights reserved.