У меня есть следующая сущность:
public class Person
{
public Guid Id { get; set; }
public string Name { get; set; }
}
Это мой контекст БД
public class PersonDbContext : DbContext
{
private static readonly ILoggerFactory
Logger = LoggerFactory.Create(x => x.AddConsole());
public DbSet<Person> Persons { get; set; }
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
{
optionsBuilder
.UseLoggerFactory(Logger)
.UseSqlServer(
"Server=(localdb)\\mssqllocaldb;Database=PersonDb;Trusted_Connection=True;MultipleActiveResultSets=true");
}
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder
.Entity<Person>()
.Property<DateTime>("Created")
.HasDefaultValueSql("GETUTCDATE()")
.ValueGeneratedOnAdd();
modelBuilder
.Entity<Person>()
.Property<DateTime>("Updated")
.HasDefaultValueSql("GETUTCDATE()")
.ValueGeneratedOnAddOrUpdate();
}
}
Как видно из переопределения OnModelCreating
, я добавляю свойства тени Обновлено / Создан для Person
сущности.
Я установил для этих свойств значения SQL значения по умолчанию
Created
при добавлении значения Updated
когда значение добавлено или обновлено
Ниже приведен код клиента
var personId = Guid.Parse("CF5EE27D-C694-408A-9F7B-080FF6315843");
using (var dbContext = new PersonDbContext())
{
var person = new Person
{
Id = personId,
Name = "New Person"
};
dbContext.Add(person);
await dbContext.SaveChangesAsync();
}
using (var dbContext = new PersonDbContext())
{
var person = dbContext.Persons.Find(personId);
var personName = person.Name;
person.Name = $"{personName} {DateTime.UtcNow}";
dbContext.SaveChanges();
}
Я могу подтвердить, что оба свойства установлены в UT C дата при вставке нового человека. Однако при обновлении свойство Updated
не устанавливается.
Это сгенерированное t- sql:
info: Microsoft.EntityFrameworkCore.Database.Command[20101]
Executed DbCommand (1ms) [Parameters=[@p1='?' (DbType = Guid), @p0='?' (Size = 4000)], CommandType='Text', CommandTimeout='30']
SET NOCOUNT ON;
UPDATE [Persons] SET [Name] = @p0
WHERE [Id] = @p1;
SELECT [Updated]
FROM [Persons]
WHERE @@ROWCOUNT = 1 AND [Id] = @p1;
Чтение документации по генерируемому значению при добавлении или update Я вижу следующее предупреждение:
Однако, если вы укажете, что свойство DateTime генерируется при добавлении или обновлении, вы должны указать способ создания значений. Один из способов сделать это - настроить значение по умолчанию GETDATE () (см. Значения по умолчанию), чтобы генерировать значения для новых строк. Затем вы можете использовать триггер базы данных для генерации значений во время обновлений (например, в следующем примере триггера).
Тогда я не понимаю, какова цель ValueGeneratedOnAddOrUpdate()
, если он ведет себя как ValueGeneratedOnAdd()
и я должен вручную вмешаться (создать триггер), чтобы установить это свойство.
Действительно, если я изменю определение свойства Updated
shadow на
modelBuilder
.Entity<Person>()
.Property<DateTime>("Updated")
.HasDefaultValueSql("GETUTCDATE()")
.ValueGeneratedOnAdd();
И переопределим SaveChanges
на PersonDbContext
public override int SaveChanges()
{
ChangeTracker.DetectChanges();
foreach (var entry in ChangeTracker.Entries().Where(entity => entity.State == EntityState.Modified))
{
entry.Property("Updated").CurrentValue = DateTime.UtcNow;
}
return base.SaveChanges();
}
Это делает то, что ожидается.
Итак, вопрос в том, как правильно установить значения по умолчанию для свойств тени в EF Core.
Это упрощенный пример из моего более крупного проекта, поэтому использование HasData
для сущностей в OnModelCreating
переопределении не является хорошим вариантом (из-за множества сущностей).
Я использую EF Core 3.1 .1
<PackageReference Include="Microsoft.EntityFrameworkCore" Version="3.1.1" />
<PackageReference Include="Microsoft.EntityFrameworkCore.Design" Version="3.1.1" />
<PackageReference Include="Microsoft.EntityFrameworkCore.SqlServer" Version="3.1.1" />
<PackageReference Include="Microsoft.EntityFrameworkCore.Tools" Version="3.1.1"/>