Skip to content

Custom DB Providers

Stelio Kontos edited this page Sep 25, 2023 · 6 revisions

If you need to work with a database type that doesn't have a built-in DatabaseProvider in PetaPoco, you can write your own in a separate assembly.

Custom providers should usually inherit from PetaPoco.Providers.DatabaseProvider. That class shows you all the things you can override, and the existing providers in the Providers directory give you examples of how a provider needs to be customized for a given database type.

(You can also inherit from one of the built-in providers if you just need a more specialized version.)

Sample

Here's some sample code for a custom provider.

public class FooDatabaseProvider : DatabaseProvider
{
    public override DbProviderFactory GetFactory()
    {
        // Need to specify class and assembly of the DbProviderFactory
        return GetFactory("Foo.Data.Provider.FooFactory, Foo.Data.Provider");
    }

    public override string GetParameterPrefix(string connectionString)
    {
        // This database prefixes parameters in SQL statements with : instead of @
        return ":";
    }

    public override object ExecuteInsert(Database db, IDbCommand cmd, string primaryKeyName)
    {
        // This database doesn't return a row ID on an INSERT for us to return to the caller,
        // so just perform the insert and return -1
        ExecuteNonQueryHelper(db, cmd);
        return -1;
    }

    public override string BuildPageQuery(long skip, long take, SQLParts parts, ref object[] args)
    {
        // Paged queries aren't supported by this provider
        throw new NotSupportedException("The Foo provider does not support paging.");
    }
}

Usage

Out of the box, you can use a provider like the one above with the fluent configuration syntax.

var config = DatabaseConfiguration.Build()
    .UsingConnectionStringName("MyConnection")
    .UsingProvider<FooDatabaseProvider>();
using (var db = config.Create())
{
    ...
}

You can also use the constructor that lets you pass in a provider instance.

var connectionString = "some connection string";
using (var db = new Database(connectionString, new FooDatabaseProvider()))
{
    ...
}

If you want to use any of the other Database constructors, you need to do a little more so that PetaPoco's internal methods know about your provider. The static method DatabaseProvider.RegisterCustomProvider<T>() lets PetaPoco know that when the database type or data provider name starts with a given string, it should use your provider.

// app.config has <add name="MyDb" connectionString="..." providerName="Foo.Data.Provider" />

DatabaseProvider.RegisterCustomProvider<FooDatabaseProvider>("Foo");
using (var db = new Database("MyDb"))
{
    // PetaPoco sees that providerName starts with Foo
    // and knows which database provider to instantiate
    ...
}

To make things simpler for consumers of your custom provider, you can add a static method to your class so that it knows how to register itself.

public class FooDatabaseProvider : DatabaseProvider
{
    public static void Register()
    {
        DatabaseProvider.RegisterCustomProvider<FooDatabaseProvider>("Foo");
    }

    // etc.
}

// And then somewhere in your application startup code do
FooDatabaseProvider.Register()