8

Is there a way to make the EFTracing provider work with EF 4.1?

EFTracing seems to need an objectcontext and I use dbcontext.

Thanks in advance!

w4ik
  • 1,276
  • 2
  • 19
  • 33
eka808
  • 2,257
  • 3
  • 29
  • 41

3 Answers3

12

Whilst the previous answers work, I've found them problematic, a much simpler solution is to use the Clutch.Diagnostics.EntityFramework package from NuGet that uses MiniProfiler behind the scenes. It is significantly simpler to get working than EFTracingProvider, and a much more flexible solution.

The project is on GitHub at https://github.com/Kukkimonsuta/Clutch

For EFTracingProvider like functionality install the NuGet package and then implement IDbTracingListener like this:

using System;
using System.Data.Common;
using System.Diagnostics;
using Clutch.Diagnostics.EntityFramework;

/// <summary>
/// 
/// </summary>
public class DbTracingListener : IDbTracingListener
{
    /// <summary>
    /// 
    /// </summary>
    /// <param name="connection"></param>
    /// <param name="command"></param>
    /// <param name="result"></param>
    /// <param name="duration"></param>
    public void CommandExecuted(DbConnection connection, DbCommand command, object result, TimeSpan duration)
    {
        Debug.WriteLine(command.CommandText);
        Debug.WriteLine(string.Format("Executed in: {0}", duration));
    }

    /// <summary>
    /// 
    /// </summary>
    /// <param name="connection"></param>
    /// <param name="command"></param>
    public void CommandExecuting(DbConnection connection, DbCommand command)
    {

    }

    /// <summary>
    /// 
    /// </summary>
    /// <param name="connection"></param>
    /// <param name="command"></param>
    /// <param name="exception"></param>
    /// <param name="duration"></param>
    public void CommandFailed(DbConnection connection, DbCommand command, Exception exception, TimeSpan duration)
    {

    }

    /// <summary>
    /// 
    /// </summary>
    /// <param name="connection"></param>
    /// <param name="command"></param>
    /// <param name="result"></param>
    /// <param name="duration"></param>
    public void CommandFinished(DbConnection connection, DbCommand command, object result, TimeSpan duration)
    {

    }
}
RTPeat
  • 640
  • 6
  • 13
  • 5
    This was a lifesaver. Thanks so much. For those who are interested, you don't even necessarily have to create a DbTracingListener. You can also just do something as simple as this: `Clutch.Diagnostics.EntityFramework.DbTracing.Enable(new GenericDbTracingListener().OnFinished(c => Log(c.Command.ToTraceString())));` where Log is whatever function you write to log the Sql Text. I put this in the constructor of my Entities (i.e. DbContext) class for a WCF Data Services project and it's working fine. – Nate Cook Jun 22 '13 at 20:01
12

Yes, you can. I'm using the community version with both database-first DbContexts and code-first DbContexts. This answer is based on a discussion thread on the project site.

For database-first/designer DbContexts (via ADO.NET DbContext Generator templates), you can simply add the following constructor:

public abstract class MyDbContext : DbContext
{
    protected MyDbContext(string nameOrConnectionString)
        : base(EFTracingProviderUtils.CreateTracedEntityConnection(nameOrConnectionString), true)
    {
        // enable sql tracing
        ((IObjectContextAdapter) this).ObjectContext.EnableTracing();
    }
}

For code first DbContexts its a bit more complicated since the EFTracingProvider wants a full entity connection string. You have to create an instance of EFTracingConnection manually. The following example will work for both database first and code first contexts.

public abstract class MyDbContext : DbContext
{
    protected MyDbContext(string nameOrConnectionString)
        : base(CreateTracingConnection(nameOrConnectionString), true)
    {
        // enable sql tracing
        ((IObjectContextAdapter) this).ObjectContext.EnableTracing();
    }

    private static DbConnection CreateTracingConnection(string nameOrConnectionString)
    {
        try
        {
            // this only supports entity connection strings http://msdn.microsoft.com/en-us/library/cc716756.aspx
            return EFTracingProviderUtils.CreateTracedEntityConnection(nameOrConnectionString);
        }
        catch (ArgumentException)
        {
            // an invalid entity connection string is assumed to be a normal connection string name or connection string (Code First)

            ConnectionStringSettings connectionStringSetting =
                ConfigurationManager.ConnectionStrings[nameOrConnectionString];
            string connectionString;
            string providerName;

            if (connectionStringSetting != null)
            {
                connectionString = connectionStringSetting.ConnectionString;
                providerName = connectionStringSetting.ProviderName;
            }
            else
            {
                providerName = "System.Data.SqlClient";
                connectionString = nameOrConnectionString;
            }

            return CreateTracingConnection(connectionString, providerName);
        }
    }

    private static EFTracingConnection CreateTracingConnection(string connectionString, string providerInvariantName)
    {
        // based on the example at http://jkowalski.com/2010/04/23/logging-sql-statements-in-entity-frameworkcode-first/
        string wrapperConnectionString =
            String.Format(@"wrappedProvider={0};{1}", providerInvariantName, connectionString);

        EFTracingConnection connection =
            new EFTracingConnection
                {
                    ConnectionString = wrapperConnectionString
                };

        return connection;
    }
}
jrummell
  • 42,637
  • 17
  • 112
  • 171
  • 1
    I had some issues with the above, but this is a very workable solution and jrummell saved me tones of time by posting the solution to the hardest part of the problem. More information about this can be found on the discussion tread on codeplex here: http://efwrappers.codeplex.com/discussions/262707 – Stephen M. Redd Aug 13 '11 at 21:58
  • jrummel : really thank you for your help, i can finally use 4.1 instead of 4.0 :-) – eka808 Sep 06 '11 at 08:33
  • 1
    The Clutch tracer mentioned by RTPeat in my opinion is much simpler than jumping through all these hoops. I wasted a whole day on this before trying the Clutch tracer and the Clutch tracer was working in 10 minutes. – Nate Cook Jun 22 '13 at 20:04
5

If you are using DBContext and MVC Model First, meaning using EntityConnections then the following sample code should be all you need:

    public partial class BrickHouseFitnessContext : DbContext
{

    public BrickHouseFitnessContext(): base(EntityConnectionWrapperUtils.CreateEntityConnectionWithWrappers(ConfigurationManager.ConnectionStrings["BrickHouseFitnessContext"].ConnectionString, "EFTracingProvider"), true)
    {
    }

Also:

In the Web.Config file add the following sections:

  <system.data>
<DbProviderFactories>
  <add name="EF Tracing Data Provider" invariant="EFTracingProvider" description="Tracing Provider Wrapper" type="EFTracingProvider.EFTracingProviderFactory, EFTracingProvider, Version=1.0.0.0, Culture=neutral, PublicKeyToken=def642f226e0e59b" />
  <add name="EF Generic Provider Wrapper" invariant="EFProviderWrapper" description="Generic Provider Wrapper" type="EFProviderWrapperToolkit.EFProviderWrapperFactory, EFProviderWrapperToolkit, Version=1.0.0.0, Culture=neutral, PublicKeyToken=def642f226e0e59b" />
</DbProviderFactories>

and:

    <add key="EFTracingProvider.logToConsole" value="true" />
<add key="EFTracingProvider.logToFile" value="C:\BrickHouseFitnessSqlLog.txt" />

There is no need to include the ExtendedEntities or the other ObjectContext derived class mentioned in the original article. Run that code and you should see your log file as specified, with all the SQL commands in it. I am bypassing database intialization when tracing is enabled,

Mario
  • 51
  • 1
  • 2