#c# #.net-core #entity-framework-core #ef-code-first #ef-fluent-api
#c# #.net-ядро #entity-framework-core #ef-code-first #ef-fluent-api
Вопрос:
Мы пытаемся сгенерировать ненулевой столбец rowversion на SQL Server с EF Core 3.1, используя Fluent API:
public class Person
{
public int Id { get; set; }
public byte[] Timestamp { get; set; }
}
public class PersonEntityConfiguration : IEntityTypeConfiguration<Person>
{
public void Configure(EntityTypeBuilder<Person> builder)
{
builder.HasKey(p => p.Id);
builder.Property(p => p.Timestamp)
.IsRowVersion()
.IsRequired();
}
}
Это отлично работает, когда вся таблица является новой:
public partial class PersonMigration : Migration
{
protected override void Up(MigrationBuilder migrationBuilder)
{
migrationBuilder.CreateTable(
name: "Persons",
columns: table => new
{
Id = table.Column<int>(nullable: false)
.Annotation("SqlServer:Identity", "1, 1"),
Timestamp = table.Column<byte[]>(rowVersion: true, nullable: false)
},
constraints: table =>
{
table.PrimaryKey("PK_Persons", x => x.Id);
});
}
}
Однако иногда нам нужно добавить версию строки в существующую таблицу. В этом случае EF Core генерирует недопустимую миграцию:
public partial class PersonTimestampMigration : Migration
{
protected override void Up(MigrationBuilder migrationBuilder)
{
migrationBuilder.AddColumn<byte[]>(
name: "Timestamp",
table: "Persons",
rowVersion: true,
nullable: false,
defaultValue: new byte[] { });
}
}
Сгенерированное выше значение по умолчанию вызовет исключение при применении к базе данных:
Не удалось выполнить DbCommand (1 мс) [Параметры=[], CommandType=’Text’, CommandTimeout=’30’]
ИЗМЕНИТЬ ТАБЛИЦУ [Persons] ДОБАВИТЬ [Timestamp] rowversion NOT NULL ПО УМОЛЧАНИЮ 0x;
Microsoft.Data.SqlClient.SQLException (0x80131904): значения по умолчанию не могут быть созданы для столбцов типа данных timestamp. Таблица ‘Persons’, столбец ‘Timestamp’.
Не удалось создать ограничение или индекс. Смотрите предыдущие ошибки.
Это известная ошибка в EF Core? Проблема может быть устранена путем ручного удаления defaultValue: new byte[] { }
из миграции, но есть ли способ запретить генерирование значения по умолчанию с использованием Fluent API?
Комментарии:
1.
ROWVERSION
Тип данных в SQL Server всегда обрабатывается database engine — поэтому, я полагаю, вы не можете определить для него значение по умолчанию — зачем, в любом случае? В чем видимая выгода? Это не ошибка EF Core — это особенность SQL Server ..2. @marc_s: Ошибка заключается в том, что EF Core не должен генерировать ограничение по умолчанию, поскольку он знает, что значение всегда заполняется базой данных.
IsRowVersion
настраивает свойство какValueGeneratedOnAddOrUpdate
иIsConcurrencyToken
.3. ХОРОШО — это правильный момент — но, как вы сами говорите — поскольку вы также это знаете — просто не указывайте значение по умолчанию в вашей модели! Также на заметку: присвоение имени этому столбцу
Timestamp
немного опасно и не рекомендуется — в конце концов, это все еще зарезервированное ключевое слово T-SQL ….. постарайтесь избежать любых потенциальных конфликтов в вашем именовании, если вы когда-либо сможете!4. Я не указываю значение по умолчанию. EF Core неправильно генерирует ее для меня, когда я настраиваю свойство с
.IsRowVersion().IsRequired()
(в существующей таблице). Это решило бы мою проблему, если бы был способ подавить это значение по умолчанию. Справедливо указать имя столбца.
Ответ №1:
Это известная ошибка в EF Core?
Это наверняка ошибка / дефект, но, вероятно, неизвестно, поскольку это происходит даже в последнем на данный момент предварительном просмотре EF Core 5.0. Или известен, но с низким приоритетом (для них) — вы должны проверить отслеживание проблем в EF Core.
Пробовал добавлять явно .HasDefaultValue(null)
и .HasDefaultValueSql(null)
— ничего не помогает, поэтому единственный вариант — вручную удалить defaultValue: new byte[] { }
из миграции. Хорошо то, что когда вы это делаете, это работает, и столбец создается и заполняется успешно, даже если в таблице есть существующие записи (по этой причине EF Core добавляет такой defaultValue
аргумент для новых обязательных столбцов в целом, но, как мы видим, не следует этого делать для ROWVERSION
).