• .NET 云原生架构师训练营(模块二 基础巩固 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

    appsettings.json

    "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池

    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; }
    }
    

    Fluent API

    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 是自动生成的

    通过数据批注方式添加创建时间,修改时间默认值

    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
    

    启动程序,新增一条数据,可以看到创建时间,修改时间默认值

    并发token

    并发标记: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; }
    }
    

    Fluent API

    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; }
    }
    

    Fluent API

    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

    知识共享许可协议

    本作品采用知识共享署名-非商业性使用-相同方式共享 4.0 国际许可协议进行许可。

    欢迎转载、使用、重新发布,但务必保留文章署名 郑子铭 (包含链接: http://www.cnblogs.com/MingsonZheng/ ),不得用于商业目的,基于本文修改后的作品务必以相同的许可发布。

    如有任何疑问,请与我联系 (MingsonZheng@outlook.com) 。

  • 相关阅读:
    【Gitbook】实用配置及插件介绍
    【Git】学习记录
    【Ubuntu】使用记录
    intellij idea
    【应用】信息短时存储
    leetcode pow(x,n)实现
    SSM框架-----------SpringMVC+Spring+Mybatis框架整合详细教程
    《平凡的世界》之我看
    垃圾收集器与内存分配策略(三)
    垃圾收集器与内存分配策略(二)
  • 原文地址:https://www.cnblogs.com/MingsonZheng/p/14203821.html
Copyright © 2020-2023  润新知