天天看點

Entity Framework Core 2.0 入門1.建立資料庫和Model使用Model與資料庫互動 查詢和儲存關聯資料.

該文章比較基礎, 不多說廢話了, 直接切入正題.

該文分以下幾點:

  • 建立Model和資料庫
  • 使用Model與資料庫互動
  • 查詢和儲存關聯資料

EF Core支援情況

Entity Framework Core 2.0 入門1.建立資料庫和Model使用Model與資料庫互動 查詢和儲存關聯資料.

EF Core的資料庫Providers:

Entity Framework Core 2.0 入門1.建立資料庫和Model使用Model與資料庫互動 查詢和儲存關聯資料.

此外還即将支援CosmosDB和 Oracle.

EFCore 2.0新的東西:

查詢:

  • EF.Functions.Like()
  • Linq解釋器的改進
  • 全局過濾(按類型)
  • 編譯查詢(Explicitly compiled query)
  • GroupJoin的SQL優化.

 映射:

  • Type Configuration 配置
  • Owned Entities (替代EF6的複雜類型)
  • Scalar UDF映射
  • 分表

性能和其他

  • DbContext Pooling, 這個很好
  • Raw SQL插入字元串.
  • Logging
  • 更容易定制配置

1.建立資料庫和Model

準備.net core項目

項目結構如圖:

Entity Framework Core 2.0 入門1.建立資料庫和Model使用Model與資料庫互動 查詢和儲存關聯資料.

由于我使用的是VSCode, 是以需要使用指令行:

mkdir LearnEf && cd LearnEf
dotnet new sln // 建立解決方案

mkdir LearnEf.Domains && cd LearnEf.Domains
dotnet new classlib // 建立LearnEf.Domains項目

cd ..
mkdir LearnEf.Data && cd LearnEf.Data
dotnet new classlib // 建立LearnEf.Data項目

cd ..
mkdir LearnEf.UI && cd LearnEf.UI
dotnet new console // 建立控制台項目

cd ..
mkdir LearnEf.Tests && cd LearnEf.Tests
dotnet new xunit // 建立測試項目      

為解決方案添加項目:

dotnet sln add LearnEf.UI/LearnEf.UI.csproj
dotnet sln add LearnEf.Domains/LearnEf.Domains.csproj
dotnet sln add LearnEf.Data/LearnEf.Data.csproj
dotnet sln add LearnEf.Tests/LearnEf.Tests.csproj      

為項目之間添加引用:

LearnEf.Data依賴LearnEf.Domains:

cd LearnEf.Data
dotnet add reference ../LearnEf.Domains/LearnEf.Domains.csproj      

LearnEf.Console依賴LearnEf.Domains和LearnEf.Data:

cd ../LearnEf.UI
dotnet add reference ../LearnEf.Domains/LearnEf.Domains.csproj ../LearnEf.Data/LearnEf.Data.csproj      

LearnEf.Test依賴其它三個項目:

cd ../LearnEf.Tests
dotnet add reference ../LearnEf.Domains/LearnEf.Domains.csproj ../LearnEf.Data/LearnEf.Data.csproj ../LearnEf.UI/LearnEf.UI.csproj      

(可能需要執行dotnet restore)

在Domains項目下直接建立兩個Model, 典型的一對多關系Company和Department:

using System;
using System.Collections.Generic;

namespace LearnEf.Domains
{
    public class Company
    {
        public Company()
        {
            Departments = new List<Department>();
        }

        public int Id { get; set; }
        public string Name { get; set; }
        public DateTime StartDate { get; set; }
        public List<Department> Departments { get; set; }
    }
}      
namespace LearnEf.Domains
{
    public class Department
    {
        public int Id { get; set; }
        public int CompanyId { get; set; }
        public Company Company { get; set; }
    }
}      

添加Entity Framework Core庫:

首先Data項目肯定需要安裝這個庫, 而我要使用sql server, 參照

官方文檔

, 直接在解決方案下執行這個指令:

dotnet add ./LearnEf.Data package Microsoft.EntityFrameworkCore.SqlServer
dotnet restore      

建立DbContext:

在Data項目下建立MyContext.cs:

using LearnEf.Domains;
using Microsoft.EntityFrameworkCore;

namespace LearnEf.Data
{
    public class MyContext : DbContext
    {
        public DbSet<Company> Companies { get; set; }
        public DbSet<Department> Departments { get; set; }
    }
}      

指定資料庫Provider和Connection String:

在EFCore裡, 必須明确指定Data Provider和Connection String.

可以在Context裡面override這個Onconfiguring方法:

Entity Framework Core 2.0 入門1.建立資料庫和Model使用Model與資料庫互動 查詢和儲存關聯資料.

有一個錯誤, 應該是Server=localhost;

(這裡無需調用父類的方法, 因為父類的方法什麼也沒做).

UseSqlServer表示使用Sql Server作為Data Provider. 其參數就是Connection String.

在運作時EfCore第一次執行個體化MyContext的時候, 就會觸發這個OnConfiguring方法. 此外, Efcore的遷移Api也可以獲得該方法内的資訊.

EF Core遷移:

簡單的來說就是 Model變化 --> 建立migration檔案 --> 應用Migration到資料庫或生成執行腳本.

添加Migration (遷移):

由于我使用的是VSCode+dotnet cli的方法, 是以需要額外的步驟來使dotnet ef指令可用.

可以先試一下現在的效果:

Entity Framework Core 2.0 入門1.建立資料庫和Model使用Model與資料庫互動 查詢和儲存關聯資料.

可以看到, dotnet ef 指令還不可用.

是以參考官方文檔: 

https://docs.microsoft.com/en-us/ef/core/miscellaneous/cli/dotnet

可執行項目(Startup project)需要EFCore遷移引擎庫, 是以對LearnEf.UI添加這個庫:

dotnet add ./LearnEf.UI package Microsoft.EntityFrameworkCore.Design
dotnet restore      

然後打開LearnEf.UI.csproj 添加這段代碼, 這個庫是EF的指令庫:

<ItemGroup>
    <DotNetCliToolReference Include="Microsoft.EntityFrameworkCore.Tools.DotNet" Version="2.0.0" />
  </ItemGroup>      

最後内容如下:

Entity Framework Core 2.0 入門1.建立資料庫和Model使用Model與資料庫互動 查詢和儲存關聯資料.

然後再執行dotnet ef指令, 就應該可用了:

Entity Framework Core 2.0 入門1.建立資料庫和Model使用Model與資料庫互動 查詢和儲存關聯資料.

現在, 添加第一個遷移:

cd LearnEf.UI
dotnet ef migrations add Initial --project=../LearnEf.Data      

--project參數是表示需要使用的項目是哪個.

指令執行後, 可以看到Data項目生成了Migrations目錄和一套遷移檔案和一個快照檔案:

Entity Framework Core 2.0 入門1.建立資料庫和Model使用Model與資料庫互動 查詢和儲存關聯資料.

檢查這個Migration.

Entity Framework Core 2.0 入門1.建立資料庫和Model使用Model與資料庫互動 查詢和儲存關聯資料.

前邊帶時間戳的那兩個檔案是遷移檔案.

另一個是快照檔案, EFCore Migrations用它來跟蹤所有Models的目前狀态. 這個檔案非常重要, 因為下次你添加遷移的時候, EFcore将會讀取這個快照并将它和Model的最新版本做比較, 就這樣它就知道哪些地方需要有變化.

這個快照檔案解決了老版本Entity Framework的一個頑固的團隊問題.

使用遷移檔案建立腳本或直接生成資料庫.

生成建立資料庫的SQL腳本:

dotnet ef migrations script --project=../LearnEf.Data/LearnEf.Data.csproj      
Entity Framework Core 2.0 入門1.建立資料庫和Model使用Model與資料庫互動 查詢和儲存關聯資料.

Sql腳本直接列印在了Command Prompt裡面. 也可以通過指定--output參數來輸出到具體的檔案.

這裡, 正常的做法是, 針對開發時的資料庫, 可以通過指令直接建立和更新資料庫. 而針對生産環境, 最好是生成sql腳本, 然後由相關人員去執行這個腳本來完成資料庫的建立或者更新.

直接建立資料庫:

dotnet ef database update --project=../LearnEf.Data/LearnEf.Data.csproj --verbose      

--verbose表示顯示執行的詳細過程, 其結果差不多這樣:

Entity Framework Core 2.0 入門1.建立資料庫和Model使用Model與資料庫互動 查詢和儲存關聯資料.

這裡的執行過程和邏輯是這樣的: 如果資料庫不存在, 那麼efcore會在指定的連接配接字元串的地方建立該資料庫, 并應用目前的遷移. 如果是生成的sql腳本的話, 那麼這些動作必須由您自己來完成.

然後檢視一下生成的表. 

不過首先, 如果您也和我一樣, 沒有裝Sql server management studio或者 Visual Studio的話, 請您先安裝VSCode的mssql這個擴充:

Entity Framework Core 2.0 入門1.建立資料庫和Model使用Model與資料庫互動 查詢和儲存關聯資料.

重新開機後, 建立一個Sql檔案夾, 然後建立一個Tables.sql檔案, 打開指令面闆(windows: Shift+Ctrl+P, mac: Cmd+Shift+P), 選擇MS SQL: Connect.

Entity Framework Core 2.0 入門1.建立資料庫和Model使用Model與資料庫互動 查詢和儲存關聯資料.

然後選擇Create Connection Profile:

Entity Framework Core 2.0 入門1.建立資料庫和Model使用Model與資料庫互動 查詢和儲存關聯資料.

輸入Sql的伺服器位址:

Entity Framework Core 2.0 入門1.建立資料庫和Model使用Model與資料庫互動 查詢和儲存關聯資料.

再輸入資料庫名字:

Entity Framework Core 2.0 入門1.建立資料庫和Model使用Model與資料庫互動 查詢和儲存關聯資料.

選擇Sql Login(我使用的是Docker, 如果windows的話, 可能使用Integrated也可以):

Entity Framework Core 2.0 入門1.建立資料庫和Model使用Model與資料庫互動 查詢和儲存關聯資料.

輸入使用者名:

Entity Framework Core 2.0 入門1.建立資料庫和Model使用Model與資料庫互動 查詢和儲存關聯資料.

密碼:

Entity Framework Core 2.0 入門1.建立資料庫和Model使用Model與資料庫互動 查詢和儲存關聯資料.

選擇是否儲存密碼:

Entity Framework Core 2.0 入門1.建立資料庫和Model使用Model與資料庫互動 查詢和儲存關聯資料.

最後輸入檔案的名字:

Entity Framework Core 2.0 入門1.建立資料庫和Model使用Model與資料庫互動 查詢和儲存關聯資料.

随後VSCode将嘗試連接配接該資料庫, 成功後右下角會這樣顯示 (我這裡輸入有一個錯誤, 資料庫名字應該是LearnEF):

Entity Framework Core 2.0 入門1.建立資料庫和Model使用Model與資料庫互動 查詢和儲存關聯資料.

随後在該檔案中輸入下面這個sql語句來查詢所有的Table:

--  Table 清單
SELECT * FROM INFORMATION_SCHEMA.TABLES
WHERE TABLE_TYPE='BASE TABLE';      

執行sql的快捷鍵是windows: Shift+Ctrp+E, mac: Cmd+Shift+E, 或者滑鼠右鍵.

結果如圖:

Entity Framework Core 2.0 入門1.建立資料庫和Model使用Model與資料庫互動 查詢和儲存關聯資料.

OK表是建立成功了(還有一個遷移曆史表, 這個您應該知道).

接下來我看看表的定義:

-- Companies表:
exec sp_help 'Companies';      
Entity Framework Core 2.0 入門1.建立資料庫和Model使用Model與資料庫互動 查詢和儲存關聯資料.

其中Name字段是可空的并且長度是-1也就是nvarchar(Max).

Departments表的Name字段也是一樣的.

再看看那個MigrationHistory表:

-- MigrationHistory:
SELECT * FROM dbo.__EFMigrationsHistory;      
Entity Framework Core 2.0 入門1.建立資料庫和Model使用Model與資料庫互動 查詢和儲存關聯資料.

可以看到, efcore到migration 曆史表裡面隻儲存了MigrationId.

在老版本到ef裡, migration曆史表裡面還儲存着當時到遷移的快照, 建立遷移的時候還需要與資料庫打交道. 這就是我上面提到的如果團隊使用ef和源碼管理的話, 就會遇到這個非常令人頭疼的問題.

如果使用asp.net core的話.

在解決方案裡再建立一個asp.net core mvc項目:

mkdir LearnEf.Web && cd LearnEf.Web
dotnet new mvc      

在解決方案裡添加該項目:

dotnet sln add ./LearnEf.Web/LearnEf.Web.csproj      

為該項目添加必要的引用:

cd LearnEf.Web
dotnet add reference ../LearnEf.Domains/LearnEf.Domains.csproj ../LearnEf.Data/LearnEf.Data.csproj      

為測試項目添加該項目引用:

cd ../*Tests
dotnet add reference ../LearnEf.Web/LearnEf.Web.csproj      

操作完之後, 我們可以做以下調整, 去掉MyContext裡面的OnConfiguring方法, 因為asp.net core有内置的依賴注入機制, 我可以把已經建構好的DbContextOptions直接注入到構造函數裡:

這樣的話, 我們可以讓asp.net core來決定到底使用哪個Data Provider和Connection String:

Entity Framework Core 2.0 入門1.建立資料庫和Model使用Model與資料庫互動 查詢和儲存關聯資料.

這也就意味着, Web項目需要引用EfCore和Sql Provider等, 但是不需要, 因為asp.net core 2.0這個項目模版引用了AspNetCore.All這個megapack, 裡面都有這些東西了.

Entity Framework Core 2.0 入門1.建立資料庫和Model使用Model與資料庫互動 查詢和儲存關聯資料.

雖然這個包什麼都有, 也就是說很大, 但是如果您使用Visual Studio Tooling去部署的話, 那麼它隻會部署那些項目真正用到的包, 并不是所有的包.

接下來, 在Web項目的Startup添加EfCore相關的配置:

public void ConfigureServices(IServiceCollection services)
        {
            services.AddMvc();
            services.AddDbContext<MyContext>
                (options => options.UseSqlServer("Server=localhost; Database=LearnEf; User Id=sa; Password=Bx@steel1;"));
        }      

這句話就是把MyContext注冊到了asp.net core的服務容器中, 可以供注入, 同時在這裡指定了Data Provider和Connection String.

與其把Connection String寫死在這裡, 不如使用appSettings.json檔案:

Entity Framework Core 2.0 入門1.建立資料庫和Model使用Model與資料庫互動 查詢和儲存關聯資料.

然後使用内置的方法讀取該Connection String:

public void ConfigureServices(IServiceCollection services)
        {
            services.AddMvc();
            services.AddDbContext<MyContext>
                (options => options.UseSqlServer(Configuration.GetConnectionString("DefaultConnection")));
        }      

回到指令行進入Web項目, 使用dotnet ef指令:

Entity Framework Core 2.0 入門1.建立資料庫和Model使用Model與資料庫互動 查詢和儲存關聯資料.

說明需要添加上面提到的庫, 這裡就不重複了.

然後, 手動添加一個Migration叫做InitialAspNetCore:

dotnet ef migrations add InitialAspNetCore --project=../LearnEf.Data      

看一下遷移檔案:

Entity Framework Core 2.0 入門1.建立資料庫和Model使用Model與資料庫互動 查詢和儲存關聯資料.

是空的, 因為我之前已經使用UI那個項目進行過遷移更新了. 是以我要把這個遷移删掉:

dotnet ef migrations remove --project=../LearnEf.Data      

然後這兩個遷移檔案就删掉了:

Entity Framework Core 2.0 入門1.建立資料庫和Model使用Model與資料庫互動 查詢和儲存關聯資料.

多對多關系和一對一關系:

這部分的官方文檔在這: 

https://docs.microsoft.com/en-us/ef/core/modeling/relationships

對于多對多關系, efcore需要使用一個中間表, 我想基本ef使用者都知道這個了, 我就直接貼代碼吧.

建立一個City.cs:

namespace LearnEf.Domains
{
    public class City
    {
        public int Id { get; set; }
        public string Name { get; set; }
    }
}      

Company和City是多對多的關系, 是以需要建立一個中間表,叫做 CompanyCity:

namespace LearnEf.Domains
{
    public class CompanyCity
    {
        public int CompanyId { get; set; }
        public int CityId { get; set; }
        public Company Company { get; set; }
        public City City { get; set; }
    }
}      

修改Company:

Entity Framework Core 2.0 入門1.建立資料庫和Model使用Model與資料庫互動 查詢和儲存關聯資料.

修改City:

Entity Framework Core 2.0 入門1.建立資料庫和Model使用Model與資料庫互動 查詢和儲存關聯資料.

盡管Efcore可以推斷出來這個多對多關系, 但是我還是使用一下FluentApi來自定義配置一下這個表的主鍵:

MyContext.cs:

using LearnEf.Domains;
using Microsoft.EntityFrameworkCore;

namespace LearnEf.Data
{
    public class MyContext : DbContext
    {
        public MyContext(DbContextOptions<MyContext> options)
            : base(options)
        {

        }
        public DbSet<Company> Companies { get; set; }
        public DbSet<Department> Departments { get; set; }
        public DbSet<CompanyCity> CompanyCities { get; set; }

        protected override void OnModelCreating(ModelBuilder modelBuilder)
        {
            modelBuilder.Entity<CompanyCity>()
                .HasKey(c => new { c.CompanyId, c.CityId });
        }

        // protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
        // {
        //     optionsBuilder.UseSqlServer("Server=localhost; Database=LearnEf; User Id=sa; Password=Bx@steel1;");
        //     base.OnConfiguring(optionsBuilder);
        // }
    }
}      

完整的寫法應該是:

Entity Framework Core 2.0 入門1.建立資料庫和Model使用Model與資料庫互動 查詢和儲存關聯資料.

其中紅框裡面的部分不寫也行.

接下來建立一個一對一關系, 建立Model叫Owner.cs:

namespace LearnEf.Domains
{
    public class Owner
    {
        public int Id { get; set;}
        public int CompanyId { get; set; }
        public string Name { get; set; }
        public Company Company { get; set; }
    }
}      
Entity Framework Core 2.0 入門1.建立資料庫和Model使用Model與資料庫互動 查詢和儲存關聯資料.

配置關系:

protected override void OnModelCreating(ModelBuilder modelBuilder)
        {
            modelBuilder.Entity<CompanyCity>()
                .HasKey(c => new { c.CompanyId, c.CityId });

            modelBuilder.Entity<CompanyCity>().HasOne(x => x.Company)
                .WithMany(x => x.CompanyCities).HasForeignKey(x => x.CompanyId);

            modelBuilder.Entity<CompanyCity>().HasOne(x => x.City)
                .WithMany(x => x.CompanyCities).HasForeignKey(x => x.CityId);

            modelBuilder.Entity<Owner>().HasOne(x => x.Company).WithOne(x => x.Owner)
                .HasForeignKey<Owner>(x => x.CompanyId);
        }      

這裡面呢, 這個Owner對于Company 來說 是可空的. 而對于Owner來說, Company是必須的. 如果針對Owner想讓Company是可空的, 那麼CompanyId的類型就應該設定成int?.

再添加一個遷移:

dotnet ef migrations add AddRelationships --project=../LearnEf.Data      

檢視遷移檔案:

Entity Framework Core 2.0 入門1.建立資料庫和Model使用Model與資料庫互動 查詢和儲存關聯資料.

檢視一下快照;

Entity Framework Core 2.0 入門1.建立資料庫和Model使用Model與資料庫互動 查詢和儲存關聯資料.

沒問題, 那麼更新資料庫:

dotnet ef database update AddRelationships --project=../LearnEf.Data --verbose      

更新成功:

Entity Framework Core 2.0 入門1.建立資料庫和Model使用Model與資料庫互動 查詢和儲存關聯資料.

對現有資料庫的反向工程. 

這部分請檢視

吧, 很簡單, 我實驗了幾次, 但是目前還沒有這個需求.

輸出Sql語句.

對于asp.net core 2.0項目, 參考官方文檔: 

https://docs.microsoft.com/en-us/aspnet/core/fundamentals/logging/?tabs=aspnetcore2x

實際上, 項目已經配置好Logging部分了, 預設是列印到控制台和Debug視窗的. 源碼: 

https://github.com/aspnet/MetaPackages/blob/dev/src/Microsoft.AspNetCore/WebHost.cs

而對于console項目, 文檔在這: 

https://docs.microsoft.com/en-us/ef/core/miscellaneous/logging

需要對LearnEf.Data項目添加這個包: 

cd LearnEf.Data
dotnet add package Microsoft.Extensions.Logging.Console
dotnet restore      

然後為了使用console項目, 需要把MyContext改回來:

Entity Framework Core 2.0 入門1.建立資料庫和Model使用Model與資料庫互動 查詢和儲存關聯資料.

這部分首先是使用LoggerFactory建立了一個特殊的Console Logger. .net core的logging可以顯示很多的資訊, 這裡我放置了兩個過濾: 第一個表示隻顯示Sql指令, 第二個表示細節的顯示程度是Information級别.

最後還要在OnConfiguring方法裡告訴modelBuilder使用MyLoggerFactory作為LoggerFactory.

這就配置好了.

插入資料.

這部分很簡單, 打開UI項目的Program.cs:

Entity Framework Core 2.0 入門1.建立資料庫和Model使用Model與資料庫互動 查詢和儲存關聯資料.

這裡都懂的, 建立好model之後, 添加到context的DbSet屬性裡, 這時context就開始追蹤這個model了.

SaveChanges方法, 會檢查所有被追蹤的models, 讀取他們的狀态. 這裡用到是Add方法, context就會知道這個model的狀态是new, 是以就應該被插入到資料庫. 然後它就根據配置會生成出相應的sql語句, 然後把這個SQL語句執行到資料庫. 如果有傳回資料的話, 就取得該資料.

下面就運作一下這個console程式:

dotnet run --project=./LearnEf.UI      

看下控制台:

Entity Framework Core 2.0 入門1.建立資料庫和Model使用Model與資料庫互動 查詢和儲存關聯資料.

可以看到輸出了sql語句, 而且這個出入動作後, 做了一個查詢把插入資料生成的Id取了回來.

預設情況下log不顯示傳進去的參數, 這是為了安全. 但是可以通過修改配置來顯示參數:

Entity Framework Core 2.0 入門1.建立資料庫和Model使用Model與資料庫互動 查詢和儲存關聯資料.

然後控制台就會顯示這些參數了:

Entity Framework Core 2.0 入門1.建立資料庫和Model使用Model與資料庫互動 查詢和儲存關聯資料.

批量插入操作.

Entity Framework Core 2.0 入門1.建立資料庫和Model使用Model與資料庫互動 查詢和儲存關聯資料.

可以使用AddRange添加多條資料. 其參數可以是params或者集合.

可以看到這個和之前Add的Sql語句是完全不同的:

Entity Framework Core 2.0 入門1.建立資料庫和Model使用Model與資料庫互動 查詢和儲存關聯資料.

這個語句我不是很明白.

批量添加不同類型的資料:

Entity Framework Core 2.0 入門1.建立資料庫和Model使用Model與資料庫互動 查詢和儲存關聯資料.

使用context的AddRange或Add方法, DbContext可以推斷出參數的類型, 并執行正确的操作. 上面的方法就是使用了DbContext.AddRange方法, 一次性添加了兩種不同類型的model.

這兩個方法對于寫一些通用方法或者處理複雜的情況是很有用的.

Sql Server對于批量操作的限制是, 一次隻能最多處理1000個SQL指令, 多出來的指令将會分批執行.

如果想更改這個限制, 可以這樣配置參數:

Entity Framework Core 2.0 入門1.建立資料庫和Model使用Model與資料庫互動 查詢和儲存關聯資料.

簡單查詢.

針對DbSet, 使用Linq的ToList方法, 會觸發對資料庫對查詢操作:

首先把Company的ToString方法寫上:

Entity Framework Core 2.0 入門1.建立資料庫和Model使用Model與資料庫互動 查詢和儲存關聯資料.

這樣友善輸入到控制台.

然後寫查詢方法:

Entity Framework Core 2.0 入門1.建立資料庫和Model使用Model與資料庫互動 查詢和儲存關聯資料.

看結果:

Entity Framework Core 2.0 入門1.建立資料庫和Model使用Model與資料庫互動 查詢和儲存關聯資料.

EfCore到查詢有兩類文法, 一種是Linq方法, 另一種是Linq查詢文法:

這種是Linq方法:

Entity Framework Core 2.0 入門1.建立資料庫和Model使用Model與資料庫互動 查詢和儲存關聯資料.

下面這種是Linq查詢文法:

Entity Framework Core 2.0 入門1.建立資料庫和Model使用Model與資料庫互動 查詢和儲存關聯資料.

我基本都是使用第一種方法.

除了ToList(Async)可以觸發查詢以外, 周遊foreach也可以觸發查詢:

Entity Framework Core 2.0 入門1.建立資料庫和Model使用Model與資料庫互動 查詢和儲存關聯資料.

但是這種情況下, 可能會有性能問題. 因為:

在周遊開始的時候, 資料庫連接配接打開, 并且會一直保持打開的狀态, 直到周遊結束.

是以如果這個周遊很耗時, 那麼可能會發生一些問題.

最好的辦法還是首先執行ToList, 然後再周遊.

查詢的過濾.

這部分和以前的EF基本沒啥變化.

Entity Framework Core 2.0 入門1.建立資料庫和Model使用Model與資料庫互動 查詢和儲存關聯資料.

這個很簡單, 不說了.

這裡列一下可觸發查詢的Linq方法:

Entity Framework Core 2.0 入門1.建立資料庫和Model使用Model與資料庫互動 查詢和儲存關聯資料.

還有個兩個方法是DbSet的方法, 也可以觸發查詢動作:

Entity Framework Core 2.0 入門1.建立資料庫和Model使用Model與資料庫互動 查詢和儲存關聯資料.

上面這些方法都應該很熟悉, 我就不寫了.

過濾的條件可以直接家在上面的某些方法裡面, 例如:

Entity Framework Core 2.0 入門1.建立資料庫和Model使用Model與資料庫互動 查詢和儲存關聯資料.

通過主鍵查詢, 就可以用DbSet的Find方法:

Entity Framework Core 2.0 入門1.建立資料庫和Model使用Model與資料庫互動 查詢和儲存關聯資料.

這個方法有個優點, 就是如果這條資料已經在Context裡面追蹤了, 那麼查詢的時候就不查資料庫了, 直接會傳回記憶體中的資料.

EF.Functions.Like 這個方法是新方法, 就像是Sql語句裡面的Like一樣, 或者字元串的Contains方法:

Entity Framework Core 2.0 入門1.建立資料庫和Model使用Model與資料庫互動 查詢和儲存關聯資料.

這個感覺更像Sql語句, 輸出到Console的Sql語句如下:

Entity Framework Core 2.0 入門1.建立資料庫和Model使用Model與資料庫互動 查詢和儲存關聯資料.

這裡還要談的是First/FirstOrDefault/Last/LastOrDefaut方法.

使用這些方法必須先使用OrderBy/OrderByDescending排序. 雖然不使用的話也不會報錯, 但是, 整個過程就會變成這樣, context把整個表的資料家在到記憶體裡, 然後傳回第一條/最後一條資料. 如果表的資料比較多的話, 那麼就會有性能問題了.

更新資料.

Entity Framework Core 2.0 入門1.建立資料庫和Model使用Model與資料庫互動 查詢和儲存關聯資料.

很簡單, context所追蹤的model屬性變化後, SaveChanges就會更新到資料庫.

當然, 多個更新操作和插入等操作可以批量執行.

離線更新.

Entity Framework Core 2.0 入門1.建立資料庫和Model使用Model與資料庫互動 查詢和儲存關聯資料.

就是這種情況, 新的context一開始并沒有追蹤one這個資料. 通過使用Update方法, 追蹤并設定狀态為update. 然後更新到資料庫.

Entity Framework Core 2.0 入門1.建立資料庫和Model使用Model與資料庫互動 查詢和儲存關聯資料.

可以看到, 在這種情況下, EfCore會更新該model到所有屬性.

Update同樣也有DbSet的UpdateRange方法, 也有context到Update和UpdateRange方法, 這點和Add是一樣的.

還有一種方法用于更新, 這個以後再說.

删除資料.

DbContext隻能删除它追蹤的model.

Entity Framework Core 2.0 入門1.建立資料庫和Model使用Model與資料庫互動 查詢和儲存關聯資料.

非常簡單, 從log可以看到, 删除動作隻用到了主鍵:

Entity Framework Core 2.0 入門1.建立資料庫和Model使用Model與資料庫互動 查詢和儲存關聯資料.

如果是删除的離線model, 那麼Remove方法首先會讓Dbcontext追蹤這個model, 然後設定狀态為Deleted.

删除同樣有RemoveRange方法.

Raw SQL查詢/指令:

這部分請看文檔:

指令: DbContext.Database.ExecuteSqlCommand();

Entity Framework Core 2.0 入門1.建立資料庫和Model使用Model與資料庫互動 查詢和儲存關聯資料.
Entity Framework Core 2.0 入門1.建立資料庫和Model使用Model與資料庫互動 查詢和儲存關聯資料.

查詢: DbSet.FromSql()

https://docs.microsoft.com/en-us/ef/core/querying/raw-sql

;

這個方法目前還有一些限制, 它隻能傳回實體的類型, 并且得傳回domain model所有的屬性, 而且屬性的名字必須也得一一對應. SQL語句不可以包含關聯的導航屬性, 但是可以配合Include使用以達到該效果(

https://docs.microsoft.com/en-us/ef/core/querying/raw-sql#including-related-data

).

Entity Framework Core 2.0 入門1.建立資料庫和Model使用Model與資料庫互動 查詢和儲存關聯資料.
Entity Framework Core 2.0 入門1.建立資料庫和Model使用Model與資料庫互動 查詢和儲存關聯資料.

更多的傳遞參數方式還需要看文檔.

查詢和儲存關聯資料.

插入關聯資料.

我之前忘記在Department裡面添加Name字段了, 現在添加一下, 具體過程就不寫了.

插入關聯資料有幾種情況:

1.直接把要添加的Model的導航屬性附上值就可以了, 這裡的Department不需要寫外鍵.

Entity Framework Core 2.0 入門1.建立資料庫和Model使用Model與資料庫互動 查詢和儲存關聯資料.

看一下Sql:

Entity Framework Core 2.0 入門1.建立資料庫和Model使用Model與資料庫互動 查詢和儲存關聯資料.

這個過程一共分兩步: 1 插入主表, 2,使用剛插入主表資料的Id, 插入子表資料.

2.為資料庫中的資料添加導航屬性.

Entity Framework Core 2.0 入門1.建立資料庫和Model使用Model與資料庫互動 查詢和儲存關聯資料.

這時, 因為該資料是被context追蹤的, 是以隻需在它的導航屬性添加新記錄, 然後儲存即可.

3.離線資料添加導航屬性.

這時候就必須使用外鍵了.

Entity Framework Core 2.0 入門1.建立資料庫和Model使用Model與資料庫互動 查詢和儲存關聯資料.

預加載關聯資料 Eager Loading.

也就是查詢的時候一次性把資料和其導航屬性的資料一同查詢出來.

Entity Framework Core 2.0 入門1.建立資料庫和Model使用Model與資料庫互動 查詢和儲存關聯資料.

看看SQL:

Entity Framework Core 2.0 入門1.建立資料庫和Model使用Model與資料庫互動 查詢和儲存關聯資料.

這個過程是分兩步實作的, 首先查詢了主表, 然後再查詢的子表. 這樣做的好處就是性能提升.

(FromSql也可以Include).

預加載子表的子表:

可以使用ThenInclude方法, 這個可以老版本ef沒有的.

Entity Framework Core 2.0 入門1.建立資料庫和Model使用Model與資料庫互動 查詢和儲存關聯資料.

這裡查詢Department的時候, 将其關聯表Company也查詢了出來, 同時也把Company的關聯表Owner也查詢了出來.

查詢中映射關聯資料.

Entity Framework Core 2.0 入門1.建立資料庫和Model使用Model與資料庫互動 查詢和儲存關聯資料.

使用Select可以傳回匿名類, 裡面可以自定義屬性.

這個匿名類隻在方法内有效.

看下SQL:

Entity Framework Core 2.0 入門1.建立資料庫和Model使用Model與資料庫互動 查詢和儲存關聯資料.

可以看到SQL中隻Select了匿名類裡面需要的字段.

如果需要在方法外使用該結果, 那麼可以使用dynamic, 或者建立一個對應的struct或者class.

使用關聯導航屬性過濾, 但是不加載它們.

Entity Framework Core 2.0 入門1.建立資料庫和Model使用Model與資料庫互動 查詢和儲存關聯資料.

SQL:

Entity Framework Core 2.0 入門1.建立資料庫和Model使用Model與資料庫互動 查詢和儲存關聯資料.

這個比較簡單. 看sql一切就明白了.

修改關聯資料.

也會分兩種情況, 被追蹤和離線資料.

被追蹤的情況下比較簡單, 直接修改關聯資料的屬性即可:

Entity Framework Core 2.0 入門1.建立資料庫和Model使用Model與資料庫互動 查詢和儲存關聯資料.

看一下SQL:

Entity Framework Core 2.0 入門1.建立資料庫和Model使用Model與資料庫互動 查詢和儲存關聯資料.

确實改了.

這種情況下, 删除關聯資料庫也很簡單:

Entity Framework Core 2.0 入門1.建立資料庫和Model使用Model與資料庫互動 查詢和儲存關聯資料.
Entity Framework Core 2.0 入門1.建立資料庫和Model使用Model與資料庫互動 查詢和儲存關聯資料.

删除了.

下面來看看離線狀态下的操作.

Entity Framework Core 2.0 入門1.建立資料庫和Model使用Model與資料庫互動 查詢和儲存關聯資料.

這裡需要使用update, 把該資料添加到context的追蹤範圍内.

Entity Framework Core 2.0 入門1.建立資料庫和Model使用Model與資料庫互動 查詢和儲存關聯資料.

這個就比較怪異了.

它update了該departmt和它的company以及company下的其他department和company的owner. 這些值倒是原來的值.

這是因為, 看上面的代碼, 查詢的時候department的關聯屬性company以及company下的departments和owner一同被加載了.

盡管我隻update了一個department, 但是efcore把其他關聯的資料都識别出來了.

從DbContext的ChangeTracker屬性下的StateManger可以看到有多少個變化.

這一點非常的重要.

如何避免這個陷阱呢?

可以這樣做: 直接設定dbContext.Entry().State的值

Entity Framework Core 2.0 入門1.建立資料庫和Model使用Model與資料庫互動 查詢和儲存關聯資料.

這時, 再看看SQL:

Entity Framework Core 2.0 入門1.建立資料庫和Model使用Model與資料庫互動 查詢和儲存關聯資料.

嗯. 沒錯, 隻更新了需要更新的對象.

2.1版本将于2018年上半年釋出, 請檢視官網的路線圖: 

https://github.com/aspnet/EntityFrameworkCore/wiki/roadmap

完. 

下面是我的關于ASP.NET Core Web API相關技術的公衆号--草根專欄:

Entity Framework Core 2.0 入門1.建立資料庫和Model使用Model與資料庫互動 查詢和儲存關聯資料.