EntityFramework6学习总结6(导航属性-新增、事务的使用)

带有导航属性的字段(主外键关系),主子表同时插入数据,子表可以使用主表的ID。

表关系如下:新闻表外键(新闻类别ID)对应到新闻类别表主键。

实例:

                using (NewsDbContext dbContext = new NewsDbContext())
                {
                    //打印sql信息
                    dbContext.Database.Log += c => Console.WriteLine($"sql:{c}");

                    NewsClassify newsClassify = new NewsClassify()
                    {
                        Name = "娱乐新闻",
                        Sort = 4,
                        Remark = "快乐就完事了"
                    };

                    News news = new News()
                    {
                        NewsClassifyId = newsClassify.Id,
                        Title = "Angelababy扮部落首领保卫粮食",
                        Image = "/NewsPic/20200908174647.jpg",
                        Contents = "6月25日,Angelababy工作室曝光了一组baby在《奔跑吧》中的新造型,这次她扮演起部落首领保卫粮食,画面中,baby身穿草绿色流苏套装,腰间挂着织网,为配合衣着,baby还特意挑染了头发,戴上孔雀花纹耳环,一股自然的气息扑面而来。",
                        PublishDate = DateTime.Now,
                        Remark = "哈哈哈哈"
                    };

                    dbContext.Set<NewsClassify>().Add(newsClassify);
                    dbContext.Set<News>().Add(news);
                    dbContext.SaveChanges();
                }

查询结果:

上面实例可以说明,调用一次SaveChanges方法,如果两个表有主外键关系,可以使用自增的ID。

如果两张表没有主外键关系,其中一张表在新增数据时要使用另一张表的主键,如果仅调用一次SaveChanges方法是不能获取到的。

如下图所示,新闻类别表和日志表,Log表的OperateUserID字段值取NewsClassify表的ID。

实例:

                using (NewsDbContext dbContext = new NewsDbContext())
                {
                    //打印sql信息
                    dbContext.Database.Log += c => Console.WriteLine($"sql:{c}");

                    NewsClassify newsClassify = new NewsClassify()
                    {
                        Name = "教育新闻",
                        Sort = 5,
                        Remark = "教育新闻"
                    };

                    NewsLog newsLog = new NewsLog()
                    {
                        OperateDate=DateTime.Now,
                        OperateUserID= newsClassify.Id,
                        LogContent="新增了一条新闻类别数据"
                    };

                    dbContext.Set<NewsClassify>().Add(newsClassify);
                    dbContext.Set<NewsLog>().Add(newsLog);
                    dbContext.SaveChanges();
                }

执行结果: 

 

NewsClassify表出入了一条ID为6的数据,但是NewsLog表的OperateUserID字段为0,并没有取6。

如果要解决上面的问题,可以对两个表分别调用SaveChanges方法。

                using (NewsDbContext dbContext = new NewsDbContext())
                {
                    //打印sql信息
                    dbContext.Database.Log += c => Console.WriteLine($"sql:{c}");

                    NewsClassify newsClassify = new NewsClassify()
                    {
                        Name = "科技新闻",
                        Sort = 6,
                        Remark = "科技新闻"
                    };

                    dbContext.Set<NewsClassify>().Add(newsClassify);
                    dbContext.SaveChanges();

                    NewsLog newsLog = new NewsLog()
                    {
                        OperateDate = DateTime.Now,
                        OperateUserID = newsClassify.Id,
                        LogContent = "新增了一条新闻类别数据-科技新闻"
                    };
                   
                    dbContext.Set<NewsLog>().Add(newsLog);
                    dbContext.SaveChanges();
                }

执行结果: 

 

这样就可以保证NewsLog的OperateUserID等于新增的NewsClassify的ID。

不过上面的方式存在一个问题,无法保证两个操作在同一个事务中,因为调用一次SaveChanges方法就会开启一个事务。

下面引入事务,首先引用一个程序集System.Transactions

实例: 

                using (NewsDbContext dbContext = new NewsDbContext())
                {
                    using (TransactionScope transaction = new TransactionScope())
                    {
                        //打印sql信息
                        dbContext.Database.Log += c => Console.WriteLine($"sql:{c}");

                        NewsClassify newsClassify = new NewsClassify()
                        {
                            Name = "科技新闻",
                            Sort = 6,
                            Remark = "科技新闻"
                        };

                        dbContext.Set<NewsClassify>().Add(newsClassify);
                        dbContext.SaveChanges();

                        NewsLog newsLog = new NewsLog()
                        {
                            OperateDate = DateTime.Now,
                            OperateUserID = newsClassify.Id,
                            LogContent = "新增了一条新闻类别数据-科技新闻"
                        };

                        dbContext.Set<NewsLog>().Add(newsLog);
                        dbContext.SaveChanges();

                        transaction.Complete();//提交事务
                    }
                }

 执行结果: 

TransactionScope不仅可以对同一个DbContext的多次SaveChanges提供事务。还可以对不同DbContext提供事务,实例如下:

                using (NewsDbContext dbContext = new NewsDbContext())
                using (NewsDbContext dbContext1 = new NewsDbContext())
                {
                    using (TransactionScope transaction = new TransactionScope())
                    {
                        //打印sql信息
                        dbContext.Database.Log += c => Console.WriteLine($"sql:{c}");
                        dbContext1.Database.Log += c => Console.WriteLine($"sql:{c}");

                        NewsClassify newsClassify = new NewsClassify()
                        {
                            Name = "交通新闻",
                            Sort = 8,
                            Remark = "交通新闻"
                        };

                        dbContext.Set<NewsClassify>().Add(newsClassify);
                        dbContext.SaveChanges();

                        NewsLog newsLog = new NewsLog()
                        {
                            OperateDate = DateTime.Now,
                            OperateUserID = newsClassify.Id,
                            LogContent = "新增了一条新闻类别数据-交通新闻"
                        };

                        dbContext1.Set<NewsLog>().Add(newsLog);
                        dbContext1.SaveChanges();

                        transaction.Complete();//提交事物
                    }
                }

 执行结果: 

上面的实例中开启了两个DbContext,dbContext和dbContext1。其中dbContext对NewsClassify表做操作,dbContext1对NewsLog表做操作。

然后调用transaction.Complete()对两个DbContext的修改提交到数据库中。

EF中也可以使用DbContextTransaction开启一个事物,实例如下:

        public static void Show()
        {
            using (NewsDbContext dbContext = new NewsDbContext())
            {
                //打印sql信息
                dbContext.Database.Log += c => Console.WriteLine($"sql:{c}");
 
                {
                    DbContextTransaction trans = null;
                    try
                    {
                        trans = dbContext.Database.BeginTransaction();//开启事物
                        string sql = "SELECT * FROM News where Id=@Id";
                        SqlParameter parameter = new SqlParameter("@Id", 2);
                        List<News> newList = dbContext.Database.SqlQuery<News>(sql, parameter).ToList();
                        trans.Commit();//提交事物
 
                        foreach (var item in newList)
                        {
                            Console.WriteLine(item.Title);
                        }
                    }
                    catch (Exception ex)
                    {
                        if (trans != null)
                        {
                            trans.Rollback();
                        }
                        throw ex;
                    }
                    finally
                    {
                        trans.Dispose();
                    }
                }
 
            }
        }

 执行结果:  

 总结:

1.如果两个表有主外键关系,调用一次SaveChanges方法,可以使用自增的ID。

2.如果两个表没有主外键关系,调用一次SaveChanges方法,则不可以使用自增的ID。

3.一次SaveChanges方法为一个事务。

4.如果要使多个SaveChanges方法在一个事务中,可以使用TransactionScope手动开启一个事务,此方法开启事务的级别高于SaveChanges的事务。所以即使某个SaveChanges成功了,但是有任一SaveChanges失败,则成功的SaveChanges也不会更新到数据库中。只有调用了TransactionScope.Complete()才会把所有SaveChanges的更改保存到数据库中。

5.TransactionScope可以完成一个DbContext的多次SaveChanges。

6.TransactionScope可以完成不同DbContext的事务。

7.EF中也可以使用DbContextTransaction开启事物。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值