FirebirdSQL / NETProvider

Firebird ADO.NET Data Provider
https://www.firebirdsql.org/en/net-provider/
Other
161 stars 66 forks source link

Suggestion: code example for setting up DbProviderFactories #1048

Closed PhilPJL closed 2 years ago

PhilPJL commented 2 years ago

I'm currently migrating an app from .NET Framework to .NET 6 and for now making the app multi-target. Using EntityFramework.Firebird 9.01 on .NET 4.8 and .NET 6. Problem is that this works fine for .NET 4.8 in app.config, but not supported in .NET 6

    <DbProviderFactories>
      <remove invariant="FirebirdSql.Data.FirebirdClient" />
      <add name="FirebirdClient" description="FirebirdClient" invariant="FirebirdSql.Data.FirebirdClient" type="FirebirdSql.Data.FirebirdClient.FirebirdClientFactory, FirebirdSql.Data.FirebirdClient" />
    </DbProviderFactories>
  </system.data>
  <entityFramework>
    <defaultConnectionFactory type="EntityFramework.Firebird.FbConnectionFactory, EntityFramework.Firebird" />
    <providers>
      <provider invariantName="FirebirdSql.Data.FirebirdClient" type="EntityFramework.Firebird.FbProviderServices, EntityFramework.Firebird" />
      <provider invariantName="System.Data.SqlClient" type="System.Data.Entity.SqlServer.SqlProviderServices, EntityFramework.SqlServer" />
    </providers>

I'll (try to) track down how to do it in code, but would be great if was added to your documentation.

cincuranet commented 2 years ago

Good idea. I'll add that.

In the meantime, you can use this code.

PhilPJL commented 2 years ago

Thanks. Works fine. Shame it doesn't work for .NET 4.8 as well.

PhilPJL commented 2 years ago

My final(-ish) code is

public static void Main(string[] args)
{
...
#if !NETFRAMEWORK
  DbProviderFactories.RegisterFactory(FbProviderServices.ProviderInvariantName, FirebirdClientFactory.Instance);
#else
  var dataSet = ConfigurationManager.GetSection("system.data") as System.Data.DataSet;

  dataSet.Tables[0].Rows.Add("FirebirdClient"
      , "FirebirdClient"
      , "FirebirdSql.Data.FirebirdClient"
      , "FirebirdSql.Data.FirebirdClient.FirebirdClientFactory, FirebirdSql.Data.FirebirdClient");
#endif

  DbConfiguration.SetConfiguration(new FirebirdConfiguration() { });
...
}

private sealed class FirebirdConfiguration : DbConfiguration
{
    public FirebirdConfiguration()
    {
        SetProviderServices(FbProviderServices.ProviderInvariantName, FbProviderServices.Instance);
    }
}

So no need for app.config at all.

Rand-Random commented 2 years ago

Had the same requirement some time ago, did the following

internal class Foo : IFoo
{
    internal class DpResolver : IDbDependencyResolver
    {
        public object GetService(Type type, object key)
        {
            if (type == typeof(DbProviderFactory))
                return FirebirdClientFactory.Instance;
            if (type == typeof(IProviderInvariantName))
                return new DpInvariantName();

            return null;
        }

        public IEnumerable<object> GetServices(Type type, object key)
        {
            return new[] { GetService(type, key) }.ToList().Where(o => o != null);
        }

        class DpInvariantName : IProviderInvariantName
        {
            public string Name { get; } = EntityFramework.Firebird.FbProviderServices.ProviderInvariantName;
        }
    }

    static Foo()
    {
    #if NET47
        System.Data.Entity.DbConfiguration.Loaded += (_, args) =>
        {
            args.AddDependencyResolver(new DpResolver(), true);
        };
    #else
        DbProviderFactories.RegisterFactory(EntityFramework.Firebird.FbProviderServices.ProviderInvariantName, FirebirdClientFactory.Instance);
    #endif
    }
}

Code is ~2years old, don't really remember why I did it this way.

cincuranet commented 2 years ago

Done via 89e3ddb34284bdf6078fbc0d6acd0622f1f0de9a.