EntityFramework 6.x和EntityFramework Core插入數據探討


前言

一直以來對EF和EF Core都是單獨分開來寫,從未以比較的形式來講解,如果您既用過EF 6.x也用過用EF Core是否有了解過EF和EF Core在插入數據時和返回主鍵有何異同呢?本篇博客是坐在電腦旁本打算寫寫EF 6.x插入數據注意的問題,心想何不比較二者呢?我也是在探索中(邊敲代碼邊寫博客中),下面我們來看看。

EF 6.x和EF Core插入數據異同

            using (var ctx = new EfDbContext())
            {
                ctx.Database.Log = Console.WriteLine;
                var customer = new Customer()
                {
                    Email = "2752154844@qq.com",
                    Name = "Jeffcky",
                    Orders = new List<Order>()
                    {
                       new Order()
                       {
                           Code = "1",
                           CreatedTime = DateTime.Now,
                           ModifiedTime = DateTime.Now,
                           Quantity = 10,
                           Price =100
                       }
                    }
                };
            }

上述Customer和Order為一對多關系,Order實體中有Customer實體的外鍵,上述我們同時給Customer和Order賦了值,所以當我們插入Customer的同時Order表中也插入了數據,此時Order的CustomerId是Customer的主鍵,我們根本不需要為Order中的CustomerId顯式賦值,這一點毋庸置疑。我想說的是如果兩個表沒有很強的關聯關系,怎么說呢,換言之兩個表沒有配置所謂的關系又或許我們沒有配置關系,一個表中列需要用到另外一個表的主鍵,那么這種的情況下,我們會以怎樣的方式插入數據呢?實踐是檢驗真理的唯一標准,下面我們來試試。

    public class TestA
    {
        public int Id { get; set; }
        public string Other { get; set; }
    }

    public class TestB
    {
        public int Id { get; set; }
        public int TestAId { get; set; }
        public string Other { get; set; }
    }
        protected override void OnModelCreating(DbModelBuilder modelBuilder)
        {
            modelBuilder.Entity<TestA>()
                .ToTable("TestAs")
                .HasKey(p => p.Id)
                .Property(p => p.Other);

            modelBuilder.Entity<TestB>()
               .ToTable("TestBs")
               .HasKey(p => p.Id)
               .Property(p => p.Other);
        }

上述我們給出TestA和TestB,TestA和TestB沒有任何關系,但是我們在插入TestB數據時需要得到Test的主鍵,那我們下面就進行如下數據添加。

            using (var ctx = new EfDbContext())
            {
                ctx.Database.Log = Console.WriteLine;
                var testA = new TestA() { Other = "other" };
                ctx.TestAs.Add(testA);
                ctx.SaveChanges();
                var testB = new TestB() { Other = "other", TestAId = testA.Id };
                ctx.TestBs.Add(testB);
                ctx.SaveChanges();
            }

 

此時我們看到提交后數據最終能夠保存到數據庫中,反觀上述提交代碼,我們首先是提交了TestA保存到數據庫后然后拿到TestA的主鍵,然后再是提交TestB並保存到數據庫中。那我們有沒有考慮是否直接一次性提交呢,注釋TestA提交,如下:

            using (var ctx = new EfDbContext())
            {
                ctx.Database.Log = Console.WriteLine;
                var testA = new TestA() { Other = "other" };
                ctx.TestAs.Add(testA);
                //ctx.SaveChanges();
                var testB = new TestB() { Other = "other", TestAId = testA.Id };
                ctx.TestBs.Add(testB);
                ctx.SaveChanges();
            }

WOW不行啊,下面我們來看看在EF Core中實現是不是可以,試試就知道了,別猜測。

            modelBuilder.Entity<TestA>(e =>
            {
                e.ToTable("TestAs");
                e.HasKey(p => p.Id);
                e.Property(p => p.Other);
            });


            modelBuilder.Entity<TestB>(e =>
            {
                e.ToTable("TestBs");
                e.HasKey(p => p.Id);
                e.Property(p => p.Other);
            });
            using (var context = new EFCoreDbContext())
            {
                var testA = new TestA() { Other = "other" };
                context.TestAs.Add(testA);
                //ctx.SaveChanges();
                var testB = new TestB() { Other = "other", TestAId = testA.Id };
                context.TestBs.Add(testB);
                context.SaveChanges();
            }

如果分兩次提交那么無論是在EF 6.x還是EF Core中都是一樣沒有任何不同(在EF Core中沒有測試也不用測試)。如果是一次性提交,此時在EF 6.x中的TestB中的TestAId為插入的是0,而EF Core中的TestB中的TestAId為-2147482647即INT類型最小值,至少找到了不同所在。Jeff自問自答的模式要來了,是不是就這樣結束了呢?上述我們對TestA和TestB兩個實體未配置任何關系,我們經過測試證明一次性提交並未達到我們預期,要是我們依然在不配置關系的前提下給出導航屬性然后一次性提交呢,如下:

    public class TestA
    {
        public int Id { get; set; }
        public string Other { get; set; }
    }

    public class TestB
    {
        public int Id { get; set; }
        public int TestAId { get; set; }
        public string Other { get; set; }
        public TestA TestA { get; set; }
    }

接下來我們在EF Core控制台再次運行上述代碼看看,您思考下會不會將TestA中的主鍵添加進去呢。

 

如果您在EF 6.x中同樣添加上述導航屬性也是好使的,我就不測試了,那到此我們得出結論:若兩個實體未顯式配置任何關系但一個表需要得到另外一個表的主鍵,無論是在EF 6.x還是在EF Core中進行一次性提交不好使,只是在EF 6.x中一個表需要得到另外一個表的主鍵為0,而在EF Core中卻是INT類型最小值,若我們顯式配置了導航屬性,那么無論是在EF 6.x還是EF Core中一次性提交可達到我們預期。 

比較EF 6.x和EF Core插入數據返回主鍵

如果是主鍵為INT類型,默認情況無論是EF 6.x還是EF Core都將自動映射配置為自增長,要是我們顯式配置了主鍵,那么對於EF 6.x和EF Core會有何不同呢?我們首先看看EF 6.x,如下(我們清除之前已提交數據):

            using (var ctx = new EfDbContext())
            {
                ctx.Database.Log = Console.WriteLine;

                var testA = new TestA() { Id = 1, Other = "other" };
                ctx.TestAs.Add(testA);
                ctx.SaveChanges();
            }

 

從上述我們提交三次看出,壓根不叼我們設置的值,那么我們看看生成的SQL語句是怎樣的呢,如下圖:

這下我們明白了此時通過scope_identity返回為當前會話和當前作用域中的TestA表生成的最新標識值。接下來我們來看看EF Core。

            using (var context = new EFCoreDbContext())
            {
                var testA = new TestA() { Id = 1, Other = "other" };
                context.TestAs.Add(testA);
                context.SaveChanges();
            }

 當我們進行第二次提交后將拋出異常,如下:

我們同樣看看在EF Core中生成的SQL是怎樣的。

原來如此沒有返回當前會話自增長值,同時我們知道不能顯式插入值,那就是關閉了IDENTITY_Insert。所以我們得出結論:在以INT作為主鍵且自增長時,在EF 6.x中能夠顯式給出值,而在EF Core中不能顯式給定值即關閉了IDENTITY_INSERT不能顯式插入主鍵值。

總結

本節我們詳細敘述了EF 6.x和EF Core中插入數據和返回主鍵的不同之處,雖然作用不大,可以作為了解,最近比較累,可能會停更一小段時間,好好休息一下,書出版了會及時告知同行關注者。


免責聲明!

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



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