<kbd id="afajh"><form id="afajh"></form></kbd>
<strong id="afajh"><dl id="afajh"></dl></strong>
    <del id="afajh"><form id="afajh"></form></del>
        1. <th id="afajh"><progress id="afajh"></progress></th>
          <b id="afajh"><abbr id="afajh"></abbr></b>
          <th id="afajh"><progress id="afajh"></progress></th>

          Asp-Net-Core開(kāi)發(fā)筆記:快速在已有項(xiàng)目中引入EFCore

          共 6866字,需瀏覽 14分鐘

           ·

          2023-10-13 17:41

          1前言

          很多項(xiàng)目一開(kāi)始選型的時(shí)候沒(méi)有選擇EFCore,不過(guò)EFCore確實(shí)好用,也許由于種種原因后面還是需要用到,這時(shí)候引入EFCore也很方便。

          本文以 StarBlog 為例,StarBlog 目前使用的 ORM 是 FreeSQL ,引入 EFCore 對(duì)我來(lái)說(shuō)最大的好處是支持多個(gè)數(shù)據(jù)庫(kù),如果是 FreeSQL 的話,服務(wù)注冊(cè)的時(shí)候是單例模式,只能連接一個(gè)數(shù)據(jù)庫(kù),如果需要使用 FreeSQL 同時(shí)連接多個(gè)數(shù)據(jù)庫(kù),需要自行做一些額外的工作。

          要實(shí)現(xiàn)的效果是:把訪問(wèn)記錄單獨(dú)使用一個(gè)數(shù)據(jù)庫(kù)來(lái)存儲(chǔ),并且使用 EFCore 管理。

          2安裝工具

          首先安裝 EFCore 的 cli 工具

          dotnet tool install --global dotnet-ef

          3項(xiàng)目架構(gòu)

          先來(lái)回顧一下項(xiàng)目架構(gòu):基于.NetCore開(kāi)發(fā)博客項(xiàng)目 StarBlog - (2) 環(huán)境準(zhǔn)備和創(chuàng)建項(xiàng)目

          StarBlog
          ├── StarBlog.Contrib
          ├── StarBlog.Data
          ├── StarBlog.Migrate
          ├── StarBlog.Web
          └── StarBlog.sln

          為了解耦,和數(shù)據(jù)有關(guān)的代碼在 StarBlog.Data 項(xiàng)目下,因此引入 EFCore 只需要在 StarBlog.Data 這個(gè)項(xiàng)目中添加依賴(lài)即可。

          4添加依賴(lài)

          StarBlog.Data 項(xiàng)目中添加以下三個(gè)依賴(lài)

          • Microsoft.EntityFrameworkCore
          • Microsoft.EntityFrameworkCore.Sqlite
          • Microsoft.EntityFrameworkCore.Tools

          EFCore 對(duì) SQLite 的支持很弱(根本原因是微軟提供的 SQLite 驅(qū)動(dòng)功能太少),所以只適合在本地開(kāi)發(fā)玩玩,實(shí)際部署還是得切換成 C/S 架構(gòu)的數(shù)據(jù)庫(kù)(PgSQL/MySQL/SQL Server)才行。

          添加后項(xiàng)目的 .csproj 文件新增的依賴(lài)類(lèi)似這樣

          <PackageReference Include="Microsoft.EntityFrameworkCore" Version="6.0.18" />
          <PackageReference Include="Microsoft.EntityFrameworkCore.Sqlite" Version="6.0.18" />
          <PackageReference Include="Microsoft.EntityFrameworkCore.Tools" Version="6.0.18">
            <PrivateAssets>all</PrivateAssets>
            <IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
          </PackageReference>

          目前 StarBlog 還在使用 .Net6 所以我添加的 EFCore 是 6.x 版本,等后續(xù) .Net8 正式版發(fā)布之后,我會(huì)把這個(gè)項(xiàng)目升級(jí)到 .Net8

          5創(chuàng)建 DbContext

          DbContext 是 EFCore 與數(shù)據(jù)庫(kù)交互的入口,一般一個(gè)數(shù)據(jù)庫(kù)對(duì)應(yīng)一個(gè)。

          現(xiàn)在來(lái) StarBlog.Data 項(xiàng)目下創(chuàng)建一個(gè)。

          using Microsoft.EntityFrameworkCore;
          using StarBlog.Data.Models;

          namespace StarBlog.Data;

          public class AppDbContext : DbContext {
            public DbSet<VisitRecord> VisitRecords { getset; }
            
            public AppDbContext(DbContextOptions<AppDbContext> options) : base(options) { }
          }

          因?yàn)橹恍枰?EFCore 管理訪問(wèn)記錄,所以只需要一個(gè) DbSet

          6實(shí)體類(lèi)配置

          然后來(lái)創(chuàng)建個(gè)配置,雖然也可以用 Data Annotation 來(lái)配置,但 EFCore 推薦使用 Fluent Config 方式來(lái)配置數(shù)據(jù)表和字段。

          創(chuàng)建 StarBlog.Data/Config/VisitRecordConfig.cs 文件

          public class VisitRecordConfig : IEntityTypeConfiguration<VisitRecord> {
            public void Configure(EntityTypeBuilder<VisitRecord> builder) {
              builder.ToTable("visit_record");
              builder.HasKey(e => e.Id);
              builder.Property(e => e.Ip).HasMaxLength(64);
              builder.Property(e => e.RequestPath).HasMaxLength(2048);
              builder.Property(e => e.RequestQueryString).HasMaxLength(2048);
              builder.Property(e => e.RequestMethod).HasMaxLength(10);
              builder.Property(e => e.UserAgent).HasMaxLength(1024);
            }
          }

          主要是配置了主鍵和各個(gè)字段的長(zhǎng)度。

          數(shù)據(jù)類(lèi)型這塊 EFCore 會(huì)自動(dòng)映射,具體請(qǐng)參考官方文檔。

          7主鍵類(lèi)型選擇

          這里插播一下題外話,關(guān)于主鍵類(lèi)型應(yīng)該如何選擇。

          目前主要有幾種方式:

          • 自增
          • GUID
          • 自增+GUID
          • Hi/Lo

          這幾種方式各有優(yōu)劣。

          • 自增的好處是簡(jiǎn)單,缺點(diǎn)是在數(shù)據(jù)庫(kù)遷移或者分布式系統(tǒng)中容易出問(wèn)題,而且高并發(fā)時(shí)插入性能較差。
          • GUID好處也是簡(jiǎn)單方便,而且也適用于分布式系統(tǒng);MySQL的InnoDB引擎強(qiáng)制主鍵使用聚集索引,導(dǎo)致新插入的每條數(shù)據(jù)都要經(jīng)歷查找合適插入位置的過(guò)程,在數(shù)據(jù)量大的時(shí)候插入性能很差。
          • 自增+GUID是把自增字段作為物理主鍵,GUID作為邏輯主鍵,可以在一定程度上解決上述兩種方式的問(wèn)題。
          • Hi/Lo可以?xún)?yōu)化自增列的性能,但只有部分?jǐn)?shù)據(jù)庫(kù)支持,比如SQL Server,其他的數(shù)據(jù)庫(kù)暫時(shí)還沒(méi)研究。

          8DesignTime 配置

          因?yàn)槲覀兊捻?xiàng)目是把 AspNetCore 和數(shù)據(jù)分離的,所以需要一個(gè) DesignTime 配置來(lái)讓 EFCore 知道如何執(zhí)行遷移。

          StarBlog.Data 中創(chuàng)建 AppDesignTimeDbContextFactory.cs 文件

          public class AppDesignTimeDbContextFactory : IDesignTimeDbContextFactory<AppDbContext> {
            public AppDbContext CreateDbContext(string[] args) {
              var builder = new DbContextOptionsBuilder<AppDbContext>();

              var connStr = Environment.GetEnvironmentVariable("CONNECTION_STRING");
              if (connStr == null) {
                var dbpath = Path.Combine(Environment.CurrentDirectory, "app.log.db");
                connStr = $"Data Source={dbpath};";
              }

              builder.UseSqlite(connStr);
              return new AppDbContext(builder.Options);
            }
          }

          這里從環(huán)境變量讀取數(shù)據(jù)庫(kù)連接字符串,如果讀不到就使用默認(rèn)的數(shù)據(jù)庫(kù)文件。

          9數(shù)據(jù)庫(kù)遷移

          這塊主要是使用兩組命令

          • migrations - 用于監(jiān)控?cái)?shù)據(jù)庫(kù)的修改
          • database - 將修改同步到數(shù)據(jù)庫(kù)里

          cd 到 StarBlog.Data 目錄下,執(zhí)行

          dotnet ef migrations add InitialCreate -o Migrations 

          之后可以看到 Migrations 目錄下生成了遷移的代碼

          如果需要指定數(shù)據(jù)庫(kù)文件,可以設(shè)置環(huán)境變量。

          Windows的使用:

          set CONNECTION_STRING = "Data Source=app.db;"

          Linux的也差不多,把 set 換成 export

          export CONNECTION_STRING = "Data Source=app.db;"

          運(yùn)行以下命令同步到數(shù)據(jù)庫(kù)

          dotnet ef database update

          執(zhí)行之后就會(huì)在 StarBlog.Data 下生成 SQLite 數(shù)據(jù)庫(kù)文件。

          10在AspNetCore項(xiàng)目里集成EFCore

          先把數(shù)據(jù)庫(kù)連接字符串寫(xiě)到配置文件 appsettings.json

          {
            "ConnectionStrings": {
              "SQLite""Data Source=app.db;Synchronous=Off;Cache Size=5000;",
              "SQLite-Log""Data Source=app.log.db;"
            }
          }

          Program.cs 里注冊(cè)服務(wù)

          builder.Services.AddDbContext<AppDbContext>(options => {
            options.UseSqlite(builder.Configuration.GetConnectionString("SQLite-Log"));
          });

          搞定~

          11db-first

          從已有數(shù)據(jù)庫(kù)生成實(shí)體類(lèi),一般新項(xiàng)目不推薦這種開(kāi)發(fā)方式,不過(guò)在舊項(xiàng)目上使用還是比較方便的,EFCore 的 cli tool 也提供很豐富的代碼生成功能。

          這里提供一下例子:

          • 使用 PostgreSql 數(shù)據(jù)庫(kù),要把其中 pe_shit_data 庫(kù)的所有表生成實(shí)體類(lèi)
          • 生成的 DbContext 類(lèi)名為 ShitDbContext
          • DbContext 類(lèi)的命名空間為 PE.Data
          • 實(shí)體類(lèi)放在 ShitModels 目錄下,命名空間為 PE.Data.ShitModels

          命令如下

          dotnet ef dbcontext scaffold `
          "Host=cuc.dou3.net;Database=pe_shit_data;Username=postgres;Password=passw0rd" `
          Npgsql.EntityFrameworkCore.PostgreSQL `
          -f `
          -c ShitDbContext `
          --context-dir . `
          --context-namespace PE.Data `
          -o ShitModels `
          --namespace PE.Data.ShitModels `

          這個(gè)是 powershell 的命令,如果是 Linux 環(huán)境,把每一行命令末尾的反引號(hào)換成 \ 即可。

          12參考資料

          • https://learn.microsoft.com/en-us/ef/core/cli/dotnet
          • https://learn.microsoft.com/zh-cn/ef/core/managing-schemas/scaffolding


          瀏覽 147
          點(diǎn)贊
          評(píng)論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          評(píng)論
          圖片
          表情
          推薦
          點(diǎn)贊
          評(píng)論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          <kbd id="afajh"><form id="afajh"></form></kbd>
          <strong id="afajh"><dl id="afajh"></dl></strong>
            <del id="afajh"><form id="afajh"></form></del>
                1. <th id="afajh"><progress id="afajh"></progress></th>
                  <b id="afajh"><abbr id="afajh"></abbr></b>
                  <th id="afajh"><progress id="afajh"></progress></th>
                  福利一区二区 | av天堂手机在线 av性爱在线直播 | 欧美特大黄 | 伊人大香蕉www | 日本色情视频在线播放 |