sql >> Databáze >  >> RDS >> Mysql

Jak vytvořit CreatedOn a UpdatedOn pomocí EF Core 2.1 a Pomelo

Problém:

Zúžil jsem to na (co se zdá být) chyba v Pomelo. Problém je zde:

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

Problém je v tom, že Pomelo vytváří defaultValue vlastnost pro DateTime a další struktury při generování migrace. Pokud je při migraci nastavena výchozí hodnota, přepíše strategii generování hodnoty a SQL pak vypadá nesprávně.

Řešením je vygenerovat migraci a poté ručně upravit soubor migrace tak, aby nastavil defaultValue na null (nebo odstraňte celý řádek).

Změňte například toto:

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

K tomu:

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

Migrační skript pak vyplivne správný SQL s DEFAULT CURRENT_TIMESTAMP pro TIMESTAMP . Pokud odeberete [Column(TypeName = "TIMESTAMP")] atribut, bude používat datetime(6) sloupec a vyplivněte DEFAULT CURRENT_TIMESTAMP(6) .

ŘEŠENÍ:

Přišel jsem s řešením, které správně implementuje Created Time (aktualizovaný databází pouze po INSERT) a Aktualizovaný čas (aktualizovaný databází pouze po INSERT a UPDATE).

Nejprve definujte svou entitu takto:

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

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

Potom přidejte následující do 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);
}

To vytváří perfektní počáteční migraci (kde migrationBuilder.CreateTable se používá) a vygeneruje očekávané 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),

Toto by mělo pracovat také na migracích, které aktualizují existující tabulky, ale ujistěte se, že defaultValue je vždy null.

SetBeforeSaveBehavior a SetAfterSaveBehavior řádky brání EF v tom, aby se někdy pokusil přepsat čas vytvoření výchozí hodnotou. Efektivně umožňuje, aby sloupce Created a Updated byly čteny pouze z pohledu EF, což umožňuje databázi dělat veškerou práci.

Můžete to dokonce extrahovat do metody rozhraní a rozšíření:

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

Poté implementujte rozhraní do všech vašich entit s časovým razítkem:

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

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

To vám umožní nastavit Entitu z OnModelCreating() takhle:

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

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



  1. Dotaz MYSQL vrací „resource id#12“ namísto číselné hodnoty, kterou by měl vrátit

  2. Vyberte všechny sloupce větší než nějaká hodnota

  3. Změňte typ sloupce z Date na DateTime během migrace ROR

  4. DATE_FORMAT() Příklady – MySQL