Controlling Database Generation5:08 with James Churchill
Let's make a simple change to our ComicBook entity class and see how EF handles updates to our model.
To follow along commiting your changes to this course, you'll need to fork the dotnet-comic-book-gallery-model repo. Then you can clone, commit, and push your changes to your fork like this:
git clone <your-fork> cd dotnet-comic-book-gallery-model git checkout tags/v2.4 -b controlling-database-generation
Storing Calculated Values
AverageRating column is storing a calculated value. Our system doesn't store ratings, so we're assuming (or imagining) that there'll be an automated, scheduled process that will calculate the rating for each comic book and update the records in our database.
Storing calculated data has tradeoffs. On the upside, it's quick to retrieve a value as it doesn't need to be calculated. On the downside, there's a risk that the calculated value will be "stale", meaning that the stored calculated value might not represent the current state of the source data. The likelihood of this happening is directly related to how often the calculated value is generated or refreshed from the source data.
We went with the approach of storing a calculated value in order to keep our code base as simple as possible so that we could keep the focus on learning Entity Framework. In a real-life project, the
AverageRating value would probably be calculated every time that it was requested, though ultimately, our approach would be guided and informed by the overall performance of the system.
We made our first pass at the comic book entity and 0:00 context classes, but we're far from done with our entity data model. 0:02 Let's make a simple change to our comic book in the class and 0:07 see how EF handles updates to our model. 0:10 Allot a property of type decimal named AverageRating. 0:17 This property will store the average value 0:25 of all of the ratings that this comic book has received. 0:27 Allot a question mark after the data type to make this property nullable. 0:31 That will allow a comic book to be added to the database, 0:35 even if it doesn't have an average rating value. 0:38 Now that we've updated our entity, let's run our app. 0:41 As soon as we try to use the context's ComicBooks db set property, 0:46 EF throws an exception. 0:50 The model back in the context, context has changed since the database was created. 0:54 Consider using code first migrations to update the database. 0:59 EF detected that we changed the model and 1:03 threw an exception because the database isn't in sync with our model. 1:05 How does EF know when the model has changed? 1:10 When EF created our database, it included a table named migration history. 1:15 Using the SQL Server Object Explorer Window, 1:20 we can right click on the table and select View Data to see the table's data. 1:23 The table contains a single row. 1:30 The model column contains a compressed version of the EDMX for 1:34 the model that was used to create the database. 1:38 When running our app, EF generates the in memory representation of the EDMX for 1:41 our model in its current state. 1:46 If EF detects an existing database, 1:49 it queries the EDMX from the migration history table and 1:51 compares the current in memory model to the model stored in the database. 1:54 If they aren't compatible, then EF will, by default, 1:59 throw an exception to let us know that the database isn't compatible with our model. 2:03 To resolve the problem, 2:08 EF is suggesting that we consider using code first migrations. 2:09 Migrations give you exact control over the propagation of model changes to 2:13 the database without losing any existing data. 2:17 We'll be covering code first migrations in a later course. 2:21 For this course, we'll be dropping and 2:24 creating our database every time our model changes. 2:27 To get this behavior, 2:31 we need to configure the strategy that EF uses when initializing the database. 2:32 We can do this using the database SetInitializer method. 2:38 The SetInitializer method needs to be called before the context class is used. 2:42 So let's add back the context class constructor 2:47 in order to make the method call when the class is being initialized. 2:51 public Context(), followed by a set of curly braces, 2:55 then using the context's Database property, 3:01 call the SetInitializer method, passing in an instance 3:05 to the DropCreateDatabaseIfModelChanges class. 3:11 The DropCreateDatabaseIfModelChanges class is a generic class, 3:17 whose type needs to be set to our context class. 3:21 The DropCreateDatabaseIfModelChanges class is a database initializer that 3:28 will drop and create the database every time that the model changes. 3:32 Two other database initializer classes are available, including 3:39 CreateDatabaseIfNotExists, which is the initializer that EF uses by default. 3:44 And DropCreateDatabaseAlways, which will drop and 3:52 create the database every time that the app is ran. 3:56 Always dropping and creating the database is helpful if you wanna start from 4:00 the same baseline database every time that you run your app. 4:04 Now that we've updated the database initializer, 4:11 let's try running our app again. 4:13 And no errors. 4:16 Press Enter to continue execution. 4:18 Using the SQL Server Object Explorer, we can view the comic book's table columns 4:21 and see that we now have an average rating column. 4:26 Let's do a quick review of this section. 4:34 We saw how to detect, install, and configure SQL Server LocalDB. 4:37 We've learned how EF creates a database from our model and some of the conventions 4:41 that EF uses to determine what the database should look like. 4:46 We also saw three options for configuring the name of the database and how to 4:50 use database initializers to control the database initialization process. 4:54 In the next section, we'll complete our model by adding more entities and 5:00 defining relationships between our entities. 5:04 See you after the break. 5:06
You need to sign up for Treehouse in order to download course files.Sign up