我使用 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 仍然返回使用它而不是另一个,所以问题仍然存在。
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)
{ }
}