4.2 Implementing the Post Repository
Now that we know how we will store our data, we can finally implement this in our repositories. We'll start with the post repository.
1.Introduction2 lessons, 05:56
2.Managing Posts3 lessons, 38:13
3.Tag Management2 lessons, 27:29
4.Storing Data3 lessons, 47:22
5.Testing Functionality2 lessons, 33:06
6.User Management3 lessons, 1:11:48
7.Security and User Authentication2 lessons, 34:17
8.Enhancing the User Experience2 lessons, 36:38
9.The Front-End2 lessons, 36:01
10.Conclusion1 lesson, 01:22
4.2 Implementing the Post Repository
Now, that we finally have a way of storing our data we need to write the code for our post and tag repositories. We're going to start with our post repository because we already have a class for that. And, we're going to start with the easiest method, the Get method. Let's first of all get rid of the models and then dot because I like to just have the class name. So we will need a using statement for our model's namespace. But here we basically want to create our database context, so we will use a using statement, var db = new CmsContext(). And then we want to return the appropriate information, so return db.Posts. We need to include all of the author information because just about every time that we want to display one or multiple posts, we also need that author information to display as well. So here we will use the Include method, and we will simply specify Author. And then we want the SingleOrDefault method. This is going to be perfect for this Get method, because it will return null if one doesn't exist. Otherwise, it will return the post. So we want the post where the post.Id is equal to the value of the id parameter. So the next easiest method is the GetAll method. So we want to start the same way, we want to create our database context and the reason why I'm doing it this way, such as opening a database connection, essentially, and then closing it, is because we really don't want any open connections. Because of Entity Framework, we could very easily be doing database work behind the scenes inside of our views, and we don't really want to do that. We want our repositories to give us information, and then all of the database stuff should be done by that time. So let's create our db variable. We want to, once again, new up our CmsContext. And here we can return db.Posts, we need the include method, where we will include the author. And whenever we retrieve all of the posts, we usually want them in descending order according to the date that they were created. So we can use the OrderByDescending method. And we will specify the Created property. And we should go ahead and use the ToArray method or we could also do ToList. I like to use ToArray whenever I'm returning an IEnumerable of something. And the reason why we are doing this is so that that query is automatically executed and we get those results. Otherwise, we will run into some issues because this OrderByDescending is an operator that is not executed, until we enumerate over the collection. So because we automatically do that with the ToArray method, we don't have to worry about any of that. So now, let's focus on the Edit method. The first thing we need is another database context. So let's just copy that code from another method and let's paste it in. And then we want to retrieve the post with this ID. So let's call this variable post, and we will use db.Posts and then SingleOrDefault, and we want the post where the Id equals to the value of the id parameter. Now, it's possible that this post is null, so if it is null, then we can do a variety of different things. We could just return but that's not very useful. Instead, we could throw a new KeyNotFoundException. Now ideally we would have an exception that is explicitly for our PostRepository class or for a Repository in general. But for right now this is going to be fine and, let's have a message that says that a post with the id of, and then we will concatenate our id, does not exist in the data store. That's a little bit longer but, at least that is descriptive as to what's going on. Let's put this on two lines so that it all fits on one screen. And if we do have a post then we want to update that with the information from our updated item. So the first thing we need to update is the id, so post.Id = updatedItem.Id. But remember that the Id is actually part of the URL itself, so this needs to be made URL friendly. And probably the easiest way to do that is to write an extension method because we're also going to have to do this with our our tags as well. So let's go to our solution explorer, and inside of our Models name space, let's add a new class that's called StringExtensions. And we need to make this a public static class. We also need public static. This is going to return a string. And let's call this, MakeUrlFriendly. And since this is an extension method for string objects, this string and let's just call the parameter value. So, the first thing we need to do is make this lower case. So value equals value.ToLower, we'll use the ToLowerInvariant method, and while we're here, we can go ahead and get rid of all of the spaces in this string, and we can replace them with a dash. So will use the Replace method. We want to replace a space with a dash, but we should also remove everything that is not an alphanumeric character. So let's do value = Regex. We need a using statement for System.Text.RegularExpressions. And we will use the replace method we want this value as our first argument. And then for our regular expression, we basically want to omit everything that is 0 through 9 and then a through z and the dash as well. And we're going to replace everything that is not one of those with an empty string and then we will return the value. So we can go back to our post repository and we can do post.Id = updatedItem.Id.MakeUrlFriendly. Although this really isn't safe because it could be possible that Id is blank in which case we need to take the title and then convert that Into a URL-friendly value. So let's do this, var newId = updatedItem.Id. And then we will check to see if the newId is null or empty. Actually, let's do white space. We'll pass in the newId, and that is not the correct method. IsNullOrWhiteSpace and if it is, then we will set newId=updatedItem.Title. And then instead of setting the post.Id = updatedItem.Id, we will use the newId and we will make that URL friendly. And then we update the other properties, so post.Title = updateItem.Title. We don't want to modify the created or the author. So that just leaves the Content = updatedItem.Content and then the date published. So Published = updatedItem.Published. We also need to say the tags, so post.Tags = updatedItem.Tags. And we need to make these URL-friendly as well. So we can use the select method and we want to call the MakeUrlFriendly method on each one of those tags. And because tags is an IList, we want to use the ToList method. And then we want to save our changes. So we will use our context and it's save changes method. Now, I should mention that we are completely encapsulating the units of work pattern inside of a repository. Entity Framework is built upon the unit of work, and in masterfully designed software, you don't see it done this way. You see the units of work used in conjunction with a repository, but in our case, we're keeping things as simple as possible, so it's okay for us to be doing this. Ideally, we wouldn't, but that also requires a lot more code. Let's move on to the Create method. The first thing we need is our context so once again let's copy that code from another method and paste it in and we should first of all check to see if we have a post with an id of our model. Now let's make sure that we're not doing this inside of the controller because if we are we need to change it because that should really be done inside of the repository. So here's the create method for post requests. We check if the model is invalid and then we just call the create method. So no, we don't have to make any changes here. So let's first of all query the data base, db.Posts, and we want the single or default methods, and we want to check to see if the p.Id is equal to model.Id. And then if post is not null then we need to throw an exception because there is already a post with this given Id. So throw new and really there's nothing specific for this case. But let's do an argument exception. And we can say that A post with the id of, and then concatenate the ID, or rather model.id and then already exists. But, if it doesn't exist, then we want to add it to our database. But we need to do a few things first. We need to ensure that the ID is URL-friendly, but first, we need to check to see if the ID is null or whitespace, because if it is, we need to assign it the value of our title. So, if string.IsNullOrEmpty(model.Id), then model.Id = model.Title. And then we will set model.Id = model.Id, and then we will call the MakeUrlFriendly method. And we don't have to do anything with the title, or the content, or the date. But we do need to do something with the tags, so we can say model.Tags = to model.Tags and once again we will select the tags and call the MakeUrlFriendly method on each one of those tags and then we want to call the ToList method. And then we need to save this object to the database so we will use db.Posts.Attach we will pass in the model object. And then Db.savechanges. Although now that I think about it, we really shouldn't be doing this type of stuff inside of the repository. Because a repository is for putting something in, getting something out and modifying something that's already there. We shouldn't be massaging data or anything like that we should be passing a completed post object to our post repository. So this type of stuff we should be doing inside of the controller or if we had a service layer we should be doing it inside of there. So let's take that code and let's put it inside of our controller. So the first thing we want to do in our create method for for post requests, is to check the model state which we are doing, then we can paste that code in. So we are checking the model.Id, we are assigning it the title, if it doesn't exist then we make the ID url friendly, we make the tags URL friendly, and then we create that post. But here we need a try. So we will wrap this code within a try. So if Create is successful, then we will redirect to the index action. Otherwise, we can have a blanket exception catch. Because, if we have an exception, then we want to go back to the view. Hopefully, the only exception that we would have would be that the Id already exists. But we don't need to do any type of, http not found or anything like that. We just want to go back to the view. So with a blanket exception catch, we can do that and we need to add an error to our model state, so modelState.AddModelError. For the key, we will just have key and we can pass the exception object itself. And then we need to return the view passing in the model. And we basically need to do the same type of thing inside of the Edits method for post requests. So we can take this same code. Let's go to the Edits method. Now, we no longer want to check to see if a post with a given Id already exists because we are doing that inside of the repository. So we can take that code out and we will, first of all, check the model state. Then we will massage our data. But here, we want our try, so we will try to edit the post. But if that is not successful, we will have two catches here. The first catch will be for the key not found exception and in this case we want to return the http not found because we get this exception if the post Id is not a valid Id. In which case the resource doesn't exist so we return http not found. But if we have any other type of exception, let's just go back to the view. So, we will once again add an error to our ModelState with the AddModelError method. The key doesn't matter. But we will pass in the exception object, and we also need to return to the view. And we will pass in the model there. So let's look at everything else. That should be all that we need for the Edits method. The Edit method for the GetRequest We are retrieving the post, if it doesn't exist HTTP not found, otherwise we send that to the view. That is complete. So let's move on up. Let's see this Create method we just wrote, so we'll go to the other Create method. We no longer need to pre-populate with the tags, that was just for testing purposes. So in fact, we don't even need this model variable. We can just pass in a new post object and that will be fine. And, for the index we retrieve all the posts and pass them to the view. I don't think we have a view for the index, so that is something that we will definitely need to add later. But that should be all that we need to do right now for our post controller. Let's go back to our post repository. We need to modify the Edit method because we no longer want to do all of this massaging of data. We basically want to take the Id from our updated item. And assign that to the post Id. So we will do that right there. We don't need to do anything with the tags. So we can just assign the tags to tags. And then save our changes. So that should be everything that we need to do for our post repository and post controller right now. In the next lesson, we're going to look at our tag repository. We of course are going to implement that, but we also need to duplicate some of that functionality to our post repository. Because if you'll remember, we have the ability to delete tags but we don't for posts. So we will do all of that in the next lesson.