1 00:00:05,270 --> 00:00:08,940 In the previous video we got our code writing data to the database. 2 00:00:08,940 --> 00:00:12,280 Next we're going to look at how to get the data back out again. To do that, 3 00:00:12,300 --> 00:00:18,180 we're going to use a cursor. In database terms a cursor allows us to access individual records in the 4 00:00:18,180 --> 00:00:19,260 database. 5 00:00:19,260 --> 00:00:25,150 We can move backwards and forwards in the cursor, and it takes care of retrieving the rows for us. Once 6 00:00:25,430 --> 00:00:27,550 we position the cursor at a particular row, 7 00:00:27,720 --> 00:00:32,640 we can then use it to read the individual columns or fields of data. 8 00:00:32,640 --> 00:00:33,870 Now you'll often use a cursor 9 00:00:33,930 --> 00:00:39,000 even if you only expect to get a single row back from a query. You don't have to worry about how many 10 00:00:39,000 --> 00:00:45,240 rows will be retrieved. They're all accessed via the database cursor. Your database query could return 11 00:00:45,240 --> 00:00:51,060 thousands of rows, and that could be a problem because smart phones have limited amounts of memory. All 12 00:00:51,060 --> 00:00:55,050 that data possibly wouldn't fit in the memory we've got available, 13 00:00:55,050 --> 00:00:59,620 but a cursor takes care of this and points to just a single row at a time. 14 00:00:59,820 --> 00:01:03,880 So we can access and manipulate the data without having to load it all into memory, 15 00:01:04,220 --> 00:01:09,600 and this avoids the performance issues of having to retrieve thousands of records into memory. A cursor 16 00:01:09,600 --> 00:01:14,370 enables us to manipulate the data, but only retrieves it one record at a time, 17 00:01:14,370 --> 00:01:16,700 as you'll see when we start writing our code. 18 00:01:17,070 --> 00:01:20,270 So Android comes with a cursor class built in so we can use that. 19 00:01:20,280 --> 00:01:21,440 So let's give that a go now. 20 00:01:21,680 --> 00:01:25,010 What I'm going to do is come down here, after our 21 00:01:25,020 --> 00:01:29,970 last statement we added which was the val generatedId for the database insert. And I'm going to type val 22 00:01:30,570 --> 00:01:40,120 query is equal to database.rawQuery, and in parentheses and double quotes, 23 00:01:40,230 --> 00:01:45,390 SELECT * FROM contacts. 24 00:01:45,780 --> 00:01:53,990 Then the second argument, we're going to pass null to it. The rawQuery method returns a cursor. The first parameter's 25 00:01:54,020 --> 00:01:59,740 the SQL query that we want to use to retrieve the data, and I've set the second argument to null. 26 00:01:59,750 --> 00:02:03,230 Now if you want to know what the second argument is let's have a look at the documentation, 27 00:02:06,180 --> 00:02:09,580 and you can see there that second argument is the selectionArgs. 28 00:02:09,860 --> 00:02:16,910 This provides values that we can include in a WHERE clause to our SQL query, or into our SQL query, and we'll 29 00:02:16,910 --> 00:02:18,550 have a look at that a little bit later. 30 00:02:18,590 --> 00:02:21,750 For now I've just set that to null. And by the way, with these windows, 31 00:02:22,370 --> 00:02:27,440 these documentation windows, they often contain more text than will fit in them, and they always 32 00:02:27,440 --> 00:02:32,070 seem to start off the same size when you first open one, regardless of their contents. 33 00:02:32,090 --> 00:02:36,500 So make sure you either resize them or scroll down, so that you get to see all the information. 34 00:02:36,590 --> 00:02:40,050 In this case the information didn't require me to scroll. 35 00:02:40,390 --> 00:02:45,660 And by the way, we can also see that if we have a look at the return information for rawQuery, 36 00:02:45,770 --> 00:02:50,090 we can see that it's a cursor object positioned before the first record. 37 00:02:50,340 --> 00:02:53,390 It tells us here that it's positioned before the first entry. 38 00:02:53,690 --> 00:02:58,970 Another thing to note there is the SQL string must not be semi-colon terminated, as you would 39 00:02:58,970 --> 00:03:02,420 normally do when you're creating SQL source code or 40 00:03:02,420 --> 00:03:06,710 what you've done earlier in this section of the course, when using a sqlite3 command 41 00:03:06,710 --> 00:03:08,820 line, program. 42 00:03:09,160 --> 00:03:15,920 Alright, so that's rawQuery. There's also a query method as well, or several query methods to be precise, and they 43 00:03:15,920 --> 00:03:20,800 allow you to specify ORDER BY clauses, as well as more filtering and grouping. 44 00:03:21,170 --> 00:03:25,250 And it's definitely worth checking those methods out when you come to write your own apps. 45 00:03:25,310 --> 00:03:30,570 We're going to be using something similar later, and you'll understand what the various arguments are 46 00:03:30,590 --> 00:03:35,230 once we've done that. But I'm using rawQuery here just to keep things simple. 47 00:03:35,420 --> 00:03:40,700 Now at the moment actually, if I hover over that, you notice that we've got this warning from Android Studio that this 48 00:03:40,700 --> 00:03:45,960 cursor should be freed up after use with close, hash close. 49 00:03:45,980 --> 00:03:50,780 Now if you're familiar with Java you'd probably use a try with resources to achieve that. 50 00:03:50,780 --> 00:03:56,180 More importantly if you're converting Java code that uses try with resources, you may struggle to do 51 00:03:56,180 --> 00:03:57,190 that in Kotlin. 52 00:03:57,470 --> 00:04:02,450 And that's because Kotlin doesn't use the same syntax as Java, and there isn't actually a try with resources 53 00:04:02,450 --> 00:04:04,480 syntax as such in Kotlin. 54 00:04:04,700 --> 00:04:09,280 Instead Kotlin provides the use function to achieve the same thing. 55 00:04:09,320 --> 00:04:12,430 So let's just type a bit of code and then we'll check out the documentation. 56 00:04:12,560 --> 00:04:15,400 So it's query.use, and 57 00:04:16,399 --> 00:04:18,800 notice that it's adding a code block after that, and 58 00:04:18,829 --> 00:04:25,970 we'll have a look at the documentation for use. Basically, it executes the given block function on this resource 59 00:04:26,330 --> 00:04:29,040 and then closes it down correctly. 60 00:04:29,060 --> 00:04:33,210 So in this case it'll close the cursor, whether or not an exception is thrown. 61 00:04:33,590 --> 00:04:40,520 So you can use the use function with any closeable object, in the same way that Java allows try with resources 62 00:04:40,520 --> 00:04:43,810 to be used with any closeable object. 63 00:04:43,870 --> 00:04:45,010 Alright, so back in our code now. 64 00:04:46,190 --> 00:04:51,000 I'm going to put all the code to deal with our cursor inside that block. 65 00:04:51,040 --> 00:04:57,440 Now inside the code block that we've added here, we refer to the object that was called on it as it, and you can see 66 00:04:57,440 --> 00:04:59,720 that IntelliJ helpfully tells us that as well - 67 00:04:59,840 --> 00:05:00,790 it:Cursor. 68 00:05:01,090 --> 00:05:05,370 It's adding that for us as a reminder of what you need to do there. 69 00:05:06,060 --> 00:05:07,940 So to write the code we'll do something like: 70 00:05:07,970 --> 00:05:15,140 if, this is in the code block, parentheses it.moveToFirst. 71 00:05:15,230 --> 00:05:20,480 So again, the reason that we're using it and we're not using query here, is that we're referring 72 00:05:20,480 --> 00:05:22,040 to the object that it was called on 73 00:05:22,040 --> 00:05:25,900 as it. And that's why we've got it.moveToFirst here rather than query - 74 00:05:25,930 --> 00:05:27,110 dot moveToFirst. 75 00:05:27,390 --> 00:05:31,490 Query is a cursor, and we're telling it to move to the first record. 76 00:05:31,550 --> 00:05:37,220 Now it's actually quite possible that our sequel query didn't return any records. In which case, the moveTo 77 00:05:37,220 --> 00:05:39,260 First method would return false. 78 00:05:39,350 --> 00:05:44,880 So that's why we're checking that it did manage to move to the first record before we do any more processing. 79 00:05:44,880 --> 00:05:47,150 And just to confirm that if you want to check that. 80 00:05:47,180 --> 00:05:50,550 Have a look at the documentation for moveToFirst, and you can see 81 00:05:50,980 --> 00:05:56,030 it tells us there specifically that this method will return false if the cursor is empty. 82 00:05:56,330 --> 00:06:01,130 So OK, so if it returns true then the cursor's positioned at the first record and we can start reading the 83 00:06:01,130 --> 00:06:01,740 data. 84 00:06:01,940 --> 00:06:03,920 So let's put some code in that code block, 85 00:06:04,160 --> 00:06:07,700 knowing that at this point we guaranteed to have at least one record. 86 00:06:07,740 --> 00:06:10,010 So I'll put a comment here that we're going to "Cycle through all the records" 87 00:06:17,910 --> 00:06:22,800 with parentheses query, and by the way we aren't yet cycling through all records. I'm about to do that a little 88 00:06:22,800 --> 00:06:33,420 bit later, but for now though we're going to query a single record using with query. Then within the with query cold block we'll put 89 00:06:33,580 --> 00:06:45,190 val id equals getLong parentheses zero, val name equals getString parentheses 1, val phone equals get 90 00:06:45,190 --> 00:06:49,550 Int 2, and val email 91 00:06:49,720 --> 00:06:54,930 equals getString 3. So again, we're not cycling through all the records yet. 92 00:06:54,930 --> 00:06:55,800 We're going to do that in a minute, 93 00:06:55,800 --> 00:06:56,970 hence the comment. 94 00:06:57,180 --> 00:07:00,670 For now though we're just reading the values for the first record. 95 00:07:00,810 --> 00:07:06,140 Now note that we're using the get methods which need the index of a column and a table, and obviously it's 96 00:07:06,250 --> 00:07:06,540 get 97 00:07:06,560 --> 00:07:08,840 and then the type of data. 98 00:07:09,020 --> 00:07:10,730 So we've got a long here, we've got a 99 00:07:10,740 --> 00:07:12,270 string here, we've got an int here, 100 00:07:12,300 --> 00:07:12,990 etc. 101 00:07:13,560 --> 00:07:19,180 So these, all of these functions need an index of the column and the table. So remember that computers 102 00:07:19,180 --> 00:07:21,650 index the first item as index 0, 103 00:07:21,900 --> 00:07:27,050 so that's why we're reading the first column into ID, the second into name, the third into phone and 104 00:07:27,060 --> 00:07:32,600 the last into email. And the ID is a long value where its name and email are strings, and because 105 00:07:32,630 --> 00:07:34,610 we've stored the phone number as an integer, 106 00:07:34,750 --> 00:07:37,960 we're using getInt rather than getString but it works the same. 107 00:07:38,130 --> 00:07:42,360 In reality we really shouldn't have used an integer for the phone number, but I just wanted to show you 108 00:07:42,360 --> 00:07:44,760 how to retrieve different types of data. 109 00:07:45,210 --> 00:07:49,830 And that's also what I meant in an earlier video when I warned about SQLite columns not really 110 00:07:49,830 --> 00:07:51,170 having a data type. 111 00:07:51,210 --> 00:07:55,680 There's nothing to prevent us from storing a string in the phone field, but that would break out Kotlin 112 00:07:55,700 --> 00:07:58,070 code when it tried to read an int. 113 00:07:58,210 --> 00:07:58,520 Alright. 114 00:07:58,530 --> 00:08:02,980 So for our simple example, we're going to display the data in the logcat. 115 00:08:03,010 --> 00:08:04,170 So what I'm trying to do, 116 00:08:05,760 --> 00:08:11,340 is below the lines that retrieve the data, I'm going to type val 117 00:08:11,340 --> 00:08:15,120 result equals, then double quotes, 118 00:08:15,200 --> 00:08:27,090 ID colon $id Name equals $name phone equals $phone and email equals $email. 119 00:08:28,510 --> 00:08:30,990 Then I'm going to type Log.d parentheses 120 00:08:31,150 --> 00:08:43,480 TAG comma onCreate colon reading data $result, and you can see that IntelliJ is helpfully 121 00:08:43,500 --> 00:08:49,800 telling us that this is all attached to the With that we've actually set up for this query and the appropriate 122 00:08:49,800 --> 00:08:58,540 code block. Alright so finally, the other thing we want to do here now is we want to close the database. So database.close, so calling 123 00:08:58,590 --> 00:09:04,230 the close method. Closing the database is a good idea, but you'd normally do that when the app is closed, 124 00:09:04,650 --> 00:09:05,570 rather than here. 125 00:09:05,850 --> 00:09:10,270 That way the database is available while the app's running and you don't have to keep opening it. 126 00:09:10,360 --> 00:09:16,640 And we could also have wrapped all this code up in a database dot use block, just like we did for the cursor code. 127 00:09:16,790 --> 00:09:23,070 I didn't do that here because, as I've said, it's more usual to keep the database open until the app finishes. 128 00:09:23,070 --> 00:09:28,650 In fact if you wanted to use this basic approach in a real app, you'd probably create a separate class 129 00:09:28,650 --> 00:09:31,060 to handle all the database accesses. 130 00:09:31,440 --> 00:09:32,670 We're not going to do that. 131 00:09:32,680 --> 00:09:35,270 We're going to be using a content provider instead. 132 00:09:35,430 --> 00:09:40,370 At the moment though, we're just seeing how to run SQL statements from our Kotlin code. 133 00:09:40,470 --> 00:09:44,270 Alright so at this point in time, we're now ready to run this simple app. We're going to run it now. 134 00:09:47,700 --> 00:09:54,160 OK, I'm going to select the same one that I ran it on last, click OK. I'll just fast forward this until 135 00:09:54,160 --> 00:09:59,830 it gets to the stage of running. 136 00:09:59,890 --> 00:10:04,680 Alright so you can see we've got an error immediately. So when that happens, open 137 00:10:04,940 --> 00:10:12,020 up the logcat tab and see what we can see there, and we might have to remove the filter there so 138 00:10:12,020 --> 00:10:16,820 that we can say all the information. Also I've noticed that sometimes Android Studio continues to show 139 00:10:16,920 --> 00:10:21,900 unrelated log entries, even with Show only selected application over here to the right selected. 140 00:10:21,980 --> 00:10:25,940 If that happens just select your application again, in the second drop-down from the left, 141 00:10:25,940 --> 00:10:26,580 so this one here. 142 00:10:28,130 --> 00:10:32,780 In my case I don't need to do that. The reason I'm not seeing all the output here is because we've got /mainactivity 143 00:10:32,770 --> 00:10:38,390 still showing there. Again, I could select that again, 144 00:10:38,590 --> 00:10:44,220 and notice by doing that now it actually clears the log of all that unrelated information. 145 00:10:44,220 --> 00:10:48,610 And we're back to looking and seeing why our application crashed. 146 00:10:48,610 --> 00:10:54,610 Now one technique for reading these tech traces is to read the first bit that describes the error, then ignore 147 00:10:54,700 --> 00:10:57,130 the rest of the block - all the lines starting with at, 148 00:10:57,130 --> 00:11:04,840 in other words. Now down down up to here and have a look at this first line: table contacts already exists, 149 00:11:05,440 --> 00:11:09,340 when compiling, and it gives us the SQL that was executing. 150 00:11:09,340 --> 00:11:11,890 So that's pretty clear as to what the problem was. 151 00:11:12,330 --> 00:11:13,720 And again just to be clear though, 152 00:11:16,750 --> 00:11:21,500 you can see down here that it was caused by sqlite exceptions. So that told us fairly quickly anyway, even if we 153 00:11:21,500 --> 00:11:25,880 didn't already know, that it was complaining about the CREATE TABLE statement 154 00:11:25,880 --> 00:11:27,890 and you can see that to the right of the screen there now. 155 00:11:28,250 --> 00:11:31,700 So basically we knew that there was a sqlite exception of the code, 156 00:11:31,700 --> 00:11:36,770 so the problem was probably relating to our database code. We probably guessed that anyway because we haven't 157 00:11:36,770 --> 00:11:41,820 added any other code, but it is always useful to check these logs just to make sure that's the case. 158 00:11:42,200 --> 00:11:44,980 So basically the sqlite 159 00:11:45,320 --> 00:11:48,270 exception is complaining about the CREATE TABLE statement. 160 00:11:48,440 --> 00:11:53,750 And if we skip to the next block, eventually we see some code here that we can click. Anything in blue 161 00:11:53,750 --> 00:11:59,090 is the code that we've been working on, so we can click on that to navigate to the line of code that 162 00:11:59,090 --> 00:12:04,730 is actually causing the problem. And you can see that that's the line that caused the execSQLs method, which 163 00:12:04,740 --> 00:12:08,920 means the problem's going to be in the SQL statement a couple of lines further up - 164 00:12:08,990 --> 00:12:10,950 line 24 in fact. 165 00:12:11,330 --> 00:12:16,120 Basically the table contacts already exists and that's why we're getting that crash. 166 00:12:16,130 --> 00:12:20,930 Now fortunately while testing, there's an easy way to fix that. We can just come up here and change the 167 00:12:20,930 --> 00:12:22,510 SQL code slightly 168 00:12:22,760 --> 00:12:30,220 and add the words IF NOT EXISTS after the CREATE TABLE statement. So CREATE TABLE IF NOT EXISTS. 169 00:12:30,720 --> 00:12:35,650 contacts. So in other words, the table won't be attempted to be recreated 170 00:12:35,870 --> 00:12:37,240 if it's already found. 171 00:12:37,330 --> 00:12:39,200 So I'm just going to click on and run, 172 00:12:42,090 --> 00:12:47,910 close logcat for now. And we'll just go back and check our app. This time our app has worked. 173 00:12:47,920 --> 00:12:50,730 We haven't got a crash this time so that's a good sign. 174 00:12:50,760 --> 00:12:57,740 And we will go back to our logcat again, and we can just type /main, and we can quickly see that we've 175 00:12:57,740 --> 00:13:01,670 got some data showing on the screen there now. So it's doing what we expect. 176 00:13:01,670 --> 00:13:06,080 Well it sort of is. We get the details for the first row appearing, 177 00:13:06,230 --> 00:13:10,440 but the ID for the row that's just been created is now 4 rather than 2. 178 00:13:10,800 --> 00:13:15,310 And that's because our code keeps adding those two records every time we run it. 179 00:13:15,320 --> 00:13:19,530 Now normally you'd be adding new rows when the user does something, such as saving a new contact. You 180 00:13:19,580 --> 00:13:23,130 wouldn't normally run these Insert queries each time the app runs. 181 00:13:23,440 --> 00:13:25,930 And we don't want to keep adding the same two rows, 182 00:13:25,960 --> 00:13:28,750 and we can easily prevent that by dropping the table. 183 00:13:28,880 --> 00:13:34,210 Let's just make a quick change to the code to do that, and we'll add it immediately after our database is being 184 00:13:34,220 --> 00:13:35,960 defined on line 23. 185 00:13:35,990 --> 00:13:43,960 We're going to type database.execSQL, and in parentheses I'm going to type double quotes DROP TABLE 186 00:13:44,500 --> 00:13:50,990 IF EXISTS contacts. So I'm going to DROP THE TABLE every time 187 00:13:50,990 --> 00:13:53,700 IF it EXISTS. Let's actually run that again, 188 00:13:55,960 --> 00:13:57,500 and confirm that that works. 189 00:14:00,660 --> 00:14:05,310 This time you can see we've got record added with id 2, and that confirms that the table was dropped 190 00:14:05,400 --> 00:14:08,400 immediately after we got access to the database object. 191 00:14:08,450 --> 00:14:13,620 Now generally I prefer to put the SQL statements into a string variable like I did for the CREATE TABLE 192 00:14:13,620 --> 00:14:15,160 on line 25. 193 00:14:15,210 --> 00:14:20,260 This makes it easier to log the SQL which makes debugging easier if you make a mistake. 194 00:14:20,640 --> 00:14:23,490 You can just include the SQL as a string as we're doing here. 195 00:14:23,780 --> 00:14:29,200 But I do recommend using a variable and logging it's value, especially while developing your app. 196 00:14:29,250 --> 00:14:31,920 You can always delete the logging later once the app's working. 197 00:14:31,920 --> 00:14:37,020 Also be aware that these debug logging commands are stripped out by the build system when you create 198 00:14:37,020 --> 00:14:42,630 the release version of your app. Basically when you use Log.d, the logging lines are removed automatically 199 00:14:43,080 --> 00:14:45,730 so they won't affect your apps performance. 200 00:14:45,740 --> 00:14:48,910 Alright so there's one last change to make before we stop this video. 201 00:14:49,290 --> 00:14:56,520 We can loop through all the rows in the cursor by using moveToNext instead of moveToFirst. Remember 202 00:14:56,520 --> 00:14:59,350 that the cursor's positioned before the first record, 203 00:14:59,400 --> 00:15:06,130 and that means that moveToNext will do the same thing as moveToFirst, the first time it's used. 204 00:15:06,150 --> 00:15:09,260 So let's go ahead and make a simple change to our code to check that. 205 00:15:09,330 --> 00:15:11,690 So I'm going to close down logcat first. 206 00:15:11,970 --> 00:15:18,190 And the change we want to make here - at the moment we've got an if statement here on line 49. I'm going to change the 207 00:15:18,220 --> 00:15:22,840 if to while. I'm creating a while loop 208 00:15:22,850 --> 00:15:28,680 now instead, and I'm going to change this code here, or rather I'm going to remove some of this now, because we in fact 209 00:15:28,680 --> 00:15:32,460 have added the code now to cycle through all records. 210 00:15:32,460 --> 00:15:36,210 So now when we run this we should find that we've got two entries showing on the screen, so let's run 211 00:15:36,210 --> 00:15:38,570 this. Stop the app and run it again, and we'll bring up logcat. 212 00:15:42,830 --> 00:15:44,120 Let's have a look and see what it gives us. And obviously I've 213 00:15:47,560 --> 00:15:50,840 made a mistake there so what I'm going to do is just stop that, 214 00:15:50,840 --> 00:15:58,380 stop our app. And you can see what I've done there. I basically didn't change this properly. I put while it.move 215 00:15:58,380 --> 00:15:59,600 ToFirst. 216 00:15:59,600 --> 00:16:05,280 So it always continually cycled back to the first record, so that therefore the while statement never became 217 00:16:05,280 --> 00:16:05,670 false and 218 00:16:05,670 --> 00:16:07,150 we never exited the loop. 219 00:16:07,190 --> 00:16:09,000 And of course I talked about it but we didn't do it. 220 00:16:09,030 --> 00:16:13,700 We need to add a moveToNext, 221 00:16:13,850 --> 00:16:16,590 bearing in mind that with moveToNext, 222 00:16:16,730 --> 00:16:21,150 it does the same thing as moveToFirst, the first time it's used. So it'll move to the first record, then 223 00:16:21,160 --> 00:16:23,630 automatically progress through to the next record and so on. 224 00:16:23,840 --> 00:16:24,800 Let's run it again, 225 00:16:25,040 --> 00:16:27,370 and we should find this time we'll see both records. 226 00:16:30,150 --> 00:16:35,770 This time you can see now, we've got reading data ID 1 and ID 2, and clearly the values are different 227 00:16:35,770 --> 00:16:37,150 there on the screen as well. 228 00:16:37,210 --> 00:16:42,590 Basically the logcat's showing both records correctly and our very simple app's working fine. 229 00:16:43,060 --> 00:16:49,000 So this is an incredibly basic app, but we've seen how to create a database using the SQLite 230 00:16:49,300 --> 00:16:50,700 database class. 231 00:16:50,740 --> 00:16:56,980 We then created a table and inserted records by executing the appropriate SQL statements. 232 00:16:57,000 --> 00:17:01,540 Now I've said several times that you wouldn't write a real app this way. At the very least you'd create 233 00:17:01,540 --> 00:17:04,119 a class to handle all the database access. 234 00:17:04,150 --> 00:17:08,329 You'd also want to make sure that your query isn't performed on the main thread. 235 00:17:08,500 --> 00:17:11,880 That's not a good idea because database operations can be slow. 236 00:17:12,050 --> 00:17:16,619 Now there are ways to handle this using things like content providers and cursor loaders, and we're 237 00:17:16,780 --> 00:17:18,550 going to be looking at both of those. 238 00:17:18,550 --> 00:17:23,640 But the basics of executing SQL statements from Kotlin code will still be needed. 239 00:17:23,650 --> 00:17:24,720 Now we know how to do that, 240 00:17:24,730 --> 00:17:29,320 we're ready to look at more suitable ways of dealing with databases. In the next video though, we're going to 241 00:17:29,320 --> 00:17:35,920 have a look at where our database is stored on the device, so that we can open it using the sqlite command 242 00:17:35,920 --> 00:17:41,350 line, and check that it's been set up correctly. When debugging, it's very useful to be able to examine 243 00:17:41,350 --> 00:17:44,130 the data that's been stored in your database. 244 00:17:44,140 --> 00:17:47,680 So in the next video we'll find out how to do just that. 245 00:17:47,680 --> 00:17:48,940 See you in the next video.