The intent of this article is to explain the concept of entity framework core, code first migrations and data annotations in entity framework core.
Table of Contents
Introduction
In the previous articles (data access approach, code first approach and WebAPI), we learnt a lot about entity framework and its practical implementations. The intent of this article is to explain the concept of entity framework core. We’ll go step by step to explore the topic of entity framework core. We’ll explore the code first approach using EF Core and learn about data annotations as well. We’ll also cover code first migrations in this article along with an understanding of how to seed the database. I’ll use Visual Studio 2017 for the tutorial. For the database, we would be using SQL Server. You can make use of the local dB if you do not have SQL Server installed.
Series Info
We'll follow a five-article series to learn the topic of entity framework in detail. All the articles will be in tutorial form except the last where I'll cover the theory, history, use of entity framework. The following are the topics of the series:
- Learning Entity Framework (Day 1): Data Access Approaches of Entity Framework in .NET
- Learning Entity Framework (Day 2): Code First Migrations in Entity Framework in .NET
- Learning Entity Framework (Day 3): Code First Migrations in ASP.NET WebAPI 2.0 in .NET
- Learning Entity Framework (Day 4): Understanding Entity Framework Core and Code First Migrations in EF Core
- Learning Entity Framework (Day 5): Entity Framework (The Theory)
Entity Framework Core
EF Core is also an ORM, but it's not an upgrade to Entity Framework 6, and it shouldn't be regarded as such. Instead, Entity Framework Core is a lightweight, extensible, and cross-platform version of Entity Framework. Therefore, it comes with a bunch of new features and improvements over Entity Framework 6, and it's currently at version 2. For ASP.NET Core 1, version 1 should be used, and for ASP.NET Core 2, version 2 is advised. Entity Framework does not support all the features of Entity Framework 6. Entity Framework Core is recommended for new apps that don't require the heavy set of features Entity Framework 6 offers, or for apps that target .NET Core. It comes with a set of providers which could be used with a variety of databases. It could be used with Microsoft SQL Server, of course, but also with SQLite, Postgres, SQL Server Compact Edition, MySQL, and IBM DB2. And there's also an in-memory provider for testing purposes. EF Core can be used both for a code-first approach, which will create the database from the code, or a database-first approach, which is convenient if the database is already there. The following section will show the basic implementation of Entity Framework Core in a console application and of course, it could be used in any type of .NET application like MVC, Web API, Windows which needs to interact with the database. We'll start out by adding EF Core it to our project. We'll also investigate migrations, a way to migrate between different versions of our underlying datastore. We’ll also check out how we can seed the database with data from code. Let's dive in by introducing Entity Framework Core.
Where Can EF Core be Used
Entity Framework Core runs on .NET Core, and .NET Core runs in a lot of places. It runs inside of the full .NET Framework that is any version that is 4.5.1 or newer, and .NET Core itself can run on the CoreCLR (that's the runtime) and CoreCLR can run natively, not only in Windows but also on Mac and Linux. And the other place you can use EF Core on the Universal Windows Platform, or UWP for Windows 10, so that runs on any device or PC that can run Windows 10. Though, that doesn't necessarily mean you should use Entity Framework Core in all of these scenarios, and that's a really important point to keep in mind because Entity Framework Core is a brand new set of APIs. It doesn't have all of the features that you might be used to with Entity Framework 6, and while some of those features will be coming in future versions of EF Core, there are a few that will never be part of Entity Framework Core, so it's important to understand that, and that you may not want to start every single new project with the Entity Framework Core. Be sure that Entity Framework Core has the features that you need. If you want to target cross-platform or UWP, you have to use Entity Framework Core, but for .NET apps, you can still use Entity Framework 6, and in fact for ASP.NET Core apps that will definitely stay on Windows. In other words, on a Windows Server, you can still build separate APIs using full .NET with the Entity Framework 6, and just have your ASP.NET Core app talk to that Entity Framework 6-based library.
Code First Approach using Entity Framework Core
Data access approaches are same in Entity Framework 6 and Entity Framework Core apart from some of the new features that EF Core provides. There are minor differences and implementation techniques that come along with the related packages. Let’s see the EF Core in action step by step using code first approach. We’ll cover more topics like data annotations and other migration techniques while walking through the practical implementation.
Adding Entities
- As previously explained, for the code first approach, the application should have entities that would eventually result in the database tables. So create a console application to start within .NET Framework 4.6.2. Name the application
EmployeeManagement
and solution name as EFCore
.
- Add two entity classes, one named
Department
and other as Employee
. There would be one too many relationships between department
and employee
. For example, a department
can have multiple employee
s and an employee
would be associated with any one department
.
Department
Code
namespace EmployeeManagement
{
public class Department
{
public int DepartmentId { get; set; }
public string DepartmentName { get; set; }
public string DepartmentDescription { get; set; }
}
}
Employee
Code
namespace EmployeeManagement
{
public class Employee
{
public int EmployeeId { get; set; }
public string EmployeeName { get; set; }
public int DepartmentId { get; set; }
public virtual Department Departments { get; set; }
}
}
- The department entity has department name and description property and the entity
employee
has EmployeeId
, Name
and DepartmentId
property that acts as a navigation property for department
s. Add a property Employee
s denoting the collection of employees in Department
entity as the department
can have many employee
s. Similarly, a property of type Department
is added in Employee
class that returns a single department
and not the list.
public virtual ICollection<Employee> Employees { get; set; }
Data Annotations
- By giving the class an ID with name
Id
, this field is automatically regarded as the primary key. DepartmentId
, for example, the class name, followed by ID
would be possible as well. If we would name this differently, the convention doesn't apply. But we can apply the key data annotation from System.ComponentModel.DataAnnotations
. Personally, I like to apply the key annotation anyway, even if convention would ensure this property would be regarded as primary key, I feel it makes Entity
classes so much more understandable at first glance. But, well, I've got the same gripe with a lot of convention-based approaches, so this is totally up to you. The following is the way in which you can add a [Key]
for the property you want to make a primary key.
- Similarly, add the key for
EmployeeId
. For example, a primary key for Employee
entity.
- Another thing of importance is a generation of ID primary keys. By convention, primary keys that are of integer or GUID data type will be set up to have their values generated on add. In other words, our ID will be an identity column. To explicitly state this, we can use another annotation, the database-generated annotation from the
System.ComponentModel.DataAnnotations.SchemaNamespace
. It has three possible values:
null
for no generation, - identity for generation on add, and
- computed for generation on add or update.
We need the identity option. A new key will be generated when an Employee
is added. How this value is generated depends on the database provider being used. Database providers may automatically set up value generation for some property types, while others will require you to manually set up how the value is generated. In our case, we'll be using SQL Server. So we're good to go. A new integer primary key will be automatically generated without further setup.
- We want to signify the relationship between
Department
and Employee
. If we look back at the Department
entity, we already defined a collection of Employee
, but we want to navigate through our object graph from a point of interest to the parent department. So we need a property to refer to that parent department. And we need to state what the foreign key property will be. Again, there's a convention-based and an explicit approach possible. By convention, a relationship will be created when there is a navigation property discovered on a type. And a property is considered a navigation property if the type it points to cannot be mapped as a scalar type by the current database provider. So, if we add a property Department
of type Department
, this is considered the navigation property, and a relationship will be created. Relationships that are discovered by convention will always target the primary key of the principal entity. And in this case, that's the ID
of the Department
. That will be our foreign key. It's not required to explicitly define this foreign key property on the dependent
class. And the dependent class, well, that's our Employee
class. But it is recommended, so we'll add one. So that's the convention-based approach. If we do not want the convention-based approach to be followed, which states that a foreign key will be named according to the navigation property's class name followed by id
, so DepartmentId
in our case, we can again use an annotation for that. The foreign key annotation from the System.ComponentModel.DataAnnotations.Schema
namespace.
- The entity classes properties do not have any data annotation w.r.t. mandatories or max lengths. If we leave our entity classes like this, our database columns will allow
null
for fields that should not be null
. And we'll be off max
and varchar
length instead of a specific maximum size. It's best practice to ensure these field restrictions are applied at the lowest possible level. So, in our case, that's the database itself. This ensures the best possible integrity. So let's apply these attributes. For Employee
, the EmployeeName
was required with a maxLength
of 50
. And for the Department
entity, we want these as well. Let's make Name
required with a maximum length of 50
.
Code
using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace EmployeeManagement
{
public class Employee
{
[Key]
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public int EmployeeId { get; set; }
[Required]
[MaxLength(50)]
public string EmployeeName { get; set; }
public int DepartmentId { get; set; }
[ForeignKey("DepartmentId")]
public virtual Department Department { get; set; }
}
}
Adding DB Context
In this section, we'll create a context to interact with our database and that context represents a session with the database, and it can be used to query and save instances of our entities. Our entity classes are just classes. We didn't need any extra dependencies to create those but the DBContext
, that's part of Entity Framework Core. And we'll also need a provider. In our case, we'll use the SQL Server provider, so we can connect to a LocalDB
instance.
- Let's open the NuGet dialog. Right click on the project and select "Manage NuGet Packages…" option.
- We want to look for the
Microsoft.EntityFrameworkCore.SqlServer
package. If we install that, the Entity Framework core dependencies will be added as well, so we'll have all we need for now.
- Select the latest stable version and click Install.
- Accept the license agreement.
As you can guess by now, no need to do this when you're on ASP.NET Core 2 and you've referenced the Microsoft.AspNetCore.All
package. That includes the necessary references for Entity Framework Core.
- Now let's add a new class,
EmployeeManagementContext
.
- Have the class inherit
DBContext
. DBContext
can be found in the Microsoft.EntityFrameworkCore
namespace. Bigger applications often use multiple contexts. For example, were we to add some sort of reporting module to our application, that would fit in a separate context. There's no need for all the entities that map to tables in a database to be in the same context. Multiple contexts can work on the same database. In our case, we only have two entities, so one context is sufficient.
- In this context, we now want to define
DbSet
s for our entities. Such a DbSet
can be used to query and save instances of its entity type. LINQ queries against a DbSet
will be translated into queries against the database. Add two properties each for entity classes that we have returning DbSet
of the entity.
Code
using Microsoft.EntityFrameworkCore;
namespace EmployeeManagement
{
public class EmployeeManagementContext : DbContext
{
public DbSet<Employee> Employees { get; set; }
public DbSet<Department> Departments { get; set; }
}
}
- How do we tell the context that which database it has to associate to? Well, that's through a connection string. We need to provide this connection string to our
DBContext
. In other words, we need to configure this DBContext
. And there are essentially two ways of doing this. Let's open our EmployeeManagementContext
again. The first way of doing this is through overriding the OnConfigure
method on the DBContext
. This has an optionsBuilder
as a parameter. And that optionsBuilder
provides us with a method--UseSqlServer
. This tells the DBContext
it's being used to connect to a SQL server database, and it's here that we can provide a connection string. So that's one way.
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
{
optionsBuilder.UseSqlServer("connectionstring");
base.OnConfiguring(optionsBuilder);
}
- But let's look at the other way--via the constructor. So, let's comment
OnConfiguring
out, and have a look at the DBContext
definition. The DBContext
exposes a constructor that accepts DBContext
options.
- So, let's add a constructor that calls this constructor overload. What this allows us to do, and what isn't possible when overriding the
OnConfigure
method, is that we can provide options at the moment we register our DBContext
. And that's a more logical approach.
public EmployeeManagementContext
(DbContextOptions<EmployeeManagementContext> options) : base (options)
{
}
- To get the instance of this context class now, let’s add a new class named
Initialize
and add a static
method responsible for returning context instance. The GetContext()
method overload on these options, so we can use now--UseSqlServer
. It's from the Microsoft.EntityFrameworkCore
namespace, so let's add that using
statement. And in this method, we can pass in the connection string. So, let's add a variable to hold this connection string for now. The next logical question is, what would that connection string look like? Well, we're going to be using local DB, as this is installed automatically together with Visual Studio. But if you have a full SQL Server installation in your network, it'll work as well. Just make sure you change the connection string accordingly. The name (localdb)\MSSQLLocalDB
is the default instance name, but it can be different on your machine depending on whatever you inputted on install. So, if you're not sure, have a look at the SQL Server Object Explorer window. If you don't see that on your machine, you can find it underneath the View menu item.
public class Initialize
{
public static EmployeeManagementContext GetContext()
{
var connectionString = @"Server=(localdb)\mssqllocaldb;
Database=EmployeeManagementDB;Trusted_Connection=True;";
DbContextOptionsBuilder<EmployeeManagementContext> options =
new DbContextOptionsBuilder<EmployeeManagementContext>();
options.UseSqlServer(connectionString);
return new EmployeeManagementContext(options.Options);
}
}
- Call the
GetContext()
method to create the instance of context class in Program.cs. Ideally, when we run the application and instance of context class get created, the database should be ready at local db.
Code
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace EmployeeManagement
{
class Program
{
static void Main(string[] args)
{
var context = Initialize.GetContext();
context.EnsureSeedDataForContext();
}
}
}
- This is a code-first approach for a new database, so the database should be generated if it doesn't exist yet. Let's open our
EmployeeManagementContext
again to make sure that happens. To the constructor that will be used when requesting an instance from the container through dependency injection, we call EnsureCreated()
on the database object. This database is an object is defined on DBContext
. If the database already exists, nothing will happen, but if it doesn't, this call ensures it is effectively created.
Context constructor
public
EmployeeManagementContext
(DbContextOptions<EmployeeManagementContext> options) : base (options){
Database.Migrate();
}
- Run the application. Once the application is run and Program.cs’s
main
method executes the GetContext()
method, let's open that SQL Object Explorer window again. Let's refresh the database list from our MSSQLLocalDB
instance. And it looks like our EmployeeManagementDB
data is there. Let's have a look at the tables. Apparently, two tables have been created, a Departments
and an Employee
table, the pluralized names of our entities.
- The
Departments
table has a primary key, DepartmentId
, a DepartmentName
with a maximum length of 50
, which cannot be null
. If you look at the Department
entity, we see that the column definition matches the definition of the fields on our Department
entity. Let's have a look at the Employees
table. It has a DepartmentId
, which is a foreign key, and it has an EmployeeName
field, which is required, thus cannot be null
, and a maximum length of 50
. So that matches our Employee
entity. The attributes we applied to the properties on our entity classes were, thus, taken into account. So far, so good. But this is only one way of doing this.
If we work like this, we work by ensuring the database is created by calling Database.EnsureCreated()
. But if we do that, well, we're forgetting something. Just as code evolves, a database evolves as well. Let's look into migrations to see how we can improve on what we've done up until now and how we can handle an evolving database.
Code First Migrations in EF Core
Just as our code evolves, so does the database. New tables might be added after a while, existing tables might be dropped or altered. Migrations allow us to provide code to change the database from one version to another. They're an important part of almost all applications, so let's look into it. What we are going to do, we are going to use migrations to create the initial database version, version 1. So, we'll replace what we did in the previous demo by this new and better approach. The reason is that by doing that, we'll have code in place to start from no database at all, rather than having to provide an already existing one. Then, we'll add another migration to migrate to a new version, version 2. To allow for something like this, we'll first need to create an initial snapshot of our database. In the Entity Framework core world, this is achieved with tooling, so we'll have to add these tools first. And these tools are essentially just another set of dependencies that add commands we can execute.
- Let's add the package
Microsoft.EntityFrameworkCore.Tools
.
- So, then we'll have to create that initial snapshot or migration of our database and schema. For that, we have to be able to execute one of the commands we just enabled. And executing those commands, well, you can do that in the package manager console. If you don't currently see that, you can get it via Tools, NuGet Package Manager, Package Manager Console.
- The command we're looking for is the Add-Migration command. It expects a name for the migration we're going to add. So, let's say we want to name it
EmployeeManagementInitialMigration
.
- It gives us the error that it cannot create the object of type
EmployeeManagementContext
and asks us to add an implementation of IDesignTimeContextFactory
. So let’s create a new class named DesignTimeContextFactory
inheriting from IDesignTimeDbContextFactory
of our context class and add the CreateDbContext
method which creates optionsBuilder
and returns the context class instance with these options as a parameter.
Code
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Design;
using Microsoft.Extensions.Configuration;
namespace EmployeeManagement
{
public class DesignTimeDbContextFactory :
IDesignTimeDbContextFactory<EmployeeManagementContext>
{
public EmployeeManagementContext CreateDbContext(string[] args)
{
var optionsBuilder =
new DbContextOptionsBuilder<EmployeeManagementContext>();
optionsBuilder.UseSqlServer(@"Server=(localdb)\mssqllocaldb;
Database=EmployeeManagementDB;Trusted_Connection=True;");
return new EmployeeManagementContext(optionsBuilder.Options);
}
}
}
- Now run the Add-Migration command, i.e.,
Add-Migration EmployeeManagementInitialMigration
:
If we look at our solution now, we see there's a new Migrations folder. And it contains two files. One, a snapshot of our current context model.
Let's have a look at that.
- This contains the current model as we defined through our entities, including the annotations we provided. We can find our
Department
entity and our Employee
entity. And at the end of the file, the relation between Department
and Employee
.
- The second file we see is the
EmployeeManagement InitialMigration
. That's the name we just gave to our migration. This contains the code needed by the migration builder to build this version of the database, both Up (from current to the new version) and Down (from this version to the previous version). If we look at Up, we see two CreateTable
statements and a CreateIndex
statement. That means it's starting from no database at all, and this migration contains the code to build the initial database. And if we look at Down, we see what should happen to end up with an empty database--two DropTable
statements.
If new migrations are added, new files like this will be created, and by executing them in order our database can evolve together with our code. By the way, you don't need to run the Add-Migration command to generate these files. We could've written them by hand. And that might still be feasible for one or two or three tables maybe. But it's definitely not something you want to do for a larger database. So, these tools are quite helpful. So far, so good.
- There's one more thing we have to do. We have to ensure that the migration is effectively applied to our database. And there's another command for that. It's called the update-database command. If we execute this, the migrations will be applied to our current database. Rather than doing it from command, I’ll show you how we can do this from code.
- Let's open the context again. What we can do is replace
Database.EnsureCreated()
by Database.Migrate()
. This will execute migrations, which, if there's no database yet, will create it. And that's really all we have to do. But as said, we're replacing what we did in the previous clip because, well, most applications do require migrations. And for those, it's a good idea to start from no database at all if you have the chance.
public EmployeeManagementContext
(DbContextOptions<EmployeeManagementContext> options) : base (options)
{
Database.Migrate();
}
- So, what we want to do is remove the current database first. If we don't do that, this call will try and apply the migrations. For example, create the
Departments
and Employees
tables, and that will fail because they already exist. In the SQL Server Object Explorer, right-click the existing database and delete it.
If you do want to provide an existing database, you can follow the same flow we just did, but delete the first migration file. Generally speaking, though, that's not a good place to be unless your application must start from an existing database. Let's give this a try.
- Run the application.
- Let's have a look at our
localDB
server. Let's refresh the databases list. Our database was created again, but by working like this instead of how we did it previously, we've ensured our database can migrate from not existing at all to its initial version and upcoming versions after that. A better approach than what we did in the previous sections. Let's have a look at the database itself.
It now contains an additional table--_EFMigrationsHistory
. Let's have a look at what's in there. Entity Framework Core uses this table in the database to keep track of which migrations have already been applied to the database.
This ensures that that Database.Migrate()
call, or alternatively, the Update-Database call from the command line doesn't try to execute the same migrations over and over again.
- Let’s continue with adding a new migration. An
Employee
doesn't seem to have a salary. We may have missed that on purpose because this allows us to look into an additional migration. So let's add that Salary
property.
Code
using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace EmployeeManagement
{
public class Employee
{
[Key]
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public int EmployeeId { get; set; }
[Required]
[MaxLength(50)]
public string EmployeeName { get; set; }
public int DepartmentId { get; set; }
public int Salary { get; set; }
[ForeignKey("DepartmentId")]
public virtual Department Department { get; set; }
}
}
- Then, let's execute the
Add-Migration
command again so the file gets generated for us. Let's name this migration EmployeeManagementAddSalaryToEmployee
.
Our Migrations folder now includes a new file.
And if looking at this file, we see that the Up
method contains the code to add the Salary
column, and the Down
method contains the code to drop the column again.
- Let's run the application again.
- Let's have a quick look at the database.
Employee
s now indeed contain a Salary
column.
- Let's have a look at that
EFMigrationHistory
table. And, indeed, it also contains the new migration. And that's how we can work with migrations to migrate our database from one version to another. But if we look at the data that's in these tables, we see there's nothing there yet. No Employees
, Department
. To add data to start with, we should seed the database. Let’s see in the next section how we can do that.
Seeding the Database
We still haven't got data in our database. It would be nice to have some to test with. That principle, providing your database with data to start with, is called seeding the database. It's often used to provide master data.
We saw how we do that in EF 6 versions. Here, we’ll discuss another approach to seed the database.
- We'll write an extension method on our context. So, let's start with that extension method. Let's add a new class,
EmployeeManagementContextExtensions
. Let's make it static
.
- Let's add one
static
method to it, EnsureSeedDataForContext
. The method has one parameter of type EmployeeManagementContext
named context, and it's decorated with this, which tells the compiler it extends EmployeeManagementContext
. The first thing we want to do is check if the database already contains our sample data. We want to insert departments
and their employees
. So, let's check if the Departments
table is empty. An employee
can't exist without a department, so that's sufficient. If it's not empty, we already have data in there, and we don't want to insert additional data. And, otherwise, we can start adding data. We first create a Department
with the name "Technology
" and provide three employees (Jack
, Kim
, Shen
) to that department
. We do not provide IDs as these are now auto-generated by the database. Then we'll want to add these to the context. For that, we can use Add
method or AddRange
method if there are multiple departments on the Departments DBSet
on our context. And from this moment on, the entities are tracked by the context. But they aren't inserted yet. For that, we must call SaveChanges
on the context. Calling SaveChanges
on the context will effectively execute the statements on our database.
Code
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace EmployeeManagement
{
public static class EmployeeManagementContextExtensions
{
public static void EnsureSeedDataForContext
(this EmployeeManagementContext context)
{
if (context.Departments.Any())
{
return;
}
Department department = new Department
{
DepartmentName = "Technology",
Employees = new List<Employee>
{
new Employee() {EmployeeName = "Jack"},
new Employee() {EmployeeName = "Kim"},
new Employee() {EmployeeName = "Shen"}
}
};
context.Departments.Add(department);
Employee employee = new Employee
{
EmployeeName = "Akhil Mittal",
DepartmentId = 1
};
context.Employees.Add(employee);
context.SaveChanges();
}
}
}
And that's already it for the extension method. Then we need to execute this extension method.
- Call the extension method
EnsureSeedDataForContext()
after you create the instance of the context in Program.cs class. Then run the application.
Code
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace EmployeeManagement
{
class Program
{
static void Main(string[] args)
{
var context = Initialize.GetContext();
context.EnsureSeedDataForContext();
}
}
}
- Let's have a look at our database. And the
Departments
table contains sample data, and so does the Employees
table. And with that, we now know what Entity Framework Core is, its most important concepts, and how to use those.
EF Core Summary
The .NET Core and Entity Framework Core are truly cross-platform, but they're cross-platform on two levels. You can run .NET Core apps using EF Core on any of these platforms, but you can also create, debug, and build them on any one of the platforms as well, and with this cross-platform tool, Visual Studio Code and all of its rich features, plus the fact that it is open source, I've got the ability to do that coding and debugging on any one of the platforms. Visual Studio Code only enhances the flexibility we have for working with .NET Core and Entity Framework Core, but EF Core itself is also flexible. You can also deploy these apps to Docker and run them anywhere that Docker runs. Entity Framework Core is a lightweight, extensible, and cross-platform version of Entity Framework. It's recommended for new applications that don't need the full Entity Framework 6 feature set and for .NET Core applications. We created entity classes first. We can use annotations on those to define things like primary and foreign keys, required fields, and so on. Those are then registered as DBSet
s on the DBContext
. That context represents a session with the database. And it can be used to query and save instances of our entities. From that moment on, we could access our entities through LINQ. There was another important concept we looked into--migrations. Just as our code evolves, so does the database. New tables might be added. After a while, existing tables might be dropped or altered. Migrations allow us to provide code to change the database from one version to another. And, lastly, we investigated an option to seed the database providing it with data to start with. Download the complete free eBook (Diving into Microsoft .NET Entity Framework) on Entity Framework here.
History
- 9th October, 2018: Initial version