Fork me on GitHub

Next

Documentation

Previous

Marten

Getting Started Edit on GitHub


First, go get the Marten library from Nuget:

PM> Install-Package Marten

Or, using paket:

paket add nuget Marten

Or, using .Net CLI

dotnet add package Marten

The next step is to get access to a PostgreSQL 9.5+ database schema. If you want to let Marten build database schema objects on the fly at development time, make sure that your user account has rights to execute CREATE TABLE/FUNCTION statements.

Marten uses the Npgsql library to access PostgreSQL from .NET, so you'll likely want to read their documentation on connection string syntax.

Adding Marten to a .Net Core Application

Note! There's a very small sample project in the Marten codebase that shows the mechanics for wiring Marten into a .Net Core application.

By popular demand, Marten 3.12 added extension methods to quickly integrate Marten into any .Net Core application that uses the IServiceCollection abstractions to register IoC services.

In the Startup.ConfigureServices() method of your .Net Core application (or you can use IHostBuilder.ConfigureServices() as well) make a call to AddMarten() to register Marten services like so:


public class Startup
{
    public IConfiguration Configuration { get; }

    public Startup(IConfiguration configuration)
    {
        Configuration = configuration;
    }

    // This method gets called by the runtime. Use this method to add services to the container.
    // For more information on how to configure your application, visit https://go.microsoft.com/fwlink/?LinkID=398940
    public void ConfigureServices(IServiceCollection services)
    {
        // This is the absolute, simplest way to integrate Marten into your
        // .Net Core application with Marten's default configuration
        services.AddMarten(Configuration.GetConnectionString("Marten"));
    }

    // and other methods we don't care about right now...

See Integrating Marten into .Net Core Applications for more information and options about this integration.

Bootstrapping a Document Store

To start up Marten in a running application, you need to create a single IDocumentStore object. The quickest way is to start with all the default behavior and a connection string:


var store = DocumentStore
    .For("host=localhost;database=marten_testing;password=mypassword;username=someuser");

Now, for your first document type, let's represent the users in our system:


public class User
{
    public Guid Id { get; set; }
    public string FirstName { get; set; }
    public string LastName { get; set; }
    public bool Internal { get; set; }
    public string UserName { get; set; }
    public string Department { get; set; }
}


For more information on document id's, see Document Identity.

And now that we've got a PostgreSQL schema and an IDocumentStore, let's start persisting and loading user documents:


// Open a session for querying, loading, and
// updating documents
using (var session = store.LightweightSession())
{
    var user = new User { FirstName = "Han", LastName = "Solo" };
    session.Store(user);

    session.SaveChanges();
}

// Open a session for querying, loading, and
// updating documents with a backing "Identity Map"
using (var session = store.OpenSession())
{
    var existing = session
        .Query<User>()
        .Where(x => x.FirstName == "Han" && x.LastName == "Solo")
        .Single();
}

// Open a session for querying, loading, and
// updating documents that performs automated
// "dirty" checking of previously loaded documents
using (var session = store.DirtyTrackedSession())
{
}

Integrating Marten with IoC Containers

Note! Lamar supports the .Net Core abstractions for IoC service registrations, so you could happily use the AddMarten() method directly with Lamar.

The Marten team has striven to make the library perfectly usable without the usage of an IoC container, but you may still want to use an IoC container specifically to manage dependencies and the life cycle of Marten objects.

Using Lamar as the example container, we recommend registering Marten something like this:


public class MartenServices : ServiceRegistry
{
    public MartenServices()
    {
        ForSingletonOf<IDocumentStore>().Use(c =>
        {
            return DocumentStore.For(options =>
            {
                options.Connection("your connection string");
                options.AutoCreateSchemaObjects = AutoCreate.None;

                // other Marten configuration options
            });
        });

        // Register IDocumentSession as Scoped
        For<IDocumentSession>()
            .Use(c => c.GetInstance<IDocumentStore>().LightweightSession())
            .Scoped();

        // Register IQuerySession as Scoped
        For<IQuerySession>()
            .Use(c => c.GetInstance<IDocumentStore>().QuerySession())
            .Scoped();
    }
}

There are really only two key points here:

  1. There should only be one IDocumentStore object instance created in your application, so I scoped it as a "Singleton" in the StructureMap container
  2. The IDocumentSession service that you use to read and write documents should be scoped as "one per transaction." In typical usage, this ends up meaning that an IDocumentSession should be scoped to a single HTTP request in web applications or a single message being handled in service bus applications.

There's a lot more capabilities than what we're showing here, so head on over to Documentation to see what else Marten offers.

Using Marten to create databases

Marten can be configured to create (or drop & create) databases in case they do not exist. This is done via store options, through StoreOptions.CreateDatabasesForTenants.


storeOptions.CreateDatabasesForTenants(c =>
{
    // Specify a db to which to connect in case database needs to be created.
    // If not specified, defaults to 'postgres' on the connection for a tenant.
    c.MaintenanceDatabase(cstring);
    c.ForTenant()
        .CheckAgainstPgDatabase()
        .WithOwner("postgres")
        .WithEncoding("UTF-8")
        .ConnectionLimit(-1)
        .OnDatabaseCreated(_ =>
        {
            dbCreated = true;
        });
});

Databases are checked for existence upon store initialization. By default, connection attempts are made against the databases specified for tenants. If a connection attempt results in an invalid catalog error (3D000), database creation is triggered. ITenantDatabaseCreationExpressions.CheckAgainstPgDatabase can be used to alter this behaviour to check for database existence from pg_database.

Note that database creation requires the CREATEDB privilege. See PostgreSQL CREATE DATABASE documentation for more.