EntityFrameworkCore教程:更新時間映射


一、時間字段

在真實的開發中,為了跟蹤數據的變化,一般會在數據表里面有CreatedTime和UpdatedTime兩列。CreatedTime表示創建時間,新增一條數據的時候,會更新CreatedTime列的值。UpdatedTime表示更新時間,更新數據的同時也會更新UpdatedTime列的值,這時候就需要對應的映射來配置。我們修改Blog類,增加這兩個時間字段:

using System;

namespace EFCore.Model
{
    public  class Blog
    {
        public int Id { get; set; }
        public string Name { get; set; }

        /// <summary>
        /// 創建時間
        /// </summary>
        public DateTime CreatedTime { get; set; }

        /// <summary>
        /// 添加時間
        /// </summary>
        public DateTime UpdatedTime { get; set; }
    }
}

這時不做任何配置,使用遷移的方式生成數據庫,查看數據庫表結構:

可以看到數據庫里面生成的是datetime2類型的,datetime2的精度非常高。但是一般情況下不使用datetime2高精度的,使用datetime就可以了,這時候就需要我們自己做映射來配置生成datetime類型。

修改數據上下文類,增加時間字段的映射配置,代碼如下:

using EFCore.Model;
using Microsoft.EntityFrameworkCore;

namespace EFCore.Data
{
    /// <summary>
    /// 數據上下文
    /// </summary>
    public class EFDbContext : DbContext
    {
        protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
        {
            optionsBuilder.UseSqlServer("Data Source=.;Initial Catalog=EFTest;User ID=sa;Password=123456;");
        }

        public DbSet<Blog> Blogs { get; set; }

        /// <summary>
        /// 重寫OnModelCreating方法,配置映射
        /// </summary>
        /// <param name="modelBuilder"></param>
        protected override void OnModelCreating(ModelBuilder modelBuilder)
        {
            // 配置表名映射
            modelBuilder.Entity<Blog>().ToTable("Blog");
            // 將表名長度設置為250會報錯,表名最大長度限制為128
            //var tableName = string.Join("", Enumerable.Repeat("t", 250).ToArray());
            //modelBuilder.Entity<Blog>().ToTable(tableName);

            modelBuilder.Entity<Blog>(p =>
            {
                // 配置CreatedTime字段
                p.Property(t => t.CreatedTime)
                // 設置列的類型是DATETIME
                 .HasColumnType("DATETIME")
                 // 設置列的默認值
                 .HasDefaultValueSql("GETDATE()");

                // 配置UpdatedTime字段
                p.Property(t => t.UpdatedTime)
                // 設置列的類型是DATETIME
                .HasColumnType("DATETIME")
                // 設置列的默認值
                .HasDefaultValueSql("GETDATE()");
            });

            base.OnModelCreating(modelBuilder);
        }

    }
}

在使用數據遷移的方式生成數據庫表,然后查看列的數據類型:

這時候時間列的數據類型就是datetime類型了。在代碼里面給時間字段設置了默認值,我們添加一條種子數據,然后新增到數據庫,看看會不會自動生成默認值:

從截圖中可以看出:新增數據的時候,CreatedTime和UpdatedTime會自動賦當前時間的值。在修改剛才添加的種子數據,看看UdpatedTime列的值會不會更新:

可以看到:Name列的值已經發生修改,但是UpdatedTime列的值卻沒有更新。但是我們想要的效果是數據更新的時候,UpdatedTime列的值也隨之更新,該怎么辦呢?有兩種方式解決這個問題。

1、使用計算列

這種方式是對UpdatedTime字段設置使用計算列,代碼如下:

using EFCore.Model;
using Microsoft.EntityFrameworkCore;

namespace EFCore.Data
{
    /// <summary>
    /// 數據上下文
    /// </summary>
    public class EFDbContext : DbContext
    {
        protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
        {
            optionsBuilder.UseSqlServer("Data Source=.;Initial Catalog=EFTest;User ID=sa;Password=123456;");
        }

        public DbSet<Blog> Blogs { get; set; }

        /// <summary>
        /// 重寫OnModelCreating方法,配置映射
        /// </summary>
        /// <param name="modelBuilder"></param>
        protected override void OnModelCreating(ModelBuilder modelBuilder)
        {
            // 配置表名映射
            modelBuilder.Entity<Blog>().ToTable("Blog");
            // 將表名長度設置為250會報錯,表名最大長度限制為128
            //var tableName = string.Join("", Enumerable.Repeat("t", 250).ToArray());
            //modelBuilder.Entity<Blog>().ToTable(tableName);

            modelBuilder.Entity<Blog>(p =>
            {
                // 配置CreatedTime字段
                p.Property(t => t.CreatedTime)
                // 設置列的類型是DATETIME
                 .HasColumnType("DATETIME")
                 // 設置列的默認值
                 .HasDefaultValueSql("GETDATE()");

                //// 配置UpdatedTime字段
                //p.Property(t => t.UpdatedTime)
                //// 設置列的類型是DATETIME
                //.HasColumnType("DATETIME")
                //// 設置列的默認值
                //.HasDefaultValueSql("GETDATE()");

                // 配置UpdatedTime字段
                p.Property(t => t.UpdatedTime)
                // 設置列的類型是DATETIME
                .HasColumnType("DATETIME")
                // 設置UpdatedTime字段使用計算列
                .HasComputedColumnSql("GETDATE()");
            });

            // 添加一條種子數據
            modelBuilder.Entity<Blog>().HasData(
                new Blog() 
                {
                    Id=1,
                  Name="ef core 3.1.2"
                });
            base.OnModelCreating(modelBuilder);
        }

    }
}

然后刪除數據庫,從新開始生成數據庫、新增數據、修改數據這三步,我們先看新增數據后的結果:

可以看到,CreatedTime和UpdatedTime這時會有誤差,但是誤差是秒以內可以接受的。我們在看修改后的結果:

這時就會發現:UpdatedTime列的值就會發生改變了。也會發現,UpdatedTime列的數據類型是計算:

2、重寫SaveChanges方法

還有一種方式是重寫SaveChanges()方法。

我們首先在實體類庫里面定義一個IUpdatedable接口:

using System;

namespace EFCore.Model
{
    public  interface IUpdatedable
    {
        DateTime UpdatedTime { get; set; }
    }
}

然后Blog類繼承自這個接口:

using System;

namespace EFCore.Model
{
    public  class Blog:IUpdatedable
    {
        public int Id { get; set; }
        public string Name { get; set; }

        /// <summary>
        /// 創建時間
        /// </summary>
        public DateTime CreatedTime { get; set; }

        /// <summary>
        /// 添加時間
        /// </summary>
        public DateTime UpdatedTime { get; set; }
    }
}

然后在數據上下文類里面重寫SaveChanges方法:

public override int SaveChanges()
{
    var entries = ChangeTracker.Entries().ToList();
    var updateEntries = entries.Where(e => (e.Entity is IUpdatedable)
    && e.State == EntityState.Modified).ToList();

    updateEntries.ForEach(e => 
    {
        ((IUpdatedable)e.Entity).UpdatedTime = DateTime.Now;
    });
    return base.SaveChanges();
}

同時修改UpdatedTime字段不是計算列,賦默認值:

// 配置UpdatedTime字段
p.Property(t => t.UpdatedTime)
// 設置列的類型是DATETIME
.HasColumnType("DATETIME")
// 設置列的默認值
.HasDefaultValueSql("GETDATE()");

這種方式就不能使用數據遷移了,要在代碼里面調用SaveChanges方法才可以實現:

using EFCore.Data;
using EFCore.Model;
using System;

namespace EFCore.Con
{
    class Program
    {
        static void Main(string[] args)
        {
            Console.WriteLine("Hello World!");
            // 實例化數據上下文對象
            EFDbContext dbContext = new EFDbContext();
            // 生成數據庫
            bool tfTrue = dbContext.Database.EnsureCreated();
            if (tfTrue)
            {
                Console.WriteLine("數據庫創建成功!");
            }
            else
            {
                Console.WriteLine("數據庫創建失敗!");
            }

            // 查詢Id為1的數據
            var blog = dbContext.Blogs.Find(1);
            // 更改表名稱
            blog.Name = "entity framework core 3.1.21212";
            dbContext.SaveChanges();
            Console.ReadKey();
        }
    }
}

數據庫效果:

這樣也完成了更新。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM