你的位置:首页 > ASP.net教程

[ASP.net教程]EntityFramework监控sql和EntityFramework中的事务


继续上篇:EntityFramework和EntityFramework.Extended使用说明——性能,语法和产生的sql

1.监控sql

上篇中的sql监控采用的是 Microsoft SQL Server Management Studio中工具->profiler去监控的.
当然,Express版本是没有此功能的.
如果您使用不了profiler或者觉得不方便,那么,给出监控sql的第二方案.

找到的资料是英文的,还好,容易理解.
原文链接:https://blog.oneunicorn.com/2013/05/08/ef6-sql-logging-part-1-simple-logging/

a.控制台打印

var db = new PhoneBookEntities();//以后的db都是指它db.Database.Log = Console.Write;//打印sql语句db.Database.ExecuteSqlCommand("update GroupInfo set GroupName='hello' where GroupId=220");//此语句不用db.SaveChanges();一样生效

监控结果:

已于 2016/6/21 星期二 10:30:23 +08:00 打开了连接已于 2016/6/21 星期二 10:30:23 +08:00 启动了事务update GroupInfo set GroupName='hi' where GroupId=220-- 正在 2016/6/21 星期二 10:30:23 +08:00 执行-- 已在 1 毫秒内完成,结果为: 1已于 2016/6/21 星期二 10:30:23 +08:00 提交了事务已于 2016/6/21 星期二 10:30:23 +08:00 关闭了连接

b.记录sql到文件

如果控制台打印不能满足您的需求,也可以记录到文件里.
方法:

 var db = new PhoneBookEntities(); db.Database.Log = s => LogHelper.Write(s);//调用LogHelper类的方法 db.Database.ExecuteSqlCommand("update GroupInfo set GroupName='hello' where GroupId=220");//此语句不用db.SaveChanges();一样生效

LogHelper.cs

  public class LogHelper  {    public static void Write(string str)    {      var path = Path.Combine(new DirectoryInfo(AppDomain.CurrentDomain.BaseDirectory).Parent.Parent.FullName, "logs.txt");      string errmsg = string.Format("{0}", str);      System.IO.File.AppendAllText(path, errmsg);    }  }

就是这么简单!

2.EF中的事务

上面例子看到产生的sql监控记录,
db.Database.ExecuteSqlCommand("update GroupInfo set GroupName='hello' where GroupId=220");
此语句执行启动了事务.

测试研究一下怎么回事.
以下两句:
db.Database.ExecuteSqlCommand("update GroupInfo set GroupName='hi' where GroupId=209");
db.Database.ExecuteSqlCommand("update GroupInfo set GroupName='hello' where GroupId=220");
经监控,分别启动并提交了两次事务.(如果sql命令为insert,delete也是同样道理)

怎么把这两个sql语句放到一个事务里呢?别急,最后再说明.

先看看最熟悉的db.SaveChanges()语句:以下语句本身没有实际意义,为了测试而写.

var gi = db.GroupInfo.FirstOrDefault(c => c.GroupName.Contains("g1!"));var ci = db.ContactInfo.FirstOrDefault(c => c.ID == 12);ci.ContactName += "!";gi.GroupName += "!";db.SaveChanges();ci.ContactName += "!";gi.GroupName += "!";db.SaveChanges();

监控产生的sql:

已于 2016/6/21 星期二 11:06:52 +08:00 打开了连接SELECT TOP (1)   [Extent1].[GroupId] AS [GroupId],   [Extent1].[GroupName] AS [GroupName]  FROM [dbo].[GroupInfo] AS [Extent1]  WHERE [Extent1].[GroupName] LIKE N'%g1!%'-- 正在 2016/6/21 星期二 11:06:52 +08:00 执行-- 已在 1 毫秒内完成,结果为: SqlDataReader已于 2016/6/21 星期二 11:06:52 +08:00 关闭了连接已于 2016/6/21 星期二 11:06:52 +08:00 打开了连接SELECT TOP (1)   [Extent1].[ID] AS [ID],   [Extent1].[ContactId] AS [ContactId],   [Extent1].[IsDelete] AS [IsDelete],   [Extent1].[Account] AS [Account],   [Extent1].[ContactName] AS [ContactName],   [Extent1].[CommonMobile] AS [CommonMobile],   [Extent1].[HeadPortrait] AS [HeadPortrait],   [Extent1].[AttFile] AS [AttFile],   [Extent1].[GroupId] AS [GroupId]  FROM [dbo].[ContactInfo] AS [Extent1]  WHERE 12 = [Extent1].[ID]-- 正在 2016/6/21 星期二 11:06:52 +08:00 执行-- 已在 1 毫秒内完成,结果为: SqlDataReader已于 2016/6/21 星期二 11:06:52 +08:00 关闭了连接已于 2016/6/21 星期二 11:06:52 +08:00 打开了连接已于 2016/6/21 星期二 11:06:52 +08:00 启动了事务UPDATE [dbo].[ContactInfo]SET [ContactName] = @0WHERE ([ID] = @1)-- @0: '李四1!!!!!!!' (Type = String, Size = 50)-- @1: '12' (Type = Int32)-- 正在 2016/6/21 星期二 11:06:52 +08:00 执行-- 已在 1 毫秒内完成,结果为: 1UPDATE [dbo].[GroupInfo]SET [GroupName] = @0WHERE ([GroupId] = @1)-- @0: 'g1!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!' (Type = String, Size = 300)-- @1: '216' (Type = Int32)-- 正在 2016/6/21 星期二 11:06:52 +08:00 执行-- 已在 0 毫秒内完成,结果为: 1已于 2016/6/21 星期二 11:06:52 +08:00 提交了事务已于 2016/6/21 星期二 11:06:52 +08:00 关闭了连接已于 2016/6/21 星期二 11:06:52 +08:00 打开了连接已于 2016/6/21 星期二 11:06:52 +08:00 启动了事务UPDATE [dbo].[ContactInfo]SET [ContactName] = @0WHERE ([ID] = @1)-- @0: '李四1!!!!!!!!' (Type = String, Size = 50)-- @1: '12' (Type = Int32)-- 正在 2016/6/21 星期二 11:06:52 +08:00 执行-- 已在 0 毫秒内完成,结果为: 1UPDATE [dbo].[GroupInfo]SET [GroupName] = @0WHERE ([GroupId] = @1)-- @0: 'g1!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!' (Type = String, Size = 300)-- @1: '216' (Type = Int32)-- 正在 2016/6/21 星期二 11:06:52 +08:00 执行-- 已在 0 毫秒内完成,结果为: 1已于 2016/6/21 星期二 11:06:52 +08:00 提交了事务已于 2016/6/21 星期二 11:06:52 +08:00 关闭了连接

监控记录

每次db.SaveChanges()会默认开启事务,执行sql语句,提交事务.多看看,好好理解一下.

 

如何把两个db.SaveChanges()放到一个事务里呢?

写法:

  var gi = db.GroupInfo.FirstOrDefault(c => c.GroupName.Contains("g1!"));  var ci = db.ContactInfo.FirstOrDefault(c => c.ID == 12);  using (var tx = db.Database.BeginTransaction())  {  try  {    ci.ContactName += "!";    gi.GroupName += "!";    //db.SaveChanges();//这个语句影响到事务中sql的数量,有此语句事务里4条sql,没有就是2条.对于此案例,不影响结果.    ci.ContactName += "!";    gi.GroupName += "!";    db.SaveChanges();//必须要有    tx.Commit();//此语句不要漏了,否则监控结果会是释放了事务,而不是提交了事务!  }  catch (Exception)  {    tx.Rollback();  }  }

监控产生的sql:

[没有第一个db.SaveChanges()]

已于 2016/6/21 星期二 11:20:49 +08:00 打开了连接SELECT TOP (1)   [Extent1].[GroupId] AS [GroupId],   [Extent1].[GroupName] AS [GroupName]  FROM [dbo].[GroupInfo] AS [Extent1]  WHERE [Extent1].[GroupName] LIKE N'%g1!%'-- 正在 2016/6/21 星期二 11:20:49 +08:00 执行-- 已在 0 毫秒内完成,结果为: SqlDataReader已于 2016/6/21 星期二 11:20:49 +08:00 关闭了连接已于 2016/6/21 星期二 11:20:49 +08:00 打开了连接SELECT TOP (1)   [Extent1].[ID] AS [ID],   [Extent1].[ContactId] AS [ContactId],   [Extent1].[IsDelete] AS [IsDelete],   [Extent1].[Account] AS [Account],   [Extent1].[ContactName] AS [ContactName],   [Extent1].[CommonMobile] AS [CommonMobile],   [Extent1].[HeadPortrait] AS [HeadPortrait],   [Extent1].[AttFile] AS [AttFile],   [Extent1].[GroupId] AS [GroupId]  FROM [dbo].[ContactInfo] AS [Extent1]  WHERE 12 = [Extent1].[ID]-- 正在 2016/6/21 星期二 11:20:49 +08:00 执行-- 已在 0 毫秒内完成,结果为: SqlDataReader已于 2016/6/21 星期二 11:20:49 +08:00 关闭了连接已于 2016/6/21 星期二 11:20:49 +08:00 打开了连接已于 2016/6/21 星期二 11:20:49 +08:00 启动了事务UPDATE [dbo].[ContactInfo]SET [ContactName] = @0WHERE ([ID] = @1)-- @0: '李四1!!' (Type = String, Size = 50)-- @1: '12' (Type = Int32)-- 正在 2016/6/21 星期二 11:20:49 +08:00 执行-- 已在 1 毫秒内完成,结果为: 1UPDATE [dbo].[GroupInfo]SET [GroupName] = @0WHERE ([GroupId] = @1)-- @0: 'g1!!!' (Type = String, Size = 300)-- @1: '222' (Type = Int32)-- 正在 2016/6/21 星期二 11:20:49 +08:00 执行-- 已在 0 毫秒内完成,结果为: 1已于 2016/6/21 星期二 11:20:49 +08:00 提交了事务已于 2016/6/21 星期二 11:20:49 +08:00 关闭了连接

监控记录

[有第一个db.SaveChanges()]

已于 2016/6/21 星期二 11:21:49 +08:00 打开了连接SELECT TOP (1)   [Extent1].[GroupId] AS [GroupId],   [Extent1].[GroupName] AS [GroupName]  FROM [dbo].[GroupInfo] AS [Extent1]  WHERE [Extent1].[GroupName] LIKE N'%g1!%'-- 正在 2016/6/21 星期二 11:21:49 +08:00 执行-- 已在 1 毫秒内完成,结果为: SqlDataReader已于 2016/6/21 星期二 11:21:49 +08:00 关闭了连接已于 2016/6/21 星期二 11:21:49 +08:00 打开了连接SELECT TOP (1)   [Extent1].[ID] AS [ID],   [Extent1].[ContactId] AS [ContactId],   [Extent1].[IsDelete] AS [IsDelete],   [Extent1].[Account] AS [Account],   [Extent1].[ContactName] AS [ContactName],   [Extent1].[CommonMobile] AS [CommonMobile],   [Extent1].[HeadPortrait] AS [HeadPortrait],   [Extent1].[AttFile] AS [AttFile],   [Extent1].[GroupId] AS [GroupId]  FROM [dbo].[ContactInfo] AS [Extent1]  WHERE 12 = [Extent1].[ID]-- 正在 2016/6/21 星期二 11:21:49 +08:00 执行-- 已在 0 毫秒内完成,结果为: SqlDataReader已于 2016/6/21 星期二 11:21:49 +08:00 关闭了连接已于 2016/6/21 星期二 11:21:49 +08:00 打开了连接已于 2016/6/21 星期二 11:21:49 +08:00 启动了事务UPDATE [dbo].[ContactInfo]SET [ContactName] = @0WHERE ([ID] = @1)-- @0: '李四1!' (Type = String, Size = 50)-- @1: '12' (Type = Int32)-- 正在 2016/6/21 星期二 11:21:49 +08:00 执行-- 已在 1 毫秒内完成,结果为: 1UPDATE [dbo].[GroupInfo]SET [GroupName] = @0WHERE ([GroupId] = @1)-- @0: 'g1!!' (Type = String, Size = 300)-- @1: '222' (Type = Int32)-- 正在 2016/6/21 星期二 11:21:49 +08:00 执行-- 已在 1 毫秒内完成,结果为: 1UPDATE [dbo].[ContactInfo]SET [ContactName] = @0WHERE ([ID] = @1)-- @0: '李四1!!' (Type = String, Size = 50)-- @1: '12' (Type = Int32)-- 正在 2016/6/21 星期二 11:21:49 +08:00 执行-- 已在 0 毫秒内完成,结果为: 1UPDATE [dbo].[GroupInfo]SET [GroupName] = @0WHERE ([GroupId] = @1)-- @0: 'g1!!!' (Type = String, Size = 300)-- @1: '222' (Type = Int32)-- 正在 2016/6/21 星期二 11:21:49 +08:00 执行-- 已在 0 毫秒内完成,结果为: 1已于 2016/6/21 星期二 11:21:49 +08:00 提交了事务已于 2016/6/21 星期二 11:21:49 +08:00 关闭了连接

监控记录

解决最初的问题:

  var gi = db.GroupInfo.FirstOrDefault(c => c.GroupName.Contains("g1!"));  var ci = db.ContactInfo.FirstOrDefault(c => c.ID == 12);  ci.ContactName += "!";//  gi.GroupName += "!"; //这两句放到了using外面,也是可以的  using (var tx = db.Database.BeginTransaction())  {    try    {      db.Database.ExecuteSqlCommand("update GroupInfo set GroupName='hello' where GroupId=209");      db.SaveChanges();//这个语句      tx.Commit();//此语句不要漏了,否则监控结果会是释放了事务,而不是提交了事务!    }    catch (Exception)    {      tx.Rollback();    }  }

监控记录:

已于 2016/6/21 星期二 11:28:28 +08:00 打开了连接SELECT TOP (1)   [Extent1].[GroupId] AS [GroupId],   [Extent1].[GroupName] AS [GroupName]  FROM [dbo].[GroupInfo] AS [Extent1]  WHERE [Extent1].[GroupName] LIKE N'%g1!%'-- 正在 2016/6/21 星期二 11:28:28 +08:00 执行-- 已在 1 毫秒内完成,结果为: SqlDataReader已于 2016/6/21 星期二 11:28:28 +08:00 关闭了连接已于 2016/6/21 星期二 11:28:28 +08:00 打开了连接SELECT TOP (1)   [Extent1].[ID] AS [ID],   [Extent1].[ContactId] AS [ContactId],   [Extent1].[IsDelete] AS [IsDelete],   [Extent1].[Account] AS [Account],   [Extent1].[ContactName] AS [ContactName],   [Extent1].[CommonMobile] AS [CommonMobile],   [Extent1].[HeadPortrait] AS [HeadPortrait],   [Extent1].[AttFile] AS [AttFile],   [Extent1].[GroupId] AS [GroupId]  FROM [dbo].[ContactInfo] AS [Extent1]  WHERE 12 = [Extent1].[ID]-- 正在 2016/6/21 星期二 11:28:28 +08:00 执行-- 已在 1 毫秒内完成,结果为: SqlDataReader已于 2016/6/21 星期二 11:28:28 +08:00 关闭了连接已于 2016/6/21 星期二 11:28:28 +08:00 打开了连接已于 2016/6/21 星期二 11:28:28 +08:00 启动了事务 update GroupInfo set GroupName='hello' where GroupId=209-- 正在 2016/6/21 星期二 11:28:28 +08:00 执行-- 已在 1 毫秒内完成,结果为: 1UPDATE [dbo].[ContactInfo]SET [ContactName] = @0WHERE ([ID] = @1)-- @0: '李四1!!!!!' (Type = String, Size = 50)-- @1: '12' (Type = Int32)-- 正在 2016/6/21 星期二 11:28:28 +08:00 执行-- 已在 1 毫秒内完成,结果为: 1UPDATE [dbo].[GroupInfo]SET [GroupName] = @0WHERE ([GroupId] = @1)-- @0: 'g1!!!!!!' (Type = String, Size = 300)-- @1: '222' (Type = Int32)-- 正在 2016/6/21 星期二 11:28:28 +08:00 执行-- 已在 1 毫秒内完成,结果为: 1已于 2016/6/21 星期二 11:28:28 +08:00 提交了事务已于 2016/6/21 星期二 11:28:28 +08:00 关闭了连接

监控记录

事务部分,我参考的网址:https://msdn.microsoft.com/zh-cn/magazine/dn532202.aspx

 

解释: Name += "!";这么写而不是 Name="李四"; 是为了防止EF的自动优化sql.

over...