赞
踩
简介:
1.Code First 是一种使用 C# 编码来创建数据库的方法。它是 Entity Framework 中的一种数据访问方式,旨在通过编写 C# 代码来描述数据模型,然后自动生成数据库模式和表结构,从而简化了数据库开发的过程。
2.传统开发中,通常采用DbFirst的方式开发,先有数据库和表,再将对应的表转为实体。随着技术的发展,开始有了CodeFist的方式开发,先创建实体类,再通过实体类反向的创建数据库和表结构,微软的EF框架就是典型,本系统使用的ORM是SqlSugar,同样也支持CodeFisrt
注意:
1.CodeFirst可以快速开发,使用起来也要分阶段使用,比如早期随便搞,中后期需要禁用一些功能保证数据安全
2.数据库账号需要有比较高的权限,
3.Sqlite不支持删除列和修改列只能添加列
以控制台项目为例
环境信息:
除 Program.cs
外,均按照当前文件层级创建
在 Entity
文件夹下, 实体类对于创建数据库表至关重要,所以要严格检查是否存在遗漏或其他容易出错的地方,
字段的特性时在创建库表时必不可少的条件,所以要创建符合业务的有效信息
#region AuthorInfo // Author:sjx // Date:2023-06-14 16:04 #endregion namespace CodeFirstBySqlSugar.Entity; /// <summary> /// 用户表 /// </summary> [SugarTable("User")] [Description("用户表")] public class User { /// <summary> /// 用户ID,唯一标识用户的编号 /// </summary> [SugarColumn(ColumnDescription = "用户ID,唯一标识用户的编号",IsPrimaryKey = true, IsIdentity = true)] public int UserId { get; set; } /// <summary> /// 用户名,用户的登录名或昵称 /// </summary> [Required, MaxLength(20)] [SugarColumn(ColumnDescription = "用户名,用户的登录名或昵称")] public string UserName { get; set; } /// <summary> /// 密码,用户的登录密码 /// </summary> [Required, MaxLength(50)] [SugarColumn(ColumnDescription = "密码,用户的登录密码")] public string PassWord { get; set; } /// <summary> /// 姓名,用户的真实姓名 /// </summary> [SugarColumn(ColumnDescription = "姓名,用户的真实姓名")] public string FullName { get; set; } /// <summary> /// 性别,用户的性别,通常是男或女 /// </summary> [SugarColumn(ColumnDescription = "性别,用户的性别,通常是男或女")] public string Gender { get; set; } /// <summary> /// 生日,用户的出生日期 /// </summary> [SugarColumn(ColumnDescription = "生日,用户的出生日期")] public DateTime Birthday { get; set; } /// <summary> /// 手机号码,用户的手机号码 /// </summary> [MaxLength(11)] [SugarColumn(ColumnDescription = "手机号码,用户的手机号码")] public string MobileNumber { get; set; } /// <summary> /// 电子邮件,用户的电子邮件地址 /// </summary> [SugarColumn(ColumnDescription = "电子邮件,用户的电子邮件地址")] public string EmailAddress { get; set; } /// <summary> /// 地址,用户的联系地址 /// </summary> [SugarColumn(ColumnDescription = "地址,用户的联系地址")] public string Address { get; set; } /// <summary> /// 注册时间,用户注册账号的时间 /// </summary> [SugarColumn(ColumnDescription = "注册时间,用户注册账号的时间")] public DateTime RegistrationTime { get; set; } = DateTime.Now; }
创建 SqlSugarHelper.cs
类,该类只有一个数据库连接单例,用于帮助迁移数据库表和种子数据,可以根据项目的实际情况自行修改,或使用已存在的数据库连接
#region AuthorInfo // Author:sjx // Date:2023-06-14 16:23 #endregion namespace CodeFirstBySqlSugar; public class SqlSugarHelper { /// <summary> /// 数据库单例 /// </summary> /// <returns></returns> public static SqlSugarScope Db() { return new SqlSugarScope(new ConnectionConfig() { ConnectionString = "Data Source=localhost;Database=code_first_mysql;User ID=code_first_mysql;Password=code_first_mysql;pooling=true;port=3306;SslMode=none;CharSet=utf8;Convert Zero Datetime=True;Allow Zero Datetime=True;AllowLoadLocalInfile=true;", DbType = SqlSugar.DbType.MySql, InitKeyType = InitKeyType.Attribute, MoreSettings = new ConnMoreSettings() { IsAutoRemoveDataCache = true }, IsAutoCloseConnection = true }); } }
在 SeedData
文件夹下,创建 ISeedData.cs
#region AuthorInfo
// Author:sjx
// Date:2023-06-14 18:09
#endregion
namespace CodeFirstBySqlSugar.SeedData;
/// <summary>
/// 实体种子数据接口
/// </summary>
public class ISeedData { }
在 SeedData
文件夹下,创建 ISqlSugarEntitySeedData.cs
#region AuthorInfo // Author:sjx // Date:2023-06-14 16:16 #endregion namespace CodeFirstBySqlSugar.SeedData; /// <summary> /// 泛型接口 ISqlSugarEntitySeedData /// </summary> /// <typeparam name="TEntity"></typeparam> public interface ISqlSugarEntitySeedData<out TEntity> where TEntity: class, new() { /// <summary> /// 种子数据 /// </summary> /// <returns></returns> IEnumerable<TEntity> HasData(); }
在 SeedData
文件夹下,创建 UserSeedData.cs
继承 创建泛型接口 ISeedData
和 ISqlSugarEntitySeedData
有几个实体类就创建多少个种子数据类
#region AuthorInfo // Author:sjx // Date:2023-06-14 16:15 #endregion namespace CodeFirstBySqlSugar.SeedData; /// <summary> /// 种子数据 /// </summary> public class UserSeedData:ISeedData,ISqlSugarEntitySeedData<User> { /// <summary> /// 种子数据 /// </summary> /// <returns></returns> public IEnumerable<User> HasData() { return new List<User>() { new() { UserId = 1, UserName = "admin", PassWord = "123456", FullName = "管理员", Gender = "男", Birthday = DateTime.Parse("1990-01-01"), MobileNumber = "13800138000", EmailAddress = "admin@admin.com", Address = "北京市海淀区", }, new() { UserId = 2, UserName = "user", PassWord = "123456", FullName = "用户", Gender = "男", Birthday = DateTime.Parse("1990-01-01"), MobileNumber = "13800138001", EmailAddress = "user@admin.com", Address = "北京市海淀区", } }; } }
在 Program.cs
创建迁移数据库方法 InitDatabase()
,仔细阅读 注释
和 代码解释
// 初始化表结构 void InitDatabase() { // 简单写法 // SqlSugarHelper.Db().CodeFirst.InitTables(typeof(User)); // 高级写法 // 获取所有实现了 SugarTableAttribute 特性的类 var assembles = new[] { "CodeFirstBySqlSugar.dll" }; // 获取所有实现了 SugarTableAttribute 特性的类 var types = Assembly .LoadFrom(assembles[0]) .GetTypes() .Where(m => m.GetCustomAttribute<SugarTable>() != null) .ToArray(); // 遍历所有实现了 SugarTableAttribute 特性的类 foreach (var type in types) { // 初始化表结构 SqlSugarHelper.Db().CodeFirst.InitTables(type); } // 控制台输出数据库表迁移成功 Console.WriteLine($"{DateTime.Now.ToString(CultureInfo.InvariantCulture)} 数据库表迁移成功"); }
代码解释:
这段代码是一个初始化数据库表结构的函数 InitDatabase()
,用于在应用程序启动时自动迁移数据库表结构。函数使用了 SqlSugar 框架提供的 CodeFirst 功能,可以自动根据实体类生成数据库表结构。
函数分为两个部分:
第一部分使用了简单写法:
直接调用 SqlSugarHelper.Db().CodeFirst.InitTables(typeof(User))
方法初始化 User
实体对应的数据库表结构。
第二部分使用了高级写法:
首先通过 Assembly.LoadFrom
方法加载程序集 CodeFirstBySqlSugar.dll
,然后使用 GetTypes
方法获取程序集中所有的类型,再使用 LINQ 表达式筛选出所有实现了 SugarTableAttribute
特性的类型,存储在 types
数组中。
接着,函数遍历所有实现了 SugarTableAttribute
特性的类型,使用 SqlSugarHelper.Db().CodeFirst.InitTables(type)
方法初始化对应的数据库表结构。
最后,函数控制台输出数据库表迁移成功的提示信息。
在 Program.cs
创建迁移数据库方法 InsertData()
,仔细阅读 注释
和 代码解释
// 创建种子数据 void InsertData() { // 简单写法 // SqlSugarHelper.Db().Insertable(new UserSeedData().HasData().ToList()).ExecuteCommand(); // 高级写法 // 获取所有实现了 ISeedData 接口的类 var assembles = new[] { "CodeFirstBySqlSugar.dll" }; // 获取所有实现了 ISeedData 接口的类 var baseType = typeof(ISeedData); // 获取所有实现了 ISeedData 接口的类 var seedDataTypes = Assembly .LoadFrom(assembles[0]) .GetTypes() .Where(m => baseType.IsAssignableFrom(m) && m is { IsClass: true, IsAbstract: false }) .ToArray(); // 遍历所有实现了 ISeedData 接口的类 foreach (var seedDataType in seedDataTypes) { // 获取实现了 ISeedData 接口的类的实例 var instance = Activator.CreateInstance(seedDataType) as ISeedData; // 获取实现了 ISeedData 接口的类的 HasData 方法 var hasDataMethod = seedDataType.GetMethod("HasData"); // 如果实现了 ISeedData 接口的类没有 HasData 方法,则跳过 if (hasDataMethod?.Invoke(instance, null) is not IEnumerable seedData) continue; // 获取实现了 ISeedData 接口的类的泛型参数 var data = seedData.Cast<object>(); // 获取实现了 ISeedData 接口的类的泛型参数的泛型参数 var entityType = seedDataType.GetInterfaces().First().GetGenericArguments().First(); // 获取实现了 ISeedData 接口的类的泛型参数的泛型参数的表名 var tableName = SqlSugarHelper.Db().EntityMaintenance.GetEntityInfo(entityType).DbTableName; // 将实现了 ISeedData 接口的类的泛型参数的泛型参数转换为 DataTable var seedDataTable = data.ToList().ToDataTable(); // 设置 DataTable 的表名 seedDataTable.TableName = tableName; // 将 DataTable 转换为 Storageable var storage = SqlSugarHelper.Db().Storageable(seedDataTable).ToStorage(); // 执行插入操作 var insertCount = storage.AsInsertable.ExecuteCommand(); // 控制台输出插入数据的数量 Console.WriteLine($"{DateTime.Now.ToString(CultureInfo.InvariantCulture)} {tableName} 表插入 {insertCount} 条数据"); } }
代码解释:
这段代码是一个创建种子数据的函数 InsertData()
,用于在应用程序启动时自动向数据库中添加种子数据。函数使用了 SqlSugar 框架提供的 Insertable 和 Storageable 功能,可以将种子数据转换为 DataTable,并将 DataTable 转换为 Storageable,最后执行插入操作。
函数分为两个部分
第一部分使用了简单写法:
直接调用 SqlSugarHelper.Db().Insertable(new UserSeedData().HasData().ToList()).ExecuteCommand()
方法向数据库中插入 UserSeedData
类中定义的种子数据。
第二部分使用了高级写法:
首先通过 Assembly.LoadFrom
方法加载程序集 CodeFirstBySqlSugar.dll
,然后使用 GetTypes
方法获取程序集中所有的类型,再使用 LINQ 表达式筛选出所有实现了 ISeedData
接口的类型,存储在 seedDataTypes
数组中。
接着,函数遍历所有实现了 ISeedData
接口的类型,使用 Activator.CreateInstance
方法创建类型的实例,并获取类型的 HasData
方法,如果类型没有实现 HasData
方法,则跳过。如果类型实现了 HasData
方法,则调用该方法获取种子数据,并使用 Cast<object>
方法将种子数据转换为 IEnumerable<object>
类型的序列。
然后,获取类型的泛型参数,即实体类的类型,并使用 SqlSugarHelper.Db().EntityMaintenance.GetEntityInfo(entityType).DbTableName
方法获取实体类对应的表名。接着,将种子数据转换为 DataTable,并设置 DataTable 的表名为实体类对应的表名。
最后,将 DataTable 转换为 Storageable,并执行插入操作。函数控制台输出插入数据的数量。
ObjectExtension.cs
#region AuthorInfo // Author:sjx // Date:2023-06-14 17:46 #endregion namespace CodeFirstBySqlSugar; /// <summary> /// 对象扩展 /// </summary> public static class ObjectExtension { /// <summary> /// list转datatable /// </summary> /// <param name="list"></param> /// <typeparam name="T"></typeparam> /// <returns></returns> public static DataTable ToDataTable<T>(this List<T> list) { DataTable result = new(); if (list.Count <= 0) return result; var properties = list[0]?.GetType().GetProperties(); if (properties == null) return result; foreach (var pi in properties) { var colType = pi.PropertyType; if (colType.IsGenericType && colType.GetGenericTypeDefinition() == typeof(Nullable<>)) { colType = colType.GetGenericArguments()[0]; } if (IsIgnoreColumn(pi)) continue; result.Columns.Add(pi.Name, colType); } foreach (var t in list) { ArrayList tempList = new(); foreach (var pi in properties) { if (IsIgnoreColumn(pi)) continue; var obj = pi.GetValue(t, null); tempList.Add(obj); } var array = tempList.ToArray(); result.LoadDataRow(array, true); } return result; } /// <summary> /// 是否忽略列 /// </summary> /// <param name="pi"></param> /// <returns></returns> private static bool IsIgnoreColumn(MemberInfo pi) { var sc = pi.GetCustomAttributes<SugarColumn>(false).FirstOrDefault(u => u.IsIgnore == true); return sc != null; } }
GlobalUsings.cs
(可以不使用全局引用类,可忽略)#region AuthorInfo
// Author:sjx
// Date:2023-06-14 16:05
#endregion
global using System.Collections;
global using System.ComponentModel;
global using System.ComponentModel.DataAnnotations;
global using System.Globalization;
global using System.Reflection;
global using CodeFirstBySqlSugar;
global using CodeFirstBySqlSugar.Entity;
global using CodeFirstBySqlSugar.SeedData;
global using SqlSugar;
global using System.Data;
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。