Mysql
 sql >> Teknologi Basis Data >  >> RDS >> Mysql

Cara membuat CreatedOn dan UpdatedOn menggunakan EF Core 2.1 dan Pomelo

Masalah:

Saya telah mempersempit ini menjadi (yang tampaknya) bug di Pomelo. Masalah ada di sini:

https://github.com/PomeloFoundation/Pomelo.EntityFrameworkCore.MySql/issues /801

Masalahnya adalah Pomelo membuat defaultValue properti untuk DateTime dan struct lainnya saat membuat migrasi. Jika nilai default disetel pada migrasi, itu menimpa strategi pembuatan nilai, dan SQL kemudian terlihat salah.

Solusinya adalah membuat migrasi, lalu memodifikasi file migrasi secara manual untuk menyetel defaultValue ke null (atau hapus seluruh baris).

Misalnya, ubah ini:

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);

Untuk ini:

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

Skrip migrasi kemudian akan mengeluarkan SQL yang benar dengan DEFAULT CURRENT_TIMESTAMP untuk TIMESTAMP . Jika Anda menghapus [Column(TypeName = "TIMESTAMP")] atribut, itu akan menggunakan datetime(6) kolom dan keluarkan DEFAULT CURRENT_TIMESTAMP(6) .

SOLUSI:

Saya telah menemukan solusi yang mengimplementasikan Waktu yang Dibuat dengan benar (diperbarui oleh database hanya pada INSERT) dan Waktu yang diperbarui (diperbarui oleh database hanya pada INSERT dan UPDATE).

Pertama, tentukan entitas Anda seperti ini:

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

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

Kemudian, tambahkan berikut ini ke 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);
}

Ini menghasilkan migrasi awal yang sempurna (di mana migrationBuilder.CreateTable digunakan), dan menghasilkan SQL yang diharapkan:

`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),

Ini harus juga bekerja pada migrasi yang memperbarui tabel yang ada, tetapi pastikan bahwa defaultValue selalu nol.

SetBeforeSaveBehavior dan SetAfterSaveBehavior baris mencegah EF mencoba menimpa waktu yang Dibuat dengan nilai default. Ini secara efektif membuat kolom Created and Updated hanya membaca dari sudut pandang EF, memungkinkan database untuk melakukan semua pekerjaan.

Anda bahkan dapat mengekstrak ini menjadi antarmuka dan metode ekstensi:

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;
}

Kemudian implementasikan antarmuka pada semua entitas yang diberi cap waktu:

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

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

Ini memungkinkan Anda untuk mengatur Entitas dari dalam OnModelCreating() seperti ini:

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. Instal MySQL:ERROR:Gagal membuat ekstensi asli permata

  2. Bagaimana saya bisa mengulang semua baris tabel? (MySQL)

  3. php,postgresql,mysql

  4. MediumBlob dalam skema database Laravel

  5. UPDATE pernyataan untuk menetapkan kembali nilai kolom sesuai dengan rumus numerik