首先使用mvc-mini-profiler数据库分析与实体框架代码 [英] Using mvc-mini-profiler database profiling with Entity Framework Code First

查看:147
本文介绍了首先使用mvc-mini-profiler数据库分析与实体框架代码的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我在我的项目中使用了 mvc-mini-profiler 使用ASP.Net MVC 3和实体框架构建代码优先。



一切都很好,直到我尝试通过在$ code> ProfiledDbConnection 中包装连接来添加数据库分析,如文档中所述。由于我使用DbContext,我试图提供连接的方式是通过使用静态工厂方法的构造函数:

  public class MyDbContext:DbContext 
{
public MyDbContext():base(GetProfilerConnection(),true)
{}

private static DbConnection GetProfilerConnection()
{
//代码下面的错误
// return ProfiledDbConnection.Get(new SqlConnection(ConfigurationManager.ConnectionStrings [MyConnectionName]。ConnectionString));

//下面的代码工作正常...
返回新的SqlConnection(ConfigurationManager.ConnectionStrings [MyConnectionName]。ConnectionString);
}

// ...
}

当使用 ProfiledDbConnection 时,我收到以下错误:



ProviderIncompatibleException:提供者没有返回ProviderManifestToken字符串。



堆栈跟踪:

  [ArgumentException:连接不是类型'System.Data.SqlClient.SqlConnection'。] 
System.Data.SqlClient.SqlProviderUtilities.GetRequiredSqlConnection(DbConnection连接)+10486148
System.Data.SqlClient.SqlProviderServices.GetDbProviderManifestToken(DbConnection connection)+77
System.Data.Common.DbProviderServices.GetProviderManifestToken(DbConnection connection)+44

[ProviderIncompatibleException:提供程序未返回一个ProviderManifestToken字符串。]
System.Data.Common.DbProviderServices.GetProviderManifestToken(DbConnection connection)+11092901
System.Data.Common.DbProviderServices.GetPr oviderManifestToken(DbConnection connection)+11092745
System.Data.Entity.DbModelBuilder.Build(DbConnection providerConnection)+221
System.Data.Entity.Internal.LazyInternalContext.CreateModel(LazyInternalContext internalContext)+61
System.Data.Entity.Internal.RetryLazy`2.GetValue(TInput input)+1203482
System.Data.Entity.Internal.LazyInternalContext.InitializeContext()+492
System.Data.Entity.Internal .InternalContext.GetEntitySetAndBaseTypeForType(Type entityType)+26
System.Data.Entity.Internal.Linq.InternalSet`1.Initialize()+89
System.Data.Entity.Internal.Linq.InternalSet`1 .get_InternalContext()+21
System.Data.Entity.Infrastructure.DbQuery`1.System.Linq.IQueryable.get_Provider()+44
System.Linq.Queryable.Where(IQueryable`1 source,表达式1的谓词)+135

我已经通过了 ProfiledDbConnection.Get 的类型为 ProfiledDbConne ction (即使当前的MiniProfiler为空)。



MiniProfiler.Start()方法在Global Application_BeginRequest()方法之前, DbContext 被实例化。我也在调用每个请求的Start方法,无论如果用户没有正确的角色,调用stop:

  protected void Application_BeginRequest()
{
//我们不知道用户在这个阶段是谁,所以需要为每个人开始
MiniProfiler.Start();
}

protected void Application_AuthorizeRequest(Object sender,EventArgs e)
{
//如果用户不是开发人员,现在停止分析器
if (!AuthorizationHelper.IsDeveloper())
{
MvcMiniProfiler.MiniProfiler.Stop(discardResults:true);
}
}

protected void Application_EndRequest()
{
MiniProfiler.Stop();
}

我不知道这是否会影响事情,但我也使用StructureMap作为IoC for DbContext 使用以下初始化器:

 对于&My MyBB ;()的Singleton()HybridHttpOrThreadLocalScoped(); 

我明白这里有一个类似的问题,对该用户发生了什么,然而,它似乎并没有解决我的问题。



编辑:



为了清楚起见我试图将连接作为 ProfiledDbConnection 传递,以便从实体框架代码中简化生成的sql。





实体框架期待连接类型为 SqlConnection 当然这不是。



以下是我的连接字符串示例(注意providerName)

 < add name =MyDbContextconnectionString =Server = .\SQLEXPRESS; Database = MyDatabase; Trusted_Connection = true; MultipleActiveResultSets = trueproviderName =System.Data.SqlClient/> 

我尝试创建自己的版本的 ProfiledDbConnection 继承自 SqlConnection ,但它是一个密封类。



如果有一些方法告诉实体框架关于自定义连接类型,那么也许这将工作。我尝试将连接字符串中的 providerName 设置为 MvcMiniProfiler.Data.ProfiledDbConnection ,但没有起作用。 p>

所以。问题的演变可能是:您如何将自定义连接类型传递给实体框架代码?

解决方案

这是现在完全支持,查看最新的源码或从nuget获取该软件包。



如果您使用nuget,则需要MiniProfiler.EF软件包。 (1.9.1及更高版本)



支持此操作涉及到底层代理对象的大量修改,以支持充当EF代码第一代理。



要添加此支持:



在您的 Application_Start 运行:



MiniProfilerEF.Initialize();



注意:EF Code First将在表格中存储表元数据: EdmMetadata 。该元数据使用提供者作为实体密钥的一部分。如果您将提供程序初始化为非概要提供程序,则必须重新构建此元数据。删除 EdmMetadata 中的所有行可能会做的伎俩,或者一些更聪明的提供商能够透明地处理这个问题。


I'm using the mvc-mini-profiler in my project built with ASP.Net MVC 3 and Entity Framework code-first.

Everything works great until I attempt to add database profiling by wrapping the connection in the ProfiledDbConnection as described in the documentation. Since I'm using a DbContext, the way I am attempting to provide the connection is through the constructor using a static factory method:

public class MyDbContext : DbContext
{                
    public MyDbContext() : base(GetProfilerConnection(), true)
    { }

    private static DbConnection GetProfilerConnection()
    {
        // Code below errors
        //return ProfiledDbConnection.Get(new SqlConnection(ConfigurationManager.ConnectionStrings["MyConnectionName"].ConnectionString));

        // Code below works fine...
        return new SqlConnection(ConfigurationManager.ConnectionStrings["MyConnectionName"].ConnectionString);
    }

    //...
}

When using the ProfiledDbConnection, I get the following error:

ProviderIncompatibleException: The provider did not return a ProviderManifestToken string.

Stack Trace:

[ArgumentException: The connection is not of type 'System.Data.SqlClient.SqlConnection'.]
   System.Data.SqlClient.SqlProviderUtilities.GetRequiredSqlConnection(DbConnection connection) +10486148
   System.Data.SqlClient.SqlProviderServices.GetDbProviderManifestToken(DbConnection connection) +77
   System.Data.Common.DbProviderServices.GetProviderManifestToken(DbConnection connection) +44

[ProviderIncompatibleException: The provider did not return a ProviderManifestToken string.]
System.Data.Common.DbProviderServices.GetProviderManifestToken(DbConnection connection) +11092901
   System.Data.Common.DbProviderServices.GetProviderManifestToken(DbConnection connection) +11092745
   System.Data.Entity.DbModelBuilder.Build(DbConnection providerConnection) +221
   System.Data.Entity.Internal.LazyInternalContext.CreateModel(LazyInternalContext internalContext) +61
   System.Data.Entity.Internal.RetryLazy`2.GetValue(TInput input) +1203482
   System.Data.Entity.Internal.LazyInternalContext.InitializeContext() +492
   System.Data.Entity.Internal.InternalContext.GetEntitySetAndBaseTypeForType(Type entityType) +26
   System.Data.Entity.Internal.Linq.InternalSet`1.Initialize() +89
   System.Data.Entity.Internal.Linq.InternalSet`1.get_InternalContext() +21
   System.Data.Entity.Infrastructure.DbQuery`1.System.Linq.IQueryable.get_Provider() +44
   System.Linq.Queryable.Where(IQueryable`1 source, Expression`1 predicate) +135

I have stepped through and the type returned by ProfiledDbConnection.Get is of type ProfiledDbConnection (Even if the current MiniProfiler is null).

The MiniProfiler.Start() method is called within the Global Application_BeginRequest() method before the DbContext is instantiated. I am also calling the Start method for every request regardless but calling stop if the user is not in the correct role:

    protected void Application_BeginRequest()
    {
        // We don't know who the user is at this stage so need to start for everyone
        MiniProfiler.Start();
    }

    protected void Application_AuthorizeRequest(Object sender, EventArgs e)
    {
        // Now stop the profiler if the user is not a developer
        if (!AuthorisationHelper.IsDeveloper())
        {
            MvcMiniProfiler.MiniProfiler.Stop(discardResults: true);
        }
    }

    protected void Application_EndRequest()
    {
        MiniProfiler.Stop();
    }

I'm not sure if this affects things but I'm also using StructureMap as IoC for the DbContext using the following initialiser:

For<MyDbContext>().Singleton().HybridHttpOrThreadLocalScoped();

I understand that there is a similar question on here with a good explanation of what's happening for that user, however it doesn't seem to solve my problem.

EDIT:

For clarity. I am attempting to pass the connection as ProfiledDbConnection in order to profile the generated sql from Entity Framework Code First.

The Entity Framework is expecting a connection with type SqlConnection which of course this isn't.

Here is an example of my connection string (notice the providerName)

<add name="MyDbContext" connectionString="Server=.\SQLEXPRESS; Database=MyDatabase;Trusted_Connection=true;MultipleActiveResultSets=true" providerName="System.Data.SqlClient" />

I attempted to create my own version of the ProfiledDbConnection inheriting from SqlConnection but it is a sealed class.

If there is some way of telling Entity Framework about the custom connection type then perhaps this would work. I tried setting the providerName in the connection string to MvcMiniProfiler.Data.ProfiledDbConnection but that didn't work.

So. Perhaps an evolution of the question would be: How can you pass a custom connection type to Entity Framework Code First?

解决方案

This is now fully supported, check out the latest source or grab the package from nuget.

You will need the MiniProfiler.EF package if you are using nuget. (1.9.1 and up)

Supporting this involved a large set of modifications to the underlying proxy object to support acting as EF code first proxies.

To add this support:

During your Application_Start run:

MiniProfilerEF.Initialize();

Note: EF Code First will store table metadata in a table called: EdmMetadata. This metadata uses the provider as part of the entity key. If you initialized your provider as a non-profiled provider, you will have to re-build this metadata. Deleting all the rows from EdmMetadata may do the trick, alternatively some smarter providers are able to handle this transparently.

这篇关于首先使用mvc-mini-profiler数据库分析与实体框架代码的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆