Использование профилирования базы данных mvc-mini-profiler с помощью Entity Framework Code First - PullRequest
24 голосов
/ 01 июля 2011

Я использую mvc-mini-profiler в своем проекте, построенном с использованием ASP.Net MVC 3 и Entity Framework в первую очередь.

Все прекрасно работает, пока я не попытаюсь добавить профилирование базы данных, поместив соединение в ProfiledDbConnection, как описано в документации.Поскольку я использую DbContext, я пытаюсь предоставить соединение через конструктор, используя статический фабричный метод:

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);
    }

    //...
}

При использовании ProfiledDbConnection я получаю следующую ошибку:

ProviderIncompatibleException: The provider did not return a ProviderManifestToken string.

Трассировка стека:

[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

Я прошел, и тип, возвращаемый ProfiledDbConnection.Get, имеет тип ProfiledDbConnection (даже если текущий MiniProfilerнулевой).

Метод MiniProfiler.Start() вызывается в методе Global Application_BeginRequest() до создания экземпляра DbContext.Я также вызываю метод Start для каждого запроса независимо, но вызываю stop, если пользователь не в правильной роли:

    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();
    }

Я не уверен, влияет ли это на вещи, но я также использую StructureMap какIoC для DbContext с использованием следующего инициализатора:

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

Я понимаю, что здесь есть аналогичный вопрос с хорошим объяснением того, что происходит с этим пользователем, однако это, похоже, не решает моюпроблема.

РЕДАКТИРОВАТЬ:

Для ясности.Я пытаюсь передать соединение как ProfiledDbConnection, чтобы профилировать сгенерированный sql из Entity Framework Code First.

Profiled Sql

Entity Framework ожидает соединения с типом SqlConnection, что, конечно, не так.

Вот пример моей строки подключения (обратите внимание, имя провайдера)

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

Я попытался создать свою собственную версию ProfiledDbConnection, унаследованную от SqlConnection, но она запечатанаучебный класс.

Если есть какой-то способ сообщить Entity Framework о пользовательском типе соединения, возможно, это сработает.Я попытался установить providerName в строке подключения на MvcMiniProfiler.Data.ProfiledDbConnection, но это не сработало.

Итак.Возможно, эволюция вопроса будет такой: как вы можете передать пользовательский тип соединения в Entity Framework Code First?

Ответы [ 3 ]

13 голосов
/ 19 июля 2011

Теперь это полностью поддерживается, проверьте последний источник или получите пакет из nuget.

Вам понадобится пакет MiniProfiler.EF, если вы используете nuget.(1.9.1 и выше)

Поддержка этого включала большой набор модификаций базового прокси-объекта для поддержки работы в качестве первых прокси-серверов кода EF.

Чтобы добавить эту поддержку:

Во время выполнения Application_Start:

MiniProfilerEF.Initialize();

Примечание : сначала код EFбудет хранить метаданные таблицы в таблице с именем: EdmMetadata.Эти метаданные используют поставщика как часть ключа объекта.Если вы инициализировали своего провайдера в качестве непрофилированного провайдера, вам придется пересоздать эти метаданные.Удаление всех строк из EdmMetadata может помочь, в то же время некоторые более умные провайдеры могут сделать это прозрачно.

2 голосов
/ 23 июля 2011

Мне все еще не удается заставить это работать, и я обнаружил, что мне нужно переименовать или удалить строку подключения, чтобы заставить Database.DefaultConnectionFactory работать.

Пожалуйста, обратитесь к этому ответу для получения более подробной информации.

0 голосов
/ 13 июля 2011

По моему опыту, эта ошибка всегда была неверной строкой соединения или отсутствием соединения с БД, например «Произошла ошибка сетевой службы при соединении ...».

Также обратите внимание, что DbContextпросто нужен "connectionStringKey" в конструкторе, например

public MyDbContext() : 
     base("MyConnectionName", true)
    { }
...