Entity Framework入门教程(17)---记录和拦截数据库命令
记录和拦截数据库命令
这一节介绍EF6怎么记录和拦截发送给数据库的查询和操作命令。
1.记录EF发送给数据库命令(DbContext.Database.Log)
以前给了查看EF发送给数据库的命令我们需要借助数据库的追踪工具或者第三方追踪工具,现在EF6中提供了DbContext.Database.Log属性(Action<string>类型),使用这个属性我们可以很方便地记录EF发送给数据库的命令。
下边是一个栗子:
static void Main(string[] args)
{
using (EFDbContext context=new EFDbContext())
{
context.Database.Log = Console.WriteLine;
var std1 = context.Students.Find();
std1.Name = "newName";
context.SaveChanges();
Console.ReadKey();
} }
输出如下:

在上边的栗子中,Console.Write()方法属于Action<string>类型,所以可以赋值给Log属性。可以看到EF打开和关闭数据库,执行查询,和使用事务进行CUD都会被记录下来。
我们也可以自定义一个Action<string>委托的实例赋值给Log属性:
public class Logger
{
public static void Log(string message)
{
Console.WriteLine("EF Message: {0} ", message);
}
} class EF6Demo
{
public static void DBCommandLogging()
{
using (var context = new SchoolDBEntities())
{ context.Database.Log = Logger.Log;
var std1 = context.Students.Find();
std1.Name = "newName";
context.SaveChanges();
Console.ReadKey();
}
}
}
2.拦截EF生成的数据库命令(IDbCommandIntercepter)
EF6提供了拦截数据库的接口IDbCommandIntercepter,这个接口提供了拦截EF发送给数据库的命令的方法,我们也可以使用这个接口实现在context的操作执行前或执行后去做一些自定义的操作(类似mvc/api中的filter)。因为DbContext执行操作的底层实现是利用ADO.NET进行ExecuteNonQuery, ExecuteScalar, 和ExecuteReader,所以我们可以通过如NonQueryExecuted、NonQueryExecuting等方法进行拦截。
为了实现SQL命令拦截我们首先要定义一个实现IDbCommandIntercepter接口的类:
class EFCommandInterceptor : IDbCommandInterceptor
{
public void NonQueryExecuted(System.Data.Common.DbCommand command, DbCommandInterceptionContext<int> interceptionContext)
{
LogInfo("NonQueryExecuted", String.Format(" IsAsync: {0}, Command Text: {1}", interceptionContext.IsAsync, command.CommandText));
} public void NonQueryExecuting(System.Data.Common.DbCommand command, DbCommandInterceptionContext<int> interceptionContext)
{
LogInfo("NonQueryExecuting", String.Format(" IsAsync: {0}, Command Text: {1}", interceptionContext.IsAsync, command.CommandText));
} public void ReaderExecuted(System.Data.Common.DbCommand command, DbCommandInterceptionContext<System.Data.Common.DbDataReader> interceptionContext)
{
LogInfo("ReaderExecuted", String.Format(" IsAsync: {0}, Command Text: {1}", interceptionContext.IsAsync, command.CommandText));
} public void ReaderExecuting(System.Data.Common.DbCommand command, DbCommandInterceptionContext<System.Data.Common.DbDataReader> interceptionContext)
{
LogInfo("ReaderExecuting", String.Format(" IsAsync: {0}, Command Text: {1}", interceptionContext.IsAsync, command.CommandText));
} public void ScalarExecuted(System.Data.Common.DbCommand command, DbCommandInterceptionContext<object> interceptionContext)
{
LogInfo("ScalarExecuted", String.Format(" IsAsync: {0}, Command Text: {1}", interceptionContext.IsAsync, command.CommandText));
} public void ScalarExecuting(System.Data.Common.DbCommand command, DbCommandInterceptionContext<object> interceptionContext)
{
LogInfo("ScalarExecuting", String.Format(" IsAsync: {0}, Command Text: {1}", interceptionContext.IsAsync, command.CommandText));
} private void LogInfo(string command, string commandText)
{
Console.WriteLine("Intercepted on: {0} :- {1} ", command, commandText);
}
}
可以看出,IDbCommandInterceptor 接口提供了6个方法,分别用于在ADO.NET执行ExecuteNonQuery(),ExcuteReader(),ExcuteScalar()方法的执行前/后拦截命令。这个栗子目的是:记录context的操作是否是异步和发送到数据库的命令。我们也可以使用这些方法来实现自定义逻辑(和filter简直一模一样有木有)。
接下来把拦截器添加到配置中去,两种实现方式:
① 通过配置文件,在app.config或web.config中添加如下节点
<entityFramework>
<interceptors>
<interceptor type="EF6DBFirstTutorials.EFCommandInterceptor, EF6DBFirstTutorials">
</interceptor>
</interceptors>
</entityFramework>
②代码配置
public class FE6CodeConfig : DbConfiguration
{
public FE6CodeConfig()
{
this.AddInterceptor(new EFCommandInterceptor());
}
}
配置完成我们就可以记录EF发送给数据库的命令了,一个栗子:
var newStudent = new Student() { FirstName = "Bill" };
using (var context = new SchoolDBEntities())
{
context.Students.Add(newStudent);
context.SaveChanges();
}
栗子输出为:
Intercepted on: ReaderExecuting :- IsAsync: False, Command Text: INSERT [dbo].[Student]([FirstName], [StandardId], [LastName])
VALUES (@0, NULL, NULL)
SELECT [StudentID], [RowVersion] FROM [dbo].[Student]
WHERE @@ROWCOUNT > 0 AND [StudentID] = scope_identity()
Intercepted on: ReaderExecuted :- IsAsync: False, Command Text: INSERT [dbo].[Student]([FirstName], [StandardId], [LastName])
VALUES (@0, NULL, NULL)
SELECT [StudentID], [RowVersion] FROM [dbo].[Student]
WHERE @@ROWCOUNT > 0 AND [StudentID] = scope_identity()
EF系列目录链接:Entity Franmework系列教程汇总
Entity Framework入门教程(17)---记录和拦截数据库命令的更多相关文章
- Entity Framework入门教程(1)---Entity Framework简介
什么是Entity Framework 学习EF的前提:熟练使用Linq和Ado.net,因为在使用EF框架进行开发时,我们大多数情况使用Linq进行查询和操作,而EF的底层实现用的是Ado.net. ...
- Entity Framework入门教程(3)---EF中的上下文简介
1.DbContext(上下文类) 在DbFirst模式中,我们添加一个EDM(Entity Data Model)后会自动生成一个.edmx文件,这个文件中包含一个继承DbContext类的上下文实 ...
- Entity Framework入门教程(6)--- 在线场景中保存数据
在线场景中保存数据 在线场景中保存实体数据是一项相当容易的任务,因为使用的是同一个context,这个context会自动跟踪所有实体发生的更改. 下图说明了在线场景中的CUD(创建,更新,删除)操作 ...
- Entity Framework入门教程(9)---离线场景附加实体图集到上下文
附加离线实体图集到上下文 这节主要内容是通过不同的方法将离线实体附加到上下文中. 在离线场景中,保存一个实体要略微困难一些.当我们保存一个离线的实体图集或一个单独的离线实体时,我们需要做两件事.首先, ...
- Entity Framework入门教程(10)---离线场景保存和删除实体/实体图集
离线场景保存和删除实体/实体图集 这一节的内容是在离线场景中保存实体和实体图集 在离线场景中,当我们保存一个离线的实体图集或一个单独的离线实体时,我们需要做两件事.首先,我们要把实体附加到新的上下文中 ...
- Entity Framework入门教程(14)---DbFirst下的存储过程
EF6中DbFirst模式下使用存储过程 我们已经知道EF可以将L2E或Entity SQL的查询语句自动转换成SQL命令,也可以根据实体的状态自动生成Insert/update/delete的Sql ...
- ASP .NET MVC 之Entity Framework入门教程及源码
本文主要的目的是 1. 说明Entity Framework Power Tools如何使用. 2. Entity Framework 快速门 实验环境: OS: Windows Server 20 ...
- Entity Framework入门教程:SQLite数据源访问
[环境安装] 可以通过NuGet直接搜索安装SQLite需要用到的组件 或者直接使用程序包管理器控制台 > Install-Package System.Data.SQLite 通过ADO.NE ...
- Entity Framework入门教程: Entity Framework支持的查询方式
Entity Framework支持的查询方式有三种 LINQ to Entities Entity SQL Native SQL [LINQ to Entities] LINQ(语言集成查询)是从V ...
随机推荐
- REST风格架构
一说到rest 大家都耳熟能详,很多人的第一反应就是其是前后端请求后台的一种通信方式,甚至有些人将REST 和RPC 混为一谈,认为两者都是基于HTTP类似的东西.实际上很少人能叙述REST 所提出的 ...
- 报错:library not found for -lstdc++.6.0.9
在Xcode 10开发中, 报错:library not found for -lstdc++.6.0.9 解决方案:将Xcode9的libstdc++6.0.9.tbd拷贝到Xcode10中使用 X ...
- CVE-2018-8120 分析
目录 CVE-2018-8120 分析 1.实验环境 1.1.操作系统 1.2.用到的分析工具 2.假如 2.1.我想提权 2.2. 有一个处于内核空间,极少被调用的函数 2.3.R3任意修改R0地址 ...
- LeetCode算法题-Keyboard Row(Java实现)
这是悦乐书的第245次更新,第258篇原创 01 看题和准备 今天介绍的是LeetCode算法题中Easy级别的第112题(顺位题号是500).给定一个单词列表,返回可以在美国键盘的一行上使用字母表键 ...
- 【English】20190326
Throughput吞吐量[ˈθruˌpʊt] data movement数据移动 [ˈdetə ˈmuvmənt] How to improve the Throughput for data ...
- Python开发【第一篇】基础题目一
1.求1-2+3-4+5.....99的所有数的和 n = 1 s = 0 while n<100: temp = n%2 if temp == 0: #偶数 s = s-n else: s = ...
- Hadoop Compatibility in Flink
18 Nov 2014 by Fabian Hüske (@fhueske) Apache Hadoop is an industry standard for scalable analytical ...
- Linux-基础学习(一)-基本命令
开始今日份整理 1.Linux的文件目录操作 1.1 ls 简述:ls是list的缩写,用于列出指定目录或文件 常用的选项 1 -a:显示所有档案及目录(ls内定将档案名或目录名称为“.”的视为隐藏, ...
- pyinstaller 打包selenium脚本 取消cmd
更改源代码 找到文件(selenium->webdriver->common->service.py) 添加一个参数
- React 合并行 RowSpan
十年河东,十年河西,莫欺少年穷 学无止境,精益求精 今儿分享一篇关于React Table 组件合并单元行的方法! 实例效果如下: 原则就是遇到相同的供方名称,就要做行合并! 思路如下:后端计算合并的 ...