Hello and welcome,
When it comes to databases we have quite a few to select from though most of them either fall under the SQL or NoSQL categories, though we can further break it down into databases that run on a server and databases that can be embedded into our applications.
For the development environment, I found that the best approach (as a personal preference) are embedded databases since they provide a number of benefits like:
- Saving the database in source control, which makes it easier to develop on separate branches without adding complex seeding logic and it’s easier to revert to a previous state.
- It can be loaded into memory. This is of great benefit for automated testing since then we can create tests that actually run against the database constraints.
- As a side note, it happened to me many times that tests would pass but then the application miss-behaved when doing manual testing since mocks and actual entity framework contexts don’t behave the same.
- Doesn’t require special setup.
Of course there is a caveat to this and that is that you might encounter issues going from one system to another so, of course, if you’re going to use a server database in your development environment, you should account for that as well. It all depends on the nature of the project and the development stage of the project.
What is LiteDb?
LiteDb, as the documentation page mentions, is an “Embedded NoSQL database for .NET”.
We won’t be going through all of the features and documentation of the library since I personally think that the author has done quite a good job in covering it. But we will cover some use cases I personally encountered to give you some perspective as to how and for what it can be used for.
To my knowledge, there is no other NoSQL database for .NET that can be embedded, so when I start out an application or a LinqPad script that would require that data be stored in an organized fashion in a file or database, my choices are either SQLite or LiteDb, so the choice boils down as follows:
How easy is it to update the schema or the models?
While working with SQLite, especially on an ongoing development project, I inevitably ended up at modifying the schema of the database. SQLite doesn’t make this easy for me since it doesn’t allow for dropping or altering a column so I end up doing workarounds and hacks to migrate the data to a new schema.
Since LiteDb is a NoSQL database which is schemaless, then I can alter my models more easily and since there are no column restrictions in place then it’s easier to go backward and update the old models without recreating the whole collection (something akin to a table in a SQL environment).
At the moment, the only way to save files in SQL (and implied SQLite) is to either save the file to another location and then store the path to that file in the database or just save the file a byte array and then just stream it, both of which are cumbersome for small applications.
LiteDb has support for saving files directly into the database.
In a SQLite scenario, I would need to retrieve the rows, map them to objects (which can be accomplished easily with an ORM like Entity Framework) then serialize the object in my format of choice and then transmit it. This becomes a bit harder when we have nested objects.
Since LiteDb is based on BsonDocuments (which is a binary JSON that also keeps object metadata intact like inheritance chains), then it’s easy to retrieve a whole object graph and either serialize it to something else like JSON.
Working with streams?
Though I admit I do not know how easy it is to work with SQLite and streams, I do know what LiteDb gives the possibility of working with any kind of stream, that would mean I could load the database from a server using a network stream, or keep the database in memory and write it out if need be. This is useful for client-server applications that need to work offline and sync with the server periodically. If one really want, they could even implement their own kind of stream and use that, like for example an encrypted stream.
Object graphs and foreign keys
While I do admit that SQLite is more ideal when it comes to foreign keys and relationships between models/entities, LiteDb also supports this by the use of references so that you could have one/many-to-one/many relationships across collections. Also as mentioned before, since LiteDb uses BsonDocuments, you might not even need one-to-one relationships if you can embed a document directly into your model, which makes both lookup and updates more efficient.
The author already published a benchmark between LiteDb and SQLite. So from looking at that, the make takeaway is that it’s faster except when doing bulk inserts, indexes and the overall file size of the database.
Support for 3rd party applications
While I do encourage you to go and read the actual documentation page, here are a few features that other people created LiteDb to make your life easier:
- GUI editors
- Like any database, you would require an application to see the contents of a database outside of your application
- Lucene.Net Directory
- If you ever want to index your data based on text, there is a library that adds the support Lucene, which is also the backbone of ElasticSearch
- LinqPad support
- There is a driver that allows you to add a LiteDb database into Linqpad and start running queries against it.
- PowerShell support
- For those who are more accustomed to PowerShell, there is also a library that allows you to interact with the database via PowerShell
How it was used
The latest project in which I user LiteDb was for a LinqPad script that downloads my emails and archives them into that database both as text but also the full raw email with headers and everything with the addition of the attached files.
While it comes down to personal preference, these are a few of the reasons why LiteDb is part of my toolbox and while writing this post, I’m also considering to implement the Lucene part to make it easier to find specific emails via text search.
I hope you enjoyed this review and it made you consider adding LiteDb to your own toolbox as well.
Until next time,