.NET之生成数据库全流程

发表于:2021-6-22 09:38

字体: | 上一篇 | 下一篇 | 我要投稿

 作者:AZRNG    来源:鹏祥

#
Donet
  开篇语
  本文主要是回顾下从项目创建到生成数据到数据库(代码优先)的全部过程。采用EFCore作为ORM框架。
  本次示例环境:vs2019、net5、mysql
  创建项目
  本次事例代码是用过vs2019创建的ASP.NET Core Web API项目。
  可以通过可视化界面创建或者通过命令行创建。
  dotnet new webapi -o Net5ByDocker 
  创建实体类
  安装连接MySQL数据库组件。
  <PackageReference Include="Pomelo.EntityFrameworkCore.MySql" Version="5.0.0" /> 
      <PackageReference Include="Pomelo.EntityFrameworkCore.MySql.Json.Newtonsoft" Version="5.0.0" /> 
  增加实体类
  [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; 
        } 
    }
  这种只是增加实体类类型的一种方式,可能这种看着比较乱,还可以通过OnModelCreating实现,详情看参考文档。
  增加数据库上下文OpenDbContext。
  public class OpenDbContext : DbContext 
      { 
          public OpenDbContext(DbContextOptions<OpenDbContext> options) 
              : base(options) 
          { 
          } 
   
          public DbSet<User> Users { get; set; } 
      } 
  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); 
              }));
  生成迁移文件
  引用组件:
  <PackageReference Include="Microsoft.EntityFrameworkCore.Design" Version="5.0.5"> 
  <PackageReference Include="Microsoft.EntityFrameworkCore.Tools" Version="5.0.5">
  迁移命令:
  add-migration Init 
  结果:
  要看下生成的迁移文件是否是自己预期的那样子,也可以在这一步就生成数据库,命令: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); 
       } 
   } 
  设置项目启动时候调用。
  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); 
         } 
  生成数据库
  启动项目,自动生成数据库:
  表结构如下:
  如果后期数据库字段或者结构有变动,可以再次生成迁移文件然后生成数据库。
  查询数据
  /// <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); 
      } 
  } 
  一般更推荐建立指定的返回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); 
  } 
  查询结果
  { 
    "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" 
  } 
  参考文档
  实体类型: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

      本文内容不用于商业目的,如涉及知识产权问题,请权利人联系51Testing小编(021-64471599-8017),我们将立即处理
《2023软件测试行业现状调查报告》独家发布~

关注51Testing

联系我们

快捷面板 站点地图 联系我们 广告服务 关于我们 站长统计 发展历程

法律顾问:上海兰迪律师事务所 项棋律师
版权所有 上海博为峰软件技术股份有限公司 Copyright©51testing.com 2003-2024
投诉及意见反馈:webmaster@51testing.com; 业务联系:service@51testing.com 021-64471599-8017

沪ICP备05003035号

沪公网安备 31010102002173号