title: Providing an on-the fly custom db provider for EF
body: <p>As part of a profiling tool, I have a custom ADO.NET stack that acts as a "decorator" around standard ADO.NET, so it doesn't actually do any <em>work</em> - it just passes on the calls (but with logging, etc). Among other things, I have provided a <code>DbProviderFactory</code> from my custom connection that implements <code>IServiceProvider</code> and supplies a custom <code>DbProviderServices</code>.</p>
  
  <p>This works great for most tools, including LINQ-to-SQL - however, Entity Framework is not happy.</p>
  
  <p>For example - say I have:</p>
  
  <pre><code>MetadataWorkspace workspace = new MetadataWorkspace(
       new string[] { "res://*/" }, 
       new Assembly[] { Assembly.GetExecutingAssembly() });
  using(var conn = /* my custom wrapped DbConnection */)
  {
      var provider = DbProviderServices
            .GetProviderServices(conn); // returns my custom DbProviderServices
      var factory = DbProviderServices
            .GetProviderFactory(conn); // returns my custom DbProviderFactory
      ...
  </code></pre>
  
  <p>so far so good - the above two lines work; the correct (custom) provider info is returned.</p>
  
  <p>Now we can add an EF model:</p>
  
  <pre><code>    using (var ec = new EntityConnection(workspace,conn))
      using (var model = new Entities(ec))
      {
          count = model.Users.Count(); // BOOM!
      }
  </code></pre>
  
  <p>fails with exception:</p>
  
  <blockquote>
    <p>Unable to cast object of type '(my custom connection)' to type 'System.Data.SqlClient.SqlConnection'.</p>
  </blockquote>
  
  <p>which is during assignment of a connection to a command; essentially, it has defaulted to the sql-server provider for the <code>SSpace</code>, and generated a naked <code>SqlCommand</code>. It is then trying to assign <code>conn</code> to the generated command, which can't work (it <em>will</em> work correctly if all the decorators are in place, and a decorated <code>DbCommand</code> was used instead).</p>
  
  <p>Now, the whole point of wrapping this on the fly means I don't really want to have to change the EDMX to register a separate factory. I just want it to know about my lies, damned lies and decorators.</p>
  
  <p>The following <em>works</em>, by hacking into the guts of <code>SSpace</code> (setting a <code>private readonly</code> field that I have no rights to know about or abuse):</p>
  
  <pre><code>    StoreItemCollection itemCollection =
          (StoreItemCollection)workspace.GetItemCollection(DataSpace.SSpace);
      itemCollection.GetType().GetField("_providerFactory",
          BindingFlags.NonPublic | BindingFlags.Instance)
          .SetValue(itemCollection, factory);
  </code></pre>
  
  <p>With this in place, the correct factory is used by <code>SSpace</code>. However, this is clearly nasty  upon nasty.</p>
  
  <p>So: am I missing a trick here? How can I intercept the EF provider with less drastic measures?</p>