NoSQL with LiteDB
Welcome back. In this part of the tutorial series we'll be covering storing and displaying our post data in NoSQL. Specifically we'll be using LiteDB. Why LiteDB? Because it's simple, fast lightweight and easy to understand for all skill levels.
First thing's first we obviously have to install the LiteDB nuget package.
open up a command prompt or terminal emulator in your project folder and run:
dotnet add package LiteDB
Setting up LiteDB
Create a new folder inside of your models folder and name it Repos
(short for repositories), inside of that folder create a new file named BlogRepo.cs
. This class will serve as the default repository, in it we'll store all of our posts for now and maybe some more collections later.
Let's open up the file and create a new repo class
using System;
using LiteDB;
using System.Collections.Generic; // Required for using collections such as List
namespace Blog.Models.Repos{
public class BlogRepo{
public LiteDatabase DB {get;set;}
public LiteCollection<Post> Posts {get;set;}
public BlogRepo() {
DB = new LiteDatabase(@"Data/Blog.db");
Posts = DB.GetCollection<Post>("posts");
}
}
}
And that's all you need to create the database in question. Now let's create a new folder named Data in the root of our project directory, this is where all of our database files will be stored.
Let's go into our HomeController.cs
and add
using Blog.Models.Repos;
Then let's initialize the repo class in our Index action method with:
public IActionResult Index(){
BlogRepo blogRepo = new BlogRepo();
return View();
}
If we run our asp.net blog application now and go to http://localhost:5000/ we'll see that a new file named Blog.db
has been automatically created in our Data folder. However much like me before my coffee, it is completely empty and useless. Remove the repo initialization from our Index action and let's go back to our BlogRepo.cs
class.
Sample Data
For the purposes of this tutorial we'll be creating some sample data and storing it in our newly created database file. To achieve this simply create a new method in the BlogRepo.cs
class named CreateExamplePosts
public void CreateExamplePosts(){
List<Post> PostList = new List<Post>(){
new Post(){
Title = "First post",
Public = true,
CoverImagePath = "", // leave this blank for now
Excerpt = "Define the underlying",
Content = "Define the underlying principles that drive decisions and strategy for your design language bleeding edge onward and upward"
// The above text was generated by Office Ipsum http://officeipsum.com/index.php
},
new Post(){
Title = "Second post",
Public = true,
CoverImagePath = "", // still blank
Excerpt = "so what's our",
Content = "so what's our go to market strategy?. Customer centric all hands on deck yet where the metal hits the meat define"
},
new Post(){
Title = "Not visible",
Public = false,
CoverImagePath = "", // blank
Excerpt = "not important",
Content = "not important, you should not see this post"
},
new Post(){
Title = "Third post",
Public = true,
CoverImagePath = "", // blank
Excerpt = "the underlying",
Content = "the underlying principles that drive decisions and strategy for your design language not the long pole",
Deleted = true // this one should also not be visible
},
new Post(){
Title = "Fourth post",
Public = true,
CoverImagePath = "", // blank
Excerpt = "in the future",
Content = "Post scheduling made super easy",
Created = DateTime.Now.AddDays(3) // Post scheduling made easy
}
};
try{
// This will ensure that the title of the post is unique
// since we're going to be using it later in the URL
Posts.EnsureIndex(p => p.Title, true);
Posts.EnsureIndex(p => p._id, true);
// Finally let's insert all these posts into the database
Posts.InsertBulk(PostList);
}catch(LiteDB.LiteException ex){
// we'll simply ignore any exceptions that might happen here for now
}
}
Everything up there should be pretty self explanatory, except perhaps for the post that is scheduled for the future. For the purposes of this tutorial I've made it always default to DateTime.Now.AddDays(3)
which means that you'll be able to see the post 3 days after you first called the CreateExamplePosts()
method. Obviously I do not expect you to wait that long, if you wish to see it work you can simply change the AddDays(3)
part to AddMinutes(x)
x being the number of minutes you are willing to wait.
The try catch at the end ensures that if you accidentally run this method multiple times it won't show an ugly exception page telling you that the title index has to be unique and there can be no duplicate titles. Which is what we've set by calling
Posts.EnsureIndex(p => p.Title, true);
Okay, so if you run your asp.net blog application now, nothing about your database will change because we never really called the method itself. If you wish to ensure that the example data is always available you can call this method from your Startup.cs
class or you can simply throw it in the Index
action of our HomeController
class like such:
public IActionResult Index(){
BlogRepo blogRepo = new BlogRepo();
blogRepo.CreateExamplePosts();
return View();
);
}
Run the application once, then delete the blogRepo.CreateExamplePosts();
part. Unless you wish for it to try and add our example data every time you or your user visits the root of your blog page.
Displaying The Blog Posts
Okay so now that our database is filled with example data let's actually try and display it.
Remember the
return View();
part of our HomeController's index action? Well, it can take multiple parameters such as
string viewName
which tells it where to look for the razor html file to display
object model
which tells it what data to pass to said razor html file.
Change the return View();
part to
return View(blogRepo.Posts.Find(
p => p.Public == true &&
p.Created <= DateTime.Now &&
p.Deleted == false)
);
What we are doing here is calling a LiteDB method that allows us to find all the results from the collection that fit certain parameters. The query is fairly simple and self explanatory but let's go through it just in case.
-
p =>
the => or the lambda operator separates input parameters from the lambda body. -
p.Public == true
specifies a condition that has to be met by the data we're looking for, in this case the fieldPublic
of the modelPost
has to be set to true. -
&&
simply means we wish to specify an additional condition -
p.Created <= DateTime.Now &&
the fieldCreated
of the modelPost
has to be smaller than<
or equal to=
DateTime.Now
-
p.Deleted == false
the fieldDeleted
of the modelPost
has to be false
So in other words we are asking the method .Find()
to find all posts who are public, were posted either before this exact moment or at this exact moment and are not soft deleted.
Simple enough to understand right?
Aaaaand if we run our ASP.NET blog application nothing will really change, that is because we still need to tell our razor view how to display the data that we've just set it.
The View
No, still not the show.
Open up our Index.cshtml
file inside of our Views/Home
folder and add a new section to the bottom of it like this:
<section class="posts">
@foreach (var post in Model){
<div class="post">
<h2>@post.Title</h2>
<p>@post.Excerpt</p>
<a href="@post.Title.Replace(' ','-')">read more</a>
</div>
}
</section>
Rebuild and run your ASP.NET blog application and you should see 2 of the posts that we've created as part of our example data.
This means everything worked out great!
Now as you can see we've added <a href="@post.Title.Replace(' ','-')">read more</a>
this will be useful in our next tutorial where we'll be setting up individual views for our Posts.
If you have any questions or issues feel free to contact me at @arctekdev
Top comments (8)
Hi! Something seems to be missing from the Index view. Where does the Model take the values?
Do you have the Github Repo with full code?
PS: I like this tutorial!
Hiya Zoltan
No it's all there
That right there is all that's required, below that point I explain what the query itself does.
as for the github repo, not yet but I'll most likely create one today as I write the 4th part.
I am referring to the html view, not the controller, there's missing something, if I follow part 1,2 and 3. You just iterate through something in the view, but show me the whole file, maybe in the header, @model xyz... is missing? Waiting for the GitHub repo, take your time, I am just studying this, no urgency.
That is odd, I'll gladly create the repo right now for you to look at.
There ya go:
github.com/arctekdev/AspNetBlog
It works now, thanks!
\o/ all right! What was the issue if I may ask?
I was playing around with the controller, and I forgot to add a .ToList(), I did a bit different version than yours.
Awesome, glad you're experimenting, it's the best way to learn imho