我确信可以分析企业库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”。
答案 0 :(得分:11)
异常来自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设置为您的connectionstring的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在这里将为null,因为此处没有任何内容。
正如您从头开始那样调用存储过程
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。需要使用miniprofiler为每个请求启动ProfiledDbProviderFactory。
在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改为创建profiled命令。
执行您的SP而不创建ProfiledDbCommand,就像这样
Database db = DatabaseFactory.CreateDatabase();
DbCommand dbCommand = db.GetStoredProcCommand("spGetSomething");
DataSet ds = db.ExecuteDataSet(dbCommand);
答案 1 :(得分:0)
这是一个相当古老的帖子,但我认为值得一提的是我如何排除这一点。
由于我们的应用程序的实现方式,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块中的做了伎俩。只需将执行类型更改为适合要更改的方法。
miniprofiler实例是在DatabaseClass
的构造函数中获得的if (MiniProfiler.Current != null)
_miniProfiler = MiniProfiler.Current.SqlProfiler;
答案 2 :(得分:-2)
你可以尝试这样的事情。
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数据源代码SqlDatabase进行大量搜索之后,看起来并不是真的有一种简单的方法来实现这一点。抱歉。我知道我是。
这实际上似乎是Mvc-Mini-Profiler的一个问题。如果您在MVC-Mini-Profiler项目主页上查看此Issues 19 Link,您将看到其他人遇到相同的问题。
我花了很长一段时间通过带有Reflector的System.Data.SqlClient和ProfiledDbProviderFactory,试图看看问题是什么,看起来好像以下是问题所在。这可以在ProfiledDbProviderFactory类中找到。
public override DbDataAdapter CreateDataAdapter()
{
return tail.CreateDataAdapter();
}
现在问题不在于这个代码,而是当Microsoft.Practices.EnterpriseLibrary.Data.Database
类调用DbDataAdapter
的intance(在我们的例子中是尾部是SqlClientFactory)时,它会创建SqlClientFactory Command
,并且然后尝试将此命令的Connection
设置为ProfiledDbConnection
,这就是它中断了。
我已经尝试创建自己的工厂类来解决这个问题但是我太迷茫了。也许当我有空闲时间时,我会尝试解决这个问题,除非SO团队打败我。 :)