EF Core Part 2: Dealing with the Database
Creating and Updating a Database Through Code
Welcome to Part 2 of my setting up EF Core series. If you did anything with EF6 Code-First, a lot of this is going to seem familiar to you. The process is nearly the same, but we’re going to cover it anyway. If you’re looking for Database-First, skip to the Part 3.
First thing I did was create a Models solution folder directly under my project, then I added a new class that will serve as my DbContext.
Next, I added a class to serve as the Thing entity.
Now I need to register EF Core in the dependency injection container in Startup.cs so anything consuming the context can rely on the container to new up an instance when needed. I can do this with two lines of code in the ConfigureServices function in Startup.cs and adding the required using statements (4 lines total. This isn’t code golf.):
var connectionString = @"Server=(localdb)\mssqllocaldb;Database=EfBuilderDB;Trusted_Connection=True;";
services.AddDbContext(options => options.UseSqlServer(connectionString));
Yes, I hardcoded the connection string into the code. Relax, it’s just an example blog post, not production code. Normally, I’d tuck that away into the AppSettings or Web.config but that’s another thing that has changed in Core that I don’t want to get into with this post.
Now that everything is set up, I’m all ready to create my first migration. If you’re an EF6 Code-First user, there is no more
Enable Migrations you just do it. So to do that, I pop open the Package Manager Console and type
That worked! Now we’re cooking. Handy side note: if you need to back out your most recent migration, you can simply type
Remove-Migration. Thank you PMC tip!
So I have a migration, what does that even mean? It means I have a new folder in my project named Migrations, and I have a couple files in there. Those files belong to my migration.
Add-Migration use the name I supplied it and added a big-ugly-but-useful timestamp prefixed onto it, as well as an EfBuilderModelSnapshot.cs. The model snapshot is a code representation of what the table schema currently is in the database. This is a basis for comparison as I continue to develop the database and potentially change my Things class later on. When Things change, this file will help the
Add-Migration command figure out what’s changed and create the associated migration. In short: stay out of the model snapshot code.
On the plus side, I have a migration now! It looks like this:
So far, this is the sum of my work. I don’t even have a database yet! Upon inspection you might notice that there is a primary key on the Thing table already defined, but I didn’t specify a key anywhere. Or did I? Actually, I sort of did. EF Core continues with making assumptions by convention like EF6 does. I named one of the properties in Thing ThingId. EF Core recognizes this and assumes that if it reads ID that it’s the primary key. This behavior will also trigger if I had simply named it Id. These assumptions also seem to be case insensitive as well. The migration file is ok to edit if needed. Your reason for editing the migration file might include setting a default value on a column, tweaking a type, adding a constraint, or the like. All those things DBAs usually get territorial about. After all, this is what is going to create the database!
Speaking of which, I said I didn’t have a database yet, and that is true. I’ve only created the migration, I haven’t run it yet. To create the database, I need to pop open the Package Manager Console and run
Done. PMC is an interface of few words, except when you make it angry. PMC’s simple confirmation has masked something wonderful that happened, I have a database!
A table representing my Thing class is there, and a __EFMigrationHistory table. __EFMigrationHistory is simply a table that tracks what migrations have been run against the database. Next time I run an
Update-Database command, the process will check this table against the migrations in my solution and only run the ones that are needed, if any.
So let’s do a change! I promise that now that we have everything set up, this is going to go a lot easier, but not too easy. Let’s add a related table: Stuff. The Things table will have a foreign key into Stuff. Not too lean, not too complex, but meaty enough to be interesting. I like it.
I’ll start out by creating a new class in my Models folder named Stuff.
That’s the good Stuff. Now, I need to add a List of Stuff to Thing because EF Core is going to try to grab all Stuff entries related to a Thing record when referenced.
Next I need to hop over to my context and add a DbSet for Stuff so I can reference Stuff entities without needing to go through Thing.
That’s it! Using the convention-based assumptions, EF Core will recognize that Stuff’s primary key is StuffId, and that Thing has a collection of Stuffs and will create the associated relationship. Now I can run
Add-Migration once more.
Once again PMC gives me another stoic confirmation that everything went as planned, I have a new migration in my Migrations folder.
You can see in the code there’s a constraints section that details the foreign key relationship between Thing and Stuff. Now just a quick
Now you can see that the Stuff table was created with a foreign key back to Thing and we’re all set up on EF Core!