Skip to content

Database Storage

For each top level document type, Marten will generate database objects for:

  • A database table called mt_doc_[document alias], where the document alias is typically derived from the class name of the top level document type
  • A function called mt_upsert_[document alias]
  • A function called mt_update_[document alias]
  • A function called mt_insert_[document alias]
  • A function called mt_overwrite_[document alias], an upsert function that bypasses any kind of configured optimistic concurrency checks

Overriding the Database Schema

By default, all of the document type tables will be created and used from the public schema. That can be overridden globally with this usage:

cs
var store = DocumentStore.For(opts =>
{
    opts.Connection("some connection string");
    opts.DatabaseSchemaName = "other";
});

snippet source | anchor

If you choose, you can override the default database schema name for the DocumentStore by explicitly setting the schema for an individual document type through the MartenRegistry fluent interface like this:

cs
var store = DocumentStore.For(opts =>
{
    opts.Connection("some connection string");
    opts.DatabaseSchemaName = "other";

    // This would take precedence for the
    // User document type storage
    opts.Schema.For<User>()
        .DatabaseSchemaName("users");
});

snippet source | anchor

Or by using an attribute on your document type:

cs
[DatabaseSchemaName("organization")]
public class Customer
{
    [Identity] public string Name { get; set; }
}

snippet source | anchor

Type Aliases

In the not unlikely case that you need to disambiguate table storage for two or more documents with the same type name, you can override the type alias either programmatically with MartenRegistry:

cs
var store = DocumentStore.For(_ =>
{
    _.Connection(ConnectionSource.ConnectionString);

    _.Schema.For<User>().DocumentAlias("folks");
});

snippet source | anchor

or by decorating the actual document class with an attribute:

cs
[DocumentAlias("johndeere")]
public class Tractor
{
    public string id;
}

snippet source | anchor

Table Partitioning 7.26

WARNING

You may want to do manual database migrations if introducing partitioning into an existing database that does not currently use partitioning as it may require some system downtime to rebuild the document or event storage.

Marten has some direct support for utilizing and managing table partitioning with the underlying PostgreSQL database as a way to optimize your application by letting PostgreSQL largely query against smaller tables when you commonly query against a certain document member.

Marten allows you to define table partitions for:

In all cases, the table partitioning is:

  1. 100% "opt in", meaning that you have to explicitly tell Marten to do the partitioning
  2. Automatically migrated by Marten when the configured partitions are different than the actual database with all the normal Marten database migration tooling

To partition the storage for a document table on an arbitrary document member, use this syntax:

cs
var store = DocumentStore.For(opts =>
{
    opts.Connection("some connection string");

    // Set up table partitioning for the User document type
    opts.Schema.For<User>()
        .PartitionOn(x => x.Age, x =>
        {
            x.ByRange()
                .AddRange("young", 0, 20)
                .AddRange("twenties", 21, 29)
                .AddRange("thirties", 31, 39);
        });

    // Or use pg_partman to manage partitioning outside of Marten
    opts.Schema.For<User>()
        .PartitionOn(x => x.Age, x =>
        {
            x.ByExternallyManagedRangePartitions();

            // or instead with list

            x.ByExternallyManagedListPartitions();
        });

    // Or use PostgreSQL HASH partitioning and split the users over multiple tables
    opts.Schema.For<User>()
        .PartitionOn(x => x.UserName, x =>
        {
            x.ByHash("one", "two", "three");
        });

    opts.Schema.For<Issue>()
        .PartitionOn(x => x.Status, x =>
        {
            // There is a default partition for anything that doesn't fall into
            // these specific values
            x.ByList()
                .AddPartition("completed", "Completed")
                .AddPartition("new", "New");
        });

});

snippet source | anchor

Released under the MIT License.