问题描述
-
OnSQLExecuted(DbCommand cmd,DateTime start,double durationMS,string stacktrace)
我们使用一个令人讨厌的黑客,似乎在泄露性能,我很好奇我们如何实现这个回调,对应用程序的影响最小。
我们可以在通过 - 我们改变了 Database.DefaultConnectionFactory
但是,默认工厂意味着你不能同时进行两个分析工作。所以我们去了更积极的路线。
常用的技术非常简单,您可以实现: DbProviderFactory
, IDbConnectionFactory
, DbProviderServices
, DbConnection
, DbCommand
和 DbDataReader
以这样一种方式拦截呼叫和配置文件。
到目前为止,很容易...但是当您尝试连线时会变得混乱:
try
{
//确保所有工厂都加载
DbProviderFactories.GetFactory(...);
}
catch(ArgumentException)
{
}
类型type = typeof(DbProviderFactories);
DataTable表;
//超级UGLY - 这可以用另一种方式完成吗?
对象setOrTable =(type.GetField(_ configTable,BindingFlags.NonPublic | BindingFlags.Static)
type.GetField(_ providerTable,BindingFlags.NonPublic | BindingFlags.Static))GetValue空值);
if(setOrTable为DataSet)
{
table =((DataSet)setOrTable).Tables [DbProviderFactories];
}
table =(DataTable)setOrTable;
foreach(Table.Rows.Cast< DataRow>()中的DataRow行ToList())
{
DbProviderFactory factory;
try
{
factory = DbProviderFactories.GetFactory(row);
}
catch(异常)
{
continue;
}
var profType = typeof(MvcMiniProfiler.Data.EFProfiledDbProviderFactory&); MakeGenericType(factory.GetType());
DataRow profiled = table.NewRow();
profiled [Name] = row [Name];
profiled [Description] = row [Description];
profiled [InvariantName] = row [InvariantName];
profiled [AssemblyQualifiedName] = profType.AssemblyQualifiedName;
table.Rows.Remove(row);
table.Rows.Add(profiled);
}
它需要一些反思黑客和完全炸弹的最新版本的EF:
FileLoadException:给定的程序集名称或代码库无效。 (HRESULT的异常:0x80131047)
这是由和。
如何以强大而优雅的方式连接我的分析工厂和家庭?
有什么其他方式可以获得我的回调吗?
最简单的方法是使用,并钩入 EFTracingConnection
的 CommandFinished
。它不给你开始的时间,但它给你的持续时间(从现在
中减去,可能足够近)。
我将调用代码影响中等,因为您必须更改对现有上下文类的引用。这是非常简单的。
如果您只需要跟踪并且不需要实际的回调,那么NuGet软件包就有一个。
编辑(添加堆栈跟踪): EF跟踪包装器不给您堆栈跟踪。你可以得到来源并添加它没有太多的困难,但我认为会影响性能。
What is the minimal amount of code I can write to get a single callback from EF 4.1 that provides the following:
OnSQLExecuted(DbCommand cmd, DateTime start, double durationMS, string stacktrace)
At the moment we use a nasty hack that seems to be leaking performance, I am curious at how we can achieve this callback with a minimal amount of impact on the app.
We are able to wire this up in Mini Profiler by hacking around - intially we changed Database.DefaultConnectionFactory
however mucking with the default factory means you can not have two profiling factories going at the same time. So we went the more aggressive route.
The technique commonly used is pretty straight forward, you implement: DbProviderFactory
, IDbConnectionFactory
, DbProviderServices
, DbConnection
, DbCommand
and DbDataReader
in such a way that they intercept the calls and profile.
So far, easy... however it gets messy when you try to wire this up:
try
{
// ensure all the factories are loaded
DbProviderFactories.GetFactory("...");
}
catch (ArgumentException)
{
}
Type type = typeof(DbProviderFactories);
DataTable table;
// SUPER UGLY - Can this be done in another way?
object setOrTable = (type.GetField("_configTable", BindingFlags.NonPublic | BindingFlags.Static) ??
type.GetField("_providerTable", BindingFlags.NonPublic | BindingFlags.Static)).GetValue(null);
if (setOrTable is DataSet)
{
table = ((DataSet)setOrTable).Tables["DbProviderFactories"];
}
table = (DataTable)setOrTable;
foreach (DataRow row in table.Rows.Cast<DataRow>().ToList())
{
DbProviderFactory factory;
try
{
factory = DbProviderFactories.GetFactory(row);
}
catch (Exception)
{
continue;
}
var profType = typeof(MvcMiniProfiler.Data.EFProfiledDbProviderFactory<>).MakeGenericType(factory.GetType());
DataRow profiled = table.NewRow();
profiled["Name"] = row["Name"];
profiled["Description"] = row["Description"];
profiled["InvariantName"] = row["InvariantName"];
profiled["AssemblyQualifiedName"] = profType.AssemblyQualifiedName;
table.Rows.Remove(row);
table.Rows.Add(profiled);
}
It requires some reflection hacks and totally bombs on the latest version of EF:
FileLoadException: The given assembly name or codebase was invalid. (Exception from HRESULT: 0x80131047)
This was documented by both Frans and Ayende.
How do I wire up my profiling factories and family in a robust and elegant way?
Is there any other way to get my callback?
The easiest way is to use the Entity Framework tracing wrappers and hook into the EFTracingConnection
's CommandFinished
. It doesn't give you the start time, but it does give you the duration (which, subtracted from Now
, is likely close enough).
I'd call the code impact "moderate", since you do have to change references to the existing context class. It's pretty straightforward, though.
If you just want tracing and don't need the actual callback, the NuGet package has a simple default tracing system.
Edit (stack trace added): The EF tracing wrappers don't give you the stack trace. You can get the source and add it without too much difficulty, but I'd think that would impact performance.
这篇关于如何正确配置实体框架?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!