1

我正在尝试在具有 onUpdate 时间戳的 Pomelo.MySQL 中创建一个日志表,但我似乎无法使用实体框架触发它。

这是我的桌子模型

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 语句一起工作,但我想通过实体框架来解决它。

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

它可能与CURRENT_TIMESTAMP(6)而不是有关CURRENT_TIMESTAMP()吗?不确定为什么 Entity Framework 将其设置为(6).

4

1 回答 1

3

根据默认值上的 EF Core 文档,不支持数据注释:

您不能使用数据注释设置默认值。

如果 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)属性不应该是必需的。


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

class MyContext : DbContext
{
    // ...

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

如果您只想在更改表行时更新值,而不是在创建它时更新,您可以使用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()instead 将适用于大多数用例。


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


我正在使用Pomelo.EntityFramework.MySql版本2.1.4。我使用 Elastic Beanstalk 托管它,所以我需要使用旧版本的 dotnet

对于 Pomelo,上述所有内容都无法正常工作2.1.4(使用timestamportimestamp(6)可能会工作,但您需要手动更改DEFAULT语句以删除单引号,以防您为数据库搭建支架)。但是您始终可以将表定义更改为一种解决方法。

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

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

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

于 2019-12-25T22:59:42.890 回答