我确信可以对企业库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);
这会导致以下异常:
无法强制转换MvcMiniProfiler.Data类型的对象。ProfiledDbCommand'输入'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。将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是我的测试项目的名称)
在调用DB之前设置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);
这是一篇相当老的文章,但我认为值得一提的是我是如何整理的。
由于我们的应用程序的实现方式,应用Jonas的解决方案并不容易,所以我沿着改变EntLib Datablock的道路走下去(我已经在我们的项目中修改了)。
事情很简单,只需修改数据库类中的DoExecuteXXX方法,以便它们调用miniprofiler,之前我已将其更改为公开SqlProfiler。
做:
if (_miniProfiler != null)
_miniProfiler.ExecuteStart(command, StackExchange.Profiling.Data.ExecuteType.NonQuery);
每个方法开头的和
if (_miniProfiler != null)
_miniProfiler.ExecuteFinish(command, StackExchange.Profiling.Data.ExecuteType.NonQuery);
finally块中的完成了任务。只需将Execution类型更改为与所更改的方法相适应的类型。
miniprofiler实例是在DatabaseClass的构造函数中获得的
if (MiniProfiler.Current != null)
_miniProfiler = MiniProfiler.Current.SqlProfiler;
你可以试试这样做。
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);
DbConnection dbc = MvcMiniProfiler.Data.ProfiledDbConnection.Get(dbCommand.Connection, MiniProfiler.Current);
DataSet ds = db.ExecuteDataSet(dbc);
更新:
在对EntLib Data源代码SqlDatabase进行了大量搜索之后,看起来并没有一种简单的方法来实现这一点。对不起。我知道我是。
这似乎是Mvc-Mini-Profiler的一个问题。如果你在MVC-Mini-Profiler项目主页上查看这个问题19链接,你会看到其他人也有同样的问题。
我花了相当长的时间去通过System.Data.SqlClient与Reflector,和ProfiledDbProviderFactory,试图看看问题是什么,似乎下面是问题所在。这可以在ProfiledDbProviderFactory类中找到。
public override DbDataAdapter CreateDataAdapter()
{
return tail.CreateDataAdapter();
}
现在的问题不完全是这段代码,但事实是,当Microsoft.Practices.EnterpriseLibrary.Data.Database
类调用DbDataAdapter
的一个实例(尾巴在我们的情况下是SqlClientFactory),它创建SqlClientFactory Command
,然后试图设置这个命令的Connection
为ProfiledDbConnection
,这是它打破。
我试过创建自己的工厂类来解决这个问题,但我只是迷路了。也许当我有空闲时间的时候,我会尝试解决这个问题,除非SO团队比我抢先一步。:)