Entity Framework Core Part 1 - Code First Generation

Video Statistics and Information

Video
Captions Word Cloud
Reddit Comments
Captions
I think probably the most viewed video of mine in the last few months has been the one I did on in-memory databases in Entity Framework Core. And in a sense I was kind of jumping ahead, because I've had quite a few questions asking me to look rather more at the basics of Entity Framework and particularly Entity Framework Core. So this - and the next few videos actually - I'm going to be looking at various aspects of that. But for now, we're just going to look at how to get started in Entity Framework Core. So what I'm going to do here is just today the basics of how to create a database from scratch using code. So I've just set up here a program called EntityFramework and then a library called BookLibrary. And the first step that we're going to take is into that library we're going to add a couple of classes. So I'm going to have a class that I will call 'Book' and I'll make that 'public' and we'll also have a class called 'Author'. So that means we will just have an example of two classes with a relationship between them that Authors write Books. And that, in the database, will be reflected as two tables with a foreign key connecting Authors to Books. Then let's put some information in there. So because these are going to go into a database, one thing that will make them slightly different from classes that are just going to be existing in the program is they're going to need Ids. You can use typically either ints or GUIDs for Ids, but I'm just going to use an 'int'. And then we're going to say that an Author will have a 'string' which is going to be 'Name' and then an Author will have a collection of Books. Now actually you can use various different types of collection for this, but the one that is normally recommended is just to use an interface 'ICollection' generic for '<Book>' and that means that the underlying system can choose what is the most appropriate type of collection, depending on whether the Books are in memory or still stored in the database or something like that. So that's all we need for our Author, and then for our Book we'll again have an 'Id' and we'll have a 'Title' and then for a bit of variety, let's also have a 'PublicationYear' And then we will have our Author. Now I'm making an assumption here that a Book has a single Author. Practically speaking that's not necessarily true you can have a Book that is co-written by more than one Author, but for this video at least we're going to keep things simple with this idea of a one-to-many relationship - so a single Author having multiple Books. Many-to-many relationships are possible in databases - they're a little bit tricky to implement - and we'll see in a video coming up how actually in Entity Framework it's really quite easy to do that. But for the purposes of this, we've got that going. We're not going to introduce the database yet; we're just going to have some manipulation of these items. So what I will do here is just one more thing. On a Book I will give it a 'override' of 'ToString' and what we'll return there is going to be the 'Title' and then in brackets we'll put the 'YearOfPublication'. And then on our Author we'll simply have the 'ToString' returning the 'Name'. And then in my main Program, to save a little bit of effort, I've already created a selection of Books - just need to get hold of the namespace. And so here I can say 'var authors = CreateFakeData();' And then I could do something like, say, 'foreach (var author in authors)' and then I could maybe write out '{author}' - so that'll call a ToString() on Author - 'wrote ...' and then have another loop and just write out just a little indentation to make it easier to read. And then again that will call the ToString on Book and then just put a blank line between them. And then I've just spotted I've called this 'YearOfPublication' whereas in here I called it 'PublicationYear'. So if we just change those two that'll be fine. And then if we run that, we'll see that we get that information. So nothing to do with Entity Framework at that point, but we've simply put together the classes that are then going to be turned into tables in our database. So now we need to introduce Entity Framework, and I need to introduce a few NuGet packages that are going to make this work. So if we go in here, we can go to Manage NuGet Packages, and in our library I am going to firstly have EntityFrameworkCore, so that gives us the majority of the things that we want. And I'm also going to have EntityFramework.Relational, because I want this connect to a relational database - EntityFramework can be used with all sorts of databases. And then I'm going to choose the particular type of database that I want to connect to. So we could go for SQL Server - and very often I would do. So we can see there got Microsoft.EntityFramework for SQL Server. We could go for Oracle - so you can see there we've got Oracle.EntityFrameworkCore - but to keep things simple, I'm just going to go for SQLite. It shouldn't really make very much difference, if any, to the programming, but that's still what we're going to have. So there's our Microsoft. EntityFrameworkCore.SQLite. So we'll install that as well. And having done that, I now need to write one extra bit of code. So back in the library, I'm going to add a class and I'm going to call this 'BooksContext' and make it 'public'. And I'm going to derive this from a class that we've just got from that EntityFrameworkCore package called DbContext - so if we just pop in the namespace there - and this is going to be our connection point to the database itself. So this is where the real work of the database connection happens. And what I need to put in here is a couple of things. One is, I need to put in an entry for each and every one of my entity types. By that, I mean my classes that are going to be represented by tables in the database; those are called entities - and Author and Book in this case. So we'll have a property, and the collection we use here, we've got to be quite precise on is the thing called a DbSet . So that's going to be a DbSet of 'Author' called 'Authors'. And then we'll also have a DbSet of 'Book' called 'Books'. And what we're doing here, even though it's not obvious, we are actually starting to configure how the database is going to look, because by calling those things 'Authors' and 'Books' we are telling the system that that is what we would like the names of the tables to be. Thing to notice, our classes almost always, in programming, your class name is singular - 'Author' and 'Book' - but our table names will be plural and so that will sort that out, although, you know, we could choose completely different names if we wanted to and put them in there. The other thing we have to do in here is give this a constructor. And the constructor has to take some options which are going to end up providing the rules about how it actually connects to the database. So the way we pass this in a thing called 'DbContextOptions', which is actually a generic for this context type. So we pass that in there, call it 'options' and then simply pass that down to the base class. Okay. So DbContext will deal with all of that. Then in our program we've got to actually hook up to the database. So the first thing I've got to do is create those options that we were going to pass into our DbContext. So let's say 'var options =' and then we can say 'new DbContextOptionsBuilder' again instantiated for our 'BooksContext'. And then it's here that we tell it we want to use SQLite so here we say '.UseSQLite()' and then that has to take the connection string - so where it's actually going to connect to. Now in a practical application - and we'll see this more in later videos - your connection string, you don't want to hard code into your program. You want to have in some sort of config file. But just to keep things simple here, I am going to hard code it. And with SQLite, the nice thing about that connection string is we can just specify a file name. And then rather than it going in the actual executable directory, I'll do a couple of '..'s to bring it up to this level. And let's just call this 'MyLocalLibrary.db' And then on the end of that I say '.Options' to actually give us back our options object. And we'll notice if we look at that that, that is of that type that we set up as the constructor parameter for our BooksContext. So now let's actually use that; let's say 'using var db = new BooksContext(' passing in those 'options'. Just an aside I'm using the new C# 8 style of 'using' there, where I don't have to put it in its own block, and this will have its Dispose() called just when we go to scope there. Next thing I'm going to do - and again there are various ways around this - but I'm going to do it the simplest way; I'm just going to do 'db.' and then 'database' and then '.EnsureCreated();' and what that means is, because this is going to be the first time that we run it, that will actually create the database with those tables for us. And in fact if I just comment out this code for now and run it up at that point ... takes a little while because it's got to create the database ... and then the program closes because I wasn't doing anything. But we can see, because I did all those '..'s, it's put it into our folder there and so it's created our database because I did that 'EnsureCreated ()'. We can have a look in there actually. This is actually a plug-in; it's not an absolutely standard part of Visual Studio, but you can get this SQLite toolbox plug-in - have a look at that and if I just hit the connect button there, it actually automatically looks for local dbs. And there we've got the one I created. And if we look inside there, we can see that it's got table for Authors, table for Books. Those won't have any data in there yet, but they've actually got the structure put in there. Let's take that one step further then. So let's get those fake Authors that I created there, and then let's add them to the 'db.Authors'. So remember that we put in those two DbSets on there; one for Books, one for Authors. So I will take that one for 'Authors' and just do an 'AddRange ()' and pass in those fake Authors. Now notice the neat thing here. I don't explicitly have to add any of the Books because the Authors already have Books in their collections, and I've now added the Authors to the database, the database - the Entity Framework system - will follow through all those connections and make sure everything actually gets put into the database in the correct way. So all I actually have to do is - one thing to remember - I've got to do a 'db.SaveChanges();' Until you do a SaveChanges, anything you've done is only in memory. SaveChanges() starts a transaction, does whatever SQL is necessary to issue that to the database and then commits the transaction. So if anything goes wrong, nothing happens or it'll all go in there in one go. And so now if we run that again, we won't see anything. A bit quicker that time because it didn't have to create the database, but now, if we look at Authors and just do Edit Top 200 Rows, there we can see our two Authors automatically had Ids allocated to them. If we look at the Books we can see ... got all the Books, they've got their own Ids, but also it's worked out that foreign key. So we never mentioned AuthorId. It's just made the assumption that because we had, in our Book class, we had a reference for 'Author' it has decided the most sensible name for that would be 'AuthorId' as the foreign key, so it's set all of that up. Also something you'll notice, it's worked out for itself - if we look in here - is that 'Id' in both cases should be a primary key. How did it know that? Well, it knows that because everybody calls their primary key 'Id' - or not everybody, but it's a common enough convention that rather than us as a programmer having to do anything explicit to say I want you to make this the primary key, it just does it. It's what's known as a principle of convention over configuration. So because by convention, Id is very commonly a primary key, it just works these things out. All of these things can be overridden if you want to do things differently. And we'll see in a later video some of how to do that, but why go against the flow? For most things following these conventions not only makes your life easier in that you just let the tools get on with it, but also makes the code easier to read for anybody else, because most people are following the same conventions. Okay. So having got the data in there, let's just change our program a little bit to read it out. So we'll get rid of the creating of the fake data, but let's put back in the printing out. And so rather than Authors, will now just say 'db.Authors' and so that should give us our collection. Let's run that and we can see it got as far as 'Jane Austen'. So it read in 'Jane Austen', but then it hit this NullReferenceException, and that was happening actually when we got in here. If I just run that up in debug, we'll see that if we look at this Author it's 'Jane Austen'. But the Books collection is null, and this comes down to a concept in EntityFramework known as 'loading', and the contrast between 'lazy loading' and 'eager loading'. If we had lazy loading enabled, then when the system got to this point, saw that books was empty, it would have issued another query to get the Books back from the database and then be able to display them. But actually, although lazy loading is available in Entity Framework Core, it is very much deprecated. In Entity Framework 6 it was kind of the default option, but the problem with it is it can be very inefficient, because what happens here is we issue a single query to get all of the authors, which remember, as far as this example goes, is two authors. But then on each iteration of that loop we're going to be issuing another query, firstly to get Jane Austen's books and then secondly to get Ian Fleming's books. And you can imagine if this were a big system where we had a thousand authors that would be a thousand and one separate queries being issued to the database to get back the authors and all of their books. Therefore what is a much better idea is to use eager loading, where we specify upfront what it is that we want to load. And so what I would do here would be 'authors.Include(' and then using a lambda. I could say 'a' for author '=> a.Books)'. So don't just get the Authors; get the Authors and their Books. Much more on eager loading in later videos, but now if we run that we can see that that gives us the Authors and their Books. And really that's the basics of Entity Framework. We've managed to create the database, we've managed to create data for the database and we've managed to read it back. One last thing I'll just show you - and then we'll finish it for this one - is that we can also issue queries. So just make sure that we've got LINQ included here, so 'using System.Linq;' and then in here we could say 'var recentBooks = from b in db.Books where b.YearOfPublication > 1900 select b; ' And then in my loop here I could go through 'var book in recentBooks' I'm in this case going to do an 'Include' of author because, again, it works both ways. If we didn't do that, we'd just get the Books. And then I'm going to put something like 'WriteLine' and then '{book} is by' and then we can have '{book.Author}' And if I run that, we'll see it does the query and we just get the Ian Flemings because they're the modern books. So very quick introduction, but that is how you can create your first database with, in this case, a couple of classes - a one-to-many relationship. Other things like many-to-many relationships, inheritance, all those things are possible, but they'll be seen in later videos. So I hope that was helpful, and do watch out for the next one where we'll be looking at some other features of Entity Framework and Entity Framework Core
Info
Channel: Coding Tutorials
Views: 5,428
Rating: undefined out of 5
Keywords: entityframework, dotnetcore, entityframeworkcore, linq, database, coding, tutorial, sqlite, roacle, sqlserver, c#
Id: Fo8VEtIjA5I
Channel Id: undefined
Length: 20min 6sec (1206 seconds)
Published: Fri Sep 18 2020
Related Videos
Note
Please note that this website is currently a work in progress! Lots of interesting data and statistics to come.