天天看點

.NET 雲原生架構師訓練營(子產品二 基礎鞏固 EF Core 基礎與配置)--學習筆記2.4.3 EF Core -- 基礎與配置

2.4.3 EF Core -- 基礎與配置

  • 連接配接字元串
  • 異步程式設計
  • 日志
  • DbContext池
  • 類和配置表
  • 屬性和列配置
  • 并發token
  • 索引

Entity Framework Core:

https://docs.microsoft.com/zh-cn/ef/core/

連接配接字元串:

https://docs.microsoft.com/zh-cn/ef/core/miscellaneous/connection-strings

在 ASP.NET Core 配置系統非常靈活,并且可以将連接配接字元串存儲在 appsettings.json 、環境變量、使用者密鑰存儲或其他配置源中

appsettings.json

{
  "ConnectionStrings": {
    "BloggingDatabase": "Server=(localdb)\\mssqllocaldb;Database=EFGetStarted.ConsoleApp.NewDb;Trusted_Connection=True;"
  },
}           

異步程式設計:

https://docs.microsoft.com/zh-cn/ef/core/miscellaneous/async

當在資料庫中執行查詢時,異步操作将避免阻止線程。 異步操作對于在豐富的用戶端應用程式中保持響應式 UI 非常重要,并且還可以增加 web 應用程式中的吞吐量,在這些應用程式中,它們可釋放線程以處理 web 應用程式中的其他請求

var blog = new Blog { Url = "http://sample.com" };
context.Blogs.Add(blog);
await context.SaveChangesAsync();           

日志:

https://docs.microsoft.com/zh-cn/ef/core/logging-events-diagnostics/extensions-logging?tabs=v3

Entity Framework Core (EF Core) 與完全內建 Microsoft.Extensions.Logging

"Microsoft.EntityFrameworkCore.Database.Command": "Debug"           

啟動程式,查詢清單,控制台輸出

dbug: Microsoft.EntityFrameworkCore.Database.Command[20103]
      Creating DbCommand for 'ExecuteReader'.
dbug: Microsoft.EntityFrameworkCore.Database.Command[20104]
      Created DbCommand for 'ExecuteReader' (10ms).
dbug: Microsoft.EntityFrameworkCore.Database.Command[20100]
      Executing DbCommand [Parameters=[], CommandType='Text', CommandTimeout='30']
      SELECT `p`.`Id`, `p`.`CreatedAt`, `p`.`CreatedBy`, `p`.`EndDate`, `p`.`IdentityId`, `p`.`LastUpdateAt`, `p`.`LastUpdateBy`, `p`.`PlanId`, `p`.`StartDate`, `p`.`SupervisorId`, `p`.`TenantId`, `p`.`Title`, `p`.`UserId`
      FROM `Projects` AS `p`
info: Microsoft.EntityFrameworkCore.Database.Command[20101]
      Executed DbCommand (82ms) [Parameters=[], CommandType='Text', CommandTimeout='30']
      SELECT `p`.`Id`, `p`.`CreatedAt`, `p`.`CreatedBy`, `p`.`EndDate`, `p`.`IdentityId`, `p`.`LastUpdateAt`, `p`.`LastUpdateBy`, `p`.`PlanId`, `p`.`StartDate`, `p`.`SupervisorId`, `p`.`TenantId`, `p`.`Title`, `p`.`UserId`
      FROM `Projects` AS `p`
dbug: Microsoft.EntityFrameworkCore.Database.Command[20300]
      A data reader was disposed.           

DbContext池:

https://docs.microsoft.com/zh-cn/ef/core/performance/advanced-performance-topics?tabs=with-constant#dbcontext-pooling

AddDbContextPool 啟用執行個體的池 DbContext 。 上下文池可以通過重複使用上下文執行個體,而不是為每個請求建立新執行個體,進而提高大規模方案(如 web 伺服器)的吞吐量。

services.AddDbContextPool<LighterDbContext>(options =>
{
    options.UseMySql(Configuration.GetConnectionString("LighterDbContext"));
});           

AddDbContextPool使用時,在請求上下文執行個體時,EF 首先檢查池中是否有可用的執行個體。 請求處理完成後,執行個體的任何狀态都将被重置,并且執行個體本身會傳回池中。

避免在維護狀态的應用程式中使用上下文池。 例如,不應在請求之間共享的上下文中的私有字段。 在将上下文執行個體添加到池中之前,EF Core 僅重置它知道的狀态。

除高度優化的方案外,池的性能提升通常可以忽略不計。

實體類型:

https://docs.microsoft.com/zh-cn/ef/core/modeling/entity-types?tabs=data-annotations

在模型中包含類型

class MyContext : DbContext
{
    // 對應一張表(推薦)
    public DbSet<Blog> Blogs { get; set; }

    protected override void OnModelCreating(ModelBuilder modelBuilder)
    {
        // 對應一張表
        modelBuilder.Entity<AuditEntry>();
    }
}

public class Blog
{
    public int BlogId { get; set; }
    public string Url { get; set; }

    public List<Post> Posts { get; set; }
}

public class Post
{
    public int PostId { get; set; }
    public string Title { get; set; }
    public string Content { get; set; }

    public Blog Blog { get; set; }
}

public class AuditEntry
{
    public int AuditEntryId { get; set; }
    public string Username { get; set; }
    public string Action { get; set; }
}           

從模型中排除類型

[NotMapped]
public class BlogMetadata
{
    public DateTime LoadedFromDatabase { get; set; }
}           

從遷移中排除

protected override void OnModelCreating(ModelBuilder modelBuilder)
{
    modelBuilder.Entity<IdentityUser>()
        .ToTable("AspNetUsers", t => t.ExcludeFromMigrations());
}           

  • 包含和排除的屬性
  • 列名
  • 自動生成列

實體屬性:

https://docs.microsoft.com/zh-cn/ef/core/modeling/entity-properties?tabs=data-annotations

資料批注

public class Blog
{
    public int BlogId { get; set; }
    public string Url { get; set; }

    [NotMapped]
    public DateTime LoadedFromDatabase { get; set; }
}           

Fluent API

protected override void OnModelCreating(ModelBuilder modelBuilder)
{
    modelBuilder.Entity<Blog>()
        .Ignore(b => b.LoadedFromDatabase);
}           

public class Blog
{
    [Column("blog_id")]
    public int BlogId { get; set; }
    public string Url { get; set; }
}           

Fluent API (推薦)

protected override void OnModelCreating(ModelBuilder modelBuilder)
{
    modelBuilder.Entity<Blog>()
        .Property(b => b.BlogId)
        .HasColumnName("blog_id");
}           

鍵:

https://docs.microsoft.com/zh-cn/ef/core/modeling/keys?tabs=data-annotations

按照約定,将名為 Id 或的屬性 Id 配置為實體的主鍵。

class Car
{
    public string Id { get; set; }

    public string Make { get; set; }
    public string Model { get; set; }
}

class Truck
{
    public string TruckId { get; set; }

    public string Make { get; set; }
    public string Model { get; set; }
}           

可以将單個屬性配置為實體的主鍵

class Car
{
    [Key]
    public string LicensePlate { get; set; }

    public string Make { get; set; }
    public string Model { get; set; }
}           
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
    modelBuilder.Entity<Car>()
        .HasKey(c => c.LicensePlate);
}           

生成的值:

https://docs.microsoft.com/zh-cn/ef/core/modeling/generated-properties?tabs=data-annotations

通過 Fluent API 的方式添加自增列

LighterDbContext

modelBuilder.Entity<Project.Project>().Property(p => p.Id).ValueGeneratedOnAdd();           

注釋控制器中 Id 的指派

ProjectController

//project.Id = Guid.NewGuid().ToString();           

新增一條資料,傳回 Id 是自動生成的

.NET 雲原生架構師訓練營(子產品二 基礎鞏固 EF Core 基礎與配置)--學習筆記2.4.3 EF Core -- 基礎與配置

通過資料批注方式添加建立時間,修改時間預設值

Entity

/// <summary>
/// 建立時間
/// </summary>
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public DateTime CreatedAt { get; set; }

/// <summary>
/// 最後修改時間
/// </summary>
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public DateTime LastUpdateAt { get; set; }           

更新資料庫

dotnet ef migrations add ChangeLastUpdateByToString

dotnet ef database update           

啟動程式,新增一條資料,可以看到建立時間,修改時間預設值

.NET 雲原生架構師訓練營(子產品二 基礎鞏固 EF Core 基礎與配置)--學習筆記2.4.3 EF Core -- 基礎與配置

并發标記:

https://docs.microsoft.com/zh-cn/ef/core/modeling/concurrency?tabs=data-annotations

配置為并發标記的屬性用于實作樂觀并發控制。

public class Person
{
    public int PersonId { get; set; }

    [ConcurrencyCheck]
    public string LastName { get; set; }

    public string FirstName { get; set; }
}           
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
    modelBuilder.Entity<Person>()
        .Property(p => p.LastName)
        .IsConcurrencyToken();
}           

Timestamp/rowversion (推薦)

Timestamp/rowversion 是一個屬性,在每次插入或更新行時,資料庫會自動為其生成新值。 此屬性也被視為并發标記,這確定了在你查詢行後,如果正在更新的行發生了更改,則會出現異常。

public class Blog
{
    public int BlogId { get; set; }

    public string Url { get; set; }

    [Timestamp]
    public byte[] Timestamp { get; set; }
}           
class MyContext : DbContext
{
    public DbSet<Blog> Blogs { get; set; }

    protected override void OnModelCreating(ModelBuilder modelBuilder)
    {
        modelBuilder.Entity<Blog>()
            .Property(p => p.Timestamp)
            .IsRowVersion();
    }
}

public class Blog
{
    public int BlogId { get; set; }
    public string Url { get; set; }
    public byte[] Timestamp { get; set; }
}           

索引:

https://docs.microsoft.com/zh-cn/ef/core/modeling/indexes
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
    modelBuilder.Entity<Blog>()
        .HasIndex(b => b.Url);
}           

為多個列指定索引

protected override void OnModelCreating(ModelBuilder modelBuilder)
{
    modelBuilder.Entity<Person>()
        .HasIndex(p => new { p.FirstName, p.LastName });
}           

GitHub源碼連結:

https://github.com/MINGSON666/Personal-Learning-Library/tree/main/ArchitectTrainingCamp/LighterApi