Поскольку Entity Framework использует nvarchar(max) по умолчанию для строк, я хотел бы установить по умолчанию что-то еще.
В 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"));
Если я затем изменил свойство с помощью аннотаций данных, EF вместо этого использовал бы эти значения, например:
[MaxLength(128)]
public string Name { get; set; }
[Column(TypeName = "nvarchar(MAX)")]
[MaxLength]
public string Comment { get; set; }
Однако, используя 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)";
}
@CodeNotFound. Это проблема, миграция генерирует такой код в ядре EF: Comment = table.Column<string>(type: "nvarchar(256)", maxLength: 128, nullable: false),. В EF 6.1.3 этого не произошло.
Кстати, я не знаю, почему вы просто не используете nvarchar (128) вместо nvarchar (MAX)?





Есть несколько атрибутов, косвенно влияющих на тип столбца свойства string - MaxLength (например, varchar(256) против varchar(MAX), IsUnicode (например, nvarchar против varchar) и IsFixedLength (например, char против varchar).
Текущая модель API несовместима. Первый доступен через GetMaxLength и SetMaxLength, второй - через IsUnicode и IsUnicode, а для третьего нет публичного 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);
}
что не совсем правильно, потому что null в данном случае имеет двойное значение - не указано и MAX.
Правильный способ требует использования внутреннего API EF Core, который предоставляет гораздо больше методов конфигурации, в частности, позволяет передавать значение перечисления ConfigurationSource вместе со значением атрибута. Значения перечисления ConfigurationSource определяют приоритет конфигурации: Convention - самый низкий, затем DataAnnotation и, наконец, Explicit - самый высокий. Вся идея в том, что конфигурация с более низким приоритетом не перезаписывает конфигурацию, уже установленную более высоким приоритетом. Все общедоступные свободно распространяемые API используют Explcit, в то время как в нашем случае Convention идеально подходит (поскольку мы имитируем обычное значение по умолчанию).
Поэтому, если вы принимаете предупреждение «Этот API поддерживает инфраструктуру Entity Framework Core и не предназначен для использования непосредственно из вашего кода. Этот API может быть изменен или удален в будущих выпусках»., добавьте
using Microsoft.EntityFrameworkCore.Metadata.Internal;
и использовать
foreach (var property in modelBuilder.Model.GetEntityTypes()
.SelectMany(t => t.GetProperties())
.Where(p => p.ClrType == typeof(string)))
{
property.AsProperty().Builder
.HasMaxLength(256, ConfigurationSource.Convention);
}
Могу ли я узнать, было ли обновление этого ответа, это действительно работает, но, поскольку это внутренний метод, он может не поддерживаться в будущих обновлениях, поэтому есть ли лучший подход, который следует использовать вместо этого?
@StevenPrice. Когда он изменяется, или, лучше, когда EF Core публикует соглашения, ответ будет обновлен. В настоящее время даже последняя версия EFC 5.x не предоставляет общедоступный API для таких задач. Существует общедоступный интерфейс IConventionPropertyBuilder, но нет общедоступного способа его получить, поскольку конструктор класса PropertyBuilder (который его реализует) также помечен как «внутренний API».
Зачем использовать разные размеры в nvarchar и maxlength?