You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

ASP.NET Core MVC 8中自动维护CreatedAt/UpdatedAt时间字段问题

解决方案:自动维护CreatedAt和UpdatedAt字段

问题根源

  1. 创建操作:你的Create方法未手动设置CreatedAt,导致该字段被赋值为DateTime.MinValue(默认值),UpdatedAt保持为null,不符合需求。
  2. 更新操作:Edit方法直接实例化新的Gallery对象并调用Update,EF Core会将实体所有字段标记为待更新。新对象的CreatedAt是默认值,会覆盖数据库中已有的原始值,最终导致CreatedAt被重置(甚至变为NULL,如果数据库列允许为空),同时未设置UpdatedAt。

方案一:手动修正Controller代码(快速解决)

1. 修复Create方法

创建Gallery对象时,显式设置CreatedAt为UTC时间:

[HttpPost]
[ValidateAntiForgeryToken]
public IActionResult Create(GalleryVM galleryVM)
{
    Gallery? galleryExists = _db.Galleries.SingleOrDefault(p => p.Title == galleryVM.Title);
    if (galleryExists != null)
    {
        ModelState.AddModelError("Title", $"{galleryExists.Title} 已存在于系统中。");
    }

    if (ModelState.IsValid)
    {
        var galleryObj = new Gallery
        {
            Title = galleryVM.Title,
            IsPrivate = galleryVM.IsPrivate,
            AccessCode = galleryVM.AccessCode,
            CreatedAt = DateTime.UtcNow, // 设置创建时间
            UpdatedAt = null // 可选,默认即为null
        };

        _db.Galleries.Add(galleryObj);
        _db.SaveChanges();
        TempData["success"] = "Gallery创建成功";
        return RedirectToAction("Index");
    }
    return View(galleryVM);
}

2. 修复Edit方法

不要直接实例化新对象,先从数据库获取原始实体,仅更新需要修改的字段,并设置UpdatedAt:

[HttpPost]
[ValidateAntiForgeryToken]
public IActionResult Edit(GalleryVM galleryVM)
{
    if (!ModelState.IsValid)
    {
        return View(galleryVM);
    }

    var galleryObj = _db.Galleries.Find(galleryVM.Id);
    if (galleryObj == null)
    {
        return NotFound();
    }

    // 仅更新需要修改的字段
    galleryObj.Title = galleryVM.Title;
    galleryObj.IsPrivate = galleryVM.IsPrivate;
    galleryObj.AccessCode = galleryVM.AccessCode;
    galleryObj.UpdatedAt = DateTime.UtcNow; // 设置更新时间

    _db.SaveChanges();
    TempData["success"] = "Gallery更新成功";
    return RedirectToAction("Index");
}

方案二:EF Core自动处理(优雅持久化方案)

通过重写DbContext的SaveChanges方法,自动维护时间字段,避免在每个Controller中重复编写代码:

1. 在DbContext中添加时间戳处理逻辑

public class YourDbContext : DbContext
{
    // 构造函数和DbSet定义...

    public override int SaveChanges(bool acceptAllChangesOnSuccess)
    {
        UpdateEntityTimestamps();
        return base.SaveChanges(acceptAllChangesOnSuccess);
    }

    public override Task<int> SaveChangesAsync(bool acceptAllChangesOnSuccess, CancellationToken cancellationToken = default)
    {
        UpdateEntityTimestamps();
        return base.SaveChangesAsync(acceptAllChangesOnSuccess, cancellationToken);
    }

    private void UpdateEntityTimestamps()
    {
        // 跟踪所有新增或修改的Gallery实体
        var entries = ChangeTracker.Entries<Gallery>()
            .Where(e => e.State == EntityState.Added || e.State == EntityState.Modified);

        foreach (var entry in entries)
        {
            if (entry.State == EntityState.Added)
            {
                // 创建时设置CreatedAt,UpdatedAt设为null
                entry.Entity.CreatedAt = DateTime.UtcNow;
                entry.Entity.UpdatedAt = null;
            }
            else if (entry.State == EntityState.Modified)
            {
                // 更新时仅设置UpdatedAt,禁止修改CreatedAt
                entry.Entity.UpdatedAt = DateTime.UtcNow;
                entry.Property(e => e.CreatedAt).IsModified = false;
            }
        }
    }
}

2. 简化Controller代码

此时Create和Edit方法无需手动设置时间字段:

  • Create方法只需映射VM到实体并添加,无需处理时间
  • Edit方法只需获取原始实体、更新字段后保存,无需处理时间

额外建议

  • 确保实体类Gallery的CreatedAt字段在数据库中配置为不可为空,避免出现NULL值
  • 如果希望创建时UpdatedAt也自动赋值为当前时间,可以移除Added分支中的UpdatedAt = null语句

内容的提问来源于stack exchange,提问作者user18776105

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.18 22:42:06