1 00:00:00,710 --> 00:00:04,640 Now that we've gone through the process of adding repositories to our web app, 2 00:00:04,640 --> 00:00:07,600 let's talk about the pros and cons of the repository design pattern. 3 00:00:08,762 --> 00:00:12,930 Moving all of our data retrieval and persistence code into a repository. 4 00:00:12,930 --> 00:00:16,970 Or in our case, a collection of repositories helps to simplify and 5 00:00:16,970 --> 00:00:19,640 keep our controllers as lean as possible. 6 00:00:19,640 --> 00:00:24,440 It also helps us to adhere to the dry or don't repeat yourself design principle. 7 00:00:24,440 --> 00:00:29,450 Instead of duplicating EF queries or commands across controller action methods, 8 00:00:29,450 --> 00:00:32,180 we can place that code in a repository method and 9 00:00:32,180 --> 00:00:35,470 call that method from our action methods instead. 10 00:00:35,470 --> 00:00:39,920 But adding repositories to an application adds an additional layer of abstraction 11 00:00:39,920 --> 00:00:43,990 between your controller action methods and the database context. 12 00:00:43,990 --> 00:00:46,730 And in some cases this layer of abstraction can 13 00:00:46,730 --> 00:00:49,970 feel like you're adding complexity without enough of a clear benefit. 14 00:00:51,050 --> 00:00:56,815 As an alternative to using repositories, we can use Query and Command classes. 15 00:00:56,815 --> 00:01:00,845 Query and Command classes encapsulate data persistence code much in 16 00:01:00,845 --> 00:01:02,936 the same way that repositories do. 17 00:01:02,936 --> 00:01:07,766 But when you selectively on an as needed basis they can provide the same benefits 18 00:01:07,766 --> 00:01:11,740 repositories without adding as much complexity. 19 00:01:11,740 --> 00:01:14,150 Let's look at a couple of examples. 20 00:01:14,150 --> 00:01:19,000 Before we add our first class let's add two folders to the shared class library 21 00:01:19,000 --> 00:01:23,010 data folder one named queries and another named commands. 22 00:01:24,600 --> 00:01:29,870 As the folder name suggests we'll add all of our query classes to the queries folder 23 00:01:29,870 --> 00:01:32,960 and all of our command classes to the commands folder. 24 00:01:32,960 --> 00:01:37,110 To make it easier to compare using repositories to using queries and commands 25 00:01:37,110 --> 00:01:41,750 I added another copy of the comic book artist controller class to our project. 26 00:01:41,750 --> 00:01:44,560 And reverted the code back to what it was 27 00:01:44,560 --> 00:01:47,640 before we added our comic book artist repository. 28 00:01:47,640 --> 00:01:51,930 If you're following along you can find a copy of this code in the teacher's notes. 29 00:01:51,930 --> 00:01:54,460 Let's start with the Add.getAction() method. 30 00:01:54,460 --> 00:01:58,030 At the beginning of the method we have a query to retrieve the comic book 31 00:01:58,030 --> 00:02:00,390 that the user is adding an artist to. 32 00:02:00,390 --> 00:02:04,365 When using query in command classes you don't automatically 33 00:02:04,365 --> 00:02:07,346 move every query in command into it's class, 34 00:02:07,346 --> 00:02:11,254 instead you evaluate it's relative complexity and usage. 35 00:02:11,254 --> 00:02:13,713 And make a determination if your code and 36 00:02:13,713 --> 00:02:18,646 overall design will benefit from moving the query or command to it's own class. 37 00:02:18,646 --> 00:02:24,370 This query isn't overly complex but it's used at least twice. 38 00:02:24,370 --> 00:02:30,090 Once here in the ad get action method and once in the ad post action method. 39 00:02:30,090 --> 00:02:34,150 Since it's duplicated and it's what I'd call moderately complex, 40 00:02:34,150 --> 00:02:36,023 let's move it to a query class. 41 00:02:39,650 --> 00:02:43,767 Add a class named get comic book query to the queries folder. 42 00:02:48,567 --> 00:02:51,910 To start, we need a private field for the context. 43 00:02:51,910 --> 00:02:56,609 And a constructor that accepts a context instance and sets the private field. 44 00:02:59,158 --> 00:03:05,693 Private Context _context = null. 45 00:03:05,693 --> 00:03:13,160 Public GetComicBookQuery then a parameter up type Context 46 00:03:13,160 --> 00:03:18,290 named context and set the private field to that parameter value. 47 00:03:20,250 --> 00:03:25,537 Then let's add a method name execute that returns a comic book instance. 48 00:03:25,537 --> 00:03:28,940 And accepts an integer ID value, public. 49 00:03:31,361 --> 00:03:37,460 ComicBook Execute, int id. 50 00:03:37,460 --> 00:03:41,280 For the implementation we can switch back to the ControllerAction method. 51 00:03:44,939 --> 00:03:46,901 And copy the query to the clipboard. 52 00:03:50,955 --> 00:03:53,980 Add return and then paste the query from the clipboard. 53 00:03:56,150 --> 00:03:57,910 We've got some things to fix up here. 54 00:03:59,130 --> 00:04:03,922 Change context to, _context. 55 00:04:06,482 --> 00:04:10,109 ComicBookId to just id. 56 00:04:13,032 --> 00:04:18,112 And we need to add using directive for the system data 57 00:04:18,112 --> 00:04:22,973 entity namespace, using System.Data Entity. 58 00:04:25,234 --> 00:04:29,380 Now we're ready to update the action method to use our new query class. 59 00:04:29,380 --> 00:04:35,374 Remove the existing query, instantiate an instance of the GetComicBookQuery class, 60 00:04:35,374 --> 00:04:37,159 new GetComicBookQuery. 61 00:04:39,644 --> 00:04:43,310 Add a using directive for the ComicBookSharedDataQueries 62 00:04:43,310 --> 00:04:47,860 namespace passing the context property from the base controller class. 63 00:04:47,860 --> 00:04:53,955 And call the execute method, passing in the comicBookId parameter value. 64 00:04:58,616 --> 00:05:02,484 Then in the add post action method we can replace the query to set the view 65 00:05:02,484 --> 00:05:06,695 viewModel's ComicBook property with another instance of our query class. 66 00:05:13,031 --> 00:05:17,247 Now let's review the remaining EF queries in commands that are being used in this 67 00:05:17,247 --> 00:05:17,991 controller. 68 00:05:17,991 --> 00:05:20,823 And determine if any of them would be good candidates for 69 00:05:20,823 --> 00:05:23,630 moving to their own query or command classes. 70 00:05:23,630 --> 00:05:26,022 Remember we only want to create query or 71 00:05:26,022 --> 00:05:29,799 command classes to encapsulate complex or duplicated code. 72 00:05:32,028 --> 00:05:35,563 In the add post action method we've got some code related to add in 73 00:05:35,563 --> 00:05:37,330 a comic book artist. 74 00:05:37,330 --> 00:05:42,580 This code isn't repeated anywhere else and its relatively simple. 75 00:05:42,580 --> 00:05:46,030 So let's go ahead and just leave it as it is. 76 00:05:46,030 --> 00:05:50,860 In the delete get action method we've got a query to retrieve a comic book artist. 77 00:05:50,860 --> 00:05:54,490 This query is about the same level of complexity as the query that we 78 00:05:54,490 --> 00:05:56,790 just moved to a query class. 79 00:05:56,790 --> 00:06:00,080 But for now it's only used in this one location. 80 00:06:00,080 --> 00:06:03,770 Again for simplicity's sake let's leave it as it is. 81 00:06:05,220 --> 00:06:07,730 In the delete post action method we've got 82 00:06:07,730 --> 00:06:10,690 code related to deleting a comic book artist. 83 00:06:10,690 --> 00:06:15,200 But again it's relatively simple and it's not repeated anywhere else. 84 00:06:15,200 --> 00:06:16,580 So let's leave it alone. 85 00:06:18,930 --> 00:06:22,630 In the validate ComicBookArtists method we've got a query that checks if 86 00:06:22,630 --> 00:06:23,990 the provided artist and 87 00:06:23,990 --> 00:06:28,120 role combination has already been added to the comic book or not. 88 00:06:28,120 --> 00:06:32,140 Again, just like the other queries or commands that we just looked at 89 00:06:32,140 --> 00:06:36,750 it's only moderately complex, and it only appears in this one location. 90 00:06:36,750 --> 00:06:39,380 So let's just leave it alone. 91 00:06:39,380 --> 00:06:42,800 Because it's query or command, it's its own class. 92 00:06:42,800 --> 00:06:46,170 You might expect that you'd end up with a lot more classes in your project, 93 00:06:46,170 --> 00:06:48,470 than if you had used repositories. 94 00:06:48,470 --> 00:06:52,200 But as you just saw the number of classes that you'll end up with 95 00:06:52,200 --> 00:06:55,780 really depends on the complexity of your apps queries and commands. 96 00:06:55,780 --> 00:06:59,387 And whether or not they're used for more than one location. 97 00:06:59,387 --> 00:07:03,215 Even if you end up with more classes in your project than if you had used 98 00:07:03,215 --> 00:07:07,505 repositories, using query and command classes often make it a little easier 99 00:07:07,505 --> 00:07:10,890 to find a query or command that you're looking for. 100 00:07:10,890 --> 00:07:14,810 Since each class contains a single query or command. 101 00:07:14,810 --> 00:07:18,060 You don't have to determine which repository you're looking for 102 00:07:18,060 --> 00:07:21,330 then find the specific method within that repository. 103 00:07:21,330 --> 00:07:24,150 You just find the query command that you're looking for and 104 00:07:24,150 --> 00:07:25,240 directly open that file. 105 00:07:26,350 --> 00:07:27,030 Let's go ahead and 106 00:07:27,030 --> 00:07:30,850 convert the command to add a ComicBooks artist to use the command class. 107 00:07:30,850 --> 00:07:32,280 So we can look at an example. 108 00:07:33,970 --> 00:07:38,147 At a class named AddComicBookArtistCommand to the Commands folder. 109 00:07:50,531 --> 00:07:53,965 As we've see before we need a private field for the context and 110 00:07:53,965 --> 00:07:58,270 a constructor that accepts a context instance, and sets the private field. 111 00:08:00,030 --> 00:08:04,777 Private Context_context = null; public 112 00:08:04,777 --> 00:08:13,250 AddComicBookArtistCommand then a parameter of type context named context. 113 00:08:15,260 --> 00:08:19,050 And set the private field o the parameter value. 114 00:08:20,580 --> 00:08:24,040 Then add a method named execute that returns void. 115 00:08:24,040 --> 00:08:28,296 And accepts three integer values 116 00:08:28,296 --> 00:08:33,313 comicBookId, artistsId and roleId. 117 00:08:33,313 --> 00:08:37,354 For the implementation we can grab a copy of the code in the controller action 118 00:08:37,354 --> 00:08:37,867 method. 119 00:08:47,030 --> 00:08:51,090 And copy the code to add a comic book artist to the clipboard. 120 00:08:51,090 --> 00:08:52,920 Paste the code from the clipboard. 121 00:08:54,030 --> 00:08:58,690 And probably to no one's surprise got some things to fix up again. 122 00:08:58,690 --> 00:09:00,131 Add a using directive for 123 00:09:00,131 --> 00:09:04,824 the comic book shared model's name space. Remove the bad references to view model 124 00:09:04,824 --> 00:09:13,380 and lower case these identifiers ComicBookID, 125 00:09:13,380 --> 00:09:17,360 ArtistId and roleId. 126 00:09:17,360 --> 00:09:19,701 Whoops, looks like I have misspelled this parameter. 127 00:09:21,088 --> 00:09:28,661 ArtistId not artistsId, then replace Context with _context. 128 00:09:32,160 --> 00:09:36,220 Now we're ready to update the action method to use our new command class. 129 00:09:36,220 --> 00:09:37,578 Remove the existing code. 130 00:09:40,906 --> 00:09:49,450 Instantiate an instance of the AddComicBookArtistCommand class. 131 00:09:49,450 --> 00:09:55,274 Add a using directive for the missing name space; ComicBookShared.Data.Commands. 132 00:09:55,274 --> 00:09:59,464 Pass in the context property from the base controller class and 133 00:09:59,464 --> 00:10:01,210 call the execute method. 134 00:10:03,070 --> 00:10:09,407 Passing in the viewModel.ComicBookId, artistId. 135 00:10:11,499 --> 00:10:13,602 Enroll Id property values. 136 00:10:16,823 --> 00:10:19,780 Now we're ready to test our changes. 137 00:10:19,780 --> 00:10:24,340 To do that we need to comment out the ComicBooks artist controller class. 138 00:10:24,340 --> 00:10:29,080 And rename the copy of the controller that we've been modifying to the correct name. 139 00:10:29,080 --> 00:10:32,940 So that ASP.NET MVC's routing engine will find the query and 140 00:10:32,940 --> 00:10:34,490 command version of the controller. 141 00:10:36,920 --> 00:10:39,830 Change the name of the class is good enough. 142 00:10:39,830 --> 00:10:41,920 We can leave the file name alone. 143 00:10:41,920 --> 00:10:46,269 Let's separate points in the two methods that we updated to use query and 144 00:10:46,269 --> 00:10:51,133 command classes just to make sure that our testing exercises, those code pass. 145 00:11:02,067 --> 00:11:03,848 And run the WebApp. 146 00:11:06,280 --> 00:11:11,283 View the details for Bone #3, and add a new artist. 147 00:11:14,611 --> 00:11:17,420 And we've hit our first break point. 148 00:11:17,420 --> 00:11:19,523 Press F5 to continue execution. 149 00:11:24,825 --> 00:11:26,905 Select Jeff Smith for the artist. 150 00:11:29,657 --> 00:11:30,930 Pencils. 151 00:11:30,930 --> 00:11:33,400 Oop, that artist is already in use. 152 00:11:33,400 --> 00:11:38,010 So choose Archie Goodwin Pencils and save. 153 00:11:38,010 --> 00:11:40,500 And we're at our second breakpoint. 154 00:11:40,500 --> 00:11:42,680 Looks like we're good to go. 155 00:11:42,680 --> 00:11:47,670 Determining how best to organize your data access code can be a challenging exercise. 156 00:11:47,670 --> 00:11:51,230 That being said there's no need to agonize too much about it. 157 00:11:51,230 --> 00:11:55,770 Consider the requirements of your app, weigh the pros and cons of each approach. 158 00:11:55,770 --> 00:11:58,970 And choose the one you and your team thinks will be the best fit. 159 00:11:59,980 --> 00:12:02,759 Just remember to not overbuild your solution, 160 00:12:02,759 --> 00:12:05,610 only build the features that you actually need. 161 00:12:05,610 --> 00:12:08,120 You could always refactor later on. 162 00:12:08,120 --> 00:12:10,590 Let's do a quick review of the section. 163 00:12:10,590 --> 00:12:14,772 We created a base controller class in order to eliminate code duplication in our 164 00:12:14,772 --> 00:12:16,031 controllers. 165 00:12:16,031 --> 00:12:18,900 We also reviewed the repository design pattern. 166 00:12:18,900 --> 00:12:22,820 And implemented a new repository for our web app. 167 00:12:22,820 --> 00:12:25,850 And we saw how to break apart that repository 168 00:12:25,850 --> 00:12:28,670 into entity type focused repositories and 169 00:12:28,670 --> 00:12:34,140 created a generic base repository class to further reduce code duplication. 170 00:12:34,140 --> 00:12:36,920 Then we finished up with a look at how query and 171 00:12:36,920 --> 00:12:41,120 command classes could be used as an alternative to repositories. 172 00:12:41,120 --> 00:12:45,430 Next up, we'll finish the Comic Book Library Manager Web App by updating 173 00:12:45,430 --> 00:12:47,804 the series and artists sections to use EF. 174 00:12:47,804 --> 00:12:48,710 See you after the break.