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] = @0
WHERE ([ID] = @1)
-- @0: ‘李四1!!!!!!!‘ (Type = String, Size = 50)
-- @1: ‘12‘ (Type = Int32)
-- 正在 2016/6/21 星期二 11:06:52 +08:00
 执行-- 已在 1 毫秒内完成,结果为: 1

UPDATE [dbo].[GroupInfo]
SET [GroupName] = @0
WHERE ([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] = @0
WHERE ([ID] = @1)
-- @0: ‘李四1!!!!!!!!‘ (Type = String, Size = 50)
-- @1: ‘12‘ (Type = Int32)
-- 正在 2016/6/21 星期二 11:06:52 +08:00
 执行-- 已在 0 毫秒内完成,结果为: 1

UPDATE [dbo].[GroupInfo]
SET [GroupName] = @0
WHERE ([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] = @0
WHERE ([ID] = @1)
-- @0: ‘李四1!!‘ (Type = String, Size = 50)
-- @1: ‘12‘ (Type = Int32)
-- 正在 2016/6/21 星期二 11:20:49 +08:00
 执行-- 已在 1 毫秒内完成,结果为: 1

UPDATE [dbo].[GroupInfo]
SET [GroupName] = @0
WHERE ([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] = @0
WHERE ([ID] = @1)
-- @0: ‘李四1!‘ (Type = String, Size = 50)
-- @1: ‘12‘ (Type = Int32)
-- 正在 2016/6/21 星期二 11:21:49 +08:00
 执行-- 已在 1 毫秒内完成,结果为: 1

UPDATE [dbo].[GroupInfo]
SET [GroupName] = @0
WHERE ([GroupId] = @1)
-- @0: ‘g1!!‘ (Type = String, Size = 300)
-- @1: ‘222‘ (Type = Int32)
-- 正在 2016/6/21 星期二 11:21:49 +08:00
 执行-- 已在 1 毫秒内完成,结果为: 1

UPDATE [dbo].[ContactInfo]
SET [ContactName] = @0
WHERE ([ID] = @1)
-- @0: ‘李四1!!‘ (Type = String, Size = 50)
-- @1: ‘12‘ (Type = Int32)
-- 正在 2016/6/21 星期二 11:21:49 +08:00
 执行-- 已在 0 毫秒内完成,结果为: 1

UPDATE [dbo].[GroupInfo]
SET [GroupName] = @0
WHERE ([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 毫秒内完成,结果为: 1

UPDATE [dbo].[ContactInfo]
SET [ContactName] = @0
WHERE ([ID] = @1)
-- @0: ‘李四1!!!!!‘ (Type = String, Size = 50)
-- @1: ‘12‘ (Type = Int32)
-- 正在 2016/6/21 星期二 11:28:28 +08:00
 执行-- 已在 1 毫秒内完成,结果为: 1

UPDATE [dbo].[GroupInfo]
SET [GroupName] = @0
WHERE ([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...

时间: 2024-10-28 11:20:12

EntityFramework监控sql和EntityFramework中的事务的相关文章

SQL Server存储过程中使用事务

今天修改之前一个同事写的代码,发现方法中直接执行了两个sql语句,一个是删除用户,一个是删除该用户的权限.由于数据库数据比较多,导致有时候这个两个sql不能都执行成功,数据库出现了脏数据. 鉴于这个原因,我把两个sql放到了一个存储过程中执行,在存储过程中添加事务,使其要么都执行,要么都不执行. 代码框架如下: 1 CREATE PROCEDURE pro_TrancDemo @backvalue INT OUTPUT 2 AS 3 BEGIN 4 SET NOCOUNT ON; 5 6 BEG

SQL SERVER存储过程中使用事务与捕获异常

https://www.douban.com/note/559596669/ 格式类似于 CREATE PROCEDURE YourProcedure ASBEGIN    SET NOCOUNT ON; BEGIN TRY---------------------开始捕捉异常       BEIN TRAN------------------开始事务        UPDATE A SET A.names = B.names FROM 表1 AS A INNER JOIN 表2 AS B ON

SQL Server 中的事务与事务隔离级别以及如何理解脏读, 未提交读,不可重复读和幻读产生的过程和原因

原本打算写有关 SSIS Package 中的事务控制过程的,但是发现很多基本的概念还是需要有 SQL Server 事务和事务的隔离级别做基础铺垫.所以花了点时间,把 SQL Server 数据库中的事务概念,ACID 原则,事务中常见的问题,问题造成的原因和事务隔离级别等这些方面的知识好好的整理了一下. 其实有关 SQL Server 中的事务,说实话因为内容太多, 话题太广,稍微力度控制不好就超过了我目前知识能力范围,就不是三言两语能够讲清楚的.所以希望大家能够指出其中总结的不足之处,对我

一、存储过程中使用事务的简单语法

一.存储过程中使用事务的简单语法 在存储过程中使用事务时非常重要的,使用数据可以保持数据的关联完整性,在Sql server存储过程中使用事务也很简单,用一个例子来说明它的语法格式: 代码 : Create Procedure MyProcedure( @Param1 nvarchar(10),@param2 nvarchar(10))ASBeginSet NOCOUNT ON;Set XACT_ABORT ON;Begin TranDelete from table1 where name=’

存储过程中的事务

一.存储过程中使用事务的简单语法 在存储过程中使用事务时非常重要的,使用数据可以保持数据的关联完整性,在Sql server存储过程中使用事务也很简单,用一个例子来说明它的语法格式: 1 Create Procedure MyProcedure 2 3 ( @Param1 nvarchar(10), 4 5 @param2 nvarchar(10) 6 7 ) 8 9 AS 10 11 Begin 12 13 Set NOCOUNT ON; 14 15 Set XACT_ABORT ON; 16

存储过程中使用事务

一.存储过程中使用事务的简单语法 在存储过程中使用事务时非常重要的,使用数据可以保持数据的关联完整性,在Sql server存储过程中使用事务也很简单,用一个例子来说明它的语法格式: 代码 Create Procedure MyProcedure ( @Param1 nvarchar(10), @param2 nvarchar(10) ) AS Begin Set NOCOUNT ON; Set XACT_ABORT ON; Begin Tran Delete from table1 where

SQL Server中的事务日志管理(9/9):监控事务日志

当一切正常时,没有必要特别留意什么是事务日志,它是如何工作的.你只要确保每个数据库都有正确的备份.当出现问题时,事务日志的理解对于采取修正操作是重要的,尤其在需要紧急恢复数据库到指定点时.这系列文章会告诉你每个DBA应该知道的具体细节. 对于在我们关注下的所有数据库,在日志维护方面,我们的首要目标是最优化写性能,为了支持SQL Server写入日志的所有活动,包括数据修改,数据读取,索引维护等等.但是,留意下可能的日志碎片也是重要的,如前面文章介绍的,它会影响需要读取日志的过程性能,例如日志备份

EntityFramework追踪Sql语句

方法一:SQL Profile 这个工具只有sql标准版(standard) 及以上版本才有,我装的是SqlServer2012 Express,所以采用方法2. 方法二:EntityFramework.Profiler 下载:EntityFramework.Profiler 工具 ,我用的是EntityFramework.Profiler-v2.0-Build-2233 (大小15M左右) 网址:http://www.nuget.org/packages/EntityFrameworkProf

程序中使用事务来管理sql语句的执行,执行失败时,可以达到回滚的要求。

1.设置使用事务的SQL执行语句 1 /// <summary> 2 /// 使用有事务的SQL语句 3 /// </summary> 4 /// <param name="sql"></param> 5 /// <param name="conn"></param> 6 /// <param name="tran"></param> 7 /// &l