Mysql
 sql >> Cơ Sở Dữ Liệu >  >> RDS >> Mysql

Cách tạo CreatedOn và UpdatedOn bằng EF Core 2.1 và Pomelo

Vấn đề:

Tôi đã thu hẹp điều này xuống (những gì có vẻ là) một lỗi trong Pomelo. Vấn đề là ở đây:

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

Vấn đề là Pomelo tạo defaultValue thuộc tính cho DateTime và các cấu trúc khác khi tạo quá trình di chuyển. Nếu một giá trị mặc định được đặt trong quá trình di chuyển, nó sẽ ghi đè chiến lược tạo giá trị và khi đó SQL có vẻ không chính xác.

Cách giải quyết là tạo quá trình di chuyển, sau đó sửa đổi thủ công tệp di chuyển để đặt defaultValue thành null (hoặc xóa toàn bộ dòng).

Ví dụ:thay đổi điều này:

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

Về điều này:

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

Sau đó, tập lệnh di chuyển sẽ tạo ra SQL chính xác với DEFAULT CURRENT_TIMESTAMP cho TIMESTAMP . Nếu bạn xóa [Column(TypeName = "TIMESTAMP")] , nó sẽ sử dụng datetime(6) cột và nhổ ra DEFAULT CURRENT_TIMESTAMP(6) .

GIẢI PHÁP:

Tôi đã đưa ra một giải pháp thực hiện chính xác Thời gian tạo (chỉ được cập nhật bởi cơ sở dữ liệu trên INSERT) và Thời gian cập nhật (được cập nhật bởi cơ sở dữ liệu chỉ trên INSERT và UPDATE).

Trước tiên, hãy xác định thực thể của bạn như sau:

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

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

Sau đó, thêm phần sau vào 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);
}

Điều này tạo ra một quá trình di chuyển ban đầu hoàn hảo (trong đó migrationBuilder.CreateTable được sử dụng) và tạo ra SQL mong đợi:

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

Điều này nên cũng hoạt động trên các di chuyển cập nhật các bảng hiện có, nhưng hãy đảm bảo rằng defaultValue luôn luôn rỗng.

SetBeforeSaveBehaviorSetAfterSaveBehavior dòng ngăn EF cố gắng ghi đè Thời gian đã tạo bằng một giá trị mặc định. Nó làm cho các cột Đã tạo và Cập nhật chỉ được đọc theo quan điểm của EF một cách hiệu quả, cho phép cơ sở dữ liệu thực hiện tất cả công việc.

Bạn thậm chí có thể trích xuất nó thành một giao diện và phương thức mở rộng:

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

Sau đó, triển khai giao diện trên tất cả các thực thể có dấu thời gian của bạn:

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

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

Điều này cho phép bạn thiết lập Đối tượng từ bên trong OnModelCreating() như vậy:

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. Tìm kiếm MySQL trong danh sách dấu phẩy

  2. JDBC với MySQL thực sự chậm, không biết tại sao

  3. Cách trả về tập hợp kết quả dựa trên các hàng khác

  4. Xây dựng ứng dụng Android để chạy PHP và MySQL trên Android Tablet

  5. Câu lệnh MySQL CASE ... WHERE ... THEN