.NET之生成数据库全流程

运维 数据库运维
本文主要是回顾下从项目创建到生成数据到数据库(代码优先)的全部过程。采用EFCore作为ORM框架。

[[398365]]

本文转载自微信公众号「鹏祥」,作者AZRNG。转载本文请联系鹏祥公众号。

开篇语

本文主要是回顾下从项目创建到生成数据到数据库(代码优先)的全部过程。采用EFCore作为ORM框架。

本次示例环境:vs2019、net5、mysql

创建项目

本次事例代码是用过vs2019创建的ASP.NET Core Web API项目

可以通过可视化界面创建或者通过命令行创建

dotnet new webapi -o Net5ByDocker 
  • 1.

创建实体类

安装连接MySQL数据库组件

<PackageReference Include="Pomelo.EntityFrameworkCore.MySql" Version="5.0.0" /> 
    <PackageReference Include="Pomelo.EntityFrameworkCore.MySql.Json.Newtonsoft" Version="5.0.0" /> 
  • 1.
  • 2.

增加实体类

[Table("user")] 
  public class User 
  { 
      public User() 
      { 
          Id = Guid.NewGuid().ToString(); 
      } 
 
      public User(string account, string password, string creater) : this() 
      { 
          Account = account; 
          Password = password
          Deleted = false
          SetCreater(creater); 
      } 
 
      [Key
      [Comment("主键")] 
      [StringLength(36)] 
      [Required] 
      public string Id { get; private set; } 
 
      [Comment("帐号")] 
      [StringLength(36)] 
      [Required] 
      public string Account { get; private set; } 
 
      [Comment("密码")] 
      [StringLength(36)] 
      [Required] 
      public string Password { get; private set; } 
 
      [Comment("余额")] 
      [Column(TypeName = "decimal(18, 2)")] 
      [Required] 
      public decimal Money { get; set; } 
 
      [Comment("是否删除")] 
      [Column(TypeName = "tinyint(1)")] 
      [Required] 
      public bool Deleted { get; private set; } 
 
      [Comment("创建人")] 
      [StringLength(20)] 
      [Required] 
      public string Creater { get; private set; } 
 
      [Comment("创建时间")] 
      [Required] 
      public DateTime CreateTime { get; private set; } 
 
      [Comment("修改人")] 
      [StringLength(20)] 
      [Required] 
      public string Modifyer { get; private set; } 
 
      [Comment("修改时间")] 
      [Required] 
      public DateTime ModifyTime { get; private set; } 
 
      public void SetCreater(string name
      { 
          Creater = name
          CreateTime = DateTime.Now; 
          SetModifyer(name); 
      } 
 
      public void SetModifyer(string name
      { 
          Modifyer = name
          ModifyTime = DateTime.Now; 
      } 
  } 
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.
  • 12.
  • 13.
  • 14.
  • 15.
  • 16.
  • 17.
  • 18.
  • 19.
  • 20.
  • 21.
  • 22.
  • 23.
  • 24.
  • 25.
  • 26.
  • 27.
  • 28.
  • 29.
  • 30.
  • 31.
  • 32.
  • 33.
  • 34.
  • 35.
  • 36.
  • 37.
  • 38.
  • 39.
  • 40.
  • 41.
  • 42.
  • 43.
  • 44.
  • 45.
  • 46.
  • 47.
  • 48.
  • 49.
  • 50.
  • 51.
  • 52.
  • 53.
  • 54.
  • 55.
  • 56.
  • 57.
  • 58.
  • 59.
  • 60.
  • 61.
  • 62.
  • 63.
  • 64.
  • 65.
  • 66.
  • 67.
  • 68.
  • 69.
  • 70.
  • 71.
  • 72.
  • 73.

这种只是增加实体类类型的一种方式,可能这种看着比较乱,还可以通过OnModelCreating实现,详情看参考文档

增加数据库上下文OpenDbContext

public class OpenDbContext : DbContext 
    { 
        public OpenDbContext(DbContextOptions<OpenDbContext> options) 
            : base(options) 
        { 
        } 
 
        public DbSet<User> Users { get; set; } 
    } 
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.

Startup注入连接数据库操作

var connection = Configuration["DbConfig:Mysql:ConnectionString"]; 
            var migrationsAssembly = IntrospectionExtensions.GetTypeInfo(typeof(Startup)).Assembly.GetName().Name
            services.AddDbContext<OpenDbContext>(option => option.UseMySql(connection, ServerVersion.AutoDetect(connection), x => 
            { 
                x.UseNewtonsoftJson(); 
                x.MigrationsAssembly(migrationsAssembly); 
            })); 
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.

生成迁移文件

引用组件

<PackageReference Include="Microsoft.EntityFrameworkCore.Design" Version="5.0.5"
<PackageReference Include="Microsoft.EntityFrameworkCore.Tools" Version="5.0.5"
  • 1.
  • 2.

迁移命令

add-migration Init 
  • 1.

结果

image.png

要看下生成的迁移文件是否是自己预期的那样子,也可以在这一步就生成数据库,命令:Update-Database

数据种子

增加OpenDbSend类,添加数据种子

public class OpenDbSend 
 { 
     /// <summary> 
     /// 生成数据库以及数据种子 
     /// </summary> 
     /// <param name="dbContext">数据库上下文</param> 
     /// <param name="loggerFactory">日志</param> 
     /// <param name="retry">重试次数</param> 
     /// <returns></returns
     public static async Task SeedAsync(OpenDbContext dbContext, 
         ILoggerFactory loggerFactory, 
         int? retry = 0) 
     { 
         int retryForAvailability = retry.Value; 
         try 
         { 
             dbContext.Database.Migrate();//如果当前数据库不存在按照当前 model 创建,如果存在则将数据库调整到和当前 model 匹配 
             await InitializeAsync(dbContext).ConfigureAwait(false); 
 
             //if (dbContext.Database.EnsureCreated())//如果当前数据库不存在按照当前 model创建,如果存在则不管了。 
             //  await InitializeAsync(dbContext).ConfigureAwait(false); 
         } 
         catch (Exception ex) 
         { 
             if (retryForAvailability < 3) 
             { 
                 retryForAvailability++; 
                 var log = loggerFactory.CreateLogger<OpenDbSend>(); 
                 log.LogError(ex.Message); 
                 await SeedAsync(dbContext, loggerFactory, retryForAvailability).ConfigureAwait(false); 
             } 
         } 
     } 
 
     /// <summary> 
     /// 初始化数据 
     /// </summary> 
     /// <param name="context"></param> 
     /// <returns></returns
     public static async Task InitializeAsync(OpenDbContext context) 
     { 
         if (!context.Set<User>().Any()) 
         { 
             await context.Set<User>().AddAsync(new User("azrng""123456""azrng")).ConfigureAwait(false); 
             await context.Set<User>().AddAsync(new User("张三""123456""azrng")).ConfigureAwait(false); 
         } 
         await context.SaveChangesAsync().ConfigureAwait(false); 
     } 
 } 
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.
  • 12.
  • 13.
  • 14.
  • 15.
  • 16.
  • 17.
  • 18.
  • 19.
  • 20.
  • 21.
  • 22.
  • 23.
  • 24.
  • 25.
  • 26.
  • 27.
  • 28.
  • 29.
  • 30.
  • 31.
  • 32.
  • 33.
  • 34.
  • 35.
  • 36.
  • 37.
  • 38.
  • 39.
  • 40.
  • 41.
  • 42.
  • 43.
  • 44.
  • 45.
  • 46.
  • 47.
  • 48.
  • 49.

设置项目启动时候调用

public static async Task Main(string[] args) 
       { 
           var host = CreateHostBuilder(args).Build(); 
           using (var scope = host.Services.CreateScope()) 
           { 
               var services = scope.ServiceProvider; 
               var loggerFactory = services.GetRequiredService<ILoggerFactory>(); 
               var _logger = loggerFactory.CreateLogger<Program>(); 
               try 
               { 
                   var openContext = services.GetRequiredService<OpenDbContext>(); 
                   await OpenDbSend.SeedAsync(openContext, loggerFactory).ConfigureAwait(false); 
               } 
               catch (Exception ex) 
               { 
                   _logger.LogError(ex, $"项目启动出错  {ex.Message}"); 
               } 
           } 
 
           await host.RunAsync().ConfigureAwait(false); 
       } 
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.
  • 12.
  • 13.
  • 14.
  • 15.
  • 16.
  • 17.
  • 18.
  • 19.
  • 20.
  • 21.

生成数据库

启动项目,自动生成数据库

image.png

表结构如下

image.png

如果后期数据库字段或者结构有变动,可以再次生成迁移文件然后生成数据库

查询数据

/// <summary> 
/// 用户接口 
/// </summary> 
public interface IUserService 

    string GetName(); 
 
    /// <summary> 
    /// 查询用户信息 
    /// </summary> 
    /// <param name="account"></param> 
    /// <returns></returns
    Task<User> GetDetailsAsync(string account); 

 
/// <summary> 
/// 用户实现 
/// </summary> 
public class UserService : IUserService 

    private readonly OpenDbContext _dbContext; 
 
    public UserService(OpenDbContext dbContext) 
    { 
        _dbContext = dbContext; 
    } 
 
    public string GetName() 
    { 
        return "AZRNG"
    } 
 
    ///<inheritdoc cref="IUserService.GetDetailsAsync(string)"/> 
    public async Task<User> GetDetailsAsync(string account) 
    { 
        return await _dbContext.Set<User>().FirstOrDefaultAsync(t => t.Account == account).ConfigureAwait(false); 
    } 

  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.
  • 12.
  • 13.
  • 14.
  • 15.
  • 16.
  • 17.
  • 18.
  • 19.
  • 20.
  • 21.
  • 22.
  • 23.
  • 24.
  • 25.
  • 26.
  • 27.
  • 28.
  • 29.
  • 30.
  • 31.
  • 32.
  • 33.
  • 34.
  • 35.
  • 36.
  • 37.
  • 38.

一般更推荐建立指定的返回Model类,然后只查询需要的内容,不直接返回实体类

控制器方法

/// <summary> 
/// 查询用户详情 
/// </summary> 
/// <param name="account"></param> 
/// <returns></returns
[HttpGet] 
public async Task<ActionResult<User>> GetDetailsAsync(string account) 

    return await _userService.GetDetailsAsync(account).ConfigureAwait(false); 

  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.

查询结果


  "id""e8976d0a-6ee9-4e2e-b8d8-1fe6e85b727b"
  "account""azrng"
  "password""123456"
  "money": 0, 
  "deleted"false
  "creater""azrng"
  "createTime""2021-05-09T15:48:45.730302"
  "modifyer""azrng"
  "modifyTime""2021-05-09T15:48:45.730425" 

  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.

参考文档

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

实体属性:https://docs.microsoft.com/zh-cn/ef/core/modeling/entity-properties?tabs=data-annotations%2Cwithout-nrt

 

责任编辑:武晓燕 来源: 鹏祥
相关推荐

2010-05-07 14:29:45

Unix--Tripw

2016-08-23 13:35:22

MVCEFNuGet

2020-08-06 11:45:37

数据库文档Swagger

2009-12-30 14:12:53

ADO.NET Fra

2009-09-07 22:54:03

Linq组合查询

2024-08-13 10:36:25

SpringScrew数据库

2011-04-15 13:28:44

数据库设计

2017-08-23 13:50:32

2025-01-03 08:13:08

2009-11-04 16:00:20

2011-03-04 09:40:42

AJAX开发集成数据库

2020-12-24 10:20:43

文档工具语言

2010-05-13 14:27:52

访问MySQL

2009-05-14 14:23:25

微软ado.netLINQ

2010-09-30 09:11:01

2010-09-30 08:27:48

2021-09-06 10:24:12

鸿蒙HarmonyOS应用

2009-10-29 17:33:51

VB.NET线程方法

2011-05-26 15:20:46

Oracle数据库导出

2024-03-20 08:37:34

数据处理Python数据分析
点赞
收藏

51CTO技术栈公众号