11

I'm trying to use the new mvc-mini-profiler with my EF4 based app, but I have no idea how to properly get a connection to my destination datasource.

Here's as far as I have gotten.

Func<IMyContainer> createContainer = () =>
{
    var profiler = MiniProfiler.Current;

    if (profiler != null)
    {
        var rootConn = // ????
        var conn = ProfiledDbConnection.Get(rootConn);
        return ObjectContextUtils.CreateObjectContext<MyContainer>(conn);
    }
    else
    {
        return new MyContainer();
    }
};

kernel.Bind<IMyContainer>().ToMethod(ctx => createContainer()).InRequestScope();

How do I get a connection to an EF container, without the contianer itself? I would just new-up a SqlConnection, except that the connection string is wrapped in all of the EF junk.

John Gietzen
  • 48,783
  • 32
  • 145
  • 190

3 Answers3

4

Slightly less hacky way:

private static SqlConnection GetConnection()
{
    var connStr = ConfigurationManager.ConnectionStrings["ModelContainer"].ConnectionString;
    var entityConnStr = new EntityConnectionStringBuilder(connStr);
    return new SqlConnection(entityConnStr.ProviderConnectionString);
}


Amendment by John Gietzen:

This combination of all of the answers should work for ANY backing store that Entity Framework supports.

public static DbConnection GetStoreConnection<T>() where T : System.Data.Objects.ObjectContext
{
    return GetStoreConnection("name=" + typeof(T).Name);
}

public static DbConnection GetStoreConnection(string entityConnectionString)
{
    // Build the initial connection string.
    var builder = new EntityConnectionStringBuilder(entityConnectionString);

    // If the initial connection string refers to an entry in the configuration, load that as the builder.
    object configName;
    if (builder.TryGetValue("name", out configName))
    {
        var configEntry = WebConfigurationManager.ConnectionStrings[configName.ToString()];
        builder = new EntityConnectionStringBuilder(configEntry.ConnectionString);
    }

    // Find the proper factory for the underlying connection.
    var factory = DbProviderFactories.GetFactory(builder.Provider);

    // Build the new connection.
    DbConnection tempConnection = null;
    try
    {
        tempConnection = factory.CreateConnection();
        tempConnection.ConnectionString = builder.ProviderConnectionString;

        var connection = tempConnection;
        tempConnection = null;
        return connection;
    }
    finally
    {
        // If creating of the connection failed, dispose the connection.
        if (tempConnection != null)
        {
            tempConnection.Dispose();
        }
    }
}
Mark Bell
  • 28,985
  • 26
  • 118
  • 145
Steve Johnstone
  • 576
  • 3
  • 16
  • That may be the best yet. Is there a way to "magically" determine whether we want to use the SqlConnection class, or... the OracleConnection class, for example? – John Gietzen Jun 27 '11 at 13:28
  • The entity connection string has a Provider property, so you could use that in a switch statement and instantiate the connection differently depending on the provider. Then just set the return type to DbConnection and I think you'll be good to go. – Steve Johnstone Jun 27 '11 at 16:49
  • 1
    I found a more elegant way, see the `DbProviderFactories` class. – John Gietzen Jun 27 '11 at 20:01
2

Here is a slightly better performing, but slightly hackier solution to getting the store connection.

    public static DbConnection GetStoreConnection<T>() where T : System.Data.Objects.ObjectContext
    {
        return GetStoreConnection("name=" + typeof(T).Name);
    }

    public static DbConnection GetStoreConnection(string entityConnectionString)
    {
        DbConnection storeConnection;

        // Let entity framework do the heavy-lifting to create the connection.
        using (var connection = new EntityConnection(entityConnectionString))
        {
            // Steal the connection that EF created.
            storeConnection = connection.StoreConnection;

            // Make EF forget about the connection that we stole (HACK!)
            connection.GetType().GetField("_storeConnection",
                BindingFlags.NonPublic | BindingFlags.Instance).SetValue(connection, null);

            // Return our shiny, new connection.
            return storeConnection;
        }
    }
John Gietzen
  • 48,783
  • 32
  • 145
  • 190
1

You have to initialize the connection directly, as such:

var rootConn = new System.Data.SqlClient.SqlConnection(your_connection_string_minus_your_ef_junk);
CassOnMars
  • 6,153
  • 2
  • 32
  • 47
  • That doesn't exactly tell me the "proper" way to do it. – John Gietzen Jun 09 '11 at 17:26
  • This works fine for me too. Just make the SqlConnection and pass it to ObjectContextUtils.CreateObjectContext(rootConn). Done! – Tilendor Jun 20 '11 at 20:28
  • Dim oraConn As New OracleConnection(New EntityConnectionStringBuilder(ConfigurationManager.ConnectionStrings("edmEntities").ConnectionString).ProviderConnectionString) – Andrei Dvoynos Oct 11 '12 at 16:14