Entity framework 添加自定义方法
Entity framework adding Custom method
我们正在使用 newrelic 进行数据库性能监控。我们的问题是 Entity framework 正在生成 SQL 并且我们在跟踪此 SQL 查询在我们的代码库中生成的位置时遇到问题,例如
假设以下查询导致了性能问题。如何修改生成的 sql 查询并为其添加自定义评论,例如
SELECT
? AS [C1],
[GroupBy1].[K1] AS [Destination],
[GroupBy1].[A1] AS [C2]
FROM ( SELECT
[Extent1].[Destination] AS [K1],
SUM([Extent1].[SearchCount]) AS [A1]
FROM [Flight].[Item] AS [Extent1]
WHERE ([Extent1].[Origin] IN (?, ?)) AND ( NOT ((@p__linq__0 = ?) AND ([Extent1].[IsDomesticTurkish] = ?))) AND ([Extent1].[DestinationCity] IN (?, ?, ?, ?, ?, ?, ?, ?)) AND ([Extent1].[DestinationCity] IS NOT NULL)
GROUP BY [Extent1...More…
那么我该怎么做呢
var DbContext.MyDbSet.Where(myWhereEx).AddCustomComment("Hello this is a custom comment I will write it from my code")
之后输出会是这样
SELECT
? AS [C1],
[GroupBy1].[K1] AS [Destination],
[GroupBy1].[A1] AS [C2]
FROM ( SELECT
[Extent1].[Destination] AS [K1],
SUM([Extent1].[SearchCount]) AS [A1]
FROM [Flight].[Item] AS [Extent1]
WHERE ([Extent1].[Origin] IN (?, ?)) AND ( NOT ((@p__linq__0 = ?) AND ([Extent1].[IsDomesticTurkish] = ?))) AND ([Extent1].[DestinationCity] IN (?, ?, ?, ?, ?, ?, ?, ?)) AND ([Extent1].[DestinationCity] IS NOT NULL)
GROUP BY [Extent1...More…
--Hello this is a custom comment I will write it from my code
我的问题是如何实现 AddCustomComment 并在 AddCustomComment 内部修改生成的 sql,然后再转到 SQL 服务器
我不知道有任何 EF built-in 功能可以做到这一点,但这是如何完成的一个想法。
你可以使用thread-local变量来存储注释(所以每个线程都有它自己的那个变量的副本)并使用Entity Framework命令拦截器在执行之前向命令添加注释,然后清除执行命令时的注释变量。这是示例实现:
class EFCommentInterceptor : IDbCommandInterceptor {
private static readonly ThreadLocal<string> _comment = new ThreadLocal<string>();
internal static void SetComment(string comment) {
_comment.Value = comment;
}
public void NonQueryExecuting(DbCommand command, DbCommandInterceptionContext<int> interceptionContext) {
AddComment(command);
}
public void NonQueryExecuted(DbCommand command, DbCommandInterceptionContext<int> interceptionContext) {
_comment.Value = null;
}
public void ReaderExecuting(DbCommand command, DbCommandInterceptionContext<DbDataReader> interceptionContext) {
AddComment(command);
}
public void ReaderExecuted(DbCommand command, DbCommandInterceptionContext<DbDataReader> interceptionContext) {
_comment.Value = null;
}
public void ScalarExecuting(DbCommand command, DbCommandInterceptionContext<object> interceptionContext) {
AddComment(command);
}
public void ScalarExecuted(DbCommand command, DbCommandInterceptionContext<object> interceptionContext) {
_comment.Value = null;
}
private void AddComment(DbCommand command) {
if (!String.IsNullOrWhiteSpace(_comment.Value))
command.CommandText += "\r\n\r\n-- " + _comment.Value;
}
}
然后像这样添加扩展方法:
static class QueryableExtensions {
public static IQueryable<T> WithComment<T>(this IQueryable<T> query, string comment) {
EFCommentInterceptor.SetComment(comment);
return query;
}
}
注册拦截器:
DbInterception.Add(new EFCommentInterceptor());
并使用它:
using (var ctx = new MyContext()) {
ctx.MyDbSet.Where(c = c.MyColumn > 1).WithComment("Hello this is a custom comment I will write it from my code").ToArray();
ctx.MyDbSet.Take(10).ToArray(); // no comment here
ctx.MyDbSet.Take(10).WithComment("Again with comment").ToArray();
}
我们正在使用 newrelic 进行数据库性能监控。我们的问题是 Entity framework 正在生成 SQL 并且我们在跟踪此 SQL 查询在我们的代码库中生成的位置时遇到问题,例如
假设以下查询导致了性能问题。如何修改生成的 sql 查询并为其添加自定义评论,例如
SELECT
? AS [C1],
[GroupBy1].[K1] AS [Destination],
[GroupBy1].[A1] AS [C2]
FROM ( SELECT
[Extent1].[Destination] AS [K1],
SUM([Extent1].[SearchCount]) AS [A1]
FROM [Flight].[Item] AS [Extent1]
WHERE ([Extent1].[Origin] IN (?, ?)) AND ( NOT ((@p__linq__0 = ?) AND ([Extent1].[IsDomesticTurkish] = ?))) AND ([Extent1].[DestinationCity] IN (?, ?, ?, ?, ?, ?, ?, ?)) AND ([Extent1].[DestinationCity] IS NOT NULL)
GROUP BY [Extent1...More…
那么我该怎么做呢 var DbContext.MyDbSet.Where(myWhereEx).AddCustomComment("Hello this is a custom comment I will write it from my code")
之后输出会是这样
SELECT
? AS [C1],
[GroupBy1].[K1] AS [Destination],
[GroupBy1].[A1] AS [C2]
FROM ( SELECT
[Extent1].[Destination] AS [K1],
SUM([Extent1].[SearchCount]) AS [A1]
FROM [Flight].[Item] AS [Extent1]
WHERE ([Extent1].[Origin] IN (?, ?)) AND ( NOT ((@p__linq__0 = ?) AND ([Extent1].[IsDomesticTurkish] = ?))) AND ([Extent1].[DestinationCity] IN (?, ?, ?, ?, ?, ?, ?, ?)) AND ([Extent1].[DestinationCity] IS NOT NULL)
GROUP BY [Extent1...More…
--Hello this is a custom comment I will write it from my code
我的问题是如何实现 AddCustomComment 并在 AddCustomComment 内部修改生成的 sql,然后再转到 SQL 服务器
我不知道有任何 EF built-in 功能可以做到这一点,但这是如何完成的一个想法。
你可以使用thread-local变量来存储注释(所以每个线程都有它自己的那个变量的副本)并使用Entity Framework命令拦截器在执行之前向命令添加注释,然后清除执行命令时的注释变量。这是示例实现:
class EFCommentInterceptor : IDbCommandInterceptor {
private static readonly ThreadLocal<string> _comment = new ThreadLocal<string>();
internal static void SetComment(string comment) {
_comment.Value = comment;
}
public void NonQueryExecuting(DbCommand command, DbCommandInterceptionContext<int> interceptionContext) {
AddComment(command);
}
public void NonQueryExecuted(DbCommand command, DbCommandInterceptionContext<int> interceptionContext) {
_comment.Value = null;
}
public void ReaderExecuting(DbCommand command, DbCommandInterceptionContext<DbDataReader> interceptionContext) {
AddComment(command);
}
public void ReaderExecuted(DbCommand command, DbCommandInterceptionContext<DbDataReader> interceptionContext) {
_comment.Value = null;
}
public void ScalarExecuting(DbCommand command, DbCommandInterceptionContext<object> interceptionContext) {
AddComment(command);
}
public void ScalarExecuted(DbCommand command, DbCommandInterceptionContext<object> interceptionContext) {
_comment.Value = null;
}
private void AddComment(DbCommand command) {
if (!String.IsNullOrWhiteSpace(_comment.Value))
command.CommandText += "\r\n\r\n-- " + _comment.Value;
}
}
然后像这样添加扩展方法:
static class QueryableExtensions {
public static IQueryable<T> WithComment<T>(this IQueryable<T> query, string comment) {
EFCommentInterceptor.SetComment(comment);
return query;
}
}
注册拦截器:
DbInterception.Add(new EFCommentInterceptor());
并使用它:
using (var ctx = new MyContext()) {
ctx.MyDbSet.Where(c = c.MyColumn > 1).WithComment("Hello this is a custom comment I will write it from my code").ToArray();
ctx.MyDbSet.Take(10).ToArray(); // no comment here
ctx.MyDbSet.Take(10).WithComment("Again with comment").ToArray();
}