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显式赋值,这一点毋庸置疑。我想说的是若是两个表没有很强的关联关系,怎么说呢,换言之两个表没有配置所谓的关系又或许咱们没有配置关系,一个表中列须要用到另一个表的主键,那么这种的状况下,咱们会以怎样的方式插入数据呢?实践是检验真理的惟一标准,下面咱们来试试。ide

    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提交,以下:ui

            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中实现是否是能够,试试就知道了,别猜想。spa

            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两个实体未配置任何关系,咱们通过测试证实一次性提交并未达到咱们预期,要是咱们依然在不配置关系的前提下给出导航属性而后一次性提交呢,以下:code

    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中的主键添加进去呢。blog

 

若是您在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,以下(咱们清除以前已提交数据):get

            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中插入数据和返回主键的不一样之处,虽然做用不大,能够做为了解,最近比较累,可能会停更一小段时间,好好休息一下,书出版了会及时告知同行关注者。

相关文章
相关标签/搜索