EF Core預設約定規則基于領域類和DbContext類建立資料庫Schema,例如-表名稱,列名稱,表關系,主鍵&外鍵 這些都是基于契約建立的
1 EF Core約定例子
讓我們通過一個例子來了解一下約定,我們有一個項目包含了下面2個領域類,Employee和Department
public class Employee { public int Id { get; set; } public int DepartmentId { get; set; } public string Name { get; set; } public string Designation { get; set; } public Department Department { get; set; } } public class Department { public int Id { get; set; } public string Name { get; set; } public ICollection<Employee> Employee { get; set; } }
這個項目的DbContext如下:
public class CompanyContext : DbContext { public CompanyContext(DbContextOptions<CompanyContext> options) : base(options) { } public DbSet<Employee> Employee { get; set; } }
運作EF Core migrations 資料庫将建立2張表-Employee 和Department,約定負責建立資料庫Schema,即表、列、關系等,讓我們逐一檢視它們
1.1 Table
EF Core 約定建立資料庫表,表名稱和DbContext中定義的DbSet<T>屬性名稱是相同的
我們僅僅有一個DbSet類型的屬性Employee,是以EF Core将在資料庫中建立一張和屬性Emlpoyee名稱相同的表,我們可以通過改變該表的名字通過改變屬性名稱
public DbSet<Employee> Employee { get; set; }
這是非常簡單的,但是第二張表也會被建立,但是我們沒有定義DbSet,這是因為EF Core會查找Employee 類發現内部引用了Department類,是以會建立Department表
在Employee類内部引用了Department類,通過該屬性,EntityFrameworkCore找到Department模型實體,并在資料庫中為其建立一個表
public Department Department { get; set; }
1.2 Column
EF Core會根據領域類定義的屬性類建立資料庫表中對應的列
列名稱和屬性名稱保持一緻,Employee類中有4個屬性(Id,DepartmentId,Name,Designation),是以使用了屬性的名稱建立表的列
類似的Department表中也建立了2列(Id,Name)
引用和集合屬性能夠在兩張表中建立關聯,我們稍後将看這塊内容
1.3 C# 資料類型VS SQL Server列類型
接下來我們考慮EF Core 中的資料類型是如何對應到資料庫表中的資料類型,如下展示了C#資料類型和SQL Server資料庫資料類型的映射關系:
C# 資料類型 | SQL Server 資料類型 |
---|---|
int | int |
string | nvarchar(Max) |
decimal | decimal(18,2) |
float | real |
bool | bit |
long | bigint() |
datetime | datetime |
short | smallint |
在我們這個例子中,基于這兩張表的映射規則如下:
// Department table Id INT IDENTITY (1, 1) NOT Name VARCHAR (50) NOT // Employee table Id INT IDENTITY (1, 1) NOT DepartmentId INT NOT Name VARCHAR (100) NOT Designation VARCHAR (25) NOT
1.4 able Column(可空列)
可空列是針對所有的引用資料類型,例如:string,able,float?
1.5 Not Column(非空列)
EF Core會為表的主鍵建立不可為空的列,像float,int,Datetime
1.6 Primary Key(主鍵)
EF Core 會根據是否有Id屬性(或者是否包含了id文本的屬性)來建立主鍵(大小寫不敏感)如果Employee類包含了如下任何一個屬性的名稱(id,ID,iD,Id,employeeid,EmployeeId,EMPLOYEEID,EmPLoyEEid等),EF Core 會為Employee表建立主鍵1.7 Foreign Key(外鍵)
領域類引用的每個導航屬性都會建立外鍵,在我們的案例中,Employee&Department領域類,Employee表将建立一個名字為DepartmentId的外鍵這兩個實體是一對多的關系,department能包含多個employee,反之亦然
2 表之間關系
SQL Server 資料庫表關系有3種類型:
一對多關系
一對一關系
多對多關系
讓我們看一下EF Core契約是如何處理這三種情況的
2.1 一對多關系
我們将學習在EF Core 兩個領域類如何送出一對多的關系,假如我們有兩張表Country & City,我們知道在一個國家中有多個城市,意味着我們可以在這兩張表中建立一個一對多的關系
我們添加2個類,分别是Country & City
public class Country { public int Id { get; set; } public string Name { get; set; } } public class City { public int Id { get; set; } public string Name { get; set; } }
在兩張表中建立一個多對一的關系,我們有如下4種方式:
契約 1:建立一個引用導航入屬性
在City類建立引用導航屬性指向Country類:
public class City { public int Id { get; set; } public string Name { get; set; } public Country Country { get; set; } //Reference Navigation Property } public class Country { public int Id { get; set; } public string Name { get; set; } }
執行EF Core Migrations 将會在資料庫City和Country表之間産生一個一對多的關系,City表包含了可為空的CountryId外鍵
契約 2:建立一個集合導航屬性
通過添加一個集合導航屬性也可以建立一個一對多的關系
public class City { public int Id { get; set; } public string Name { get; set; } } public class Country { public int Id { get; set; } public string Name { get; set; } public ICollection<City> Cities { get; set; } // Collection Navigation Property }
這種方式和契約1做相同的工作
契約 3: 建立兩個導航屬性
也可以在實體中建立兩個導航屬性,實作一對多的關系
public class City { public int Id { get; set; } public string Name { get; set; } public Country Country { get; set; } //Reference Navigation Property } public class Country { public int Id { get; set; } public string Name { get; set; } public ICollection<City> Cities { get; set; } // Collection Navigation Property }
上面代碼我們在City實體類中添加了引用的導航屬性,在Country類中添加了集合導航屬性契約 4:使用契約 3 + 外鍵屬性
在這種情況下我們使用契約3的方式并且同時添加外鍵CountryId 屬性在City實體中
public class City { public int Id { get; set; } public string Name { get; set; } public int CountryId { get; set; } //Foreign Key entity public Country Country { get; set; } //Reference Navigation Property } public class Country { public int Id { get; set; } public string Name { get; set; } public ICollection<City> Cities { get; set; } // Collection Navigation Property }
2.2 一對一關系
在EF Core實體類中建立一對一的關系是非常簡單的,我們隻需要在兩個實體類中添加引用的導航屬性
下面代碼中我們已經建立一對一關系在Country&City實體類中
public class City { public int Id { get; set; } public string Name { get; set; } public Country Country { get; set; } //Reference Navigation Property } public class Country { public int Id { get; set; } public string Name { get; set; } public City City { get; set; } //Reference Navigation Property }
2.3 多對多關系
在兩個實體類中建立多對多關系,分别在兩個實體類中建立兩個集合導航屬性
public class City { public int Id { get; set; } public string Name { get; set; } public ICollection<Country> Country { get; set; } //Collection Navigation Property } public class Country { public int Id { get; set; } public string Name { get; set; } public ICollection<City> City { get; set; } //Collection Navigation Property }
這個通過在資料庫中添加一張名為CityCountry的表來實作,這張表将包含City和Country表的外鍵,我們在會講到如何在EF Core中使用Fluent API中會講到
總結
在這節中學習EF Core預設的契約方式源代碼位址:https://github.com/bingbing-gui/Asp.Net-Core-Skill/tree/master/EntityFrameworkCore/EFCoreConventions
參考資料
https://learn.microsoft.com/en-us/ef/core/modeling/relationships/conventions
https://www.yogihosting.com/delete-records-entity-framework-core/