Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles / database / SQL-Server

Learning Entity Framework (Day 4): Understanding Entity Framework Core and Code First Migrations in EF Core

5.00/5 (20 votes)
9 Oct 2018CPOL24 min read 29.1K   924  
Entity framework core, code first migrations and data annotations in EF Core
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:

Image 1

  1. Learning Entity Framework (Day 1): Data Access Approaches of Entity Framework in .NET
  2. Learning Entity Framework (Day 2): Code First Migrations in Entity Framework in .NET
  3. Learning Entity Framework (Day 3): Code First Migrations in ASP.NET WebAPI 2.0 in .NET
  4. Learning Entity Framework (Day 4): Understanding Entity Framework Core and Code First Migrations in EF Core
  5. Learning Entity Framework (Day 5): Entity Framework (The Theory)

Entity Framework Core

Image 2

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

  1. 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.

    Image 3

  2. 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 employees and an employee would be associated with any one department.

    Department

    Image 4

    Code

    C#
    namespace EmployeeManagement
    {
        public class Department
        {
            public int DepartmentId { get; set; }
            public string DepartmentName { get; set; }
            public string DepartmentDescription { get; set; }
        }
    }

    Employee

    Image 5

    Code

    C#
    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; }
        }
    }
  3. 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 departments. Add a property Employees denoting the collection of employees in Department entity as the department can have many employees. Similarly, a property of type Department is added in Employee class that returns a single department and not the list.

    Image 6

    C#
    public virtual ICollection<Employee> Employees { get; set; }

Data Annotations

  1. 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.

    Image 7

  2. Similarly, add the key for EmployeeId. For example, a primary key for Employee entity.

    Image 8

  3. 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.

    Image 9

  4. 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.

    Image 10

  5. 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.

    Image 11

Code

C#
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.

  1. Let's open the NuGet dialog. Right click on the project and select "Manage NuGet Packages…" option.

    Image 12

  2. 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.

    Image 13

  3. Select the latest stable version and click Install.

    Image 14

  4. Accept the license agreement.

    Image 15

    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.

    Image 16

  5. Now let's add a new class, EmployeeManagementContext.

    Image 17

  6. 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.

    Image 18

  7. In this context, we now want to define DbSets 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.

    Image 19

    Code

    C#
    using Microsoft.EntityFrameworkCore;
    
    namespace EmployeeManagement
    {
        public class EmployeeManagementContext : DbContext
        {
            public DbSet<Employee> Employees { get; set; }
            public DbSet<Department> Departments { get; set; }
        }
    }
  8. 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.

    Image 20

    C#
    protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
    {
        optionsBuilder.UseSqlServer("connectionstring");
        base.OnConfiguring(optionsBuilder);
    }
    
  9. 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.

    Image 21

  10. 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.

    Image 22

    C#
    public EmployeeManagementContext
      (DbContextOptions<EmployeeManagementContext> options) : base (options)
            {
                
            }
  11. 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.

    Image 23

    C#
    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);
            }
        }
  12. 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.

    Image 24

    Code

    C#
    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();
            }
        }
    }
  13. 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

    C#
    public
    EmployeeManagementContext
      (DbContextOptions<EmployeeManagementContext> options) : base (options){
                        Database.Migrate();
            }
  14. 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.

    Image 25

  15. 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.

    Image 26

    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.

  1. Let's add the package Microsoft.EntityFrameworkCore.Tools.

    Image 27

  2. 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.

    Image 28

  3. 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.

    Image 29

  4. 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.

    Image 30

    Code

    C#
    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);
            }
        }
    }
  5. Now run the Add-Migration command, i.e., Add-Migration EmployeeManagementInitialMigration:

    Image 31

    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.

    Image 32

    Let's have a look at that.

  6. 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.

    Image 33

  7. 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.

    Image 34

    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.

  8. 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.

    Image 35

  9. 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.

    Image 36

    C#
    public EmployeeManagementContext
      (DbContextOptions<EmployeeManagementContext> options) : base (options)
            {
                Database.Migrate();
            }
  10. 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.

    Image 37

    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.

  11. Run the application.

    Image 38

  12. 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.

    Image 39

    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.

    Image 40

  13. 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.

    Image 41

    Code

    C#
    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; }
        }
    }
  14. Then, let's execute the Add-Migration command again so the file gets generated for us. Let's name this migration EmployeeManagementAddSalaryToEmployee.

    Image 42

    Our Migrations folder now includes a new file.

    Image 43

    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.

  15. Let's run the application again.

    Image 44

  16. Let's have a quick look at the database. Employees now indeed contain a Salary column.

    Image 45

  17. 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.

    Image 46

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.

Image 47

We saw how we do that in EF 6 versions. Here, we’ll discuss another approach to seed the database.

  1. 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.

    Image 48

  2. 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.

    Image 49

    Code

    C#
    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.

  3. Call the extension method EnsureSeedDataForContext() after you create the instance of the context in Program.cs class. Then run the application.

    Image 50

    Code

    C#
    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();
            }
        }
    }
  4. 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.

    Image 51

    Image 52

EF Core Summary

Image 53

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 DBSets 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

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)