LiteDB - A .NET embedded NoSQL database

10/20/2022
6 minute read

In this article we will have a closer look at LiteDB, a .NET NoSQL Document Store in a single data file. We will discover the advantages of LiteDB and why it is a viable candidate for your next project.

We will also explore what are the differences between a NoSQL and a classical SQL database are and what this has to do with the reminiscent SQL CE or the more modern SQLite database.

LiteDB

LiteDB is a document store, which get's saved into a single file. That means that all your data resides in a single file. If you remember the good old timesCitation needed you might remember SQL Server Compact, which is also a single file database based on the SQL Server. A modern version would be SQLite, which is also a single-file database. All of them are server-less, that means you don't need to install anything additional, which then runs in a background thread and does all the work. This simplicity enables a wide variety of scenarios (especially for rapid prototyping).

Some more points, which are listed on their GitHub page:

  • Serverless NoSQL Document Store
  • Simple API, similar to MongoDB
  • 100% C# code for .NET 4.5 / NETStandard 1.3/2.0 in a single DLL (less than 450kb)
  • Thread-safe
  • ACID with full transaction support
  • Data recovery after write failure (WAL log file)
  • Datafile encryption using DES (AES) cryptography
  • Map your POCO classes to BsonDocument using attributes or fluent mapper API
  • Store files and stream data (like GridFS in MongoDB)
  • Single data file storage (like SQLite)
  • Index document fields for fast search
  • LINQ support for queries
  • SQL-Like commands to access/transform data
  • LiteDB Studio - Nice UI for data access
  • Open source and free for everyone - including commercial use

These are perfect preconditions to just try it out and use it right away, because we don't have to setup anything. Now you might ask yourself, What would be typical use-cases for this?.

  • Mobile Apps (Xamarin ready)
  • Desktop/local applications
  • Application file format
  • Smaller web applications
  • One database per account/user data store

If you checked out the LiteDB website you often see NoSQL and that almost sounds like SQL, so before we deep diver with code, we should clarify what this two terms mean.

To SQL or to NoSQL - that is the question

NoSQL stands for not only SQL. That means in contrast to SQL, which stands for structured query language, NoSQL stores in a more dynamic way. Not only means that we can also use SQL language to ask for data, but there are also other ways. Traditionally SQL databases store data in a relational structure, mainly in tables with columns, which then can refer to other tables. In case of LiteDB we store the data in documents. Documents are roughly JSON objects. Each document contains pairs of key's and their corresponding values.

So if we have a C# object like this:

public class BlogPost
{
    public string Title { get; set; }
    public string Content { get; set; }
    public bool IsPublished { get; set; }
    public string List<string> Tags { get; set; }
}

Then a typical document representing that data in a document database could look like this:

{
  "Title": "LiteDB - A .NET embedded NoSQL database",
  "Content": "This article contains a lot of information.",
  "IsPublished": true,
  "Tags": [
    ".NET",
    "NoSQL",
    "LiteDB"
  ]
}

Now the same in a traditional table and column-based SQL database wouldn't be that easy to model. Every 1 to n relationship has to be modified with a new table and foreign key relations. As the document database are "loose" in terms of structure we had no trouble modelling this, plus the structure mirrors our "real C#" entity.

Of course we simplify here a bit. On top we most probable have a unique identifier and some metadata about the object in question, but these are more details than we need right now. Hopefully you can see that it's super easy to get hierarchical data we have in our application. Everything is concise together in one object.

Comparison

Some concepts

Before we create a small application let's discuss some first baby steps, which we then later can use to create a real application. The first thing we have to do, when we want to use LiteDB is to reference the nuget package.

dotnet add package LiteDB --version 5.0.12

Or alternatively just copy and paste this part into your csproj:

<ItemGroup>
  <PackageReference Include="LiteDB" Version="5.0.12" />
</ItemGroup>

That is all to make LiteDB work. You don't need a running server or interface. That is what is meant with serverless. Everything is done by that package - so everything runs in-process alongside your application.

The second thing we have to do is to create the connection to the database, which we can do with the following command:

using var database = new LiteDatabase("database.db");

This will give us a database object, on which we can operate. If database.db does not exist in the current direct, LiteDB will create that file and open it afterwards. As initially said it is no problem if you have multiple things accessing the database at the same time as it thread-safe. That also applies for lots of the operations, especially reading from the database.

Reading from a collection is also very trivial:

var entry = database.GetCollection<MyCollection>().FindById(2);

Also pretty straightforward especially if you have a background in ORM's like Entity Framework. If we take the analogy database is our DbContext in EF and GetCollection<T> represents the DbSet<T> which we define inside our specific DbContext in EF.

We also have the power of LINQ to fetch and filter data.

var todoItems = db.GetCollection<TodoItems>().Query();

var itemsWhichShouldBeDoneByToday =
    (from item in todoItems
    where !item.IsDone && item.DeadLine <= DateTime.Now
    select item).ToList();

Of course you can also use the method chaining instead of the query language. The core idea is, that Query() returns you a IQueryable which let's you use all the power of LINQ and friends.

In the resources you will find a full-blown application, which shows how to use LiteDB a bit more in detail. We will create a small blog in a console application.

LiteDB async

One thing you might have noticed until now: All the methods I used are synchrnous. There is no await db.GetCollection<BlogPost>().ToListAsync() or friends. For scalability, especially if you have a ASP.NET Core Web App, you should consider the asynchrnous paradigm. Not only that, even if you have a regular desktop application, async makes sense, as it doesn't block the UI thread. LiteDB itself doesn't offer asynchrnous, but there is a community project, which does that: litedb-async.

LiteDB Studio

As initially said there is also a LiteDB Studio. With this UI tool you can submit queries to your "database". If you are coming from a SQL world, you can use all your well-known SQL queries and they are still working with LiteDB. There is unfortunately one big disadvantage at the moment: The studio does run only under Windows. The reason is simple: First it runs under the .NET Framework 4.7.2, which is only supported by Windows and second it is a WinForms application.

Conclusion

I hope I could give you a nice introduction into LiteDB and why it is a viable candidate for your next project.

Resources

Are my EF LINQ to SQL queries safe?

Have you ever asked yourself if your EF LINQ queries are susceptible to SQL injection attacks? Either because you are querying some user data from a text field or directly taking whatever your API hits against the database?

Multi-Tenancy with RavenDB and ASP.NET Core

Multi-tenancy is a software architecture pattern where a single instance of a software application is used by multiple customers, with each customer having separate and isolated data, configurations, and resources. RavenDB is a NoSQL document database that provides a flexible and scalable solution for multi-tenant applications. This blog post will explore why multi-tenancy exists, the advantages of using RavenDB for multi-tenant applications, and provide code examples to get you started.

Delete a record without prior loading in Entity Framework

Sometimes you have an Id of an object and want to delete the underlying thing from the database. But it doesn't make sense to load the whole object from the database to memory first. So how can we achieve this quickly?

An error has occurred. This application may no longer respond until reloaded. Reload x