Integrating MvcMiniProfiler and LLBLGenPro

MvcMiniProfiler is a lean and mean mini profiler for MVC 3 that shows the profiling results on each page displayed at runtime. Besides the custom steps you can seed everywhere in your code it supports database profiling as well. Out of the box are supported ado.net, Linq to SQL and Entity Framework. LLBLGenPro, my favorite ORM, isn’t supported though and it won’t work just like that.

Luckily, it turns out, it requires just a little effort to integrate MvcMiniProfiler into LLBLGenPro.

How does MvcMiniProfiler database profiling works

The way it works is that it wraps DbConnection, DbCommand and other Db[Stuff] and thus records the execution time by tracking their inner workings. Here is an example for MvcMiniProfiler documentation about how to start:

public static DbConnection GetOpenConnection()
{
    var cnn = CreateRealConnection(); // A SqlConnection, SqliteConnection ... or whatever

    // wrap the connection with a profiling connection that tracks timings 
    return MvcMiniProfiler.Data.ProfiledDbConnection.Get(cnn, MiniProfiler.Current);
}

If client calls DbConnection.CreateCommand on an ProfiledDbConnection instance returned from previous method it will get a wrapped whatever command original connection returns and so on. There is also a way to manually create DbCommand through ProfiledDbCommand constructor.

The support for Linq To SQL and Entity Framework is done in a similar manner.

This gets us to the point, why can’t I just use the same approach with LLBLGenPro?

Integrate MvcMiniProfiler with LLBLGenPro – why doesn’t work with same approach

The major problem with LLBLGenPro and MvcMiniProfiler integration is that LLBLGenPro doesn’t use DbConnection.CreateCommand method to create commands from existing connection. Instead it creates an instance of proper DbCommand derived class and assigns a connection to it. Thus it won’t work because it would try to assign a ProfiledDbConnection to a i.e. SqlCommand class.

So a bit more work is required to match them.

The code for adapter scenario

1. Create a DynamicQueryEngine derived class. Note: this class is database specific, thus if you work with i.e. SQL Server you’ll find it in SD.LLBLGen.Pro.DQE.SqlServer.NET20.dll assembly.

public class ProfilingDynamicQueryEngine : DynamicQueryEngine
{
    protected override DbCommand CreateCommand()
    {
         DbCommand cmd = base.CreateCommand();
         ProfiledDbCommand pCmd = new ProfiledDbCommand(cmd, null, MiniProfiler.Current);
         return pCmd;
    }
}

Here the DbCommand creation is overriden. Note that I wrap the original cmd and pass a current MiniProfiler instance as arguments to ProfiledDbCommand constructor, while I pass a null for the connection instance because it will be assigned later.

2. Derive from DataAccessAdapter class. Note: this class is generated from a template and you’ll find it in DBSpecificLayer project generated by LLBLGenPro.

public class DataAccessAdapterEx: DataAccessAdapter
{    
    protected override System.Data.Common.DbConnection CreateNewPhysicalConnection(string connectionString)
    {
        DbConnection conn = base.CreateNewPhysicalConnection(connectionString);
        // return ProfiledDbConnection.Get(conn); Pre MvcMiniProfiler 1.9
        return new ProfiledDbConnection(conn, MiniProfiler.Current);
} protected override DynamicQueryEngineBase CreateDynamicQueryEngine() { return PostProcessNewDynamicQueryEngine(new ProfilingDynamicQueryEngine()); } }

Within CreateDynamicQueryEngine I pass the class I’ve created in step #1. CreateNewPhysicalConnection will return a wrapped connection.

Instead of using DataAccessAdapter you should use the one created in step #2 - DataAccessAdapterEx. That’s it.

Conclusion

As it turns out, integrating MvcMiniProfiler with LLBLGenPro is quite easy. And the required coding might be added to LLBLGenPro templates by modifying them, so you won’t have to manually add the same code each time.

Let me know if you have feedback.

Update 19.9.2011: Updated the code because MvcMiniProiler introduced a breaking change in v1.9 (instead of ProfiledDbConnection.Get static method a constructor has to be used - thanks for swift response from David from LLBLGenPro support team)

Comments (11) -

  • martin

    26.7.2011 15:45:39 | Reply

    I'm getting an error.

    Item has already been added. Key in dictionary: '206028056'  Key being added: '206028056'

       at System.Collections.Hashtable.Insert(Object key, Object nvalue, Boolean add)
       at System.Collections.Hashtable.Add(Object key, Object value)
       at Oracle.DataAccess.Client.FetchArrayPooler.PutFetchArray(IntPtr pFetchArray)
       at Oracle.DataAccess.Client.OracleDataReader.Dispose(Boolean disposing)
       at Oracle.DataAccess.Client.OracleDataReader.Close()
       at MvcMiniProfiler.Data.ProfiledDbDataReader.Close() in C:\Users\sam\Desktop\mvc-mini-profiler\MvcMiniProfiler\Data\ProfiledDbDataReader.cs:line 68
       at SD.LLBLGen.Pro.ORMSupportClasses.PersistenceCore.CleanupDataReader(IDataReader reader, IQuery queryExecuted, Boolean disposeReader)
       at SD.LLBLGen.Pro.ORMSupportClasses.PersistenceCore.CleanupDataReader(IDataReader reader, IQuery queryExecuted)
       at SD.LLBLGen.Pro.ORMSupportClasses.DataAccessAdapterBase.ExecuteMultiRowRetrievalQuery(IRetrievalQuery queryToExecute, IEntityFactory2 entityFactory, IEntityCollection2 collectionToFill, IFieldPersistenceInfo[] fieldsPersistenceInfo, Boolean allowDuplicates, IEntityFields2 fieldsUsedForQuery)
       at SD.LLBLGen.Pro.ORMSupportClasses.DataAccessAdapterBase.FetchEntityCollectionInternal(IEntityCollection2 collectionToFill, IRelationPredicateBucket& filterBucket, Int32 maxNumberOfItemsToReturn, ISortExpression sortClauses,

    • Miha Markic

      26.7.2011 17:02:27 | Reply

      Hi martin,

      To me it looks like a problem with Oracle provider or MvcMiniProfiler in combination with it. Does it work without my changes?

      • martin

        26.7.2011 21:42:46 | Reply

        I thougt the same thing too. The oracle provider works flawless without the MvcMiniProfiler implementation. Seems to be a miniprofiler related issue. But on the other side, it works great with the Sql server provider,doesn't it ?

        • Miha Markic

          6.8.2011 17:46:46 | Reply

          Yep, it works with SQL Server. Hopefully MvcMiniProfiler guys will sort it out (assuming there is the problem).

  • William

    18.9.2011 20:17:40 | Reply

    This seems to have broken in miniprofiler 1.9. The following line no longer compiles:
       return ProfiledDbConnection.Get(conn);

    Any ideas on how to fix it?

    • Miha Markic

      19.9.2011 8:27:54 | Reply

      See the updated sources or follow David's link.

  • Rey Rahadian

    13.2.2012 7:32:33 | Reply

    hey Miha,  great post!

    i'm trying to use MvcMiniProfiler with LLBLGen 2.5,  and i'm missing the PostProcessNewDynamicQueryEngine method. could you help me out ?

    • Miha Markic

      13.2.2012 8:52:15 | Reply

      I don't have v2.5 handy but I can suggest you to check out the code generated by LLBLGenPro - DataAccessAdapter. And then implement it accordingly.

Loading