2020年9月30日 星期三

Code First 建立 Entity Framework Core 應用專案

Code First 建立 Entity Framework Core 應用專案

在前一個文章 Console 專案與 EF Core 讀取已經存在的資料庫 ,說明了如何 DbContext 類別,來讀取後端資料庫內的紀錄;在這裡將要練習另外一種 Entity Framework Core 的架構,稱作 Code First ,也就是說,開發過程中,會先來使用 C# 類別定義出各種對應到後端資料庫內資料表的 Entity 類別,接著,透過這些 Entity 類別,產生出後端的資料,或者,直接進行存取。

對於建立和設定模型的相關資訊,可以參考這裡 建立和設定模型

請按照底下的步驟來進行操作

建立練習專案

  • 打開 Visual Studio 2019
  • 點選 [建立新的專案] 按鈕
  • 在 [建立新專案] 對話窗內,選擇 [主控台應用程式 (.NET Core)] 專案樣板
  • 在 [設定新的專案] 對話窗內,於 [專案名稱] 欄位內輸入 efCodeFirst
  • 點選 [建立] 按鈕,以便開始建立這個專案

加入 Entity Framework Core 要使用到的 NuGet 套件

  • 滑鼠右擊專案內的 [相依性] 節點
  • 選擇 [管理 NuGet 套件]
  • 點選 [瀏覽] 標籤分頁頁次
  • 在 [搜尋] 文字輸入盒內,輸入 [Microsoft.EntityFrameworkCore.SqlServer]
  • 點選 [安裝] 按鈕以便安裝這個套件
  • 在 [搜尋] 文字輸入盒內,輸入 [Microsoft.EntityFrameworkCore.Tools]
  • 點選 [安裝] 按鈕以便安裝這個套件

建立 Entity Framework 要用到的 Entity 模型相關類別

  • 在專案下,建立 [Models] 目錄

  • 在 [Models] 目錄下,建立 [Department] 類別,其程式碼如下

    這裡宣告這個 Department Entity 內,有兩個欄位,分別是 Id 與 Name;另外,他與 Course 這個 Entity 具有一對多的關聯,也就是說,一個 Department 會有多個 Course 紀錄

public class Department
{
    public Department()
    {
        Courses = new HashSet<Course>();
    }
    public int Id { get; set; }
    public string Name { get; set; }
    public virtual ICollection<Course> Courses { get; set; }
}
  • 在 [Models] 目錄下,建立 [Course] 類別,其程式碼如下

    這裡宣告這個 Course Entity 內,有兩個欄位,分別是 Id 與 Name,並且也宣告一個 Foreign Key 外鍵 DepartmentId 與一個導航屬性 Department,這裡表示了 Course 這個 Entity 將會對應到一個 Department Entity上;另外,他與 StudentGrade 這個 Entity 具有一對多的關聯,也就是說,一個 Course 會有多個 StudentGrade 紀錄。因為通常在學校內,一個課程內,將會有多個學生的考試成績紀錄。

public class Course
{
    public Course()
    {
        StudentGrades = new HashSet<StudentGrade>();
    }
    public int Id { get; set; }
    public string Name { get; set; }
    public int DepartmentId { get; set; }
    public virtual Department Department { get; set; }
    public virtual ICollection<StudentGrade> StudentGrades { get; set; }
}
  • 在 [Models] 目錄下,建立 [Student] 類別,其程式碼如下

    這裡宣告這個 Student Entity 內,有兩個欄位,分別是 Id 與 Name,並且也宣告一個導航屬性 Department,這裡表示了 Address 這個 Entity 將會對應到一個 StudentAddress Entity上;另外,他與 StudentGrades 這個 Entity 具有一對多的關聯,也就是說,一個 Student 會有多個 StudentGrade 紀錄。因為通常在學校內,一個學生內,將會有多個課程的考試成績紀錄。

    從這裡將會推論,學生 Student 與 課程 Course 這兩個類別,將會呈現了多對多的關係,而StudentGrade這個 Entity,則是扮演著這兩個 Entity 之間的一對多的關係。

public class Student
{
    public Student()
    {
        StudentGrades = new HashSet<StudentGrade>();
    }
    public int Id { get; set; }
    public string Name { get; set; }
 
    public virtual StudentAddress Address { get; set; }
    public virtual ICollection<StudentGrade> StudentGrades { get; set; }
}
  • 在 [Models] 目錄下,建立 [StudentAddress] 類別,其程式碼如下

    這裡宣告這個 StudentAddress Entity 內,有五個欄位,分別是 Id 、 Address 、 City 、 State 、 Country,並且也宣告一個 Foreign Key 外鍵 StudentId 與一個導航屬性 Student ,這裡表示了 StudentAddress 這個 Entity 將會與 Student Entity 呈現了一對一的關係。

public class StudentAddress
{
    public int Id { get; set; }
    public string Address { get; set; }
    public string City { get; set; }
    public string State { get; set; }
    public string Country { get; set; }
 
    public int StudentId { get; set; }
    public virtual Student Student { get; set; }
}

建立資料庫架構的 DbContent 類別

  • 在 [Models] 目錄下,建立 [DataContext] 類別,其程式碼如下

    這裡建立一個 DataContext 類別,該類別繼承了 DbContext 這個類別;在這個 DataContext 內,使用 DbSet 類別,宣告了三個屬性,說明了這個資料庫內共有三個資料表,有兩個欄位,分別是 Id 與 Name;另外,他與 Course 這個 Entity 具有一對多的關聯,也就是說,一個 Department 會有多個 Course 紀錄

public class DataContext : DbContext
{
    public virtual DbSet<Student> Student { get; set; }
    public virtual DbSet<StudentGrade> StudentGrade { get; set; }
    public virtual DbSet<StudentAddress> StudentAddress { get; set; }
    public virtual DbSet<Course> Course { get; set; }
    public virtual DbSet<Department> Department { get; set; }

    public DataContext()
    {
    }

    public DataContext(DbContextOptions<DataContext> options)
        : base(options)
    {
    }

    protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
    {
        if (!optionsBuilder.IsConfigured)
        {
            optionsBuilder.UseSqlServer("Data Source=(localdb)\\MSSQLLocalDB;Initial Catalog=SchoolCodeFirst");
        }
    }

    protected override void OnModelCreating(ModelBuilder modelBuilder)
    {
    }

}

現在 Entity Model 相關資料已經建立完成

建立資料庫

這裡將會有兩種方式,一種是透過命令列下達指令,另外一種是在程式碼中呼叫 API,首先,先確認該電腦上的 [(localdb)\MSSQLLocalDB] 內,沒有 SchoolCodeFirst 這個資料庫

(localdb)\MSSQLLocalDB

使用 PowerShell 來建立資料庫

  • 切換到 [套件管理器主控台] 視窗

    若沒有看到 [套件管理器主控台] 視窗,點選功能表 [工具] > [NuGet 套件管理員] > [套件管理器主控台]

  • 在 [套件管理器主控台] 輸入底下內容

Add-Migration InitialCreate
Update-Database
  • 若看到底下的訊息顯示出來之後,就表示該資料庫已經建立在 [(localdb)\MSSQLLocalDB]

(localdb)\MSSQLLocalDB

每個封裝均由其擁有者提供授權給您。NuGet 對於協力廠商封裝不負任何責任,也不提供相關的任何授權。某些封裝可能包含須由其他授權控管的相依項目。請遵循封裝來源 (摘要) URL 決定有無任何相依項目。

套件管理員主控台主機版本 5.7.0.6726

輸入 'get-help NuGet' 可查看所有可用的 NuGet 命令。

PM> Add-Migration InitialCreate
Build started...
Build succeeded.
To undo this action, use Remove-Migration.
PM> Update-Database
Build started...
Build succeeded.
Applying migration '20200926142800_InitialCreate'.
Done.
PM> 

使用 SQL Server Management Studio (SSMS) 產生 ERD

  • 安裝好 SQL Server Management Studio (SSMS) 之後,請打開這個應用程式

  • 首先會看到 [連線至伺服器] 對話窗

  • 請在 [伺服器名稱] 內,輸入 (localdb)\.

  • 最後,點選 [連線] 按鈕

  • 成功連線之後,將會顯示 [物件總管] 視窗

  • 請展開 [物件總管] 視窗內的 [(localdb.)] > [資料庫] > [School] 節點

  • 滑鼠右擊 [資料庫圖表] 節點,從彈出功能表選取 [新增資料庫圖表] 選項

  • 第一次將會出現 [此資料庫沒有使用資料庫圖表所需的一或多個支援物件。您要建立它們嗎?] 訊息

  • 點選 [是] 按鈕

  • 此時將會出現 [加入資料表] 對話窗

  • 請將全部資料表都選取起來

    想要全部選取,可以先點選第一個資料表 (Course),接著按下 [Shift] 按鍵,點選最後一個資料表(StudentGrade)

  • 最後,點選 [加入] 按鈕

  • 若這些資料表沒有正常排列顯示,請在空白處,使用滑鼠右擊,選擇 [排列資料表],這樣就會看到這個資料庫所以資料表之間的關聯 ERD,哪些是 一對一關係、一對多關係、多對一關係、多對多關係

  • 透過這裡產生的 ERD,來確認這裡使用 Code First 方式,所建立起來的資料庫架構,是否違當初所設計的內容。

使用 API 來建立資料庫

  • 打開專案內的 [Program.cs] 這個檔案
  • 輸入底下程式碼
class Program
{
    static void Main(string[] args)
    {
        var context = new DataContext();
        context.Database.EnsureDeleted();
        context.Database.EnsureCreated();
    }
}

首先將會看到建立起一個 DataContext 類別的 context 物件,透過這個物件便可以操作資料庫行為;接下來呼叫了 context.Database.EnsureDeleted(); API,若此時資料庫系統中有這裡定義的資料庫,會將該資料庫先刪除,接著呼叫 context.Database.EnsureCreated(); API,這裡將會開始建立這個資料庫。

 




2020年9月28日 星期一

Console 專案與 EF Core 讀取已經存在的資料庫

 

Console 專案與 EF Core 讀取已經存在的資料庫

在前一個文章 Entity Framework Core - 反向工程 建立 Entity Model建立 Entity Model ,說明了如何使用反向工程與 Scaffold-DbContext 指令來產生出 Entity Framework Core 需要的 Entity & DbContext 相關類別。

因為有了這些 Entity 定義類別,便可以進行資料庫的操作,在這裡,將會來練習如何開始使用 Entity Framework Core 來讀取資料庫,這裡將會顯示 Person 資料表內的紀錄清單,並且請按照 LastName , FirstName 來排序。

請按照底下的步驟來進行操作

建立練習專案

  • 打開 Visual Studio 2019
  • 點選 [建立新的專案] 按鈕
  • 在 [建立新專案] 對話窗內,選擇 [主控台應用程式 (.NET Core)] 專案樣板
  • 在 [設定新的專案] 對話窗內,於 [專案名稱] 欄位內輸入 DBEntityFrameworkCore
  • 點選 [建立] 按鈕,以便開始建立這個專案

加入 Entity Framework Core 要使用到的 NuGet 套件

  • 滑鼠右擊專案內的 [相依性] 節點
  • 選擇 [管理 NuGet 套件]
  • 點選 [瀏覽] 標籤分頁頁次
  • 在 [搜尋] 文字輸入盒內,輸入 [Microsoft.EntityFrameworkCore.SqlServer]
  • 點選 [安裝] 按鈕以便安裝這個套件
  • 在 [搜尋] 文字輸入盒內,輸入 [Microsoft.EntityFrameworkCore.Tools]
  • 點選 [安裝] 按鈕以便安裝這個套件

使用反向工程來產生 Entity Framework 要用到的 Entity 模型相關類別

  • 切換到 [套件管理器主控台] 視窗

    若沒有看到 [套件管理器主控台] 視窗,點選功能表 [工具] > [NuGet 套件管理員] > [套件管理器主控台]

  • 在 [套件管理器主控台] 輸入底下內容

    因為都在同一個專案內,所以,這裡可以省略 StartupProject & Project 這兩個參數,因此,底下的指令會更為精簡

Scaffold-DbContext "Data Source=(localdb)\MSSQLLocalDB;Initial Catalog=School" Microsoft.EntityFrameworkCore.SqlServer -OutputDir Models -f

現在 Entity Model 相關資料已經建立完成

由於在 [Models] 資料夾內,建立了一個 [SchoolContext] 類別,這個類別將會指向 SQL Server 上的 [School] 資料庫,也就是說,想要對這個資料庫進行任何操作:新增、讀取、修改、刪除,都可以透過這個 [SchoolContext] 類別來做到;而想要知道有那些 Entity 物件對應到資料庫的那些資料表內,請查看 [SchoolContext] 類別的 DbSet 屬性,在這裡將會有這些 Entity 可以存取 Course , CourseInstructor , Department , OfficeAssignment , OnsiteCourse , Outline , Person , StudentGrade ,同樣的,這些名稱也會出現在該資料庫內的資料表。

using System;
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Metadata;

namespace EFCoreReverseEngineering.Models
{
    public partial class SchoolContext : DbContext
    {
        ...
        public virtual DbSet<Course> Course { get; set; }
        public virtual DbSet<CourseInstructor> CourseInstructor { get; set; }
        public virtual DbSet<Department> Department { get; set; }
        public virtual DbSet<OfficeAssignment> OfficeAssignment { get; set; }
        public virtual DbSet<OnsiteCourse> OnsiteCourse { get; set; }
        public virtual DbSet<Outline> Outline { get; set; }
        public virtual DbSet<Person> Person { get; set; }
        public virtual DbSet<StudentGrade> StudentGrade { get; set; }
        ...
    }
}

請打開這個 [Program.cs] 檔案,完成底下的程式碼

using DBEntityFrameworkCore.Model;
using Microsoft.EntityFrameworkCore;
using System;
using System.Linq;
using System.Threading.Tasks;

namespace DBEntityFrameworkCore
{
    class Program
    {
        static async Task Main(string[] args)
        {
            SchoolContext context = new SchoolContext();
            var people = await context.Person
                .OrderBy(x=>x.LastName)
                .ThenBy(x=>x.FirstName)
                .ToListAsync();
            foreach (var item in people)
            {
                Console.WriteLine($"人員:{item.LastName} {item.FirstName}");
            }
        }
    }
}

從上面的程式碼中,可以看到首先建立了一個 SchoolContext 型別的 context 物件,這個物件就代表了遠端的資料庫,當想要讀取 Person 資料表內的紀錄,只需要使用 context.Person 這樣的方式,就可以取得 Person 資料表內的紀錄,這樣的用法對於 C# 開發者並不陌生,因為,就把 Person 這個屬性,當作是一個集合 Collection 類型的物件,因為是集合類型,所以在 Person 這個屬性(DbSet)內,就會擁有了多筆的 Person 型別的物件。

另外,對於要使用 Entity Framework Core 來對資料庫紀錄操作的時候,通常會搭配著 LINQ 功能來進行查詢,對於開發者而言,是不需學習 SQL 語言,就可以存取資料庫了。

因此,因為這裡使用了這樣的敘述,將會把 Person 資料表內的所有紀錄,按照 LastName 先做排序,接著按照 FirstName 來排序,最後顯示在螢幕上。

var people = await context.Person
    .OrderBy(x=>x.LastName)
    .ThenBy(x=>x.FirstName)
    .ToListAsync();

這裡將會是輸出結果

人員:Abercrombie Kim
人員:Alexander Carson
人員:Alonso Meredith
人員:Anand Arturo
人員:Barzdukas Gytis
人員:Browning Meredith
人員:Bryant Carson
人員:Carlson Robyn
人員:Fakhouri Fadi
人員:Gao Erica
人員:Griffin Rachel
人員:Harui Roger
人員:Holt Roger
人員:Jai Damien
人員:Justice Peggy
人員:Kapoor Candace
人員:Li Yan
人員:Lopez Sophia
人員:Martin Randall
人員:Morgan Isaiah
人員:Norman Laura
人員:Olivotto Nino
人員:Powell Carson
人員:Rogers Cody
人員:Serrano Stacy
人員:Shan Alicia
人員:Stewart Jasmine
人員:Suarez Robyn
人員:Tang Wayne
人員:Van Houten Roger
人員:Walker Alexandra
人員:White Anthony
人員:Xu Kristen
人員:Zheng Roger





2020年9月27日 星期日

Entity Framework Core - 反向工程 建立 Entity Model建立 Entity Model

Entity Framework Core - 反向工程 建立 Entity Model建立 Entity Model

在 Entity Framework Core - 建立練習使用的 Contoso University 資料庫 內,已經說明了如何建立起 Contoso 大學的資料庫架構與相關測試資料,現在,將會需要建立起 .NET C# 使用的 Entity Model,這裡提到的 Entity ,就是 Entity Framework 內的 Entity 這個名詞。想要在 C# 內建立一個類別,可以透過這個類別來存取 資料庫 內的紀錄,需要讓這個類別繼承 DbContext 類別,並且宣告 DbSet 屬性 ,實體類型,這裡的泛型型別 T ,將會對應到資料庫內的 Table 表格。

現在開始來練習這個開發過程,這樣的技術稱之為 Entity Framework Core - 反向工程,在此將會使用 Console 專案來做為示範。

建立練習專案

  • 打開 Visual Studio 2019
  • 點選 [建立新的專案] 按鈕
  • 在 [建立新專案] 對話窗內,選擇 [主控台應用程式 (.NET Core)] 專案樣板
  • 在 [設定新的專案] 對話窗內,於 [專案名稱] 欄位內輸入 EFCoreReverseEngineering
  • 點選 [建立] 按鈕,以便開始建立這個專案

加入 Entity Framework Core 要使用到的 NuGet 套件

  • 滑鼠右擊專案內的 [相依性] 節點
  • 選擇 [管理 NuGet 套件]
  • 點選 [瀏覽] 標籤分頁頁次
  • 在 [搜尋] 文字輸入盒內,輸入 [Microsoft.EntityFrameworkCore.SqlServer]
  • 點選 [安裝] 按鈕以便安裝這個套件
  • 在 [搜尋] 文字輸入盒內,輸入 [Microsoft.EntityFrameworkCore.Tools]
  • 點選 [安裝] 按鈕以便安裝這個套件

使用反向工程來產生 Entity Framework 要用到的 Entity 模型相關類別

  • 切換到 [套件管理器主控台] 視窗

    若沒有看到 [套件管理器主控台] 視窗,點選功能表 [工具] > [NuGet 套件管理員] > [套件管理器主控台]

  • 在 [套件管理器主控台] 輸入底下內容

Scaffold-DbContext "Data Source=(localdb)\MSSQLLocalDB;Initial Catalog=School" Microsoft.EntityFrameworkCore.SqlServer -StartupProject EFCoreReverseEngineering -Project EFCoreReverseEngineering -OutputDir Models -f

現在 Entity Model 相關資料已經建立完成,底下是輸入 [Scaffold-DbContext] 指令的相關執行內容

每個封裝均由其擁有者提供授權給您。NuGet 對於協力廠商封裝不負任何責任,也不提供相關的任何授權。某些封裝可能包含須由其他授權控管的相依項目。請遵循封裝來源 (摘要) URL 決定有無任何相依項目。

套件管理員主控台主機版本 5.7.0.6726

輸入 'get-help NuGet' 可查看所有可用的 NuGet 命令。

PM> Scaffold-DbContext "Data Source=(localdb)\MSSQLLocalDB;Initial Catalog=School" Microsoft.EntityFrameworkCore.SqlServer -StartupProject EFCoreReverseEngineering -Project EFCoreReverseEngineering -OutputDir Models -f
Build started...
Build succeeded.
PM>

請查看 Visual Studio 內的方案總管視窗內,將會看到自動建立了一個方案資料夾,稱之為 [Models],在這個資料夾內存在著許多檔案。

Entity Framework DbContext

現在來打開 [Department.cs] 這個檔案,從名稱可以看的出來,這裡指的就是 SQL Server 資料庫上的 Department 資料表 Table。

using System;
using System.Collections.Generic;

namespace EFCoreReverseEngineering.Models
{
    public partial class Department
    {
        public Department()
        {
            Course = new HashSet<Course>();
        }

        public int DepartmentId { get; set; }
        public string Name { get; set; }
        public decimal Budget { get; set; }
        public DateTime StartDate { get; set; }
        public int? Administrator { get; set; }

        public virtual ICollection<Course> Course { get; set; }
    }
}

另外,查看 SQL Server 上的 Department 資料表的結構定義,其宣告如下:

CREATE TABLE [dbo].[Department] (
    [DepartmentID]  INT           NOT NULL,
    [Name]          NVARCHAR (50) NOT NULL,
    [Budget]        MONEY         NOT NULL,
    [StartDate]     DATETIME      NOT NULL,
    [Administrator] INT           NULL,
    CONSTRAINT [PK_Department] PRIMARY KEY CLUSTERED ([DepartmentID] ASC)
);

透過 Department 資料表的綱要宣告,可以來理解透過反向工程所產生的 Entity Model 為什麼是這樣宣告的。

因此,在資料庫上的每個資料表,都會在 [Models] 資料夾內,產生一個類別檔案,另外,也會針對這個資料庫,產生一個 [SchoolContext.cs] 檔案,其內容如下。

這裡建立了一個 [SchoolContext] 類別,這個類別將會指向 SQL Server 上的 [School] 資料庫,也就是說,想要對這個資料庫進行任何操作:新增、讀取、修改、刪除,都可以透過這個 [SchoolContext] 類別來做到,因此,對於使用 Entity Framework Core 的開發者,只需要會使用 C# 程式碼,就可以進行資料庫的紀錄存取操作了。

using System;
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Metadata;

namespace EFCoreReverseEngineering.Models
{
    public partial class SchoolContext : DbContext
    {
        public SchoolContext()
        {
        }

        public SchoolContext(DbContextOptions<SchoolContext> options)
            : base(options)
        {
        }

        public virtual DbSet<Course> Course { get; set; }
        public virtual DbSet<CourseInstructor> CourseInstructor { get; set; }
        public virtual DbSet<Department> Department { get; set; }
        public virtual DbSet<OfficeAssignment> OfficeAssignment { get; set; }
        public virtual DbSet<OnsiteCourse> OnsiteCourse { get; set; }
        public virtual DbSet<Outline> Outline { get; set; }
        public virtual DbSet<Person> Person { get; set; }
        public virtual DbSet<StudentGrade> StudentGrade { get; set; }

        protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
        {
            if (!optionsBuilder.IsConfigured)
            {
#warning To protect potentially sensitive information in your connection string, you should move it out of source code. See http://go.microsoft.com/fwlink/?LinkId=723263 for guidance on storing connection strings.
                optionsBuilder.UseSqlServer("Data Source=(localdb)\\MSSQLLocalDB;Initial Catalog=School");
            }
        }

        protected override void OnModelCreating(ModelBuilder modelBuilder)
        {
            modelBuilder.Entity<Course>(entity =>
            {
                entity.Property(e => e.CourseId)
                    .HasColumnName("CourseID")
                    .ValueGeneratedNever();

                entity.Property(e => e.DepartmentId).HasColumnName("DepartmentID");

                entity.Property(e => e.Title)
                    .IsRequired()
                    .HasMaxLength(100);

                entity.HasOne(d => d.Department)
                    .WithMany(p => p.Course)
                    .HasForeignKey(d => d.DepartmentId)
                    .OnDelete(DeleteBehavior.ClientSetNull)
                    .HasConstraintName("FK_Course_Department");
            });

            modelBuilder.Entity<CourseInstructor>(entity =>
            {
                entity.HasKey(e => new { e.CourseId, e.PersonId });

                entity.Property(e => e.CourseId).HasColumnName("CourseID");

                entity.Property(e => e.PersonId).HasColumnName("PersonID");

                entity.HasOne(d => d.Course)
                    .WithMany(p => p.CourseInstructor)
                    .HasForeignKey(d => d.CourseId)
                    .OnDelete(DeleteBehavior.ClientSetNull)
                    .HasConstraintName("FK_CourseInstructor_Course");

                entity.HasOne(d => d.Person)
                    .WithMany(p => p.CourseInstructor)
                    .HasForeignKey(d => d.PersonId)
                    .OnDelete(DeleteBehavior.ClientSetNull)
                    .HasConstraintName("FK_CourseInstructor_Person");
            });

            modelBuilder.Entity<Department>(entity =>
            {
                entity.Property(e => e.DepartmentId)
                    .HasColumnName("DepartmentID")
                    .ValueGeneratedNever();

                entity.Property(e => e.Budget).HasColumnType("money");

                entity.Property(e => e.Name)
                    .IsRequired()
                    .HasMaxLength(50);

                entity.Property(e => e.StartDate).HasColumnType("datetime");
            });

            modelBuilder.Entity<OfficeAssignment>(entity =>
            {
                entity.HasKey(e => e.InstructorId);

                entity.Property(e => e.InstructorId)
                    .HasColumnName("InstructorID")
                    .ValueGeneratedNever();

                entity.Property(e => e.Location)
                    .IsRequired()
                    .HasMaxLength(50);

                entity.Property(e => e.Timestamp)
                    .IsRequired()
                    .IsRowVersion()
                    .IsConcurrencyToken();

                entity.HasOne(d => d.Instructor)
                    .WithOne(p => p.OfficeAssignment)
                    .HasForeignKey<OfficeAssignment>(d => d.InstructorId)
                    .OnDelete(DeleteBehavior.ClientSetNull)
                    .HasConstraintName("FK_OfficeAssignment_Person");
            });

            modelBuilder.Entity<OnsiteCourse>(entity =>
            {
                entity.HasKey(e => e.CourseId);

                entity.Property(e => e.CourseId)
                    .HasColumnName("CourseID")
                    .ValueGeneratedNever();

                entity.Property(e => e.Days)
                    .IsRequired()
                    .HasMaxLength(50);

                entity.Property(e => e.Location)
                    .IsRequired()
                    .HasMaxLength(50);

                entity.Property(e => e.Time).HasColumnType("smalldatetime");

                entity.HasOne(d => d.Course)
                    .WithOne(p => p.OnsiteCourse)
                    .HasForeignKey<OnsiteCourse>(d => d.CourseId)
                    .OnDelete(DeleteBehavior.ClientSetNull)
                    .HasConstraintName("FK_OnsiteCourse_Course");
            });

            modelBuilder.Entity<Outline>(entity =>
            {
                entity.Property(e => e.OutlineId).HasColumnName("OutlineID");

                entity.Property(e => e.CourseId).HasColumnName("CourseID");

                entity.Property(e => e.Title)
                    .IsRequired()
                    .HasMaxLength(100);

                entity.HasOne(d => d.Course)
                    .WithMany(p => p.Outline)
                    .HasForeignKey(d => d.CourseId)
                    .OnDelete(DeleteBehavior.ClientSetNull)
                    .HasConstraintName("FK_Outline_Course");
            });

            modelBuilder.Entity<Person>(entity =>
            {
                entity.Property(e => e.PersonId).HasColumnName("PersonID");

                entity.Property(e => e.EnrollmentDate).HasColumnType("datetime");

                entity.Property(e => e.FirstName)
                    .IsRequired()
                    .HasMaxLength(50);

                entity.Property(e => e.HireDate).HasColumnType("datetime");

                entity.Property(e => e.LastName)
                    .IsRequired()
                    .HasMaxLength(50);
            });

            modelBuilder.Entity<StudentGrade>(entity =>
            {
                entity.HasKey(e => e.EnrollmentId);

                entity.Property(e => e.EnrollmentId).HasColumnName("EnrollmentID");

                entity.Property(e => e.CourseId).HasColumnName("CourseID");

                entity.Property(e => e.Grade).HasColumnType("decimal(3, 2)");

                entity.Property(e => e.StudentId).HasColumnName("StudentID");

                entity.HasOne(d => d.Course)
                    .WithMany(p => p.StudentGrade)
                    .HasForeignKey(d => d.CourseId)
                    .OnDelete(DeleteBehavior.ClientSetNull)
                    .HasConstraintName("FK_StudentGrade_Course");

                entity.HasOne(d => d.Student)
                    .WithMany(p => p.StudentGrade)
                    .HasForeignKey(d => d.StudentId)
                    .OnDelete(DeleteBehavior.ClientSetNull)
                    .HasConstraintName("FK_StudentGrade_Student");
            });

            OnModelCreatingPartial(modelBuilder);
        }

        partial void OnModelCreatingPartial(ModelBuilder modelBuilder);
    }
}