我确信可以分析企业库 SQL 命令,但我一直无法弄清楚如何包装连接。这是我想出的:
Database db = DatabaseFactory.CreateDatabase();
DbCommand dbCommand = db.GetStoredProcCommand(PROC);
ProfiledDbCommand cmd = new ProfiledDbCommand(dbCommand, dbCommand.Connection, MvcMiniProfiler.MiniProfiler.Current);
db.AddInParameter(cmd, "foo", DbType.Int64, 0);
DataSet ds = db.ExecuteDataSet(cmd);
这会导致以下异常:
Unable to cast object of type 'MvcMiniProfiler.Data.ProfiledDbCommand' to type 'System.Data.SqlClient.SqlCommand'.
最佳答案
异常来自Entlib Database.DoLoadDataSet中的这一行
((IDbDataAdapter) adapter).SelectCommand = command;
在这种情况下,适配器是 SqlDataAdapter 类型,它需要一个 SqlCommand,ProfiledDbProviderFactory 创建的命令是 ProfiledDbCommand 类型,如您在异常中看到的那样。
此解决方案将通过覆盖 ProfiledDbProviderFactory 中的 CreateDataAdapter 和 CreateCommand 为 EntLib 提供通用 DbDataAdapter。 它似乎可以正常工作,但如果我发现了这个黑客攻击可能产生的任何不良后果(或它可能导致的眼睛酸痛;),我深表歉意。 开始了:
创建两个新类 ProfiledDbProviderFactoryForEntLib 和 DbDataAdapterForEntLib
public class ProfiledDbProviderFactoryForEntLib : ProfiledDbProviderFactory { private DbProviderFactory _tail; public static ProfiledDbProviderFactory Instance = new ProfiledDbProviderFactoryForEntLib(); public ProfiledDbProviderFactoryForEntLib(): base(null, null) { } public void InitProfiledDbProviderFactory(IDbProfiler profiler, DbProviderFactory tail) { base.InitProfiledDbProviderFactory(profiler, tail); _tail = tail; } public override DbDataAdapter CreateDataAdapter() { return new DbDataAdapterForEntLib(base.CreateDataAdapter()); } public override DbCommand CreateCommand() { return _tail.CreateCommand(); } } public class DbDataAdapterForEntLib : DbDataAdapter { private DbDataAdapter _dbDataAdapter; public DbDataAdapterForEntLib(DbDataAdapter adapter) : base(adapter) { _dbDataAdapter = adapter; } }
在 Web.config 中,将 ProfiledDbProviderFactoryForEntLib 添加到 DbProviderFactories 并将 ProfiledDbProviderFactoryForEntLib 设置为连接字符串的 providerName
<configuration> <configSections> <section name="dataConfiguration" type="..." /> </configSections> <connectionStrings> <add name="SqlServerConnectionString" connectionString="Data Source=xyz;Initial Catalog=dbname;User ID=u;Password=p" providerName="ProfiledDbProviderFactoryForEntLib" /> </connectionStrings> <system.data> <DbProviderFactories> <add name="EntLib DB Provider" invariant="ProfiledDbProviderFactoryForEntLib" description="Profiled DB provider for EntLib" type="MvcApplicationEntlib.ProfiledDbProviderFactoryForEntLib, MvcApplicationEntlib, Version=1.0.0.0, Culture=neutral"/> </DbProviderFactories> </system.data> <dataConfiguration defaultDatabase="..." /> <appSettings>... <system.web>... etc ... </configuration>
(MvcApplicationEntlib是我测试项目的名字)
在对数据库进行任何调用之前设置 ProfiledDbProviderFactoryForEntLib(警告对黑客敏感的读者,这是它变得丑陋的地方)
//In Global.asax.cs protected void Application_Start() { ProfiledDbProviderFactoryForEntLib profiledProfiledDbProviderFactoryFor = ((ProfiledDbProviderFactoryForEntLib)DbProviderFactories.GetFactory("ProfiledDbProviderFactoryForEntLib")); DbProviderFactory factory = DbProviderFactories.GetFactory("System.Data.SqlClient"); //or whatever predefined factory you want to profile profiledProfiledDbProviderFactoryFor.InitProfiledDbProviderFactory(MiniProfiler.Current, factory); ...
这可能会以更好的方式或在其他地方完成。 MiniProfiler.Current 在这里将为空,因为这里没有分析任何内容。
像开始时一样调用存储过程
public class HomeController : Controller { public ActionResult Index() { Database db = DatabaseFactory.CreateDatabase(); DbCommand dbCommand = db.GetStoredProcCommand("spGetSomething"); DbCommand cmd = new ProfiledDbCommand(dbCommand, dbCommand.Connection, MiniProfiler.Current); DataSet ds = db.ExecuteDataSet(cmd); ...
编辑: 好吧不确定你想如何使用它。跳过手动创建 ProfiledDbCommand。 ProfiledDbProviderFactory 需要为每个请求使用 miniprofiler 启动。
在 Global.asax.cs 中,删除您对 Application_Start 所做的更改(上面第 3 步中的出厂设置),将其添加到 Application_BeginRequest。
ProfiledDbProviderFactoryForEntLib profiledProfiledDbProviderFactoryFor = ((ProfiledDbProviderFactoryForEntLib) DbProviderFactories.GetFactory("ProfiledDbProviderFactoryForEntLib")); DbProviderFactory factory = DbProviderFactories.GetFactory("System.Data.SqlClient"); profiledProfiledDbProviderFactoryFor.InitProfiledDbProviderFactory(MvcMiniProfiler.MiniProfiler.Start(), factory);
从 ProfiledDbProviderFactoryForEntLib 中删除 CreateCommand 方法,让 ProfiledDbProviderFactory 创建分析命令。
像这样在不创建 ProfiledDbCommand 的情况下执行您的 SP
Database db = DatabaseFactory.CreateDatabase(); DbCommand dbCommand = db.GetStoredProcCommand("spGetSomething"); DataSet ds = db.ExecuteDataSet(dbCommand);
关于c# - 带有 Microsoft 企业库的 MVC Mini Profiler,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/7093944/