4.3 Writing the Tag Repository
Our tag repository will be different from typical repositories (like our post repository). We'll implement it in this lesson.
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.3 Writing the Tag Repository
Our tag repository is going to be a little different from a typical repository for two reasons. First of all we don't have an actual entity for our tags, our tags are simply strings. And then second our tags are stored inside of the posts table, so in order to retrieve the tags we are going to have to first of all retrieve the posts. So we have this I tag repository interface, so obviously we need a concrete tag repository. So let's go to our data folder, let's add a new class and let's just call it tag repository. Now of course we want to implement the ITagRepository interface and probably the first method we should implement is the GetAll method, because this will probably be the easiest thing. So first of all, we need our database context, so let's create that db variable. We want a new up CmsContext and then we want to retrieve all of our posts, because that is the only way that we can retrieve all of our tags. So we want to return db.posts and then we are going to call the SelectMany method because we are going to select each post's tag's property. And if you'll remember this tags property already has some logic inside of it, it's taking the value from the database and automatically splitting that value on a comma, so we end up with an IEnumberable of string. And the select many method is going to take all of those IEnumerable of strings and join them into a single collection so that all that we have to do is call the distinct method that will allow us to get only the unique tags. Because as far as the GetAll method is concerned, we just want those unique tags, we're not concerned with any duplicates at that point. Now the Exists method is probably something that we will get rid of, just to keep things consistent with what we implemented in our post repository. Because all of the checking to see if things existed were done inside of the repository, and then we re-factored our post controller to handle exceptions. So we will probably do the same thing for our tag repository and tag controller, but for now we will leave the Exists method and then we will remove it whenever we need to. Now for the edit method, we first of all need our context, so let's copy that from the GetAll method, let's paste it inside of the edit method, and then we want to retrieve all of our posts with the given tag because in order to update the tags, we have to update the posts, because the tags are part of the post. So we want db.posts we use the where operator and we want the posts where the tag contains the existing tag, but we should also ensure that we are doing a comparison that ignores case. So we can use a string comparer and we have a variety of choices, we can use CurrentCultureIgnoreCase, InvariantCultureIgnoreCase, or OrdinalIgnoreCase. Let's do CurrentCultureIgnoreCase, and then we want to enumerate this collection. So we will go ahead and execute that query, and we can use the ToList method. That's going to be fine although i think the two arrays should be fine as well. So let's break this up into different lines so it kinda makes sense as to what's going on on a single screen here. And then we want to loop over our posts, so let's use a for each loop var post in posts. And then we want to remove the existing tag and then add in the new tag and the order really doesn't matter here so we can do post.Tags and then Remove and then we specify the existing tag, and then we can add in the new tag so post.Tags.Add(newTag). And then we simply want to update the database. So we've made our changes, now we need to save it. So we call db.SaveChanges() and that should be it for the edit method. Now I'm not exactly sure how entity framework is going to like this little bit of code here, so we're going to have to test it, see what it does and doesn't like and then go from there. And the delete method is going to be very similar, in fact it's going to be almost the same except that we are not adding in a new tag. So we can basically copy and paste the code from our edit method. Let's get rid of the code that adds the new tag and then we just need to change the variable names. So instead of existingTag, we have tag and that will delete a tag from our data store. Now one thing we haven't done here is any checking to see if we have a post with a given tag. Like for the edits method. If we get to this for each loop and we don't have any posts, then we don't have any posts with that tag, thus the tag doesn't exist. So here we could check to see if not posts.Any, then we can throw an exception. So throw new and in this case we can use the KeyNotFoundException. We can say that the tag and then concatenate existing tag and then does not exist and that will allow us to catch this exception inside of the controller and then we can return an HTTP not found result in that case. And we can do the same thing for the delete method, so we can just copy that, and before the for each loop we will paste it in. We need to change this variable name to tag and that should be it for our repository. So let's go to our tag controller and here we are using this exists method, although in this case, this is a good place to use it because this is the edits method that handles get requests. And we are given a tag and we want to just ensure that that tag exists. So yeah, we could keep this method but my fear is that we are going to forget that the edits method and the delete method will automatically check for us, so I don't want to call Exists, and then call Edit, or Exists and then Delete. Because that's hitting the database two times, and we don't really need to in those cases. So, we could do something like this, we could have a try, and then var model equals underscore repository and we can call the get method. Now of course we don't have that method yet, but we can pass the tag to that method and then that will give us the tag, or it will at least ensure that the tag exists. So then if it does we can return view and then passing the tag, although we could do model. And then we can have a catch and we could see if we catch a NotFoundException and in which case we would simply return HttpNotFound. So that's a little bit better, I think. So let's get rid of this other code, and let's get this get method inside of our repository. So we can replace our exists method. So we can change the return type to string, we can change the name to Get, and we will keep the parameter, so that means we need to go back to the concrete repository, and we need to modify this exists method. And we basically need to do what we did inside of the edits method, except we don't need to enumerate over the posts or anything like that, we simply want to get the posts and check to see if we have any posts. After this call to posts.any, although we need to change these variable names, then we can simply return the tag. So, return tag. Something else that we could do is just get to one of the posts, and then return the actual tag, but in this case, this is going to be fine. And if we wanted to, we could say ToLower and that would match the value that we have in the database. So now let's go back to our tag controller and let's look at some of the other methods. So we have the edit method for post requests and this logic is a little different, we are retrieving all of the tags. We check to see if the existing tag is not within our tags and, if so, then we get a not found. We also check to see if the new tag is inside of our tags, if it is, then we simply redirect to the index, because we don't need to do anything there, but if validation passes, then we do the editing. So, we are essentially hitting the database two times, one to retrieve all of our tags, the other to edit the tags, and I guess in this case, that's okay. Although ideally we would probably be doing this inside of the repository and we might end up doing that. But for now, let's leave that because that's going to add a lot of extra complexity to our repository and I don't want to do that right now, I'll just be honest. Okay, so now we go to our delete method. Now we no longer have this exists method, but this is the delete method that handles the get request. So we can basically take what we have for our edit method, and then copy and paste that into this delete method, because it's a essentially the same thing. We're using the get method just to ensure that we have a tag with that value and then we are passing that to the view, otherwise we are returning an HTTP not found result. But the Delete method for our Post request is going to be a little bit different because now We can simply call the delete method, and then wrap that around a try, and if everything is okay then, that's fine. And then we can catch the KeyNotFoundException and if we have that exception, then we know that that does not exist so we can return HTTP not found. And I think that's all that we need to do for our tag controller and repository, so let's close these files. And we need to go to our post repository and controller because we need to add the functionality for deleting a post. So let's open up those files. We also need the I post repository open as well because we need to specify a delete method. So we can go ahead and say void delete and then, post model. Or, you know what, we probably won't have the post, all we really need is the id so we can have string id. And, if later we recognize that we do need a post, we could also add an overload there. So, let's go to our post repository, and let's implement that method. So, we want public void Delete(string id), and we need our database context, so let's copy that and paste it in. Then we want to retrieve the post with a given ID, so we can do post, or db.posts, and then SingleOrDefault, and for our lambda expression, p.Id equals to id. Then we can check to see if post is equal to null, and if it is, then we will throw a new KeyNotFoundException and we will say that the post with the id of, and then concatenate id does not exist. But if we do have a post then we want to delete it. So we have db.Posts, then we Remove that post, and then we save the changes with db.SaveChanges. So we now can go to our post controller and we want to add the delete methods and we can probably start with the edits methods, those are going to be very similar. So here is the get version of edits, there's the post version. Let's copy all of this code and, then let's paste it and, of course we need to change the names, so let's start with the get version. Let's call this delete, let's also change the route to delete, that's kind of important. It's also change this comment just to keep things consistent there. And here, we are retrieving the post, if it's not null, then, we get HTTP not found, otherwise we pass that post to the view. So, that's okay. And then, for the post request. So, we call this method Delete, let's change the route to Delete, as well as this comment. Now we don't really need the model here so we can get rid of that parameter. We don't really need to check the model state because there's really nothing to check. We only have the post id, and that is what we are going to use to delete. So we can get rid of basically all of this code except for when we start using our repository. So instead of calling the delete method or the edit method, we call the delete, passing in the post id and then we redirect to the index action method. Otherwise, if the post is not found, we return HTTP not found, and if an exception did happen, then let's not catch that. Ideally, we would, and display a useful message, but let's not catch that. And that should be it for our post controller and our post repository. Although I have a feeling we will probably add one more method to our post repository, and that is to retrieve the posts with a given id or with a given tag, rather, but we will do that whenever we actually need that method. So now we just need to finalize everything with our tag and post controllers, as well as our repositories, because we haven't done any testing on those repositories. So there are a few views that we need to create and then we will just ensure that everything behaves as they should. And we will do that in the next lesson.