Thank you to our sponsors who keep this newsletter free to the reader:
New to C# and .NET, or want a refresher on modern .NET?
C# 11 and .NET 7 - Modern Cross-Platform Development Fundamentals
is a concise, beginner-friendly introduction to the C# language,
.NET libraries, and ASP.NET Core.
QuadSpinner Highlighter is an open-source Visual Studio extension that lets you highlight important objects and arbitrary texts to help you navigate your code more easily.
Did you know you can turn PostgreSQL into a fully-fledged Document database?
Marten is a .NET library that allows developers to use the PostgreSQL database as both a document database and a fully-featured event store.
You don't need to install anything else to be able to use PostgreSQL as a document database, outside of the Nuget package. Marten relies on the JSONB support available since PostgreSQL 9.4.
In this week's newsletter, I want to introduce you to the basics of working with Marten and show you how easy it is to get started.
Let's dive in.
Installing And Configuring Marten
What are you going to need to start using PostgreSQL as a Document datbase?
Other than a running instance of PostgreSQL, of course, you will need to install the Marten Nuget package:
dotnet add package Marten
Marten can build the required database schema and necessary tables on the fly, and I suggest using this approach in development. For a production environment, you definitely want to apply schema changes on your own with migration scripts.
To register Marten with dependency injection, you need to call the AddMarten
method.
Here's an example Marten configuration inside of a .NET 7 application:
builder.Services.AddMarten(options =>
{
options.Connection(builder.Configuration.GetConnectionString("Marten"));
});
This will register a few services with dependency injection:
IDocumentStore
- used to create sessions, generate schema migrations, and do bulk insertsIDocumentSession
- used for read and write operationsIQuerySession
- used for read operations
Let's see how we can work with documents using Marten.
Storing Documents With Marten
Storing documents in the database is very straightforward. You need to create
a new DocumentStore
instance, and open an IDocumentSession
which exposes
methods for storing and persisting documents.
Let's see how we can store a Product
document:
var store = DocumentStore.For("Connection string to PostgreSQL");
using var session = store.OpenSession();
var product = new Product
{
Name = "C# 11 and .NET 7 - Modern Cross-Platform Fundamentals",
Price = 46.87
};
session.Store(product);
await session.SaveChangesAsync();
We're creating a new DocumentStore
instance which we use to open
a session to PostgreSQL. And then we just call Store
and pass in
the Product
instance. Note that Marten will populate the
Product.Id
at this point. Marten can populate keys of Guid
,
int
, long
, and other data types. It uses the HiLo algorithm
for numeric keys. Finally, when we call SaveChangesAsync
the
Product
is serialized into JSON and persisted as a document.
An important thing to be aware of is that the IDocumentSession
created by OpenSession
doesn't track changes on the entities automatically.
You need to create a session with dirty checking enabled by
calling DirtyTrackedSession
on the DocumentStore
to enable
automatic change detection.
Querying Documents With Marten
Marten has rich support for querying documents in the database. You can write and execute queries using LINQ, which you are familiar with if you worked with EF Core. And you can also write and execute SQL queries, because it's still a PostgreSQL database underneath.
Here's an example query to return products that have a higher price than the one which is specified:
var store = DocumentStore.For("Connection string to PostgreSQL");
using var session = store.QuerySession();
var products = session.Query<Product>().Where(p => p.Price > 9.99).ToList();
Marten also has support for:
- Including related documents
- Batched queries
- Paging
- Full text search
Advanced Options With Marten
Marten can utilize the full capabilities PostgreSQL has to offer, notably transactions and indexing. Marten sessions are transactional by default, either all of the documents are persisted together or none of them are. And you can configure indexes on your documents for faster queries.
Marten isn't just a document database on top of PostgreSQL!
You have fully-fledged support for event sourcing with Marten, as well as projections. This makes it a perfect choice for implementing CQRS. But this is a topic for a separate newsletter.
Closing Thoughts
I'm absolutely amazed with Marten and what it has to offer. And PostgreSQL is also my favorite database, so it's like a match made in heaven. I don't get too excited about learning new technologies, but Marten has been an endless source of joy this past week.
I still need to explore a few more topics before I can consider it for production use:
- Schema migrations
- Relationships and foreign keys
- Advanced configuration options
Considering that PostgreSQL is cheaper than most document databases, I think using Marten is an interesting alternative. And if you are familiar with SQL databases, you can still use all of that knowledge.