Setting up Entity Framework Core

The Entity Framework (EF) was first released as part of .NET Framework 3.5 with Service Pack 1 back in late 2008. Since then, it has evolved, as Microsoft has observed how programmers use an object-relational mapping (ORM) tool in the real world.

The version included with .NET Framework 4.6 is Entity Framework 6.1.3 (EF6). It is mature, stable, and supports the old EDMX design-time way of defining the model as well as complex inheritance models, and a few other advanced features. However, EF6 is only supported by the .NET Framework, not by the .NET Core.

The cross-platform version, Entity Framework Core (EF Core), is different. Microsoft has named it that way to emphasize that it is a reset of functionality. Although EF Core has a similar name, you should be aware that it currently varies from EF6.

Look at its pros and cons:

  • Pros
    • EF Core is available for the .NET Core as well as the .NET Framework, which means it can be used cross-platform on Linux and macOS as well as Windows.
    • EF Core supports modern cloud-based, non-relational, schema-less data stores, such as Microsoft Azure Table Storage and Redis.
  • Cons
    • EF Core will never support the EDMX design-time XML file format.
    • EF Core does not (yet) support lazy loading or complex inheritance models and other advanced features of EF6.

Using Visual Studio 2017

In Visual Studio 2017, press Ctrl + Shift + N or go to File | New | Project....

In the New Project dialog, in the Installed | Templates list, expand Visual C#, and select .NET Core. In the center list, select Console App (.NET Core), type name as Ch08_EFCore, change the location to C:Code, type solution name as Chapter08, and then click on OK.

Right-click on Dependencies and choose Manage NuGet packages. In Package Manager, click on the Browse tab and, in the search box, enter Microsoft.EntityFrameworkCore.SqlServer, and click on Install:

Using Visual Studio 2017

Review the changes, as shown in the following screenshot, and accept the license agreement:

Using Visual Studio 2017

Using Visual Studio Code

Use Visual Studio Code to open the Ch08_EFCore folder that you created earlier.

In Integrated Terminal, enter the dotnet new console command.

In the Explorer pane, click on the Ch08_EFCore.csproj file.

Add a package reference to EF Core for SQLite, as shown highlighted in the following markup:

    <Project Sdk="Microsoft.NET.Sdk"> 
 
      <PropertyGroup> 
        <OutputType>Exe</OutputType> 
        <TargetFramework>netcoreapp1.1</TargetFramework> 
      </PropertyGroup> 
 
      <ItemGroup> 
        <PackageReference  
          Include="Microsoft.EntityFrameworkCore.Sqlite"  
          Version="1.1.1" /> 
      </ItemGroup> 
 
    </Project> 

In Integrated Terminal, enter the dotnet restore command.

Entity Framework Core models

EF Core uses a combination of conventions, annotation attributes, and Fluent API statements to build a model at runtime so that any actions performed on the classes can later be automatically translated into actions performed on the actual database.

EF Core conventions

The code we will write will use the following conventions:

  • The name of a table is assumed to match the name of a DbSet<T> property in the DbContext class, for example, Products.
  • The names of the columns are assumed to match the names of properties in the class, for example, ProductID.
  • The string .NET type is assumed to be an nvarchar type in the database.
  • The int .NET type is assumed to be an int type in the database.
  • A property that is named ID or the name of the class with ID as the suffix is assumed to be a primary key. If this property is any integer type or the Guid type, then it is also assumed to be IDENTITY (automatically assigned value when inserting).

Note

There are many other conventions, and you can even define your own, but that is beyond the scope of this book, and you can read about them at the following link: https://docs.microsoft.com/en-us/ef/core/modeling/

EF Core annotation attributes

Conventions often aren't enough to completely map the classes to the database objects. A simple way of adding more smarts to your model is to apply annotation attributes.

For example, in the database, the maximum length of a product name is 40, and the value cannot be null (empty). In a Product class, we could apply attributes to specify this:

    [Required] 
    [StringLength(40)] 
    public string ProductName { get; set; } 

When there isn't an obvious map between .NET types and database types, an attribute can be used. For example, in the database, the column type of UnitPrice for the Products table is money. .NET does not have a money type, so it should use decimal instead:

    [Column(TypeName = "money")] 
    public decimal? UnitPrice { get; set; } 

In the Category table, the Description column can be longer than the 8,000 characters that can be stored in an nvarchar variable, so it needs to map to ntext instead:

    [Column(TypeName = "ntext")] 
    public string Description { get; set; } 

There are many other attributes, but they are beyond the scope of this book.

EF Core Fluent API

The last way that the model can be defined is using the Fluent API. It can be used instead of attributes or in addition to them. For example, look at the following two attributes in a Product class:

    [Required] 
    [StringLength(40)] 
    public string ProductName { get; set; } 

They could be deleted and replaced with this Fluent API statement in the Northwind class' OnModelBuilding method:

    modelBuilder.Entity<Product>() 
      .Property(product => product.ProductName) 
      .IsRequired() 
      .HasMaxLength(40); 

Building an EF Core Model

In both Visual Studio 2017 and Visual Studio Code, add three class files to the project named Northwind.cs, Category.cs, and Product.cs.

Northwind.cs should look like this:

    using Microsoft.EntityFrameworkCore; 
 
    namespace Packt.CS7 
    { 
      // this manages the connection to the database 
      public class Northwind : DbContext 
      { 
        // these properties map to tables in the database 
        public DbSet<Category> Categories { get; set; } 
        public DbSet<Product> Products { get; set; } 
 
        protected override void OnConfiguring( 
          DbContextOptionsBuilder optionsBuilder) 
        { 
          // for Microsoft SQL Server 
          // optionsBuilder.UseSqlServer( 
          // @"Data Source=(localdb)mssqllocaldb;" + 
          // "Initial Catalog=Northwind;" + 
          // "Integrated Security=true;"); 
 
          // for SQLite 
          optionsBuilder.UseSqlite( 
            "Filename=../../../../Northwind.db"); 
        } 
 
        protected override void OnModelCreating( 
          ModelBuilder modelBuilder) 
        { 
          // example of using Fluent API instead of attributes 
          modelBuilder.Entity<Category>() 
          .Property(category => category.CategoryName) 
          .IsRequired() 
          .HasMaxLength(40); 
        } 
      } 
    } 

Category.cs should look like this:

    using System.Collections.Generic; 
    using System.ComponentModel.DataAnnotations.Schema; 
 
    namespace Packt.CS7 
    { 
      public class Category 
      { 
        public int CategoryID { get; set; } 
        public string CategoryName { get; set; } 
 
        [Column(TypeName = "ntext")] 
        public string Description { get; set; } 
 
        // defines a navigation property for related rows 
        public virtual ICollection<Product> Products { get; set; } 
 
        public Category() 
        { 
          this.Products = new List<Product>(); 
        } 
      } 
    } 

Product.cs should look like this:

    using System.ComponentModel.DataAnnotations; 
    using System.ComponentModel.DataAnnotations.Schema; 
 
    namespace Packt.CS7 
    { 
      public class Product 
      { 
        public int ProductID { get; set; } 
 
        [Required] 
        [StringLength(40)] 
        public string ProductName { get; set; } 
 
        [Column(TypeName = "money")] 
        public decimal? UnitPrice { get; set; } 
 
        // these two define the foreign key relationship 
        // to the Categories table 
        public int CategoryID { get; set; } 
        public virtual Category Category { get; set; } 
      } 
    } 

Note that you did not need to include all columns from a table as properties on a class.

Note

The two properties that relate the two entities, Category.Products and Product.Category, are both marked as virtual. This allows EF to inherit and override them to provide extra features, such as lazy loading. Currently, EF Core does not support lazy loading, but EF6 does. Microsoft intends to add lazy loading support into EF Core soon.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
18.116.10.201