Entity Framework Core 2 20190805
Entity Framework Core 2 20190805
by Julie Lerman
This course helps those with experience in earlier versions of EF and EF Core, and developers
completely new to Entity Framework. Learn how to build data models with EF Core and use EF
Core to let your software interact with data in your databases.
INTRODUCTION
Entity Framework Core 2 is the newest version of Microsoft's O/RM for performing database
persistence in .NET-based software. EF Core is a lightweight and extensible version of Entity
Framework that has been written from the ground up. Whether you are new to EF Core or looking
to see how to shift your earlier EF experience to EF Core, this course can help you get started.
First, you'll learn how to define an EF Core data model to act as a bridge between your .NET
objects and your database. You'll then learn how to interact with the data model using EF Core's
various APIs. Finally, you'll be shown how to incorporate this model into a desktop application
based on the .NET Framework and a cross-platform ASP.NET Core MVC application. By the end of
this course, you will be able to build .NET framework, or .NET Core software using EF Core 2. All
coding will be done in Visual Studio 2017 in a Windows environment.
Course Overview
Course Overview
Welcome to Pluralsight. My name is Julie Lerman, and you may know me as one of the most
recognized authorities in the world on Entity Framework, Microsoft's data access platform for. NET
development. I'm so excited to share with you the newest version of Entity Framework Core. EF
Core 2 brings back more of the features many developers depended on in earlier versions of EF, as
well as new innovations beyond that first iteration of EF Core, it's the version that finally feels
ready to many developers and businesses who were originally reluctant to try out EF Core. If
you're already using Entity Framework or that first version of EF Core, this course will help you
learn how to leverage your existing EF knowledge to quickly get up to speed with EF Core 2. If
you're brand new to EF, you'll learn the basics and get insights that will take you further than a
standard baby steps lesson. Whether you're building software for Windows or cross platform apps
for. NET Core, this course will give you an understanding of the variety of environments where you
can build and deploy apps that use EF Core 2. You'll learn how to build and interact with data
models and then build a desktop app and a cross platform ASP. NET Core app that use EF Core 2
for their data access. While this course will use a familiar environment, Visual Studio 2017 on
Windows, everything you learn here will apply to any of the environments where you can build.
NET Framework or. NET Core software. I hope you'll join me on this journey as you get quickly up
to speed on using Entity Framework Core 2.
Hello. I'm Julie Lerman, and welcome to Entity Framework Core 2: Getting Started where you'll
learn about the latest version of Microsoft's modern data access platform. This getting started
course is designed with a number of people in mind. If you've got experience with Entity
Framework, you might be aware that EF Core has been rewritten from scratch to achieve some
new goals and you may be happy that you chose to skip over the first iteration of EF Core. If you
are coming from that first version of EF Core, things have improved greatly, and I still recommend
that you take this opportunity to learn about this new version. Here, you'll learn about the
similarities to and differences from EF Core 1, EF 6, or perhaps earlier versions of EF that you're
using. If you've never used Entity Framework before, you'll first learn why you would want to use
EF Core and then be guided through, not only building a simple application that uses EF Core for its
data persistence, but you'll be getting this guidance and insights from one of the top Entity
Framework experts in the world. I've been working with Entity Framework since before its initial
release in 2008 and I've written four books on it. You'll find lots of Entity Framework courses from
me in the Pluralsight library already, so I promise you're in good hands here. If you're looking at EF
Core for your team's projects, this first module will give you valuable insight, even if you're not
interested in the actual coding that follows in the rest of the course. This course is designed to
provide a thorough introduction to EF Core 2. This first module focuses on concepts, the whats,
wheres, and whys of EF Core while the subsequent modules will focus on coding. There, you'll
start by building a data model using EF Core's DbContext and also learn how to use EF Core's
migrations to create and evolve the database where EF Core will be persisting your data. With a
data model and a database in hand, you'll then start coding against that data model to interact
with the database, and then we'll create a desktop application and a web application incorporating
EF Core and your new data model into each of those apps. Even though EF Core is cross platform,
this course will focus on Windows because the EF Core APIs are no different from one platform to
another, so with the exception of some of the tooling, what you learn about EF Core will transfer
to other platforms. I'll be coding in Visual Studio 2017 on a Windows 10 operating system. It is
possible to follow allow with Visual Studio 2015, except for the demos where I'm using ASP. NET
Core, those require 2017. If you don't have Visual Studio 2017, you can always grab the
Community Edition for free or a 90-day trial of the Professional or Enterprise versions to follow
along with all of the demos. This module will focus on providing you with high level, conceptual
information. You may already know that EF Core is a data access platform, but I'll be sure you
understand more about what it is and why I think it can be valuable in your software development.
One of EF Core's goals was to align with. NET Core's goals of being cross platform, but Entity
Framework Core is still instrumental in full. NET Framework applications and this has been
worrisome to developers who are only hearing bits and pieces of this information. I'll explain how
EF Core aligns with. NET and Windows and how this relates to its Cross-platform capabilities. Then
I'll be sure you know about the great variety of platforms and application types where you can
include EF Core, as well as what your coding environment can look like since there are so many
possibilities. I'll be sure you understand the overall workflow of how EF Core works within your
applications before you start coding followed by some important pointers on getting from EF6 to
EF Core before moving onto EF Core 2. Then I'll provide an overview of the new features that EF
Core 2 brings to the table, some of which we will dig into further on in this course and other which
I'll leave for more advanced courses on EF Core 2. And finally, I'll finish up with a quick look at
what's coming up in the next minor version, which is EF Core 2. 1. 0.
Entity Framework Core, or EF Core, is an evolution of Microsoft's object relational mapper, Entity
Framework, which has been around since 2008. It encompasses a set of. NET APIs for performing
data access in your software and it's the official data access platform for Microsoft. The official
documentation describes EF Core as a lightweight and extensible version of Entity Framework. In
other words, this was not simply an update from the latest Entity Framework, EF6, it's a different
kind of Entity Framework. EF Core was first released in late June of 2016 after over 2 years of
effort, many alphas, many betas, and even a few release candidates, this first version was followed
by a great amount of change with EF Core 2, which was released a year later. Along with. NET Core
and ASP. NET Core, EF Core 2 is seen by many as the first solid version, although EF Core 1 is still
supported for those instances that are already in production. There was an important update with
the version named EF Core 2. 1 and brought a lot of new features to it. I'll talk a little bit more
about the 2. 1 update further on in this module. Object relational mappers, or ORMs, are designed
to reduce the friction between how data is structured in relational database and how you define
your classes. Without an ORM, we typically have to write a lot of code to transform database
results into instances of the types in our software. An ORM allows us to express our queries using
our classes, and then the ORM itself builds and executes the relevant SQL for us, as well as
materializing objects from the data that came back from the database. While a typical ORM infers
that the classes and database tables are of a similar structure, Entity Framework has a mapping
layer in between, and that gives us a lot more flexibility in how to get from objects to tables and
from object properties to table columns. And for these mappings, Entity Framework does start
with some assumptions. We refer to those as conventions. But then you can apply additional
mapping rules on top of those conventions to be sure that in your specific scenario, that data is
able to find its way back and forth between your objects and your database. So why an ORM over
other ways of doing data access? And why this ORM? Why Entity Framework Core? Using an ORM
can really eliminate a slew of redundant data interaction coding tasks. In doing so, EF Core can
really enhance developer productivity. It also provides consistency in the tasks that it does rather
than having various members of your team invent their own means of designing their data access
tasks. Not to say that there isn't a learning curve for EF Core, especially if you want to leverage its
advanced features. But in simpler scenarios, the learning curve can be quick. EF Core has a
dedicated team at Microsoft, and Entity Framework has been around for over 10 years and has
gone through a number of evolutionary steps as it gains functionality and has become more
sophisticated. The last version of what we might refer to as classic Entity Framework, and that's
EF6, has over 14 million downloads. It's used in myriad applications and will continue to be
supported and maintained. But the evolution to EF Core in order to continue to innovate on Entity
Framework shows that this investment will continue to be of high importance to Microsoft. Most
ORMs allow you to connect to a variety of databases, and EF Core is no exception. While Microsoft
maintains rich providers for SQL Server and SQLite and even an InMemory provider that's
incredible for automated testing, there are many other third party providers as well, some
commercial and some from the community. Rather than writing the relevant SQL to target
whatever relational database you're working with, EF Core uses the LINQ syntax that's part of the.
NET Framework. LINQ to Entities allows developers to use a consistent and strongly typed query
language regardless of which database they're targeting. Additionally, LINQ for Objects is used for
querying other elements in. NET, even InMemory objects. So developers benefit from their
knowledge of LINQ whether they're using LINQ to Entities, LINQ to Objects, or some other flavor of
LINQ. Using an ORM allows developers to focus on their domain, their business rules and their
business objects. They don't have to worry about direct interaction with a database or being
intimately familiar with the database schema. Developers still need to understand how Entity
Framework Core works and some of its nuances with regards, for example, to tracking changes
that need to be persisted to the database or patterns for working in disconnected applications. But
that follows the importance of understanding how any of your tools work and not just blindly
using them in your software. The evolution that EF Core brought to Entity Framework, perhaps a
revolution, is that it was rewritten from scratch in order to embody modern software practices, as
well as be able to run on many operating systems whether combined with. NET Framework on
Windows or with. NET Core, which can run on Windows, macOS, and Linux. It can also run on
mobile devices such as any Windows 10 application created with a universal Windows platform or
Xamarin-based applications, which add in iOS and Android devices. EF Core is open-source and
available on GitHub. Notice the URL is github. com/aspnet/EntityFrameworkCore. Here, you can
watch it evolve, raise issues that you might discover, download and experiment with the latest
bits, even those that aren't officially released yet, and most importantly, you can clone the
repository, add in your own fixes or features, and submit those as pull requests to become part of
Entity Framework Core. Do keep in mind that any pull requests that are submitted from the
community do go through a rigorous examination before they're accepted into the official code
base. The release cycle for EF Core is relatively rapid compared to the 2- year cycle from days gone
by. Instead, it's tied to the release cycle of. NET Core with patches and updates being pushed out
every few quarters.
Here is a high-level look at EF Core's workflow which I feel is important to understand before
jumping into any code. The puzzle pieces involved fall into four different categories. First, you
need the classes that describe your domain, the business problem that your software is going to
solve, and this part actually has nothing to do with Entity Framework. Then you use Entity
Framework APIs to define a data model based on those domain classes. You also use Entity
Framework APIs to write and execute LINQ to Entities queries against those classes, and in your
code, you'll need to call Entity Framework's save changes to push data back to the database. What
Entity Framework's APIs will do for you is keep track of the state of objects that it's aware of, it'll
determine the SQL it needs to save data back to the database, and for queries, Entity Framework
will transform your LINQ to Entities queries into SQL, execute that SQL, and then create objects
from the query results. The last major puzzle piece is that Entity Framework manages all of the
interaction with the data store. I've talked about the data model being dependent on existing
classes. Some developers are starting a new project from scratch and will most likely start by
planning how the domain will function and that will help them define the classes. Then they can go
ahead and code the classes, and when it's time to add in the data persistence, you can then create
DB Context classes to define data models that wrap those domain classes. The data model can
then be used with Entity Framework migrations to create and evolve the database, but that's not
always how your projects evolve. So often, we already have an existing database and while those
database tables, and views, and store procedures may not necessarily reflect what your domain
classes should look like, they do provide a good head start and it's possible with Entity Framework
Core to start by reverse engineering one or more tables into a DbContext class that is your data
model and a set of domain classes, but this is a one-shot deal, it's simply to give you a head start
on coding the classes in the context, then you can finetune that data model that got generated
and even move forward with migrations to evolve that pre-existing database as the domain
evolves. I'll certainly spend more time further on in this course on taking advantage of EF Core's
ability to reverse engineer from an existing database and that uses a feature called scaffolding.
When defining the data model, your classes aren't required to exactly match the schema of the
database. Entity Framework does have a lot of default rules for how it will infer what the database
schema looks like and that helps it determine what the SQL should be for commands and queries
and also how to create objects from query results coming back from the database, for example, it
presumes that property names match the column names in the map table, it also makes
presumptions about types in many other facets, but you can affect most of the mappings, for
example, a custom mapping is helping Entity Framework understand that the FirstName property
doesn't follow convention when it maps to the database, but instead, should map to a column
named First_Name that's an nvarchar with a length of 30 and that it's not nullable. I'll also take
advantage of an EF core convention when it is on my context. That's one that ensures Entity
Framework will understand that the name of the table I'm mapping to is plural. But keep in mind,
these are facets of the database schema and they don't, by default, drive the business logic and
validations in your code. With this information in hand, let's now look at a basic workflow of how
Entity Framework works in an application. As I said earlier, it really all starts with your domain
classes, not with Entity Framework, but with those classes, you can then use Entity Framework's
DbContext API to wrap the classes into a model and instruct Entity Framework as to how those
classes in the model map to the database schema. With this understanding and the help of the
relevant database provider, Entity Framework can then translate queries that you write and link to
entities against your classes into SQL that's understood by your database. It then executes the
query and uses the results to return populated instances of your objects, again, taking away all of
that redundant work that we normally have to do. You could also map to views, instead of tables,
and if you need to, you can even execute stored procedures, maybe if Entity Framework just can't
create efficiently performing SQL or if the query is just too hard to express with LINQ. Entity
Framework can keep track of objects as long as the DbContext is in scope, for example, this could
happen in a desktop application. If you edit or add or delete an object, Entity Framework will be
aware of it. With disconnected apps though, we do have patterns to inform Entity Framework of
this state of an object when it comes back from whatever was working with it. Then with a single
command, save changes, Entity Framework can use all that state information to build and execute
the relevant insert, update, or delete commands on the database. This is, of course, a really high-
level explanation without getting into all of the advanced things you can do to affect the default
workflow of Entity Framework. While this getting started course will focus on some very basic
implementations of EF Core as you learn about EF Core for the first time, Entity Framework is
absolutely a key ingredient for larger, more complex systems as well. My Pluralsight course, Entity
Framework in the Enterprise, is designed to demonstrate patterns and practices for using EF in
applications that require more advanced architecture and you can benefit from these patterns in
small applications too. The course does use Entity Framework 6 as its base, but the patterns and
guidance are generalized and totally applicable to Entity Framework Core as well. You'll find the
URL for this course in the resources at the end of this module.
If you've been using EF Core already, you're probably interested in knowing what new features
have been added to EF Core 2. For those of you who are coming from EF6 or earlier and are
learning about EF Core for the first time, you should also be aware of what features were added to
the first iteration of EF Core and how that compares to EF6. Rather than go over that in detail
again, I'll point you to the first module of the original Entity Framework Core Getting Started
course and that first module is an overview just like this one, but in addition to going over the new
features in that course, I also discussed how EF Core compares to EF6, what features were in EF
Core 1, what features will never be coming to EF Core that were in EF6, and I also provided
guidance on deciding if you should upgrade or migrate existing code, as well as how to choose EF
Core over EF6 for new projects. And as you watch that, do keep in mind that the changes to EF
Core 2 that you'll learn here do change that story somewhat. EF Core 2 was already in progress by
the time EF Core 1 had initially been released. There was also a significant change for. NET Core 2
and. NET Standard 2 projects and that impacts things like tooling and project metadata files, but it
doesn't impact how EF Core itself functions. In the later modules of this course, you'll see solutions
built in. NET Framework and that creating those projects referencing EF Core's NuGet packages
and running migrations hasn't changed since doing the same with EF Core 1 beyond the need to
make sure that. NET Standard 2 SDK is installed on your machine. I'll also be creating. NET
Standard and ASP. NET Core projects, and when I do that, the changes that came in. NET Core 2
will be apparent. The most significant impact is that the project files for those projects are now CS
proj files, not project JSON, but none of this affects how you use EF Core. The changes that EF Core
2 brings are about new features, bug fixes, and performance enhancements.
I'll provide a quick review of some of the key features that came in EF Core 2. Most of these do fall
under the category of intermediate or advanced usage and I won't be demonstrating them in this
getting started course, however, I will include links to some resources for further information
about them at the end of this module and I will cover them in more detail in a future course. In the
querying category, you will see a demo later on of the new EF. Function. Like method, in addition
to that, LINQ queries have been made more efficient in a variety of scenarios, most notably, more
LINQ querying methods will be able to become part of the SQL that's run on the database, rather
than left for post query client-side evaluation. It's now possible to define query filters in your
DbContext for individual entities, and these filters will be applied to any queries that your app is
executing before that query goes to the database. Even though EF Core compiles queries on your
behalf, it's also now possible to explicitly compile queries as we were able to do in EF6 and earlier
versions. If you use GroupJoin in your queries, you'll notice that the SQL that it generates is much
smarter in EF Core 2 than it was in the first version of EF Core. Under the category of mappings,
new to EF Core 2 are features we had in EF6 and can now benefit from again. Thanks to
community member, Paul Middleton, we can map to user-defined scalar functions in our
database. When applying mappings with affluent API, you can once again create a class to contain
all of the configurations for a single type. One of the most important changes that I was waiting for
is support for value objects, which Entity Framework had always provided with its complex types
since the very first version of Entity Framework. The support had not been worked into EF Core 1,
but now in EF Core 2, we have something better that replaces complex types and it's called owned
entities. I've got a link in the resources to a pair of articles that I wrote about this and some other
related features in EF Core 2 that should be of interest to anyone with an eye for domain driven
design. Table splitting is also something we are able to do since the first version of EF, that means
being able to define an entity and have different sets of its properties mapped to different tables
in the database. This feature is also related to the new value object support provided by the
owned entities that I just mentioned. DbContext pooling is a really cool performance feature that
allows EF Core at runtime to use a pool of pre-created DbContext instances, rather than
instantiating a new context every time. While I won't be covering the use of raw SQL queries and
commands until the intermediate course, this feature does have a nice enhancement in EF Core 2,
which is that it now takes advantage of string interpolation that was introduced in C#6 and VB14.
We'll definitely be logging the SQL that's run by queries and commands throughout this course
and I was really happy to see that logging got a lot easier to use since the first iteration of EF Core.
You will get some hands-on experience with this further on in this course. One of the benefits of
the ground-up rewrite of EF Core is that most of the logic that's used under the covers is no longer
hidden away in private, inaccessible methods. Instead, EF Core is made up of hundreds of services
that you can override with your own versions, and with EF Core 2, it's now a lot easier to tell EF
Core how and when to use your custom overrides for these services. An interesting way to see
everything that changed between EF Core 1. 1 and EF Core 2 is on GitHub. If you go to the
Releases page for the EF Core repository, you can see a list of features and bugs fixed as the APIs
made their way to EF Core 2. You can start by scrolling down to the EF Core 2. 0. 0-preview 1 and
look at what's listed there, then scroll up to see the preview 2, and then to the actual 2. 0. 0
release, and continuing up, you can see what happened after that, which is a list of mostly bug
fixes that came for 2. 0. 1.
EF Core 2. 1 is already well underway and it's targeted to be released some time in the first half of
2018, which is a pretty wide target. But by the time you're watching this course, it may have
already been released. This upcoming minor version has a long list of new features along with
more tweaks and bug fixes. Most of the new features coming in EF Core 2. 1 wouldn't have made
it into the scope of basics that are covered in this getting started course, so they will make great
additions to a followup course on EF Core 2. Before looking at the list of what is coming in EF Core
2. 1, I do want to be sure you're aware of the EF Core roadmap that the team maintains where
they describe where EF Core is at and what they're plans on for its future. It's an important place
to check up on features you're interested in to see if there already in EF Core, coming soon, or on a
back burner. Here is the list of the most interesting features coming in EF Core 2. 1. Notice that
again, I've marked which features are ones that are finally making their way from EF6 into EF Core,
such as GroupBy, lazy loading, database seeding, system transactions, the ability to intercept
events, and very interestingly, the ability to update a data model based on changes made to the
database. The reason I find this last one extra interesting is that it's a feature that we associate to
the EDMX designer-based way of reverse engineering from a database that we've had since the
first version of Entity Framework, but now that capability will be added to the code first
scaffolding workflow. You may be aware of the initial proof of concept for allowing EF Core to
interact with no SQL databases long before EF Core was even released, in fact, back when it was
still referred to as EF7. Well EF Core 2. 1 will have a provider for interacting with a Cosmos DB
document database, that's going to be super cool. Feel free to pause the video to look over the
rest of this list before moving on.
This module has provided an overview of things that I think are important for you to know about
EF Core to help you make decisions about using it, as well as prepare you before rolling up your
sleeves to start coding. You should now have a decent understanding of the benefits of using an
object relational mapper and of using EF Core. You've learned about the Cross-platform nature of
EF Core, but that it also continues to be a critical part of. NET Framework solutions. I've provided a
high-level view of the puzzle pieces of EF Core and how it fits into the workflow of your
application. If this is your first look at EF Core and you're coming from EF6, remember that I've
suggested reviewing the first module of the getting started course I created for the first version of
EF Core where I spend some time discussing how EF Core relates to EF6, as well as what EF Core
originally brought to the table. With all of this due diligence behind us, you've then got an
overview of new features that EF Core 2 provides. Since you'll only see some of those in action in
this course, I gave you brief descriptions of the most prominent features new to EF Core 2. And
don't forget that EF Core 2. 1 is coming down the pipeline and you've seen the list of some of the
most interesting things to expect from this next minor version. Here are the links to resources that
I mentioned throughout this module. You can find the EF Core repositories on GitHub, the
roadmap, a number of articles I mentioned, shortened links to the first getting started course for
EF Core version 1, as well as my EF in the Enterprise course that I mentioned. And here is a link to
the Visual Studio downloads if you need to get Visual Studio 2017 installed before moving onto the
next module where you will dive right into the code. I'm Julie Lerman, and thanks for watching
Entity Framework Core 2: Getting Started.
Hello. I'm Julie Lerman, and welcome back to Entity Framework Core 2: Getting Started. In this
module, we'll dive into Visual Studio 2017 to build your first EF Core data model. We'll start by
setting up a solution and some full. NET Framework projects to host the business classes and the
EF Core 2 data access. Then we'll add EF Core 2 into the data access project and build up a data
model using its APIs. Once the data model has been created, you'll learn how to use EF Core
migrations to create a database from the model or just generate SQL scripts so you can create the
database when you're ready. With the first model created, we'll recreate it, and a little faster this
time in a solution for a cross-platform ASP. NET Core project. Then we'll modify the model adding
in some more complicated relationships, a many-to-many and a one-to-one, to see how EF Core 2
translates them to the database. We'll migrate the database a second time to apply those model
changes, and when we're all done, you'll have classes, a database, and an EF Core 2 power data
layer to start coding with.
Remember that EF Core 2 has a dependency on. NET Standard 2, but that's not installed by Visual
Studio 2017. You can check to see if you've got the correct version using the command line. First,
type dotnet to see if dotnet is even installed. If it's there, then type dotnet --version and it will list
the version of the dotnet command line interpreter or CLI. Mine is the newest, 2. 0. 3, which aligns
with the current version of EF Core, which is 2. 0. 1, these were released in November 2017. If you
need to install the latest version of the SDK, you can go to microsoft. com/net/download to get it.
The URL redirected to Windows because I'm on a Windows machine. You'll be downloading the.
NET Core SDK, which will also install the runtime for you. Once that's installed, you can get to work
in Visual Studio 2017. The first order of business is to create a new solution and I'll use the new
solution template just to make that easier to do. I'm calling my solution SamuraiApp. Once I've
created the solution, I'll add some projects and I should give you a little context about the domain,
why I'm calling SamuraiApp. If you followed the work I've been doing with Entity Framework,
when EF6 came out and it was so powerful, I referred to it as the Ninja edition. In the early stages
of EF Core, Microsoft was calling it EF7 and it made sense to me that I should graduate from 6 with
ninjas to 7 with samurais, especially in honor of one of my favorite movies, The Seven Samurais.
Eventually, this was renamed from EF7 to EF Core, but I'm sticking with my samurai's domain.
Once I've created the solution, I'll add in some projects. The first will be a project to host my
classes that represent my business domain. I'll create a class library project, but notice I'm using
the template we've always used, the one that targets. NET Framework. With this first demo, I'm
going to stick with full. NET because of its familiarity. I'll call this project SamuraiApp. Domain.
Once that's there, I'll create another. NET Framework Class Library project and this one I'll call
SamuraiApp. Data. The goal of this module is only to build my data model and create the database,
but I do want to make sure you understand that if I were building tests or a user interface, I would
be putting those in separate projects. I find following separation of concerns to be really helpful
when I design applications, and in a larger app, I would separate things even more. I'm not really
going to use the test or UI project in this module, but I wanted you to see that they would be
separate projects. Now I've got my solutions set up and I'm ready to start adding in some code. I'll
start with a new Samurai class, make sure it's public, and then I'll just paste in a few properties
that I'm going to use for this demo. If you're following along, all of this code is available in the
beginning portion of this module's download or you can pause the video and type in what I'm
showing you here. I'm intentionally keeping things very simple for this first look at EF Core. My
Samurai class has an Id property and that will be used for the identifier, it has a name and a list of
quotes that would be famous quotes that the samurai spoke in the movie. I also have a BattleId to
reference a particular battle that the samurai has fought in. This constructor ensures that the list
of quotes is already instantiated before I try to use it in code. These extraneous using statements
are distracting, so I'll go ahead and remove them. Yeah, that's better. Now I'll add-in the other two
classes, Quote and Battle, and again, for simplicity I'll just copy and paste them in from the
downloads. Here is the Quote class with its Id property for tracking it and the text that will contain
the spoken quote. I've also got a reference property back to Samurai and an explicit integer
property that will contain the foreign key value, which is the Id of the Samurai. And finally, here is
the Battle class, it has an Id property, the name of the battle, the start and end dates of the battle,
and a list of the Samurais that were in that battle and that's where we'll leave the classes for now.
You may be wondering why I've defined this module so that a Samurai can only be in one battle,
it's not because my Samurais are such bad fighters that they always die in the first battle, it's
because with EF Core defining a many-to-many relationship is currently a little more complicated
than I want to show you in this very first look at creating a model. After we get through this first
pass of the model, I'll not only correct this relationship and make it a more appropriate many-to-
many relationship for samurais and battles, but I'll also add in a one-to-one relationship so you can
see how those work with EF Core. So that's it for my domain classes. It's pretty simple, but I do
have some relationships in here that we'll be working with and that should suffice for working with
EF Core 2 for the very first time.
Now that I have my domain classes set up, it's time to think about building the data model and
that means it's time to bring in Entity Framework Core 2. There are a few ways to bring in EF Core
to a project. I'll demonstrate using the NuGet Package Manager, which is a Visual Studio extension
created by Microsoft. I can right-click on my data project, which is the project where I'll be using
EF Core and choose Manage NuGet Packages, that brings up the package manager. Right away,
you can see Entity Framework has 36 million downloads, that's version 6. 2, it's the old version of
EF, but the packages for EF Core all have the full name, Entity Framework core in them, as a
matter of fact, they're Microsoft. EntityFrameworkCore, that still has a few extra packages. You
can identify the Microsoft packages with the purple. NET icon next to them. Now I could start by
just installing Microsoft. EntityFrameworkCore, but I'll very quickly discover that I need some kind
of a provider to interact with the database. This base package only has the absolute core of EF
Core and it doesn't have additional logic that won't apply for all scenarios. For example, EF Core
will need to know what database or datastore you plan on working with and those providers are in
individual packages, so you only need to grab the one you want. To bring EF Core in, it's easier to
start by targeting the datastore you're going to be working with and let NuGet's dependencies pull
in the rest, including the base Entity Framework Core package. I plan to persist my data in SQL
Server Local DB, which is installed with Visual Studio, that means I'll need the EF Core SQL Server
package. Notice that the SQL Server package has a dependency on
EntityFrameworkCoreRelational, that's where all the logic is that's common across different
relational databases you might use with EF Core. And if we look at the relational package, it has a
dependency on the base Entity Framework Core package. The base package has dependencies on
other packages from. NETStandard, so I know that by starting with a SQL Server package, I'll get all
the packages I need and I don't have to go back and keep installing the other ones. Once I've done
that, NuGet will kick off and go find all of the packages it needs to pull down. Now Entity
Framework Core isn't built into the. NET Framework, so it's needs to ensure that all its
dependencies are also pulled into the project. When it's done, you can see I have a heck of a lot
more references in my SamuraiApp data project than I had before and that's all the stuff that got
pulled down from NuGet, and with that, I can now start building the data model. In Visual Studio
2017, you can also install packages directly by typing the relevant PowerShell commands into the
Package Manager Console. That will install the package and all of its dependencies just like it did
when we went through the NuGet Package Manager.
Even though you've already seen me bring EF Core's SQL Server provider into this project, my
DbContext is still completely unaware of that provider. If you're coming straight from EF6 or
earlier, informing the context about the provider and connection string is quite different so do
take note. There is more magic in those earlier versions to infer the provider and connection
string, but this caused some confusion and bad side effects. With EF Core, you must explicitly tell
the context what data store provider to use and explicitly give it a connection string. There are a
few ways to do this. One is directly in the DbContext class and that's what I'll do here. Hardcoding
the connection string into the context is great for demos and first looks, but not for real software.
Later, you'll see me take advantage of some features of the ASP. NET Core to inject this
information into a DbContext at runtime. In EF Core, the DbContext has a virtual method called
onConfiguring, I'll add that into my DbContext. OnConfiguring will get called internally by EF Core
and it will also pass in an optionsBuilder instance and you can use that optionsBuilder to configure
options for the DbContext. Notice that the optionsBuilder has a method called UseSqlServer.
That's an extension method and that's available because I've got a reference to the Microsoft
Entity Framework Core's SQL Server API. If I had pulled in SQLite, I would see a method called
UseSQLite here, and if I was referencing SQL CE, I'd see UseSqlCE here. So I'll choose the
UseSqlServer method which expects a parameter that's the connection string and this is how in a
single statement I can tell the DbContext hey you're going to be working with SQL Server and here
is the connection string to the database I want you to use. Now in my case, the database doesn't
exist yet, but that's not a problem. I pasted in a connection string that will point to a local DB
instance of SQL Server and I know I want my database to be called Samurai data and now I can
delete the base call to onConfiguring because internally that method won't do anything else. Now
that I've provided this information, the first time EF Core instantiates the samurai context at
runtime, it will trigger the onConfiguring method, learn that it should be using the SQL Server
provider, and at the same time, be aware of the connection string. What's extra nice is that EF
Core's migration's API will also be able to benefit from this information as you'll see in the next
step.
If you've never used Entity Framework Migrations before, it's important to understand the basics
of what this feature does and its workflow before interacting with the APIs. Here, I'll provide a
quick overview. Recall the basic workflow of Entity Framework that I introduced you to in the
previous module. Entity Framework needs to be able to comprehend how to build queries that
work with your database schema, how to reshape data that's returned from the database in order
to create your objects from them, and also as you modify the data, how to get that data into the
database. In order to do that, it has a comprehension about how the data model you've defined
through your DbContext maps to the schema of the database and it performs that logic at runtime
by reading the DbContext and using its own conventions combined with any additional custom
mapping information that you've provided to it to infer the schema of the database, and with that
information, it's able to figure out how to do those interactions, how to build queries, how to
construct commands to push data to the database, and how to transform database results into
your objects. That also means if you evolve your data model and that could be because you've
made changes to the structure of your classes or you've added more information to the
DbContext, then Entity Framework's comprehension of the database schema will also change, but
that's just what Entity Framework thinks is in the database so it's important to make sure that
what it thinks the database looks like is actually what the database looks like. Along with a code
first paradigm with Entity Framework and Entity Framework Core, we also have a full set of APIs
referred to as Migrations. With each change to your model, you can create a new migration that
describes the change and then let the Migrations API create the proper SQL script, and if you like,
Migrations API can execute that script for you right on the database.
It's time to create the first migration for the Samurai context. Recall that EF Core APIs aren't all
packaged into one big assembly because EF Core doesn't presume that just because you're going
to use one feature that you need to use all the other features. In order to create and execute
migrations, we'll need access to the migrations commands and to the migrations logic. Not every
developer working with EF Core is going to create and execute migrations, so those are in separate
packages. The commands are in a package called Entity Framework Core tools, which you can
install using the NuGet Package Manager just like I did with the other packages. Remember to add
that to the SamuraiApp. Data project. You'll run the commands in the Package Manager Console,
which is for executing PowerShell commands. Because EF Core and the commands and the context
are in the SamuraiApp. Data project, you have to be sure that the console's default project is
pointed to that. Let's take a look at what the PowerShell commands are for EF Core. I can do that
by typing get-help entityframeworkcore. Before we look at the commands, I'll scroll up so you can
see the EF magic unicorn that was embedded right into the command's help. You can see that the
commands are Add-Migration, Drop-Database, Get-DbContext, Remove-Migration, Scaffold-
DbContext, Script-Migration, and Update-Database. Add-Migration and Update-Database might be
familiar to you if you've used EF Migrations in the past. Add-Migration will look at the DbContext
and determine the data model, using that knowledge, it will create a new migration file with the
information needed to create or migrate the database to match the model. Update-Database
applies the migration to the database. Since the task right now is to add a new migration, I won't
delve further into the other commands and we'll just focus on adding migration and updating the
database. Add-Migration has a number of parameters, but I'm only going to use the required
parameter, the name of the migration file I'm creating, so I'll type add-migration and I'll name my
first migration initial and you can see right away I get an error message. Remember that I said
we're going to need two packages and I've only installed one so far. The error says that the startup
project, which currently happens to be SamuraiApp. Domain doesn't reference the EF Core's
design package. The tools that we installed use the logic that's inside the design package, but
design needs to be inside an executable project, and in order to run that from the Package
Manager Console, that project needs to be the startup project of the solution. Remember, domain
and data are both class library projects. The UI project I added earlier is an executable. So now I
have to do three things, first, UI needs a reference to the data and domain projects, next, it needs
to have the EF Core design package, which I'll install with the NuGet Package Manager, and finally,
it needs to be set as the startup project. Now back in the console with the default project still
pointed to data since that's here the migrations need to go, I can run the add migration initial
command again and this time it succeeds.
Inspecting Your First Migration
Let's take a look at the migration I just created. Notice that there is a new Migrations folder in the
data project, and in there is the new migration file called initial along with a timestamp. There is
another file in there called model snapshot and that's where Entity Framework Migrations keeps
track of the current state of the model and that's really important because next time you add a
migration, EF Core will read that snapshot, compare it to the new version of the model, and that's
how it figures out what needs to be changed in the schema. The snapshot is just a file, it's part of
the project, and it can participate fully in source control when you're using EF Core and Migrations
across members of your team. If you're coming from a previous version of Entity Framework and
you're on a team that's using migrations, this is probably cause for celebration. This is a really
important improvement that we got with EF Core. The migration uses EF Core's Migration API to
describe what needs to happen in the database, and notice the Annotation here, it specifically says
SqlServer:ValueGenerationStrategy. That's because migrations read the configuration information
that we supplied in the SamuraiContext and knew that we're targeting SQL Server and so it
interacted with the SQL Server provider to determine some important metadata. Scrolling through
the migration file, you can see that it's creating tables, and for the tables, it's creating the columns
along with particular attributes for those columns. Also, notice that it's specifying primary keys
and foreign keys, as well as constraints between those primary and foreign keys. It even specified
a few indexes and EF Core's conventional rule behind indexes is to create an index for every one of
the foreign keys that it discovers in the model. All of that is part of a method called Up and here is
another method called Down, that's used if we ever want to unwind this particular migration. So
that's it for this first migration and the migration is very similar to how migrations looked in Entity
Framework 6. The next step will be to have migrations create the database.
With the migration in place, we now have everything we need in order to create a database. Not
only do migrations give me the ability to have Entity Framework create the database for me
directly, I can also have it generate a script, which is an important feature for working with a
production database or sharing your development database changes with your team. Entity
Framework Core's script-migration command will build up the relevant SQL, in this case, it's T-SQL
because I'm using SQL Server, based on what it's discovered in the migration file. Since there is
only one migration here, this is a simple script. When you have multiple migrations, there are
particular behaviors to be aware of and I'll show you that further on in the course. Now with this
T-SQL in hand, you can let your resident database expert take care of executing it on the
production database, they may even want to make some tweaks to it. With my development
database, I'll typically let migrations go ahead and create and update the database for me on the
fly, but with a production database, a more common scenario is to take advantage of the ability to
generate the SQL and taking more control over how and when it's applied to the production
database. I've deleted the script and now I'll show you how you can let EF Core migrations directly
affect the database with the update-database command. Before I run that, I just want to remind
you that my connection string points to a SQL Server Local DB instance with a database named
SamuraiAppData, and that database doesn't exist yet. In fact, if we look back at the migration,
there is nothing in there that says create the database. That's actually handled in the internal code
inside of migrations, which first checks to see if the database exists or not before the migrations
run, if it doesn't exist, then EF Core will first create that database at the given location. If you've
created a script and you're running that, you will be responsible for creating the database yourself.
I won't be using any of the update-database parameters, although I will use a parameter that's
common across PowerShell, which is the verbose parameter, this lets you see everything that the
update-database command is doing and you can see it's discovering the correct projects, it's
rebuilding the solution, and then finding all of its assets. Finally, it applies the migration and it's
done. Now after I refresh the SQL Server Object Explorer, I can see the new database
SamuraiAppData. If I expand that further, you can see the new tables, Battles, Quotes, and
Samurais, and remember those pluralized names were driven by the way I named the DbSets in
my DbContext. I'm intentionally overlooking the EF Migrations history table for now. I'll explain
that momentarily. But first, I want to look at the tables from a different perspective. I'm now in
SQL Server Management Studio to show you a database diagram, which is a nice way to see what
EF Core migrations created from a schema. You can see that it created primary keys and that's
thanks to one of EF Core's conventions based on the fact that the property names in my classes
were named Id. You could also see that the default data type derived from my string properties is
an nvarcharMAX, which is actually a default that's driven by the database provider, not by EF Core.
If you're coming from an Entity Framework background, none of this is any different from what
you're used to with EF6 or earlier versions. We saw in the migration code that it was working out
not just the primary keys, but also foreign keys, and you can see those relationships also visualized
here in the diagram, along with the names that EF Core's conventions provided for those
constraints. So what about that history table, its job is to keep track of which migrations have been
run on the database and its columns or MigrationId and the ProductVersion that was used. Before
EF Core, migrations also stored those snapshots in here and create migrations actually had to
interact with the database and that's something that created big headaches for teams who were
using migrations and source control. So that completes step one for creating a new model and a
new database using Entity Framework Core 2 in a solution where all the projects target the full.
NET Framework.
Whether you're using EF Core in the full. NET Framework or in one of the other platforms that
support. NET Standard, you're still using the same EF Core APIs and I think it's important for you to
see EF Core in a. NET Core app as well. So I'll quickly recreate the model to be used in a cross
platform ASP. NET Core application. A good portion of the EF Core code in this ASP. NET Core
solution will be the same as the one you just saw me build. So my plan is to just hit the highlights
of creating the model. Most importantly, I'm not using the full. NET Framework, so this time, I'll
choose. NET Standard templates for the domain and data class libraries.. NET Core sits on top of.
NET Standard, so APIs are written with. NET Standard, but executables are written based on. NET
Core. If I wanted to add a console app as my executable, I would create a. NET Core based console
app, but what I really want in this solution is a website. So I'll create an ASP. NET Core web
application that relies on the. NET Core for its framework, and then on top of that, ASP. NET Core
2. 0 and that will provide the hosting and other critical pieces for the MVC application. I've copied
the exact same domain classes Quote, Battle, and Samurai that I used in the. NET Framework
solution into my new. NET Standard Domain class library. I'll be using EF Core 2 in the data library
just as I did before and I can do that in the same way. I'll install the EF Core SQL Server provider
through the NuGet Package Manager, and with that installed, let's take a look at this
Dependencies section of the project. In a. NET Framework library, this would just be references,
but for. NET Standard, it's divided into different groups. Here are the NuGet Packages that I'm
using, so inside of there is the SQL Server provider and you can drill into that to see its dependency
chain that was brought in by that package. There is a group for other projects that are referenced
in this solution, and I've already added a reference to the domain project. And finally, there is a
group for the SDK that the project is dependent on and that's the NETStandardLibrary, which was
brought in by the project template. After adding in EF Core, I'll copy in the SamuraiContext class
that I used from the other solution. I could leave these hardcoded DbContext options right here in
the class and things will just work, but because I'm using ASP. NET Core as my executable, I want
to take advantage of its support for dependency injection. So I'll remove the onConfiguring
method and instead add a constructor to the SamuraiContext class that will take in a
preconfigured options builder and that way I can let the WebApp determine which provider and
connection string to use. That means that the WebApp project needs references to EF Core and
the SQL Server provider, but I don't have to add that directly to the project because the template
that I chose set this project up to have access to all of the basic packages that an ASP. NET Core
website might need and it does that by referencing a package named AspNetCore. All, that lets
you have what you need at design time without having to go and pull in this package and that
package and another package, they're all there, and if you're using Visual Studio's tooling to
deploy your website, then it will only deploy the packages that you're actually using, not all of
them. So it's the best of both worlds for design. I do still need to add references to the data and
domain projects though. The place to specify the provider and connection string in the
AspNetCore app is in its startup file. I'll be sure this class has the EF Core and SamuraiApp. Data
namespaces at the ready. Then in the ConfigureServices method, I can add a new service to make
sure, the WebApp will know about creating and injecting my Samurai context. That's services.
AddDbContext, which is a generic method, and then I can tell it that I want the type to be
SamuraiContext. AddDbContext lets me setup the DbContext options as a parameter. So I'll use
the options variable and then a lambda to recreate the UseSqlServer method that I've removed
from the DbContext class along with the SQL Server connection string. Rather than hardcoding the
connection string, you can modify the WebApp's appsettings. json file with a setting for the
connection string and I'm naming that SamuraiConnection. Now with my UseSqlServer method, I
can just tell it to read the SamuraiConnection setting from the configuration. Finally, I'm ready to
run EF Core Migrations to create the database. Migrations is able to find those options in the
Startup file, and thanks to the AspNetCore. All package, I'll be able to run the PowerShell migration
commands without adding anymore packages to the web project or the data project. I'll be sure
that the WebApp is my startup project, then go back to the Package Manager Console, ensure that
SamuraiApp. Data is the default project, and then I can run add-migration initial. This is exactly the
same as the other solution. So by now, I hope you're understanding that there is really no
difference between using EF Core in a. NET Framework app or in a. NET Core app. The only thing
I've done differently is taking advantage of ASP. NET Core's built-in dependency injection support.
So the migration has been created and it's exactly the same as the one I created earlier. I do want
to point out that in the appsettings file I made the database name a little different in the
connection string, it's SamuraiAppDataCore this time, that way it'll be obvious when migrations
creates the database for me. And now I can run the update-database command and notice that I
didn't use the verbose flag, but I'm still getting those details, that must be an ASP. NET Core
feature. When update-database is done, I'll open up the SQL Server Object Explorer again and
there is the new SamuraiAppDataCore database with the same schema as its predecessor,
SamuraiAppData.
I'm going to add two new relationships, a many-to-many and a one-to-one into this model and
then migrate the database again. I'll be doing this quickly here, but if you want to understand the
details, you can review them in the earlier EF Core getting started course or watch the
intermediate EF Core 2 course that will be released shortly after this one. Rather than have a
samurai only be in a single battle, it should be possible for one samurai to fight in many battles
and many samurais fight in a single battle, that requires a many-to-many relationship between
them. In EF Core 2, this means a join entity to link them and I'll do that with a new class called
SamuraiBattle, it has a SamuraiId and a BattleId, these are required, but the navigation properties
to samurai in battle are optional. Now I need a list of SamuraiBattles in the Samurai class and in
the Battle class. I've commented out the properties that these are replacing. The classes are now
set up properly, but EF Core can't infer this relationship and won't be able to map to the database
nor translate queries and updates, but it's possible to assist EF Core in understanding our intent
when it's not following its own conventions. Here in the SamuraiContext class, I'm using EF Core's
Fluent API to do this. The fluent mappings go into the DbContext onModelCreating method, which
gets called internally when EF Core is working out what the data model looks like. Using the model
builder object that EF Core has passed into the method, I've told it that the SamuraiBattle entity
has a key composed from its SamuraiId and BattleId properties. Now EF Core will be able to build
the SQL for queries and database updates that respect this many-to-many relationship. So let's
move onto the one-to-one relationship. I've created a new class called SecretIdentity to keep track
of a samurai's real name. The new class has an Id, the name, and the Id of the samurai it belongs
to. The Samurai class now has a navigation property to define the secret identity. With the
navigation property in samurai and the foreign key SamuraiId property in the SecretIdentity class,
it's enough for EF Core to comprehend the relationship without any more information from me.
Keep in mind that the dependent end of a one-to-one relationship, in this case, the SecretIdentity,
is always optional as far as EF Core is concerned, there is no way to apply that constraint in the
model, or for that matter, in the database. If you want to require that samurai always has a secret
identity, you'll have to do that in your own business logic. Now it's time to migrate the database so
I can persist the new data. The steps are the same as before. I add a new migration with a add-
migration command, this time, EF Core will read the model snapshot that got created with the
previous migration and use that to figure out what's changed since then, then creates a new
migration to describe those changes. When I call update-database, it applies those schema
changes to the database and any data I already had in the database remains intact.
You've seen me use migrations to create a database from a DbContext and classes. It's also
possible to reverse engineer an existing database into a DbContext and classes. Typically, this is a
one-time procedure to get you a head start with your code if you're working with an existing
database. At some point, EF Core will support updating the model with database changes, but
that's not possible with EF Core 2. Also, with the current version, it's not easy to begin by reverse
engineering an existing database and then migrate the database with model changes. So I'll
provide a link in the resources to a blog post by Christos Matskas that explains how to make sure
you can use migrations after creating your model from an existing database. I am starting with an
empty. NET Framework class library where I've already added in the EF Core SQL Server package
and the EF Core Design package, along with our dependencies. The PowerShell command to use
for this task is scaffold-dbcontext. Here is a list of all its parameters and you can see that there is
some flexibility as to options like where the file should be created and what the DbContext should
be named. The provider and connection parameters are required, though, which makes sense.
Before running the command, I also want to point out that in addition to ensuring my new project
is the default project in the Package Manager Console, it's also the startup project in this solution
and that's something that's different than what we have to do for the other migration commands.
I'll run the scaffold-dbcontext command with just the required parameters. The provider is
Microsoft. EntityFrameworkCore. SqlServer and the connection is the connection string for my
legacy database. Notice that the connection string is in quotes. That's because there are spaces in
this string. When I run this, watch the project in the Solution Explorer. A bunch of new files are
added in. Since my legacy database has the same schema as the one we've been working with, the
classes should be familiar. Here is the Samurai class with its secret identity and it has an ICollection
of Quotes and an ICollection of SamuraiBattle. Recall that I used lists for those two properties, but
these are EF Core's defaults, which are really just a stake in the ground and you can make the
classes your own once the scaffolding is done. Also, the scaffolding did kindly ensure that the
collections are instantiate up front so we don't have to remember to do that in code constantly.
The Quotes class is familiar, so is battles, and the SamuraiBattle class has the Ids that we'll
compose for the key and the navigation properties. And there is the SecretIdentity class. Now let's
look at the new DbContext class, it's created DbSet properties for every one of the Entity classes
that was created and that's another default, which you change if you want. It also put the
connection string directly in the OnConfiguring method with a note that you might not want it
there for security reasons. And remember, I had pointed out that I put it there just for the benefit
of making the demo simple. And notice the check to see if the optionsBuilder isConfigured or not
in case you've configured it outside of the DbContext like we do in ASP. NET Core Startup class or
maybe even in a test. There are a bunch of explicit fluent mappings here for the indexes, but most
importantly, here is the mapping to specify the compose key for the SamuraiBattle Join entity,
which we did earlier as well.
Well now you've got your model and your database ready to go and you've already learned a lot
along the way. For example, just because EF Core has the name core in it, you're not limited to
using it with just. NET Core apps. You've seen me create an EF Core data model, and if you were
following along, you've done it yourself, for use in a full. NET framework solution and in a Cross-
platform ASP. NET Core solution, and outside of some setup differences, the experience was just
the same. You've also learned how to use EF Core migrations to create a database or just some
SQL script from your classes and a DbContext and even migrate that database when the model
changes and you can do that without losing existing data in the database. Alternatively, if you're
working with a legacy database, you can use migration scaffold feature to reverse engineer some
or all of the database objects into a DbContext and classes, and currently, that's a one-time, one-
way operation, but it has a huge benefit of giving you a head start on your coding. EF Core has
defaults, which we call conventions, about how it maps your classes to your database, but if your
intention doesn't always follow those conventions, you can use data annotations or EF Core's
Fluent API to provide additional mapping instructions. And if you're coming from EF6, it's
important to understand that EF Core will not magically infer the provider or the connection
string, it's up to you to specify both and you saw a few ways to do that. And remember that where
I hardcoded a connection string, for the sake of simplifying the demos, you do have the option to
store that string in some type of configuration file and then read it and apply it as necessary, but
EF Core won't do that automatically for you. In the next module, we'll work with this model and
database to learn some of the basics of using EF Core 2 to retrieve and store data in that database.
Here are some resources related to this module that you might find useful. I'm Julie Lerman, and
thanks for continuing to watch Entity Framework Core 2: Getting Started.
Hello. Welcome back to Entity Framework Core 2: Getting Started. I'm Julie Lerman, and now it's
time to learn about interacting with data in your database using EF Core 2 and the data model that
we've already built. In this module, we'll focus on interacting with simple objects and then
followup in the next module by adding in relationships. You'll start by learning how to insert,
update, and delete data using the DbContext and your data model. We'll check out the batch
support that EF Core has for data modification commands going to the database, and once there is
some data in the database, you'll then learn how to use EF Core and LINQ to write and execute
queries, including various ways to filter what data is returned from the database. The way EF Core
comprehends the state of objects is affected when you're working in disconnected applications
like websites or Web APIs of even loosely coupled applications, I'll make sure that you understand
how to ensure EF Core does the right thing to your data. Before getting started, I'll show you how
to use EF Core's logging capabilities so that we'll be able to watch what kind of SQL is getting sent
to the database. So let's get started.
As I write and run the code for interacting with the data model, I want you to be able to see the
SQL commands that are created and executed by EF Core. To do that, I'll use the logging that's
built right into. NET Core and leveraged by EF Core. The logging code will go into the Samurai
Context class. I'll need to install the Microsoft Extensions Logging Console package to the data
project before I can do that. Then I can configure the context to always output its logs to a console
window. First, I create a field called MyConsoleLogger that uses the. NET Core logger factory to
create a specialized console logger.. NET Core's logging can show you a lot of information, so I'm
putting two filters in, the first is to only show me SQL commands, so I won't have to look at
processing messages, connections, or any of the other information that the log collects. The other
filter defines the level of detail and I just want basic information that will keep out details like
stack traces and error messages. Once I've defined the logger, I'll go down to the OnConfiguring
method and tell the model builder to to use a logger factory and the one I want it to use is the
factory that I just created above and that's it. Now every time I use the SamuraiContext, the
commands that it executes on the database will be output to the console window.
I'm back in the full. NET version of the solution, and remember, I already added a console project
in there, so I'm going to take advantage of that to interact with my EF Core data model. Remember
that when I needed to use migrations in the previous module, I needed to involve the UI project,
so I've already added references to the domain and data projects, as well as pulling in the EF Core
design package, and the EF Core design packages dependencies caused NuGet to also bring in the
EF Core base package and the relational package. So everything I need to work directly against the
EF Core data model is already set up in the UI project, and in case you're wondering, I don't need
to have the EF Core SQL Server package in the UI project, the data project is the only one that's
going to be interacting with the database. Remember, I already created my database, the one
that's called Samurai data and I used migrations to create all the schema, but I haven't put any
data in there yet. In my console project, I've already added using statements for the SamuraiApp.
Domain and data namespaces to the program file, so I'll start with a new method called
InsertSamurai. I'll create a new Samurai object and set its name and then instantiate my
SamuraiContext. Recall that in the context, I defined DbSets for Samurai, Battle, and Quote. The
DbSet is how we interact with each set of types, and since I want to work with my set of samurais,
I'll start with context. Samurais. Now what I want to do is add that new samurai into my DbSet and
I can do that with the DbSet's Add method passing in the samurai as a parameter. It's also possible
to add directly from the context object and let EF Core figure out which DbSet to use. That's a
great capability for more complex situations, such as writing generic code, but for my purposes
here, I prefer to be explicit and go through the samurais DbSet. Now my context is aware of the
samurai and we refer to this as tracking. The context is now tracking the samurai. And with that,
I'll go ahead and use the DbContext SaveChanges method. What that will do is look at all the
different objects that the context is tracking, and in this case, it's just that single Samurai, and for
each object, it will read the context understanding of the state of each object. Because I used the
Add method, the context is aware that this samurai is new and should be inserted into the
database. With that information, it will coordinate its comprehension about how the Samurai class
and its properties map to the database along with the SQL Server provider to construct the correct
SQL insert statement and then it will execute that statement on the database. If that command
returns any results, EF Core will read them as well. Now we can go ahead and run my little console
app and there is all the logging information. If I open up SQL Profiler, you can see that EF Core
wrapped the command in a database transaction. SaveChanges always wraps its work in a DB
transaction, and if SaveChanges is causing multiple commands to be executed on the database, if
any of those fails, it will roll back all of them and this is default behavior, which is enough
information for now about transactions. In the log, you can see an INSERT command and then it
passes in the value of the name as a parameter. When it's done, it returns the new value that the
database generated for the Id property. EF Core will grab that returned value and use it to update
the Samurai objects Id property. By default, the logs don't show the values of the parameters for
security purposes, but you can configure your context to show them with the options builder,
EnableSensitiveDataLogging method, and notice that's once I've done that and I run the app again,
I can now see the parameter values in the log and opening up the Samurais table on the database,
there is the data I inserted.
EF Core supports bulk operations, which it didn't do in earlier versions of EF. So let's take a look at
doing an insert with multiple objects in order to see that in action. I'll add in a new method called
InsertMultipleSamurais and I'll start just by copying the InsertSamurai, then I'll add in a second
samurai, my dog Sampson. I could use a second DbSet Add command to add Sampson to the
context, but we also have an AddRange method which you can use to add multiple objects. I can
pass these objects into the AddRange method delimited by commas, I could also pass those
objects in as a list, which means I could construct the list elsewhere in my code and then pass that
list in to the AddRange method. Running this method, the log looks a lot different than it did
before. The log shows that with the help of the SQL Server provider, EF Core set up a series of
table variables to prepare for the insert. You can see the two sets of data for the two different
samurais coming in, then it uses the SQL Server merge join to execute the actual insert into the
samurais table. Now I am not a SQL Server expert, but my friend, Richie Rump is and he wrote a
blog post that explains this operation in much more detail, including the performance benefits of
how this SQL is constructed. I'm not stressing out too much about the fact that it's a little hard for
me to read. Look for a link to his post in the resources listed at the end of this module. The last bit
of this SQL is just standard for an Entity Framework insert, it just has to return the generated keys
to the objects. Remember earlier when I mentioned that you can add objects directly from the
DbContext without specifying the DbSet and that's thanks to the fact that in EF Core the
DbContext has the ability to figure out which DbSet an entity belongs to. Here is a great use for
that capability when you need to add, or update, or delete a variety of objects that are different
types. in this method, I'm creating a new Samurai and a new Battle and the two objects aren't
related to each other. Then I'm adding them directly to the DbContext using the AddRange
method. This is a really cool capability that we didn't have in older versions of EF. Before we would
explicitly have had to add the samurai to the samurai DbSet and the battle to the battle DbSet, so
that's something nice to be aware of. Something else you should be aware of with respect to how
EF Core performs batch commands is that each database provider is responsible for setting
specific limitations. The default for the SQL Server provider is 1, 000 commands in a batch. If there
are more commands than your maximum, EF Core will group them in sets based on the size that's
specified and you can change that size when you're configuring the model builder in the
SamuraiContext.
So far, I've inserted some new samurais. Now let's go ahead and query them. Like the insert, a
query is expressed against a DbSet, so I'll begin by referencing a new context instance, and then
from there, the Samurais DbSet. Now I can append methods for querying from that set and I'll just
request all of the samurais from the database and I'm using a LINQ method ToList to do that.
ToList is a LINQ execution method and that will trigger the query to be executed. This query will
bring back all of the samurais as a list of samurais. I'll throw a breakpoint in right after the query,
I'll run it, and you can see in the Locals window that the Samurais variable is now populated with
the list of samurai objects and that's the data that came back from the database. You may recall
this part of the EF Core workflow that I described in the first module. What happened when this
was run was that first EF Core transformed the query into the proper SQL, took care of the
commands in the connection string, executed the query on the database, read the results that
were returned, and then transformed those results into samurai objects. There are two ways to
express queries with LINQ, one is using the LINQ methods and the other is using LINQ query
syntax. The LINQ query syntax looks more like a SQL statement, except you still have to use an
execution method at the end. I prefer the methods and haven't used the query syntax in years, but
there are plenty of developers who do use the query syntax. The query itself is disconnected from
the method that executes the query and here's an example of that where I define the query in one
variable and then in another statement, I modify the query or I can append a LINQ execution
method to it. In addition to a LINQ execution method, there is another way to trigger a query to
execute besides using an execution method and that's by enumerating the query. As soon as EF
Core sees that you actually want some data as it hits the enumeration, it says oh wait a minute,
I've got to go to the database and get that data for you so that triggers it to execute. Then you
don't have to define the query variable in advance, you can just enumerate over the query itself,
but there is a really important performance consideration to be aware of if you are depending on
enumerations to go ahead and hit the database for you on the fly. At the beginning of that
execution, the database connection gets opened and it will stay open until the enumeration is
complete and all of the results have been streamed back. In some cases, that's perfectly fine, but
in others, for example, if you start performing a lot of operations on each one of the results while
you're looping through them, not only can it cause performance problems, it could also cause
other side effects if other people are interacting with the same database. Being the control freak
that I am, I always prefer to just use an explicit execution method, such as ToList, get all of the
results into memory, and then do whatever processing it is that I need to do on them. Your own
scenario and performance testing should be able to guide you to the best workflow for your
solution.
You probably don't always want to just get all of the rows from a database table, so let's take a
look at a few more capabilities of LINQ, although this certainly won't be exhaustive. And for those
of you who have been working with Entity Framework in the past, querying with LINQ to entities in
EF Core really hasn't changed much on the surface, although in the background, there is a lot
that's being done to improve performance. Before looking at these, I do want to point out that I've
made a change to my Program class. Rather than instantiating a new context for every one of my
methods, I've now created a class-wide context that I instantiate at startup and then I can use
whenever I want, and with this change, it's important to understand that I'm only running one
method at a time. So each time that I run one of these methods which I'm discussing, it's working
with a fresh instance of the context. If you run multiple methods on the same context, your results
might be different. Here is a new method called MoreQueries. In it, instead of just getting all the
samurais, I'm now filtering on those samurais whose name is Sampson. I'm using the LINQ Where
method which takes a lambda that I'm using to express the filter and then I'm executing it with a
ToList method. When I run it and look at the logs in the console, keep in mind that I filter the log
so you can only see the commands, but what you can't see is that EF Core is compiling and
optimizing the query in order to work out the SQL command. Depending on the complexity of the
query, it may have to go through a series of optimizations to get down to what it thinks of as the
best option. In the end, you can see that the DbCommand is just a pretty simple SELECT statement
with a predicate and the search value, Sampson, hardcoded directly into the SQL. That's following
a pattern that Entity Framework has followed since day one with Entity Framework. If you
hardcode the values into the query, then EF assumes that the value didn't just randomly come
from some data entry somewhere and it's safe, so it just hardcodes the value into the SQL, but
we're much less likely to write a query that way. What's more likely is that you do have a variable,
some data that came in from somewhere. So let's pretend that this name variable with a value
Sampson was passed in from somewhere else. Then when I use the variable in the expression, EF
Core does parameterize the query, which you can see here in the log. I've used the ToList link
execution method enough. Let's take a look at some more. Here's a list of all the execution
methods and each of the methods has an asynchronous counterpart, and all of them, except for
ToList, perform some type of aggregation when they execute and the logic of the aggregation,
first, or max, or count, or average are incorporated into the SQL that's sent to the database. There
are a few gotchas to be aware of with these methods, one is with the Last and lastOrDefault
methods. Those require that your query also does some sorting with an OrderBy LINQ method in
order to create SQL that will express the full query in the database. I'll show you what I mean
when I dive back into the code. Another gotcha to watch out for is when choosing between the
first methods and the single methods. Single expects there to be only one result from the
database that matches a query. If there is more than one, it will throw an error, but the first
method will just select the first result that matches the query. Finally, you need to understand the
difference between the First, Single, and Last methods and their OrDefault counterparts. If the
results of the plain methods are empty, EF Core will throw an exception, but if the results of
FirstOrDefault, SingleOrDefault, or LastOrDefault are empty, EF will return null. Most often, you'll
want to use the OrDefault methods and handle a null response as opposed to an exception, but
there may be times when an exception is the correct response and you'll choose the plain version
of the methods. I won't demonstrate every one of these methods, but there are some LINQ
courses on Pluralsight where you can dig deeper into constructing queries. So now let's get back to
the code. I'll change this execution method and instead of ToList, I'll use FirstOrDefault. And if I
hover over the return variable, you can see that the compiler knows the result will now be a
samurai object, not a list. I can make my expression a little more efficient because I can use the
predicate as a parameter of FirstOrDefault rather than using the combination of the where
method and FirstOrDefault. When I run it, you can see in the Locals window that the result is a
samurai object. The way FirstOrDefault resolves as SQL is with a SELECT TOP 1 query, and again, if
nothing is returned, EF Core will take care of providing the default a null value. What if I wanted to
filter on the key value? I could use FirstOrDefault, but there is a method of DbSet called Find,
which is for retrieving an object by using its key value. This isn't a LINQ method though, it's a
DbSet method that will execute right away. The Find method has a great benefit in that if the
object with that key is already in memory and being tracked by the DbContext, EF Core won't
waste its time executing a query on the database, it will just return the object that it's already
tracking. There is another way to filter queries, which is not only new to EF Core, but it's new as of
EF Core 2, and that's the ability to write Like queries the way you can write them in SQL
surrounded by wildcards. You could do this with the LINQ Contains method, but this may be more
natural for many developers, and in fact, the Contains method translates into a Like SQL query
anyway so this is even easier for EF to translate the query into SQL. I'll query for samurais whose
name starts with capital J and this feature is possible thanks to the EF functions, which are built
into EF Core, and you can use the functions Like method, which takes the property you're
searching as the first parameter and then the expression you're searching for. So in this case, I'll
just build a string that's a capital J followed by the percent symbol wildcard for anything that
comes after J. When I run the method and look at the SQL in the log, there is the Like operator
followed by J%. If your search expression is in a variable, EF Core will parameterize the SQL Like
query as you can see here in this log. Now let's take a look at that potential problem with the Last
or LastOrDefault methods that I mentioned earlier. A query using either of these methods needs
to be sorted and that's because it constructs the SQL with a descending sort and then, just like the
FirstOrDefault method, it uses SELECT TOP 1. EF Core is able to translate the full query into SQL
and the database will only return a single rowed memory. If you don't include ordering, then EF
Core isn't going to be able to construct SQL that sorts and selects Top 1. So what it does is return
the full set of results from the query into memory, and then in memory, EF Core will pick the last
item from that set and that's what it will return from this statement. And if you have a lot of
results in the initial query, this could lead to performance problems. And because LINQ queries are
translated at runtime into SQL, the compiler isn't able to warn you about it in advance. There is
much more that you can learn about using LINQ in general. Here are some other Pluralsight
courses that dig more deeply into LINQ and I'll move onto the specifics of querying with EF Core.
And with that, the next thing we'll look at is querying across relationships.
While it's true that querying is the most common thing people do in their software, you probably
need to know about updating as well. So we'll continue with our current focus on simple objects
and I'll start by retrieving a random samurai from the database, I'll modify it, and then call
SaveChanges. That's a pretty simple operation, and in the log, you can see the SELECT statement
to get the samurai, then the update statement as a result of the call to save changes, and EF Core
passed in the Id of the entity getting updated along with the value that got changed and it
performs the update using those parameters and returns the number of rows that were affected.
Now this was a super easy task for EF Core because the context was tracking the samurai from the
time it was retrieved from the database to the time that I called SaveChanges so it was aware of
exactly which property got modified, that it was an update, and because of that, it was able to
execute a really efficient command and that would have been a lot more obvious if we had more
properties in samurai and you saw that it was only passing in the Id and that one property I
modified. You've already seen batch operations in action with inserts, let's take a look at a batch
update. Here is a method for pulling back all of the existing samurais, updating them, and then
calling save changes, and again, because the context is tracking them throughout the full
operation, retrieving, updating, and saving, it knows exactly which property has changed and
creates update commands just for those properties for each of the objects that was modified. In a
single call, it sends back all of the parameters, in this case, the Id and the new name for each of
the samurais, and then constructs four different update statements using the relevant parameters.
Batch operations aren't limited to common operations. You can have a whole bunch of activities
that the context is tracking, updates, inserts, and deletes, and when you call SaveChanges, it will
still batch them all. Here, for example, I'm pulling back an editing of samurai and adding a new
Samurai, and with the context tracking both of those, I'll call SaveChanges. You can see again the
single database call sending in the Id and the new value of the samurai I got from the database, as
well as a parameter for the name property of the samurai that I'm adding. Then the UPDATE
command uses the first two parameters and the INSERT uses the parameter that was designated
for that command.
Disconnected Updates
So far in these examples, I've pulled down, modified, and saved data all at once while a single
samurai context instance remained in scope, tracking changes to the objects that it just retrieved
and that's a good way of getting an idea of how the change tracker works and it's a good pattern if
you're using an application that's totally on the client side, running on a computer or other device
where the data is stored locally or perhaps on a local network where the client computers have
access to the database on a server that's on the same network. And we refer to the data access in
these types of applications as connected. Another common scenario, however, is when the user
interface is disconnected from the back-end logic where the data is managed. For example, you
might have a website that interacts with a web service or a Web API. The service can't share a
DbContext instance across all of its web users, so each method to retrieve or update data will
instantiate its own DbContext instance and then dispose it when it's finished. In the web scenario
after an object is retrieved, it gets sent across the internet. It's impossible for the context that's in
memory on the server to know what's happening on someone's browser anyway so there is really
no point in keeping the DbContext in scope. So unlike the samples you've seen thus far, the
context won't be tracking the object, and when it's time to update the object in the database,
you'll call a new web service or Web API method that will instantiate its own DbContext and that
DbContext won't have any clue about the history of the object that it's trying to update, so it will
be your job to make sure that your code is able to inform EF Core whether an object needs to be
inserted, updated, or deleted from the database. So with that in mind, and again, continuing with
our simple objects, let's take a look at updating objects that EF Core has no clue about. I'll work
with a new type finally. Let's edit a Battle, and just as a reminder, here is the Battle class, it's got
an id, a name, start and end dates, as well as a navigation property to the Join table, and I've
already added a battle to the database using this InsertBattle method. In the
QueryAndUpdateBattle_Disconnected method, I'm emulating a disconnected scenario where I
request a battle in one context, modify it, and then use a brand-new context to push the changes
to the database. You've seen me use the DbSet Add method already. DbSet also has a method
called Update and that will tell EF Core to mark the object as modified. The context will start
tracking it first and then it will set its state to modified. After that, I call SaveChanges. In the log,
here is the SELECT statement that was used to get the battle from the database and then you can
see the UPDATE method. Remember that when the same DbContext instance was used to retrieve
and update an object, EF Core only passed in the Id and the value of the modified property. Here
it's passing in the values of all of the battle properties and that's how EF Core handles updates in a
disconnected scenario. The update method tells EF Core that something got changed, but I don't
really know exactly what got changed. So EF Core will just create SQL to update all of the
properties, even those that haven't changed. There are third-party APIs like Breeze and Trackable
Entities, both open source and free, that can help you carry all that information back and forth
across the wire if that's something that you want to do. I'll put references to them in the resources
at the end of this module. Finally, I want to be sure you're aware that just like the variety of ways
we could call Add on an entity, we also have the same variety for the update method. In addition
to plain old DbSet Update, you can also call UpdateRange and pass in a list of entities. You can call
Update and UpdateRange directly on a DbContext as well. There is one other and completely
different path for informing the DbContext change tracker of objects that should be added,
updated, and even removed. It's a little more low-level than these methods and useful when you
need to start tracking objects that are part of a set of related objects. But next, we'll turn our
attention to deleting objects with EF Core.
We've seen how to insert and update data, now it's time to learn about asking EF Core to delete
data from the database. For developers new to Entity Framework, the way EF deletes might seem
a little strange. That's because EF Core needs to be tracking an object in order to mark it as
deleted so that it knows it should send a delete command to the database and that's easy enough
if you already have that object at hand, and whether Entity Framework is already tracking that
object or you're in a disconnected scenario, you can just pass that object into the Remove method
of either DbSet or directly from the DbContext. I've added a bunch of new Samurais into the
database so I'll still have data left after I've demonstrated some deletes. Here is an example where
I have queried for a samurai and the object is still in memory. When I call DbSet Remove and pass
in that samurai instance, EF Core changes its known state to deleted. Then when you call
SaveChanges, it sends a DELETE command to the database and notice that all it sends is the
primary key value because that's really all that's needed by the DELETE command. Deletes will also
be part of batches when you call SaveChanges. Here, I am retrieving a set of samurais and then
using RemoveRange to mark all of those for deletion. When I run this, the log shows that the Ids of
all four were sent in as parameters and we see the four delete commands. And after I refresh the
Table view, you can see that most of my new samurais are gone. If EF isn't tracking the object
already, then just like it did for the disconnected updates, when I call the Remove method, first it
will begin tracking the object and then it will mark it as deleted. In fact, if you think back to the
first inserts we did, I was creating the new samurais outside of the DbContext and using add to
start tracking and mark them as added, but what if you don't already have the object. Most likely,
you would at least have the Id value of the object you want to delete. Unfortunately, it means you
first have to query the database or call the Find method to retrieve the object so that you can pass
it into the Remove method in order to tell the database to delete it and that is really annoying
because it means two trips to the database and it also begs the question, why isn't there a Delete
by Id method which just takes a key value just like the Find method does. This is something
developers have requested from Entity Framework for quite a while and there is a discussion of it
in the EF Core repository on GitHub. The capability is on a backlog, which suggests that it will
finally come to EF Core someday, hey, maybe it'll be a contribution that you make to EF Core. If
like me you really do hate the idea of that extra database trip in order to get the object from the
database so that you can delete it from the database, you might prefer to use raw SQL or stored
procedures. Here is an example of how you can use EF Core's DbContext. Database.
ExecuteSqlCommand method to call a stored procedure and pass in a parameter. EF Core's DbSet
also has a FromSql method that lets you execute queries using raw SQL or calling stored
procedures. I won't be covering those features in this course. You can learn more about them by
looking back at the EF Core Getting Started course that I created for EF Core 1. 0 and in a future
intermediate course on EF Core 2.
Let's do a quick review before moving on to working with related data. You've learned how you
can add, update, and delete from a DbSet or directly from the DbContext. You saw how easy it is
to capture logs of the SQL going to the database and even more detailed processing information
related to what EF Core and. NET are doing at runtime. We saw how EF Core batches commands
when you call SaveChanges and that EF Core requires an actual entity already in memory in order
to understand how to delete it from the database, and remember, you've always got the option of
using a stored procedure for deletes. We used LINQ's execute methods to trigger queries and then
looked at some other options for filtering and sorting. You also saw how EF Core is smart enough
to parse queries to execute as much as possible in the database, but also be able to finish up in
memory with any additional logic from the query. And you got an important lesson in how to work
with EF Core in disconnected scenarios to let it know what to do with objects that it wasn't
tracking, and therefore, doesn't know if they're new or if they've been modified. We'll expand on
all of these lessons in the next module by adding in related data to the queries and the database
updates. Here are some resources relevant to this module that you might find useful for following
up. I'm Julie Lerman, and thanks again for watching Entity Framework Core 2: Getting Started.
Hello. I'm Julie Lerman. Welcome back to Entity Framework Core 2: Getting Started. This module
focuses on interacting with related data that's in your database. Now that you've learned how to
insert, update, and delete simple objects, you'll now discover how to do the same with data that's
across relationships. It's easier to make these changes when EF Core is tracking your objects, but
it's also really important to understand how to let EF Core know what to do with objects that it
hasn't been tracking. You'll also learn about querying related data by including it in queries for the
parent data or after the parent data is already in memory. I'll teach you how you can shape query
results using projection queries. And finally, you'll see how you can navigate through relationships
when building queries, as well as filtering and sorting data. So let's get started.
We've done a lot of work interacting with simple objects. Now it's time to look at interacting with
related objects. First, we need to get some related data into the database and I'll focus on some
more samurais and their movie quotes. Remember that a samurai can have one or more quotes
and a quote has a Samurai property and a SamuraiId property, which is a foreign key that can exit
back to a samurai, and in the database, this resolves as a primary key foreign key relationship. In
this first method, I'm creating a new parent/child graph, that's a new samurai object with a quote
in its quotes collection. I'm calling the samurais DbSet Add method passing in the new samurai
object graph to tell the context to begin tracking the samurai and whatever is attached to it. The
context will mark everything in the graph is added, and when I call SaveChanges, notice that it's
not sending the two inserts in as a batch and here's why. First, it inserts the samurai and like you
saw earlier, it then returns the database generated Id of the new samurai. Then EF Core takes the
Id and uses it to compose the SQL insert for the quote. If EF Core had batched those commands, it
would have been a lot trickier to compose and likely slower to execute. If there were multiple new
children in the quotes collection, as I'm doing in this next method, notice in the log that after the
parent is inserted and EF gets the new key value back, it can use that value to insert both of the
quotes, and this time EF Core can send the quotes to the database as a single batch command.
What if you want to add a related object to a pre-existing object? In this method, I'm retrieving a
samurai from the database and then adding a new quote to it. What's important here is that the
context is still tracking the samurai, so it knows that I added the new quote, and when it's
composing the SQL, it will supply the samurai's Id to the quote, and in the log, the parameters to
the new quotes INSERT command includes the samurai Id. In code, I never set that foreign key
value. The change tracker figured that out because it was tracking the samurai, but what if you're
in a disconnected scenario and the context that you're using to save the new quote to the
database has no idea about the history of these objects. In this case, setting the samurai Id
property on the new quote is your best and simplest path to success. I first want to explain why
using the common mistakes that a lot of developer's make. You can't use the samurais DbSet Add
method to add a samurai graph because the DbContext wasn't tracking the samurai doesn't know
it came from the database even though there is already an Id there and it will mark it as added
along with a quote because that's what you told it to do, add, but when it tries to insert the
samurai back into the database, the database will throw an exception because there is already a
samurai with that primary key value. If you think a bit more about this method, there is really no
need for the context to do anything with the samurai, I didn't edit that. The goal is to insert the
quote. There are a few other complicated paths you might want to try, and believe me, I have
tried them all, but you'll end up having to add more and more code to work around EF Core's
behavior. My advice is to just avoid using the graph when the objects have different states, which
is why I prefer to simply set the foreign key on the quote. Sometimes developers don't want to
have foreign key properties in their child classes, but they make life a lot easier and I'm constantly
encouraging my clients and anyone else who will listen to me to use foreign keys. Now I've
simplified the method dramatically to reflect the most common scenario where you'll probably
already have the idea of the samurai. You don't need to retrieve the samurai object, just push that
Id into the quote. So now my method takes in a parameter which is the value of the SamuraiId and
all it needs to do is create the quote setting that SamuraiId property to the samuraiId value along
with its text and then add it to the Quotes DbSet and call SaveChanges and here is the log where
you can see that command coming in and the parameters and it works.
Now that I've got some data to work with, it's time for some more queries. There are a number of
ways to query related data. Eager Loading allows you to use the DbSet include method to retrieve
data and related data in the same call. Another way to pull back full graphs of data is by using
query projections where you can finetune the shape of the data to be returned. The third way that
you can query related data in the EF Core is with explicit loading, this is for cases when you already
have some data in memory and want to go back to the database to get some of its related data. I'll
show you how to do explicit loading later in the course when I'm building some sample
applications. There is one other mechanism for loading related data on the fly called lazy loading,
it's not currently supported in EF Core 2, however, it is on the roadmap to get implemented. Let's
begin by exploring eager loading with the Include method. Here is a link query starting with the
samurais DbSet. Include is a method of DbSet so I can type that and then IntelliSense helps me
with the lambda expression to define which navigation property I want to include and that's going
to be the quotes. Don't forget a LINQ execution method. I'll use two lists to get all of the samurais
with their quotes. First, the log shows that there were two separate queries executed. EF Core
does this to avoid flattening the data and getting loads of duplicate data returned that it then has
to sort through. This way is more efficient on the database side and more efficient for processing
the results in memory. For those of you who have used EF in the past, this is an important
performance benefit over how it used to work under the covers. The database query returns a set
of all of the samurais and a set of all the quotes for whichever set of samurais were requested.
Then in memory, it puts these graphs together. There are nine samurais, the first one has two
quotes so one query and one call to the database brought back these rich object graphs. you can
filter which samurais are returned and still retrieve the quotes for just those samurais and you can
also use a different execution method like first of default if you want, but be careful about where
you do that. Remember that include is a member of DbSet and you can't put it after first or default
because that returns a single samurai and include isn't a method of samurai. In fact, you'll hit the
same problem if you try to include using the DbSet Find method because again Find is going to
return a single samurai object, not a DbSet. Remember the FromSql method for executing queries
with raw SQL or stored procedures, we didn't look closely at that method, but I do want to point
out that you can compose include on top of FromSql. There are a variety of ways that you can
build graphs with eager loading. For example, if we were tracking various translations of the
quotes in a translated quote class and quotes could have many of these translated quotes, in my
query for the samurais, not only could I include the quotes, but I can add onto that EF Core's
ThenInclude method to drill into the quotes and pull back all of the translated quotes for each
quote, so in effect, that's getting the parent samurai its children, quotes, and then its
grandchildren, the translated quotes. You could also traverse graphs in multiple directions. For
example, in addition to quotes, recall that samurai has a secret identity navigation property. In my
query, I can include quotes and I can include secret identity. You've seen me filter which samurais
are returned here. It's really important to understand that the Include method does not allow you
to filter which related data is returned, but you'll see how to do that in the next clip.
You may have already written query projections in earlier versions of EF, or if you write SQL
queries, you've very likely used them, unless every single one of your queries is select *. In EF
Core, we use LINQ's select method to specify which properties and object we want returned. If
you're returning more than a single property, then you'll have to contain the new properties
within a type. LINQ let's you do that even if what you're projecting doesn't match an existing type
in your system. By using the new keyword and placing the list of properties in curly braces, this will
return what's known in. NET as an anonymous type, but it will only be known to the method in
which it's defined. Here I'm querying the samurais, and in the select method, I'm creating a new
type that will return the Id and name of the samurai and the result is a list of anonymous types
whose properties are an int and a string. If you need to move those anonymous types outside of
the method, you could cast them to a list of dynamic types or create another class or a struct in
your app and then project into that. Now let's add the quotes property into the projection. I'm
telling it to bring that the full property, which is a list of all the samurais quote objects. Now the
anonymous type is made up of an integer, a string, and a list of quotes, and for this first samurai,
you can see that there are two quotes. You can also navigate into a related object without bringing
back complete types. As an example, I've changed this last property, which was quotes, to just be
account of the quotes and check out the SQL, the COUNT is part of the query, not something that
happens in memory after the fact, so EF Core is pretty clever with that. And in the results, now you
can see I have an int, a string, and then another int that shows how many quotes there are. In this
particular projection, I can filter on the quotes, so I'll use the Where method on quotes to make
sure that the query is only returning quotes that contain the word happy. Notice that now I'm only
getting back one quote for that first samurai and it does have the word happy for it. So now let's
try to pull back full samurais and a filtered full list of quotes. This is the capability I was referring to
when we were looking at the Include method. With the include, you can't filter the related data
that you're getting to with the Include method. Now in projections, we should be able to do that,
but unfortunately, there is an issue with EF Core 2 and it is noted on GitHub and the team is aware
of it. What happens with the projections is the proper SQL is sent to the database, the samurais
and the filtered list of quotes are returned to memory, but EF Core isn't fixing up the graphs. So if
you look at a samurai, even though its quotes are in memory, it's not aware of them. So for now,
the simplest way to filter related objects when you want full types is really just to execute two
separate queries on the same context instance, and when you take that path, EF Core will fix up
the related data in memory so each samurai is attached to its quotes. There is so much more to
learn about projections, but I think we've reached the limit of how much I can justify showing you
in this getting started course.
So far, the focus for the retrieval has been on pulling back related objects. You could also take
advantage of related data for querying even if you don't want to retrieve those related objects.
Here is a simple example of that where I want to retrieve any samurai that has ever used the word
happy in a quote. I don't need the quotes, I just want to see those happy samurais. So I'm able to
navigate through the relationship in my where predicate, then do a subquery of the samurais
quotes where I'm determining if any of the quotes contain the word happy. Entity Framework and
the SQL Server provider transform that LINQ query into this SQL WHERE EXISTS query. When I see
these queries that Entity Framework helped compose, I'm so grateful for EF. I would have had to
lookup that syntax for how to do that kind of query because my T-SQL skills are not nearly as
competent as what Entity Framework can do. Of course, there are plenty of EF generated queries
that a DBA or other database expert will cringe at, but that's why we have the ability to call raw
SQL and stored procedures or map to views for cases where Entity Framework just can't build up
the ultimate queries. You can see in the results that I just got back one samurai and that's the only
samurai that happened to have a quote with the word happy in it, but I've only got the samurai
because that's all I asked for. I used a Where LINQ method and an any method in my subquery, but
you can use all sorts of LINQ methods to compose this type of query where the related data is
used to filter or sort the main object. Depending on how creative you need to get, it's always good
to profile the resulting queries in the database just in case it can be written more efficiently with a
procedure or review.
We've looked at adding graphs or adding data to existing graphs already, but what about updating
data that's part of a graph. Like the additions, you need to be aware that things will work
differently when the data is being tracked as the changes are being made versus if it's
disconnected and the DbContext begins tracking the object state after the changes have been
made. Let's first look at making changes to a graph of objects while EF Core is tracking them. Here
is a method where I've used include to eager load the fist samurai along with all of its quotes, then
I drill into the first quote in the collection, modify its text, and call SaveChanges. When I run this,
you can see that along with the samurai, I got three quotes and here is the SQL that got called by
SaveChanges, which is simply updating the text field of that quote that I edited. I could also easily
delete any of the quotes while the change tracker is in scope, and in this case, EF Core sends a
DELETE command to the database for that particular quote. So as usual, things are pretty simple
when the change tracker is in scope and watching what's happening with the objects. Now let's
look at a scenario where the change tracker doesn't know about the object's history. Again, I'm
retrieving the graph of a samurai and its quotes. In the next line of code, I'm creating a variable to
reference one of those quotes and then I edit its text. Now with a newly instantiated
SamuraiContext, I'm using the Quotes DbSet Update method to tell the newContext to start
tracking the quote and mark it as modified. After that, I call SaveChanges, but look at this log,
something really strange happened. When I called SaveChanges, EF Core sent commands to
update the Samurai and both quotes and the update is just pushing back the same data into the
database for objects that didn't get edited. Can you guess why this happened? I'll run this method
again with a breakpoint so we can look at the quote before and after calling the Update method.
To start with, the quote is still attached to the samurai and the samurai is attached not only to that
quote, but the other quote. So even though I'm referencing just one object in the graph, EF Core
recognizes that it's part of a graph. Before calling the update, I'm going to pull back the covers a
little bit to show you how the DbContext is keeping track of the state. It happens in the DbContext
ChangeTracker property and the ChangeTracker has a StateManager property. Remember, I
haven't called Update yet, so the StateManager is not even aware of any of those entities, much
less any changes, but after I call the Update method, the StateManager says it's now aware of
three changed entities. Even though I called Update just on the quote, it affected the entire graph,
it started tracking every object in the graph and marked every one of them as modified. And this
knowledge is really important to make sure you know how EF Core handles this data, which might
be very different than what you might have expected. So how do we get around the side effect of
EF Core's behavior? It's not an easy coding task to separate the quote from that graph, but lucky
for us, EF Core knows how to do that. We just have to use a different path. Instead of using the
DbSet Add, or Update, or Remove method, you can use the DbContext. Entry method, which gives
you a lot more control, and if you're coming from EF6, take note because this behavior is different
than it used to be. In EF Core, entry will focus specifically on the entry that you pass in and it will
ignore anything else that might be attached to it. So I can pass the quote object into the Entry
method and then use Entry's State property to set the state of that entry to Modified, which is one
of the EntityState Enums. With this change, now when I call this line of code, the ChangeTracker is
only tracking the quote, and when I call SaveChanges, it only sends an Update command to the
database for the quote. There is a lot more that you can do with the DbContext Entry method, but
for this getting started course, I'm going to leave it at that. I will spend more time examining the
change tracker in the upcoming intermediate course and I did also drill into much more detail
about this in the original EF Core Getting Started course if you want to go review that.
Review and Resources
Relationships are pretty important in our applications and you've learned how to bring related
data into memory along with the parent data that you're querying. There is also a way to get child
data after the parent is already in memory and you'll see how to do that when we work with the
sample applications. If you want to filter the child data, that would normally be possible with
projection queries, but a current issue with EF Core 2 means that you'll have to execute 2 separate
queries for now. You can, however, use that child data to filter the parent data. You learned in the
previous module that EF Core treats objects it's tracking while the modifications are being made
very differently than how it handles objects that were modified outside of the scope of the
DbContext. That lesson is even more important with related data as you saw how it treats graphs
of data. Thankfully, if you do need to isolate individual objects from a graph in order to save them
to a database, the DbContext. Entry method knows how to do that for you. So now that you've
learned how to build a model and interact with it, it's time to see how to use EF Core in
applications and that's what we'll do next. Before moving on, here are some resources that you
might find useful to learn more about interacting with related data. I'm Julie Lerman, and thanks
again for watching Entity Framework Core 2: Getting Started.
Hello, I'm Julie Lerman. Welcome back to Entity Framework Core 2: Getting Started. In those final
module, you'll get a chance to use EF Core in some actual applications, not just a test console.
There are so many places you can use EF Core now, and not just limited to Windows. But I can't
demonstrate them all. So I'll start with a rundown on where it can be used and some of the things
to keep in mind across different clients. Then we'll dive into a Windows desktop application, and
I'll use WPF for this demo. An important lesson in the desktop application will be about designing
your EF Core data access for these types of connected scenarios, when EF Core is able to keep
track of objects while they're being edited in the user interface. Then we'll switch to using EF Core
in an ASP. NET Core application. We already created the beginnings of an MVC app earlier in this
course, so I'll start by adding a controller and some views to that solution to see what the
templates can do for you. And then I'll show you how to make the MVC app more friendly to users
by enhancing the template generated code in order to retrieve, present, and persist related data.
So, let's get started.
We'll begin with building an app that's self-contained. All of its logic, the UI, the business logic, and
data access all reside in one place. This could be something like a desktop, a phone, or even a
gaming device. And the database could be stored directly on that device or perhaps on a
connected server. All of this leads to the possibility of the connected scenario you learned about
earlier where the DbContext instance can stay in scope, watching what's happening to its entities
as the user interacts with them. Keep in mind that even with this setup where everything is in one
place, a more complicated application might justify designing short-lived EF Core interactions
using a disconnected architecture, similar to what we talked about for the web applications and
APIs. I'll be building a. NET framework WPF application for the desktop example, but I do want to
address other application types you can build. In the. NET world, well, there's always Window
Forms and console apps, but you can also build Universal Windows Platform or UWP applications.
And these run on Windows 10 devices, which could be a desktop, a notebook, a phone, a tablet,
Xbox, how about HoloLens or even an IOT device, as long as it runs Windows 10. An important
point about doing this with EF Core 2, however, is that because EF Core 2 requires. NET Standard
2. 0, the UWP app must also sit on top of. NET Standard 2. 0. And that requires a version of UWP
that can only be built and run on Windows 10 Fall Creators Update, not on any of the earlier
versions of Windows 10. Also, keep in minds that working with migrations is a little extra work. It's
not as smooth right now when combining EF Core 2 and UWP. When you watch the upcoming
WPF demo, keep in mind that the user interface for UWP apps is also written with XAML. So there
will be a lot of similarities between the coding patterns that I'll be using. I have written an article
on building a simple UWP app with EF Core 2. I'll provide a link to it at the end of this module in
the resources. Remember that. NET Standard is cross-platform, so EF Core can also run on other
client devices. You could always build a. NET Core console app, but that might not be very visually
appealing. You can build device or desktop apps for Android, iOS, or Mac using Xamarin Forms,
and don't forget that there's a version of Visual Studio that runs on macOS, too. Here's an article
on the Xamarin site about using Xamarin Forms with EF Core. It was written for EF Core 1, not 2,
but it should still give you a good idea of how these technologies work together. The author
informed me that the article will be updated for EF Core 2 and. NET Standard 2 when Xamarin
irons out a few last bugs, and I'll include links to this in the resources slide.
Here's a little WPF app that I created using the model we've been working with so far. This window
is for creating and editing samurais. I could also create and edit their quotes and their secret
identity at the same time. I've already got two samurais in here, Kikuchiyo and my darling dog
Samson. They both have a secret identity and some very fascinating quotes. You can edit the
names, edit or add new quotes, and you can add new samurais. A single DbContext instance will
track all of these entities and all of the changes from the time you start the application. If you click
the Save Changes button, it will save everything that's changed since the last time you saved. I'll
close and reopen the app so you can see that my changes were indeed saved, and I'll create a new
samurai with a name, a secret identity, and a quote. If you try to close the application when
there's still data to be saved, you'll get prompted to save. And again, I'll reopen the application so
you can see it saved the new samurai. This little app is pretty simplistic so that we don't get into
the weeds of learning how to build WPF apps, and it doesn't let you do things like let you know
which data's been edited. Yet when we look at the code for this app, there are plenty of lessons
about EF Core for you to glean.
Let's see how I built this WPF application and connected it to EF Core and my data model. Most of
what I'm showing you here is the same as if I'd been using an earlier version of Entity Framework,
even the fact that I'm using EF Core with a full-blown. NET framework desktop application. I won't
be doing a step-by-step walkthrough of how I built this since I do think a WPF course is more
appropriate for that, but I will show you highlights of creating a window and its code, and you can
see the detailed XAML and CodeBehind in the sample download for this course. What's relevant to
this course is how Entity Framework Core is involved, and that's what I'll be spending more time
with. If you've done drag-and-drop WPF with earlier versions of EF, this part's really no different,
because creating the UI is really about interacting with the objects, not the DbContext. I've started
with a trimmed-back version of the solution we've been using. What I've removed is the console
app project and the test project, and in their place, I created a new WPF project and then added
references to the domain and data projects. Then after choosing the samurai object as my key
data source for building the UI, I just did standard drag-and-drop to place a list box of samurais, a
text box for the samurai's name, another text box that's tied to the samurai's secret identity
property to drill into the secret identity's real name, and then a grid that comes from the samurai's
collection of quotes. And because I did this from the objects, the UI comprehends the relationships
between those objects. Rather than having the code of the user interface communicate directly
with the Entity Framework, I've encapsulated all of the EF Core code into a separate class called
ConnectedData. That way, the Windows code can focus on user interaction logic that's not
involved with Entity Framework, and I can keep the data access code separate from that. Let's look
at that class we we can see how I bridged the UI and the DbContext. I've intentionally called this
file ConnectedData, because it tells me something important. Because the application is not
distributed over disconnected resources, it will be using a single instance of the DbContext for the
lifetime of the application. For small, connected applications, this is a totally acceptable thing to
do, and as I said earlier, as your applications grow, you might want to design them in a more
separated manner, even if it's not targeting a web app. But this demo is to show you how things
work in a connected environment. Everything I'm doing in this connected data class is based on
the knowledge that the DbContext will always be watching what's going on. As I add, edit, or
delete objects or the related objects, the context is totally aware of it. So I don't have to worry
about informing EF Core later of the state of those various objects. I've moved the database
connection string in the WPF app's App. config file and renamed the database to SamuraiWpfData
for this demo. That means I can replace the hard-coded connection string in the DbContext by
using the. NET ConfigurationManager to read the connection string from the config file and use
that as the parameter of the UseSqlServer method. Now, rather than use the migrations update-
database command to go ahead and create the database on my development machine, I'll be
migrating the database at runtime using code, which means that the application will be able to
create and migrate the database on its local machine or wherever the connection string points to.
You'll see how I'm doing that momentarily.
Now we can run the WPF application again, but this time, I'll debug so you can see how the
connected data class supports the data access for this app. When the application starts up, it starts
the main window, and when the main window starts up, it instantiates my ConnectedData class
into a variable called data, and then the ConnectedData class starts up, it in turn instantiates the
samurai context, and here's where I'm using the runtime way of making sure the database is up to
date with the migrations by calling the DbContext Database. Migrate command. And if the
database doesn't exist yet, this will create it for me as well. And because Migrate causes the
context to interact with the database, we get to see the connection string being pulled from the
App. config and used by the context. All of that happens just by starting up the application. The
next step for WPF is to load the main window. And in response, I'm making my first method call
from ConnectedData to the SamuraisListInMemory method. This method returns a list of samurai
objects that are already in memory. If the context isn't tracking any samurais yet, then it will first
execute a query on the database to get those samurais. But we won't directly bind those tracked
objects. Instead, we'll create a copy of those objects, which is an observable collection. And to do
that, we can use the DbSet. Local property followed by its ToObservableCollection method. This
sets up a two-way relationship with the context, so if you do add or delete objects in the user
interface, the context is informed and vice versa. The window then uses these results to populate
the samuraiListBox and sets the selected item of the list box to the first samurai in the list. Any
time a samurai is selected in the list box, we then call the ConnectedData's LoadSamuraiGraph
method to get the quotes and secret identity for that samurai. You might recall that in the
previous module, I said you would see explicit loading in action when we built some apps, and this
is exactly what I'm doing now. I'll use the DbContext Entry method, passing in the samurai that
was selected, and from there, I use its Reference method, which lets me load a reference
navigation property. In other words, a property that points to its single object. Here, I'm telling it I
want to get the SecretIdentity for the samurai, and finally, I add the Load method at the end of
this, which will go to the database and pull back that data. Then I use DbContext Entry a second
time, but now with its Collection method, and then I'm requesting the quotes for the samurai. And
once that data's returned, the context will fix up the graph and make sure the samurai is linked to
these children properties. The LoadSamuraiGraph method then returns this graph to the main
window, which binds it to the samuraiViewSource that got created by the drag-and-drop
operation. And that feeds the values throughout the graph to the two name text boxes and the
quotes list box. Because everything's still connected, if the user makes edits to the samurai, the
secret identity, or the list of quotes, the context will be aware of these changes. But the context
isn't literally tracking those changes in realtime. When we hit the Save button, that will lead to
SaveChanges being called. SaveChanges is one of a number of methods in EF Core that triggers
another method called DetectChanges. That will cause the context change tracker to update its
state information about the objects that it's tracking, and it does that by reading the values of
those objects. And then, EF Core can compose the necessary SQL to push to the database.
Remember that feature that alerts you if you try to close the window before saving changes?
Here's how I built that. I have a method in the ConnectedData class that reads the ChangeTracker
of the context to see if there are any entities that have changes. And you've seen this
ChangeTracker property before when I did some debugging to show you how EF knew what SQL
commands to create on SaveChanges. So here, I'm using this Entries method to see if there are any
entries that are added, modified, or deleted, and returning true if there are. In the Windows
Window_Closing method, I'm using a trick that goes back to time immemoriam. When the user
tries to close the window, if that ConnectedData method returns true, in other words, there are
unsaved changes, I just prompt the user to let them decide what to do about those changes. And
it's all pretty simple, thanks to the fact that the ChangeTracker makes it really easy for me to
discover if there are any changes still hanging around. There's one last feature of the app to point
out, which is that you can add new samurais. When you do that, the WPF window calls the
CreateNewSamurai method in the ConnectedData class. This instantiates a new Samurai object,
attaches it to the context, and returns it to the window, and I'm adding the samurai to the context
right away, and then let the user edit that new samurai directly. That way, the context will not
only be aware of changes to the samurai, but it will know if I added any related data to it as well.
So I won't have to worry about syncing up that data before I called SaveChanges. And that's yet
another benefit you get with a context that's staying in scope the whole time. Again, please keep
in mind that this isn't an architecture for a complex application. If you're looking for those types of
patterns, my Entity Framework in the Enterprise course is focused on more advanced architecture.
And even though I wrote that course using EF 6, almost everything you'll learn in that course will
also apply to EF Core. The other thing I want to point out about the ConnectedData class is that
while you might hear a lot about the repository pattern used with Entity Framework, that's not
what this class is. It simply has the logic I specifically need for my application, rather than having
generic add, update, and delete methods for each type in my model.
Now that you've seen EF Core 2 in a connected desktop application, let's turn our attentions to a
web application where EF Core resides on a server and is disconnected from any changes made to
objects in the client, such as a mobile app or a web browser. Recall that earlier in the course we
recreated the data and domain models in cross-platform. NET Standard class library projects, and
then consumed them from an ASP. NET Core MVC app. We'll revisit that solution to add in
controllers and views for creating, viewing, and editing some data. In the intermediate course,
we'll create a web API that demonstrates some of the more interesting patterns around designing
for disconnected data access, and there, I'll encapsulate the EF Core work, just as I did with the
connected data class in the WPF application. Here's the solution as we left it, and I'll give you a
quick refresher. The domain library is sitting on. NET Standard 2. 0, as is the data library. Data also
has the packages for EF Core 2's SQL Server provider and all of the relevant dependencies. I've
already added in the many-to-many and one-to-one relationships to align with the model changes
made to the. NET Framework solution, and I've migrated the database as well. The ASP. NET Core
MVC project started out with the AspNetCore. All package reference, thanks to the project
template, so I didn't have to explicitly add any of the packages I needed. I moved the provider and
connection string information into the ASP. Net Core project. The connection string is stored in an
app settings file, and then I leverage ASP. NET Core services to start up a samurai context instance
as needed and inject the provider and connection string information for me on the fly. The next
step for a basic MVC app is to add controllers and views based on the domain classes, but there's a
small glitch with ASP. NET Core's scaffolding right now, and a simple workaround, which I want to
be sure you're aware of to tide you over until this gets fixed. Let's add a controller and a view so
visitors to our website can add samurais. Visual Studio lets you do this easily by right-clicking on
the Controllers folder, choosing Add, then Controller, and then MVC Controller with views, using
Entity Framework. Next, you'll be prompted to select a model class, and you can select samurai in
the dropdown list. Then after that, you can select the SamuraiContext from the DbContext
dropdown. The rest of these options are about the user interface, and I'll just leave them at their
defaults, as well as the default for naming the controller. And here is where you're going to run
into the bug. The scaffolding tool will display an error message saying that it can't build the
controller because it can't find a DbSet for the samurai class. And notice that everything's fully
qualified. So it's really saying it can't find a DbSet for the SamuraiApp. Domain. Samurai class. This
error is happening because I've made my solution nicely designed by placing domain classes in a
separate project from the EF Core model. And for some reason, the scaffolding just can't figure
that out. But the simple workaround is to return to the DbContext file and just fully qualify the
type name of the classes for which you're defining DbSets. And once those are there, the
controller wizard does what it's supposed to do and creates a controller and some views to
interact with the samurai. The way that the template-generated controller takes care of this
connected state is to have explicit methods for adding, editing, and deleting, and because it's only
handling single objects, not graphs, it's pretty simple. Each time you select an action in one of the
views, a new controller instance will be created, and with it, a new SamuraiContext instance. The
view that shows a list of samurais and the one that shows you the details have methods that
execute queries. And after each method call, the controller and context get disposed, and of
course, they would have had no clue about what's happening in the browser anyway. There are
also methods for saving samurai data. One is from the Create view, so we know the samurai
coming in needs to be added, and there's the samurai's Add method being called before
SaveChanges. The Edit view will call the Edit method when its save button is hit, so it's clear that
the samurai has been modified. And we use the Update method, then call SaveChanges. When
Save is called from the Delete view, the DeleteConfirmed method gets the ID of the samurai,
queries for the full samurai, removes it from the context, setting its state to deleted and calls
SaveChanges. With the basics in hand, the next step is to add in the ability for the controllers and
views to comprehend some related data.
Adding Related Data into the MVC App
The samurai controller and view were awfully boring and not very useful without the related data.
Now, let's take a look at getting some of the samurai's related data into this little app. I'll start by
adding a new set of controller and views for the Quote class. This doesn't affect the existing
samurai controller or views, which are still totally unaware of the quotes. But the template did
recognize that the quote has a relationship with samurai and builds in the ability to choose a
samurai from a dropdown list when you create or edit a quote. That's a good start, except for the
fact that it's using the ID values, not the samurai names, and even with a new quote in there, as
far as the application is concerned, the samurai is still unaware of the new quote I added. And
that's how the scaffolding works for MVC apps. So it requires a little more knowledge about
building MVC applications to get it to be more useful with respect to the related data. I've made a
bunch of changes to what just got created in order to do just that. Some of the changes take
advantage of things you learned about working with graphs earlier in the course, and the rest is
more specific to how MVC controllers work and how to work with the markup in the views. I'll
show you the relevant bits of the news code that I've added and then leave you to explore the
code more deeply, as you can download it from the course's sample and even debug through it to
understand the interactions and behavior. Let's first watch the revised app in action. The Edit
screen for samurai now includes the real name from the samurai's secret identity and the quotes,
although this samurai doesn't have either of those yet. So I'll add a secret identity for Kikuchio,
and I'll save it, which brings us back to the Index view. Then I'll edit it again, and you can see that
the real name did get persisted and is now part of the samurai's data. Let's add a quote for
Kikuchio. Notice that the dropdown list now has the samurai's names, not the IDs, although I guess
I forgot to modify the label for that list. It's also defaulting to the samurai for whom I'm adding the
quote and gives me the opportunity to change that samurai if I want. With a new quote entered,
I'll click Create, and I've designed this so that the samurai details are displayed after adding a new
quote. Now you can see the name, the real name, and the list of quotes. I'll go back to editing the
samurai again. If I want to edit the quote, I could do that with the Edit link that's next to the quote,
but instead, I'm going to add another quote. I didn't make any changes to the controller method or
the view that are involved in creating new samurais, so that's still just letting me add the samurai's
name. But now when I go back to edit the samurai, again, I can enter any details I want for the
new samurai. I can also delete a samurai, and because of EF Core's default behavior, when I do
that, any related quotes or secret identity records that exist in the database will also be deleted.
So it's not really the perfect MVC application ready to throw into production, but I've done just
enough to be able to incorporate the related data into here.
Let's take a look at some of the code in the controllers and the views that are driving the app's
new ability to let the user more easily interact with the relationships. Since I didn't make any
change to the samurai's Index or Create methods, I'll jump right to the Details method. From an EF
Core perspective, what's important here is that I've modified the query to include the secret
identity and quotes for the samurai. And in the view for Detail, because the view was already
aware of the samurai type, I was able to just drill into quotes and secret identity in order to display
them, and I even got help from IntelliSense when I did this. Notice that below the markup for
displaying the samurai's name, I've now got code to display the SecretIdentity. RealName, and
further down, I'm building a table of quotes by iterating through the samurais' quotes and
displaying the text property for each one of those quotes. Here are the controller methods for
editing the samurai. The first is to display the edit page, and again, I'm eager loading the samurai,
its secret identity, and its quotes. The second Edit method is to handle a post back from that page,
and the most important change I made here is to remove the explicit binding to the ID and name
coming in from the page. That was limiting the samurai to only those two properties. Instead, I've
now told it to accept a full samurai object, and that will include the SecretIdentity. So when I call
Update, the SecretIdentity will get saved as well, even if it's new. In order for this to work, it
required that I make a change to my domain model, but it was something I should have done
anyway. In Samurai's constructor, I was already having it instantiate the Quotes list. Now I'm also
instantiating the SecretIdentity property. Otherwise, when I save the samurai in the controller, the
new SecretIdentity would have been null and not get added. There were some important changes
in the view for edits as well. Some of those changes were similar to the Details view, displaying the
real name and a list of quotes. But also, I need to keep track of the ID and samurai ID of the secret
identity. Otherwise, the form will only send back the real name without the IDs, and if you're
editing a secret identity, Entity Framework Core wouldn't be able to work out the update. Since I
don't want Edit fields for those IDs, I'm incorporating them into the view as hidden fields, just like
the template had already done for the samurai's ID. And it's the simplest way to solve that
problem, although you should definitely be using more sophisticated MVC application patterns for
doing this with sensitive data. That's really all there is of note with respect to EF Core in the
samurai controllers and views. Now let's take a look at the controller and views for Quotes. By
default, the Quotes controller was already eager loading the samurai data for a quote. Although
since I do have the SamuraiId foreign key property in the quote, that may not even be necessary.
But I'm leaving that alone. Recall that the default view for the quote was showing samurai IDs in
the dropdown. I fixed that here in the Create method and in the Edit method as well so that it uses
the Name property as the display text in the dropdown. When we create a new quote and save it,
I'm removing this code that rebuilds that dropdown list, because I'm not following the original
pattern that the template set up. Instead, I've changed this method so that when it's done, it
redirects back to the samurai's Index page. The only other changes I've made to the controllers
and views were related to these redirects; in other words, what page is displayed after a particular
action. So the key things I did to make this incorporate related data were replacing Samurai
queries with Samurai graph queries, editing some of the views to display the related data, I
ensured that the ID and foreign key ID for the SecretIdentity made the roundtrip from the
controller to the view and back to the controller, and I removed some explicit model binding in
one controller method. My recommendation is that you do download the sample and debug
through it to better understand how it works, and also of course to watch a proper ASP. NET Core
course to learn more about the ins and outs of controllers and views going beyond just interacting
with data that's retrieved and persisted using Entity Framework Core.
Now you've gotten to see or even use, if you're following along, Entity Framework Core in two
very different types of applications. First, with the WPF app, you learned about designing your
data access specifically for the long-running context that can continue tracking objects, even when
they've been sent to the user interface. I encapsulated this data access into its own class rather
than intertwining it with the user interface logic. Even with a small application like this, I always
find that to be a tactic that I'm grateful for when it comes time to maintain my software. While the
DbContext remained in scope in tracking the objects, it is expensive for EF Core to keep track of
those objects in real time. So you learned about how DetectChanges gets triggered at important
junctures in the workflow, and that's good to be aware of in order to set your expectations. When
we worked on the disconnected ASP. NET Core app, the first thing we learned was that while the
templates are very handy for adding in the code for working with a DbContext, it's pretty limited
when it comes to making the controllers and user interface present related data to the user. So
after running the templates, I showed you changes that I made to give you an idea of how to make
the app present a richer view of the related data, and I think that's nice for users rather than
having to go across many screens in order to work with the various types of objects in a graph, one
screen at a time. Also, don't forget about that little bug where the controller template has a hard
time discovering classes from the DbContext if you don't use their full namespace. Hopefully, that
bug will be gone by the time you're using those templates. Here one last time are resources that I
think are relevant to topics than I covered in this module. So now we've come to the end of this
Getting Started course for Entity Framework Core 2, and now I'm going to get to work on the
intermediate level course. And hopefully, that one will already be published by the time you've
reached this point. I'm Julie Lerman, and thanks again for watching Entity Framework Core 2:
Getting Started.