EF Core 2.1.0设置默认字符串长度和列类型

Ogg*_*las 5 c# entity-framework entity-framework-core

由于Entity Framework将nvarchar(max)字符串默认用作默认值,因此我想将其他内容设置为默认值。

https://dba.stackexchange.com/questions/48408/ef-code-first-uses-nvarcharmax-for-all-strings-will-this-hurt-query-performan

在Entity Framework 6.1.3中,我可以这样修改OnModelCreating(DbModelBuilder modelBuilder)

modelBuilder.Properties<DateTime>().Configure(c => c.HasColumnType("datetime2"));
modelBuilder.Properties<DateTime>().Configure(c => c.HasPrecision(0));

modelBuilder.Properties<string>()
    .Configure(s => s.HasMaxLength(256).HasColumnType("nvarchar"));
Run Code Online (Sandbox Code Playgroud)

如果随后我使用数据注释修改了属性,EF则改用这些值,如下所示:

[MaxLength(128)]
public string Name { get; set; }

[Column(TypeName = "nvarchar(MAX)")]
[MaxLength]
public string Comment { get; set; }
Run Code Online (Sandbox Code Playgroud)

但是使用Microsoft.EntityFrameworkCore.SqlServer 2.1.0我不能做到这一点,我也不能使用Conventions

我可以这样解决,datetime但是如果我尝试对字符串执行相同的操作,则迁移将表明type: "nvarchar(256)", maxLength: 128是否使用例如数据注释。我该如何解决?

foreach (var property in modelBuilder.Model.GetEntityTypes()
    .SelectMany(t => t.GetProperties())
    .Where(p => p.ClrType == typeof(DateTime)))
{
    property.Relational().ColumnType = "datetime2(0)";
}
Run Code Online (Sandbox Code Playgroud)

Iva*_*oev 9

有几个属性会间接影响属性的列类型string- MaxLength(例如varchar(256)vs varchar(MAX)IsUnicode(例如nvarcharvs varchar)和IsFixedLength(例如charvs varchar)。

当前的模型API不一致。第一种是通过访问GetMaxLengthSetMaxLength,第二个-通过IsUnicodeIsUnicode,并没有为第三个(仅流畅API)没有公共模型API。

因此,设置MaxLength您可以使用:

foreach (var property in modelBuilder.Model.GetEntityTypes()
    .SelectMany(t => t.GetProperties())
    .Where(p => p.ClrType == typeof(string)))
{
    if (property.GetMaxLength() == null)
        property.SetMaxLength(256);
}
Run Code Online (Sandbox Code Playgroud)

这并不完全正确,因为null在这种情况下具有双重含义-未指定和MAX

正确的方法需要使用EF Core内部API,该API提供了更多的配置方法,尤其是允许您将ConfigurationSource枚举值与属性值一起传递。ConfigurationSource枚举值定义配置的优先级- Convention最低,然后DataAnnotation最后Explicit是最高。整个想法是,较低优先级的配置不会覆盖已经由较高优先级设置的配置。所有公共语言API都使用Explcit,而在我们的情况下则Convention非常适合(因为我们正在模拟常规默认值)。

因此,如果您接受警告“此API支持Entity Framework Core基础结构,并且不能直接在您的代码中使用。此API可能会更改或在将来的版本中删除。” ,添加

using Microsoft.EntityFrameworkCore.Metadata.Internal;
Run Code Online (Sandbox Code Playgroud)

和使用

foreach (var property in modelBuilder.Model.GetEntityTypes()
    .SelectMany(t => t.GetProperties())
    .Where(p => p.ClrType == typeof(string)))
{
    property.AsProperty().Builder
        .HasMaxLength(256, ConfigurationSource.Convention);
}
Run Code Online (Sandbox Code Playgroud)

  • @StevenPrice 当它发生变化时,或者当 EF Core 公开约定时更好,那么答案将会更新。目前,即使是最新的 EFC 5.x 也没有为此类任务提供公共 API。有公共的“IConventionPropertyBuilder”接口,但没有公共方法来获取它,因为“PropertyBuilder”类(实现它)构造函数也被标记为“内部API”。 (2认同)