mishrsud / mvc-mini-profiler

Automatically exported from code.google.com/p/mvc-mini-profiler
0 stars 0 forks source link

Allow EF 4.1 to be used with the profiler #13

Closed GoogleCodeExporter closed 8 years ago

GoogleCodeExporter commented 8 years ago
Currently it doesn't look like there is a way to use EF 4.1 with the profiler 
as it does not output the provider name for the connection that it wraps.

Below is the error I get when running the profiler with MySq.l

Unable to determine the provider name for connection of type 
'MvcMiniProfiler.Data.ProfiledDbConnection'

and here is the code used to get the error

DbConnection conn = new MySqlConnection(
    ConfigurationManager.ConnectionStrings["ConnString"].ConnectionString);

var profiledConnection = MvcMiniProfiler.Data.ProfiledDbConnection.Get(conn);
return new DB(profiledConnection);
And here is the DB Context Class.

public class DB:DbContext
{
    public DB(DbConnection conn)
        : base(conn, true)
    {

    }...

Original issue reported on code.google.com by B...@marastat.com on 9 Jun 2011 at 9:19

GoogleCodeExporter commented 8 years ago
We are looking at a proposed patch to enable this.

Original comment by marc.gravell on 9 Jun 2011 at 10:22

GoogleCodeExporter commented 8 years ago
Good to hear.  If you don't have an EF 4.1 project to test it on I could help 
test it.

Original comment by B...@marastat.com on 9 Jun 2011 at 10:46

GoogleCodeExporter commented 8 years ago

Original comment by nrcraver on 20 Jun 2011 at 1:05

GoogleCodeExporter commented 8 years ago
Very nice profiler.  Any word on the patch for EF 4.1 will be released?   
Thanks.

Original comment by kyle.rogers on 20 Jun 2011 at 6:25

GoogleCodeExporter commented 8 years ago
Is there any way that I could help with testing out the proposed patch or see 
it and try it out?  I would love to be able to use this with EF 4.1.

Original comment by run...@gmail.com on 30 Jun 2011 at 9:40

GoogleCodeExporter commented 8 years ago
I wonder how about the patch? Wating~~ Thank you!

Original comment by tocha...@gmail.com on 6 Jul 2011 at 3:35

GoogleCodeExporter commented 8 years ago
Hey Marc,

Do you think you can publish the patch so we can try compiling ourshelves?

Regards,
Karan

Original comment by kido...@gmail.com on 7 Jul 2011 at 11:32

GoogleCodeExporter commented 8 years ago
Hello everyone who concern the problem,

I find some way to use min-profiler with EF 4.1 CodeFirst, but it still has 
some problem, I uploaded a demo. I hope some one can reolve the problem totally.

Thank you!

=========================

How to run the demo:

1: The ProfiledDbProvider does not support deleting database, so when you run 
the solution first time, please turn off Mini-profiler and set the EF4.1 
Ininializer to seed the database, then set the initializer to null and turn on 
Mini-profiler, and this time ,you can see it works and log sql statements.

2: the problem is if you refresh in browser , it will throw exception at line 
254 of file MiniProfiler.cs : "Head.AddSqlTiming(stats);" the Head is null. I 
traced but did not find the reason.

I hope someone can find resolve the problem.

===================================================

What I changed the Mvc-Mini-profiler : 

The reason why Mvc-Mini-profiler can not work with EF 4.1 code first is when EF 
build model it  will look for the provider's invariant name  of the connection, 
how ever when the SqlClientConnection is wrapped to ProfiledDbConnection, EF 
can not find the provider's invariant name.

So, I change the provider to register it in Web.config, and use 
DbProviderFactories.GetFactory() to create the provider, so that Ef 4.1 can  
find the provider's invariant name.

Web.config :

  <system.data>
    <DbProviderFactories>
      <remove invariant="MvcMiniProfiler.Data.ProfiledDbProvider" />
      <add name="MvcMiniProfiler.Data.ProfiledDbProvider" invariant="MvcMiniProfiler.Data.ProfiledDbProvider"
       description="MvcMiniProfiler.Data.ProfiledDbProvider"
       type="MvcMiniProfiler.Data.ProfiledDbProviderFactory, MvcMiniProfiler, Version=1.4.0.0, Culture=neutral, PublicKeyToken=cef171dc76a8e880" />
    </DbProviderFactories>
  </system.data>

ProfiledDbConnection.cs

        protected override DbProviderFactory DbProviderFactory
        {
            get
            {
                if (_factory != null) return _factory;
                DbProviderFactory tail = ripInnerProvider(_conn);
                _factory = DbProviderFactories.GetFactory("MvcMiniProfiler.Data.ProfiledDbProvider");

                ((ProfiledDbProviderFactory)_factory).InitProfiledDbProviderFactory(_profiler, tail);

                return _factory;
            }

            //get
            //{

            //    if (_factory != null) return _factory;
            //    DbProviderFactory tail = ripInnerProvider(_conn);
            //    _factory = new ProfiledDbProviderFactory();
            //    
            //    return _factory;
            //}
        }

For the provider can be created by DbProviderFactories.GetFactory(), it must 
have a static field named "Instance"(MSDN Doc):

        public static ProfiledDbProviderFactory Instance = new ProfiledDbProviderFactory();

So I add a method to initialize the instance:    

        public void InitProfiledDbProviderFactory(MiniProfiler profiler, DbProviderFactory tail)
        {
            this.profiler = profiler;
            this.tail = tail;           
        }

besides above change, in ProfiledDbProviderServices.cs, I change as below ( and 
changed WrappedConnection form internal to public)

        protected override string GetDbProviderManifestToken(DbConnection connection)
        {
            //return tail.GetProviderManifestToken(connection);
            return tail.GetProviderManifestToken(((ProfiledDbConnection)connection).WrappedConnection);
        }

==========================================================================

Original comment by tocha...@gmail.com on 8 Jul 2011 at 1:33

Attachments:

GoogleCodeExporter commented 8 years ago
Continue to Comment #8 :

I have found the reason of execption. That's because EF 4.1 will cache DbSet's 
DbCommandDefinition, so when the 2nd time show the page, it will use the 
profile of last time. CreateDbCommandDefinition is only called first time.

so I just change the private fields of _profiler all changed to 
MiniProfiler.Current, it works.

Original comment by tocha...@gmail.com on 9 Jul 2011 at 3:57

GoogleCodeExporter commented 8 years ago
I get a null reference exception in ProfiledDbProviderFactory.cs Line: 36 in 
your solution (tail is null) - apparently the CreateConnection() method is 
called before/without the InitProfiledDbProviderFactory() being called. Any 
ideas why?

Original comment by krzyszto...@gmail.com on 9 Jul 2011 at 9:10

GoogleCodeExporter commented 8 years ago
Hi @krzyszto...@gmail.com

I uploaded a new version of my solution. it runs well at my environment.

you can try it. the code is not clean, but it works.

Original comment by tocha...@gmail.com on 9 Jul 2011 at 9:27

GoogleCodeExporter commented 8 years ago
@tocha ... would you mind cloning the repo and committing your patch there, 
ideally amending the sample solution to include an EF demo as well? 

to do so view source -> create clone and use tortoise hg to push the code... 

once done I will review and merge in. 

I have had a few complaints about slow EF performance and really want to get to 
the bottom of it, so having a working sample with EF will make a massive diff. 

Note to get SQLite going with EF you need to include the SQLite LINQ dll, which 
is on their website. 

Original comment by sam.saff...@gmail.com on 10 Jul 2011 at 6:08

GoogleCodeExporter commented 8 years ago
@sam,

I'm sorry for I am not familiar with the operations of how to commit code. and 
I'am busy on a working project these days, so I guess I don't have time to 
learn this now.

So I uploaded a zipped file.It is the solution, that include a demo project 
using EF 4.1 Code First. I hope it is useful for you.

please note

1: The solution uses SQL Server Express Edition at my end, but I think you can 
change to other by change connection string at web.config.

2: The ProfiledDbProvider does not support deleting database(this is needed by 
EF 4.1 code first to initalize database), so when you run the solution first 
time, please turn off Mini-profiler (delete MiniProfiler.Start()...) and set 
the EF4.1 Ininializer[new BlogContextInitializer() at Global.asax] to seed the 
database,then compile and run the first time to prepare database, then set the 
initializer to null and turn on Mini-profiler, and compile and run once again , 
then you can see it works and log sql statements.

sorry for my English.I hope my solution is helpful for you. 

Original comment by tocha...@gmail.com on 10 Jul 2011 at 9:13

Attachments:

GoogleCodeExporter commented 8 years ago
@sam,

As far as the performance with EF, I did not find any prolem with my work 
project. this tool is quite helpful for me!

Thank you.

Original comment by tocha...@gmail.com on 10 Jul 2011 at 9:18

GoogleCodeExporter commented 8 years ago
[deleted comment]
GoogleCodeExporter commented 8 years ago
@krzyszto,

did you initialize database firstly?

if you turn off mini-profiler, can your project work?

Original comment by tocha...@gmail.com on 11 Jul 2011 at 3:23

GoogleCodeExporter commented 8 years ago
Yes, and I actually managed to start it up, but on a different machine. Not 
sure if it's the EF version (on the machine I wasn't able to run it I have the 
june ctp installed) or something else

Original comment by krzyszto...@gmail.com on 11 Jul 2011 at 8:04

GoogleCodeExporter commented 8 years ago
@krzyszto

Then I don't know the reason of null exception on your machine ~~ 

I only test the solution on EF 4.1 and use SQL Server Express.

Maybe some others can help ?

Original comment by tocha...@gmail.com on 11 Jul 2011 at 9:14

GoogleCodeExporter commented 8 years ago
I just had a look at that change but it is way off trunk, it reverts way too 
many changes we added, I would like to add it but we need a smaller changeset

Original comment by sam.saff...@gmail.com on 12 Jul 2011 at 12:28

GoogleCodeExporter commented 8 years ago
@sam,

Yes, I just made it run in my project, it's really not a general way. 

The key problem is how to make DbContext know the provider name of wrapped 
connection. When EF 4.1 builds model, it will ask for the provide name. if it 
is EntityClientProvider, it chooses model/database first mode; if any other 
else(for example SqlClientProvider), it choose code first mode. However, it can 
not get the provider name of the ProfiledDbConnection, so it will throw 
exception.

I did not find other way to make connection have provider name except using the 
DbProviderFactory API.

Any one can help?

Original comment by tocha...@gmail.com on 12 Jul 2011 at 12:44

GoogleCodeExporter commented 8 years ago
Has there been any progress on a solution for EF 4.1 support? I see this issue 
is recent so wasn't sure if someone was looking at it more or not.

Stefan

Original comment by stefan.s...@gmail.com on 15 Jul 2011 at 8:58

GoogleCodeExporter commented 8 years ago
I'm also waiting for a fix :)

Original comment by david.ma...@gmail.com on 18 Jul 2011 at 3:41

GoogleCodeExporter commented 8 years ago
I just fixed this ... will update the doco shortly ... thanks tocha! 

Original comment by sam.saff...@gmail.com on 19 Jul 2011 at 4:18

GoogleCodeExporter commented 8 years ago
Hello, 

I've just installed the latest nuget package and I'm still having problems, 
although I'm getting a different error:

Unable to find the requested .Net Framework Data Provider.  It may not be 
installed.

   at System.Data.Common.DbProviderFactories.GetFactory(String providerInvariantName)
   at MvcMiniProfiler.Data.ProfiledDbConnection.get_DbProviderFactory() in C:\Users\sam\Desktop\mvc-mini-profiler\MvcMiniProfiler\Data\ProfiledDbConnection.cs:line 73
   at System.Data.Common.DbConnection.get_ProviderFactory()
   at System.Data.Common.DbProviderServices.GetProviderFactory(DbConnection connection)
   at System.Data.Common.DbProviderServices.GetProviderServices(DbConnection connection)
   at System.Data.Entity.ModelConfiguration.Utilities.DbConnectionExtensions.GetProviderInfo(DbConnection connection, DbProviderManifest& providerManifest)
   at System.Data.Entity.DbModelBuilder.Build(DbConnection providerConnection)
   at System.Data.Entity.Internal.LazyInternalContext.CreateModel(LazyInternalContext internalContext)
   at System.Data.Entity.Internal.RetryLazy`2.GetValue(TInput input)

Perhaps I'm not doing it right, but my code works fine when I use a normal 
SqlConnection as opposed to the Profiled one. Here is my code:

        private static DbConnection GetConnection()
        {
            Database db = DatabaseFactory.CreateDatabase("ProjectQueryService");

            return ProfiledDbConnection.Get(db.CreateConnection());
        }

        private ProjectQueryContext CreateProjectQueryContext()
        {
            var context = new ProjectQueryContext(GetConnection());

            return context;
        }

        public class ProjectQueryContext : DbContext
        {
             public DbSet<ProjectSummary> Projects { get; set; }

             public ProjectQueryContext(DbConnection connection) 
                 : base(connection, true)
             { 

             }
        }

    <add name="ProjectQueryService"
         providerName="System.Data.SqlClient"
         connectionString="integrated security=true;server=P008728;database=PMPoC;" />

I'm currently learning EF 4.1 so if I'm going about this the wrong way then any 
pointers appreciated!

Original comment by david.ma...@gmail.com on 19 Jul 2011 at 8:12

GoogleCodeExporter commented 8 years ago
@david.ma 

did you set the provider in web.config as document describes?

Original comment by tocha...@gmail.com on 19 Jul 2011 at 8:19

GoogleCodeExporter commented 8 years ago
No I haven't so I guess that's the problem... I'm probably being a bit of a 
dunce here, but where is this document?

Original comment by david.ma...@gmail.com on 19 Jul 2011 at 8:25

GoogleCodeExporter commented 8 years ago
http://code.google.com/p/mvc-mini-profiler/  the middle part of the page.

Original comment by tocha...@gmail.com on 19 Jul 2011 at 8:30

GoogleCodeExporter commented 8 years ago
Thanks - it doesn't error anymore :)

However, I don't seem to have any SQL query profile info shown on my page, just 
code that I've wrapped in a step?

I've got this in my Application_Start():

    var factory = new SqlConnectionFactory(); 
    var profiled = new ProfiledDbConnectionFactory(factory);
    EFDatabase.DefaultConnectionFactory = profiled;

Then I've just created a new instance of my DbContext:

    var context = new ProjectQueryContext();

...

    public class ProjectQueryContext : DbContext
    {
        public DbSet<ProjectSummary> Projects { get; set; }

        public ProjectQueryContext()
            : base("QueryDatabase")
        {

        }
    }

Is there anything I'm missing?

Original comment by david.ma...@gmail.com on 19 Jul 2011 at 10:22

GoogleCodeExporter commented 8 years ago
By the way, just in case you're wondering... EFDatabase = Database in the 
System.Data.Entity namespace - I had to alias it.

Original comment by david.ma...@gmail.com on 19 Jul 2011 at 10:23

GoogleCodeExporter commented 8 years ago
Yes, I think you miss something.

You need create a ProfiledDbConection, then pass it to your Context.

you can download this, and check how to do it:
http://mvc-mini-profiler.googlecode.com/issues/attachment?aid=570000000&name=Min
iProfilerCodeFirst.zip&token=c04380bf07b3463577eb47d322eada18

And, please check issue 
57(http://code.google.com/p/mvc-mini-profiler/issues/detail?id=57), I reported 
there are still some problems when MiniProfiler work with EF 4.1 Code First, 
but that's not big problem, you can work around it.

Original comment by tocha...@gmail.com on 19 Jul 2011 at 10:32

GoogleCodeExporter commented 8 years ago
I am experiencing the same behavior - I cloned the repo and tried to run the 
sample. First I got a null reference exception in ProfiledDbProviderFactory.cs 
Line: 80 (tail is null) but after specifying the connection string in 
web.config I got rid of the exception and the profiler run without errors, but 
without any sql data either (see attached screenshot).

I tried to provide the connection like in the sample from tocha, but then got 
the same null reference - that goes for both a sql server compact and sql 
express connections

Original comment by krzyszto...@gmail.com on 19 Jul 2011 at 10:40

Attachments:

GoogleCodeExporter commented 8 years ago
Brilliant, thanks. All is working great now :D

Original comment by david.ma...@gmail.com on 19 Jul 2011 at 11:06

GoogleCodeExporter commented 8 years ago
David what did you change to get this working as I am also not seeing any 
Database profiling results?

Original comment by B...@marastat.com on 19 Jul 2011 at 10:28

GoogleCodeExporter commented 8 years ago
Can you please try latest, I just committed a bunch of fixes 

Original comment by sam.saff...@gmail.com on 20 Jul 2011 at 12:34

GoogleCodeExporter commented 8 years ago
Great! Thank you Sam!

Original comment by tocha...@gmail.com on 20 Jul 2011 at 2:03

GoogleCodeExporter commented 8 years ago
[deleted comment]
GoogleCodeExporter commented 8 years ago
hi! im using the v1.6 with MySql. When i launch the site, this is what i get:

1) DatabaseExists n'est pas pris en charge par le fournisseur.
2) Table 'test.edmmetadata' doesn't exist

after that, everything is ok. For the first error, i guest its something that 
is not provided by MySql (i use MySql Connector v6.3.6)

for the second one, i saw the note in the wiki page that EF Code First will 
store table metadata in a table called EdmMetadata but im not sure how to solve 
that!

another question, i see that in your global.asax, you use 
ProfiledDbConnectionFactory:

    var factory = new SqlConnectionFactory(); 
    var profiled = new ProfiledDbConnectionFactory(factory);
    EFDatabase.DefaultConnectionFactory = profiled;

what's the difference if i use it like that? is it doing the same thing?:

    DbConnection connection = new MySql.Data.MySqlClient.MySqlConnection("connectionString");
    DbConnection profiledConnection = MvcMiniProfiler.Data.ProfiledDbConnection.Get(connection);
    EFUnitOfWorkFactory.SetObjectContext(() => new MTO.Test.Data.EF.Entities(profiledConnection));

alex

Original comment by alex.jo...@hotmail.com on 20 Jul 2011 at 2:59

GoogleCodeExporter commented 8 years ago
I am also using EF 4.1 with MySql and the error message in English is
DatabaseExists is not supported by the provider.

Also as a note the MySql provider does not store table metadata in EdmMetadata 
as it will not generate the DB for you on the fly.

If I just set the DefaultConnectionFactory with the following code.

            var factory = new MySqlConnectionFactory();
            var profiled = new MvcMiniProfiler.Data.ProfiledDbConnectionFactory(factory);
            System.Data.Entity.Database.DefaultConnectionFactory = profiled;

I don't get any errors or any actually profiling of the SQL.

I am also specifying a profiled DBConnection which then throws the errors.

  DbConnection wrappedConnection = new MySqlConnection(ConfigurationManager.ConnectionStrings["Stats.Data.DB"].ConnectionString);
                    return new DB(MvcMiniProfiler.Data.ProfiledDbConnection.Get(wrappedConnection));

Also just for reference below is the MySqlConnectionFactory that I created.

    public class MySqlConnectionFactory: IDbConnectionFactory
    {
        public System.Data.Common.DbConnection CreateConnection(string nameOrConnectionString)
        {
            return new MySqlConnection(ConfigurationManager.ConnectionStrings[nameOrConnectionString].ConnectionString);
        }
    }

Original comment by B...@marastat.com on 20 Jul 2011 at 4:37

GoogleCodeExporter commented 8 years ago
i forgot to tell on my comment #37 that the sql profiling work with my settings.

Original comment by alex.jo...@hotmail.com on 20 Jul 2011 at 2:06