C# Pomelo mySQL 触发 onUpdate Timestamp

C# Pomelo mySQL trigger onUpdate Timestamp

我正在尝试在 Pomelo.MySQL 中创建一个日志 table,它有一个 onUpdate 时间戳,但我似乎无法用 Entity Framework.[=17= 触发它]

这是我的模型 table

public class OrganisationLog
{
    [Key]
    public int Id { get; set; }

    [Column(TypeName = "VARCHAR(1024)")]
    [Required(AllowEmptyStrings = false)]
    public string MachineName { get; set; }

    [DefaultValue("CURRENT_TIMESTAMP")]
    [DatabaseGenerated(DatabaseGeneratedOption.Computed)]
    public DateTime LastContact { get; set; }

    public int OrganisationId { get; set; }

    [ForeignKey("OrganisationId")]
    public Organisation Organisation { get; set; }
}

下面是应该起作用的函数。

private void UpdateOrganisationLog(Organisation organisation, string machineName)
{
    try
    {
        OrganisationLog organisationLog = _context.OrganisationLogs
            .Where(x => x.OrganisationId == organisation.Id && x.MachineName == machineName)
            .FirstOrDefault();

        if (organisationLog == null)
        {
            organisationLog = new OrganisationLog()
            {
                MachineName = machineName,
                OrganisationId = organisation.Id,
                LastContact = DateTime.Now
            };
            _context.OrganisationLogs.Add(organisationLog);
        }
        else
        {
            _context.Update(organisationLog);
        }
        _context.SaveChanges();
    }
    catch (Exception e)
    {
        Console.WriteLine("Error " + e.Message);
    }
}

我最终使用手动 SQL 语句使其工作,但我想通过 Entity Framework 来解决它。

_context.Database.ExecuteSqlCommand($"UPDATE organisationlogs SET LastContact = CURRENT_TIMESTAMP(6) WHERE Id = {organisationLog.Id}");

会不会与 CURRENT_TIMESTAMP(6) 而不是 CURRENT_TIMESTAMP() 有关?不知道为什么 Entity Framework 变成了 (6)

根据 Default Values 上的 EF Core 文档,不支持数据注释:

You can not set a default value using Data Annotations.

如果 EF Core 支持它,那么将它用于 CURRENT_TIMESTAMP 可能仍然行不通,因为它不是 System.DateTime 值,但技术上是 SQL片段。


在您的情况下,使用 .HasDefaultValueSql() 指定 SQL 片段的 FluentAPI 配置应该适用于 Pomelo 3.0.1+:

class MyContext : DbContext
{
    // ...

    protected override void OnModelCreating(ModelBuilder modelBuilder)
    {
        modelBuilder.Entity<OrganisationLog>(entity =>
        {
            entity.Property(e => e.LastContact)
                .HasDefaultValueSql("CURRENT_TIMESTAMP");
        });
    }
}

DatabaseGenerated(DatabaseGeneratedOption.Computed) 属性应该不是必需的。


如果您希望值不仅在创建时生成,而且在更改 table 行时自动更新,请改用以下模型定义:

class MyContext : DbContext
{
    // ...

    protected override void OnModelCreating(ModelBuilder modelBuilder)
    {
        modelBuilder.Entity<OrganisationLog>(entity =>
        {
            entity.Property(e => e.LastContact)
                .ValueGeneratedOnAddOrUpdate();
        });
    }
}

如果您只希望在更改 table 行时更新值,而不是在创建它时,您可以将 ValueGeneratedOnUpdate() 与 EF Core 3.1.0 一起使用。

EF Core < 3.1.0 中存在错误,ValueGeneratedOnUpdate() 无法生成正确的 C# 代码。对于大多数人来说,这应该不是问题,因为 EF Core 3.0.0 的生命周期支持无论如何都是非常有限的(并且如上所述,该功能仅由 Pomelo 自 3.0.1 起支持)。如果您无论如何都需要 3.0.1 >= Pomelo < 3.1.0 的解决方法,那么使用 ValueGeneratedOnAddOrUpdate() 将适用于大多数用例。


请参阅我们的 GitHub 存储库中的 #959,了解与 CURRENT_TIMESTAMP 一起实现对 datetime 列的支持的修复以及更多详细信息。


I'm using Pomelo.EntityFramework.MySql version 2.1.4. I'm hosting this with Elastic Beanstalk so I need to use an older version of dotnet

上面的所有内容都不会对 Pomelo 2.1.4 正常工作(使用 timestamptimestamp(6) 可能 工作,但你将需要手动更改 DEFAULT 语句以删除单引号,以防您搭建数据库)。但是您始终可以仅更改 table 定义作为解决方法。

如果您正在使用迁移,则可以将以下行(或类似内容)添加到 Up() 方法中,例如:

migrationBuilder.Sql("ALTER TABLE `OrganisationLog` CHANGE COLUMN `LastContact` datetime(6) CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP;");

不理想,但它应该适用于较旧的 Pomelo 版本。