Mysql
 sql >> база данни >  >> RDS >> Mysql

Как да създадете CreatedOn и UpdatedOn с помощта на EF Core 2.1 и Pomelo

Проблем:

Стесних това до (това, което изглежда) грешка в Pomelo. Проблемът е тук:

https://github.com/PomeloFoundation/Pomelo.EntityFrameworkCore.MyesSq /801

Проблемът е, че Pomelo създава defaultValue свойство за DateTime и други структури при генериране на миграцията. Ако при миграцията е зададена стойност по подразбиране, тя отменя стратегията за генериране на стойност и тогава SQL изглежда неправилно.

Заобиколното решение е да генерирате миграцията и след това ръчно да модифицирате файла за миграции, за да зададете defaultValue до null (или премахнете целия ред).

Например променете това:

migrationBuilder.AddColumn<DateTime>(
                name: "UpdatedTime",
                table: "SomeTable",
                nullable: false,
                defaultValue: new DateTimeOffset(new DateTime(1, 1, 1, 0, 0, 0, 0, DateTimeKind.Unspecified), new TimeSpan(0, 0, 0, 0, 0)))
                .Annotation("MySql:ValueGenerationStrategy", MySqlValueGenerationStrategy.ComputedColumn);

Към това:

migrationBuilder.AddColumn<DateTime>(
                name: "UpdatedTime",
                table: "SomeTable",
                nullable: false)
                .Annotation("MySql:ValueGenerationStrategy", MySqlValueGenerationStrategy.ComputedColumn);

След това скриптът за миграция ще изплюе правилния SQL с DEFAULT CURRENT_TIMESTAMP за TIMESTAMP . Ако премахнете [Column(TypeName = "TIMESTAMP")] атрибут, той ще използва datetime(6) колона и изплюйте DEFAULT CURRENT_TIMESTAMP(6) .

РЕШЕНИЕ:

Измислих заобиколно решение, което правилно имплементира създадено време (актуализирано от базата данни само при INSERT) и актуализирано време (актуализирано от базата данни само при INSERT и UPDATE).

Първо, дефинирайте вашия обект по следния начин:

public class SomeEntity
{
    // Other properties here ...

    public DateTime CreatedTime { get; set; }
    public DateTime UpdatedTime { get; set; }
}

След това добавете следното към OnModelCreating() :

protected override void OnModelCreating(ModelBuilder builder)
{
    // Other model creating stuff here ...

    builder.Entity<SomeEntity>.Property(d => d.CreatedTime).ValueGeneratedOnAdd();
    builder.Entity<SomeEntity>.Property(d => d.UpdatedTime).ValueGeneratedOnAddOrUpdate();

    builder.Entity<SomeEntity>.Property(d => d.CreatedTime).Metadata.SetBeforeSaveBehavior(PropertySaveBehavior.Ignore);
    builder.Entity<SomeEntity>.Property(d => d.CreatedTime).Metadata.SetAfterSaveBehavior(PropertySaveBehavior.Ignore);
    builder.Entity<SomeEntity>.Property(d => d.UpdatedTime).Metadata.SetBeforeSaveBehavior(PropertySaveBehavior.Ignore);
    builder.Entity<SomeEntity>.Property(d => d.UpdatedTime).Metadata.SetAfterSaveBehavior(PropertySaveBehavior.Ignore);
}

Това създава перфектна първоначална миграция (където migrationBuilder.CreateTable се използва) и генерира очаквания SQL:

`created_time` datetime(6) NOT NULL DEFAULT CURRENT_TIMESTAMP(6),
`updated_time` datetime(6) NOT NULL DEFAULT CURRENT_TIMESTAMP(6) ON UPDATE CURRENT_TIMESTAMP(6),

Това трябва работи и върху миграции, които актуализират съществуващите таблици, но се уверете, че defaultValue винаги е нула.

SetBeforeSaveBehavior и SetAfterSaveBehavior редовете не позволяват на EF някога да се опита да презапише времето за създаване със стойност по подразбиране. Той ефективно прави колоните Created и Updated да се четат само от гледна точка на EF, което позволява на базата данни да свърши цялата работа.

Можете дори да извлечете това в метод за интерфейс и разширение:

public interface ITimestampedEntity
    {
        DateTime CreatedTime { get; set; }
        DateTime UpdatedTime { get; set; }
    }
public static EntityTypeBuilder<TEntity> UseTimestampedProperty<TEntity>(this EntityTypeBuilder<TEntity> entity) where TEntity : class, ITimestampedEntity
{
    entity.Property(d => d.CreatedTime).ValueGeneratedOnAdd();
    entity.Property(d => d.UpdatedTime).ValueGeneratedOnAddOrUpdate();

    entity.Property(d => d.CreatedTime).SetBeforeSaveBehavior(PropertySaveBehavior.Ignore);
    entity.Property(d => d.CreatedTime).SetAfterSaveBehavior(PropertySaveBehavior.Ignore);
    entity.Property(d => d.UpdatedTime).SetBeforeSaveBehavior(PropertySaveBehavior.Ignore);
    entity.Property(d => d.UpdatedTime).SetAfterSaveBehavior(PropertySaveBehavior.Ignore);

    return entity;
}

След това имплементирайте интерфейса на всичките си обекти с времеви печат:

public class SomeEntity : ITimestampedEntity
{
    // Other properties here ...

    public DateTime CreatedTime { get; set; }
    public DateTime UpdatedTime { get; set; }
}

Това ви позволява да настроите обекта от OnModelCreating() така:

protected override void OnModelCreating(ModelBuilder builder)
{
    // Other model creating stuff here ...

    builder.Entity<SomeTimestampedEntity>().UseTimestampedProperty();
}



  1. Database
  2.   
  3. Mysql
  4.   
  5. Oracle
  6.   
  7. Sqlserver
  8.   
  9. PostgreSQL
  10.   
  11. Access
  12.   
  13. SQLite
  14.   
  15. MariaDB
  1. Ефективно съхраняване на 7 300 000 000 реда

  2. Cronjob или MySQL събитие?

  3. Как да оптимизирате изгледите на MySQL

  4. mysql_data_seek еквивалент на pdo

  5. как да дам същия сериен номер за група записи в mysql