第四章:实体类与CodeFirst
目录
- 4.1 实体类定义
- 4.2 SqlSugar特性标注
- 4.3 数据类型映射
- 4.4 主键配置
- 4.5 索引配置
- 4.6 实体关系
- 4.7 CodeFirst表创建
- 4.8 数据库迁移
- 4.9 最佳实践
- 本章小结
4.1 实体类定义
4.1.1 基础实体类
实体类是数据库表的C#对象表示,每个实体类对应一张数据库表:
// 基础实体类
public class User
{
public int Id { get; set; }
public string Name { get; set; }
public string Email { get; set; }
public int Age { get; set; }
public DateTime CreateTime { get; set; }
}
// 使用实体类
var db = new SqlSugarClient(config);
var users = db.Queryable<User>().ToList();
4.1.2 实体类约定
SqlSugar遵循以下约定:
// 约定1: 类名对应表名
public class Student { } // 对应表名 Student
// 约定2: 属性名对应列名
public class Product
{
public int ProductId { get; set; } // 对应列名 ProductId
public string ProductName { get; set; } // 对应列名 ProductName
}
// 约定3: 名为Id或{类名}Id的属性自动识别为主键
public class Order
{
public int Id { get; set; } // 自动识别为主键
public string OrderNo { get; set; }
}
public class Customer
{
public int CustomerId { get; set; } // 自动识别为主键
public string CustomerName { get; set; }
}
4.2 SqlSugar特性标注
4.2.1 表特性
使用SugarTable特性自定义表配置:
// 指定表名
[SugarTable("sys_user")]
public class User
{
public int Id { get; set; }
public string Name { get; set; }
}
// 指定表名和描述
[SugarTable("sys_user", "系统用户表")]
public class User
{
public int Id { get; set; }
public string Name { get; set; }
}
// 分表配置
[SplitTable(SplitType.Year)] // 按年分表
[SugarTable("order_{year}")]
public class Order
{
public int Id { get; set; }
public string OrderNo { get; set; }
[SplitField] // 分表字段
public DateTime CreateTime { get; set; }
}
4.2.2 列特性
使用SugarColumn特性配置列:
public class User
{
// 主键,自增
[SugarColumn(IsPrimaryKey = true, IsIdentity = true)]
public int Id { get; set; }
// 指定列名和描述
[SugarColumn(ColumnName = "user_name", ColumnDescription = "用户名")]
public string Name { get; set; }
// 指定数据类型和长度
[SugarColumn(ColumnDataType = "varchar", Length = 50)]
public string Email { get; set; }
// 设置默认值
[SugarColumn(DefaultValue = "0")]
public int Status { get; set; }
// 可空列
[SugarColumn(IsNullable = true)]
public string Remark { get; set; }
// 不映射到数据库
[SugarColumn(IsIgnore = true)]
public string TempData { get; set; }
// 创建时间,插入时自动填充
[SugarColumn(InsertServerTime = true)]
public DateTime CreateTime { get; set; }
// 更新时间,更新时自动填充
[SugarColumn(UpdateServerTime = true)]
public DateTime UpdateTime { get; set; }
// 不可更新字段
[SugarColumn(IsOnlyIgnoreUpdate = true)]
public DateTime CreateTime2 { get; set; }
// 不可插入字段
[SugarColumn(IsOnlyIgnoreInsert = true)]
public DateTime UpdateTime2 { get; set; }
// 唯一约束
[SugarColumn(IsUnique = true)]
public string Email2 { get; set; }
// 索引列
[SugarColumn(IsIndex = true)]
public string Phone { get; set; }
}
4.2.3 主键特性
配置主键的多种方式:
// 方式1: 使用IsPrimaryKey
public class User
{
[SugarColumn(IsPrimaryKey = true, IsIdentity = true)]
public int Id { get; set; }
}
// 方式2: 使用Guid主键
public class Product
{
[SugarColumn(IsPrimaryKey = true)]
public Guid Id { get; set; } = Guid.NewGuid();
}
// 方式3: 使用雪花ID
public class Order
{
[SugarColumn(IsPrimaryKey = true)]
public long Id { get; set; }
}
// 方式4: 复合主键
public class UserRole
{
[SugarColumn(IsPrimaryKey = true)]
public int UserId { get; set; }
[SugarColumn(IsPrimaryKey = true)]
public int RoleId { get; set; }
}
4.3 数据类型映射
4.3.1 C#与数据库类型对应
public class DataTypeMapping
{
// 整数类型
public int IntValue { get; set; } // int, INTEGER
public long LongValue { get; set; } // bigint, BIGINT
public short ShortValue { get; set; } // smallint, SMALLINT
public byte ByteValue { get; set; } // tinyint, TINYINT
// 小数类型
public decimal DecimalValue { get; set; } // decimal, DECIMAL
public double DoubleValue { get; set; } // float, DOUBLE
public float FloatValue { get; set; } // real, FLOAT
// 字符串类型
public string StringValue { get; set; } // nvarchar, VARCHAR
[SugarColumn(ColumnDataType = "char", Length = 10)]
public string CharValue { get; set; } // char, CHAR
[SugarColumn(ColumnDataType = "text")]
public string TextValue { get; set; } // text, TEXT
// 日期时间类型
public DateTime DateTimeValue { get; set; } // datetime, DATETIME
public DateTimeOffset DateTimeOffsetValue { get; set; } // datetimeoffset
// 布尔类型
public bool BoolValue { get; set; } // bit, BOOLEAN
// 二进制类型
public byte[] BinaryValue { get; set; } // varbinary, BLOB
// Guid类型
public Guid GuidValue { get; set; } // uniqueidentifier, VARCHAR(36)
// 可空类型
public int? NullableIntValue { get; set; }
public DateTime? NullableDateTimeValue { get; set; }
}
4.3.2 自定义类型转换
// 枚举类型映射
public enum UserStatus
{
Normal = 0,
Locked = 1,
Deleted = 2
}
public class User
{
public int Id { get; set; }
public string Name { get; set; }
// 枚举保存为整数
public UserStatus Status { get; set; }
// 枚举保存为字符串
[SugarColumn(ColumnDataType = "varchar", Length = 20)]
public UserStatus Status2 { get; set; }
}
// JSON类型映射
public class Product
{
public int Id { get; set; }
public string Name { get; set; }
// 复杂对象保存为JSON字符串
[SugarColumn(IsJson = true)]
public ProductDetail Detail { get; set; }
}
public class ProductDetail
{
public string Brand { get; set; }
public string Model { get; set; }
public List<string> Tags { get; set; }
}
// 自定义序列化
public class CustomSerialize
{
public void Configure(SqlSugarClient db)
{
db.CurrentConnectionConfig.ConfigureExternalServices = new ConfigureExternalServices()
{
SerializeService = new CustomSerializeService()
};
}
}
public class CustomSerializeService : ISerializeService
{
public string SerializeObject(object value)
{
return Newtonsoft.Json.JsonConvert.SerializeObject(value);
}
public T DeserializeObject<T>(string value)
{
return Newtonsoft.Json.JsonConvert.DeserializeObject<T>(value);
}
}
4.4 主键配置
4.4.1 单一主键
// 自增主键
public class User
{
[SugarColumn(IsPrimaryKey = true, IsIdentity = true)]
public int Id { get; set; }
}
// 手动赋值主键
public class Product
{
[SugarColumn(IsPrimaryKey = true)]
public string ProductCode { get; set; }
}
// Guid主键
public class Order
{
[SugarColumn(IsPrimaryKey = true)]
public Guid Id { get; set; } = Guid.NewGuid();
}
4.4.2 复合主键
// 用户角色关联表
[SugarTable("user_role")]
public class UserRole
{
[SugarColumn(IsPrimaryKey = true)]
public int UserId { get; set; }
[SugarColumn(IsPrimaryKey = true)]
public int RoleId { get; set; }
public DateTime CreateTime { get; set; }
}
// 插入数据
var userRole = new UserRole
{
UserId = 1,
RoleId = 2,
CreateTime = DateTime.Now
};
db.Insertable(userRole).ExecuteCommand();
4.4.3 自增主键
public class AutoIncrementExample
{
public void InsertWithIdentity()
{
var db = new SqlSugarClient(config);
var user = new User
{
Name = "张三",
Email = "zhangsan@test.com"
};
// 插入并返回自增ID
var id = db.Insertable(user).ExecuteReturnIdentity();
Console.WriteLine($"新用户ID: {id}");
// 插入后实体的Id属性也会被赋值
Console.WriteLine($"实体ID: {user.Id}");
}
}
4.5 索引配置
4.5.1 普通索引
public class User
{
[SugarColumn(IsPrimaryKey = true, IsIdentity = true)]
public int Id { get; set; }
// 普通索引
[SugarColumn(IsIndex = true)]
public string Email { get; set; }
[SugarColumn(IsIndex = true)]
public string Phone { get; set; }
}
4.5.2 唯一索引
public class User
{
[SugarColumn(IsPrimaryKey = true, IsIdentity = true)]
public int Id { get; set; }
// 唯一索引
[SugarColumn(IsUnique = true)]
public string Username { get; set; }
[SugarColumn(IsUnique = true)]
public string Email { get; set; }
}
4.5.3 复合索引
// 使用IndexAttribute创建复合索引
[SugarTable("order_detail")]
[SugarIndex("idx_order_product", nameof(OrderId), nameof(ProductId), OrderByType.Asc)]
public class OrderDetail
{
[SugarColumn(IsPrimaryKey = true, IsIdentity = true)]
public int Id { get; set; }
public int OrderId { get; set; }
public int ProductId { get; set; }
public int Quantity { get; set; }
public decimal Price { get; set; }
}
// 多个复合索引
[SugarTable("log")]
[SugarIndex("idx_user_time", nameof(UserId), nameof(CreateTime), OrderByType.Desc)]
[SugarIndex("idx_type_time", nameof(LogType), nameof(CreateTime), OrderByType.Desc)]
public class Log
{
[SugarColumn(IsPrimaryKey = true, IsIdentity = true)]
public int Id { get; set; }
public int UserId { get; set; }
public string LogType { get; set; }
public string Content { get; set; }
public DateTime CreateTime { get; set; }
}
4.6 实体关系
4.6.1 一对一关系
// 用户表
public class User
{
[SugarColumn(IsPrimaryKey = true, IsIdentity = true)]
public int Id { get; set; }
public string Name { get; set; }
// 导航属性
[Navigate(NavigateType.OneToOne, nameof(UserId))]
public UserProfile Profile { get; set; }
}
// 用户资料表
public class UserProfile
{
[SugarColumn(IsPrimaryKey = true)]
public int UserId { get; set; }
public string Avatar { get; set; }
public string Bio { get; set; }
}
4.6.2 一对多关系
// 部门表
public class Department
{
[SugarColumn(IsPrimaryKey = true, IsIdentity = true)]
public int Id { get; set; }
public string Name { get; set; }
// 导航属性: 一个部门有多个员工
[Navigate(NavigateType.OneToMany, nameof(Employee.DepartmentId))]
public List<Employee> Employees { get; set; }
}
// 员工表
public class Employee
{
[SugarColumn(IsPrimaryKey = true, IsIdentity = true)]
public int Id { get; set; }
public string Name { get; set; }
public int DepartmentId { get; set; }
// 导航属性: 多个员工属于一个部门
[Navigate(NavigateType.ManyToOne, nameof(DepartmentId))]
public Department Department { get; set; }
}
4.6.3 多对多关系
// 学生表
public class Student
{
[SugarColumn(IsPrimaryKey = true, IsIdentity = true)]
public int Id { get; set; }
public string Name { get; set; }
// 导航属性: 多对多关系
[Navigate(typeof(StudentCourse), nameof(StudentCourse.StudentId), nameof(StudentCourse.CourseId))]
public List<Course> Courses { get; set; }
}
// 课程表
public class Course
{
[SugarColumn(IsPrimaryKey = true, IsIdentity = true)]
public int Id { get; set; }
public string Name { get; set; }
// 导航属性: 多对多关系
[Navigate(typeof(StudentCourse), nameof(StudentCourse.CourseId), nameof(StudentCourse.StudentId))]
public List<Student> Students { get; set; }
}
// 中间表
public class StudentCourse
{
[SugarColumn(IsPrimaryKey = true)]
public int StudentId { get; set; }
[SugarColumn(IsPrimaryKey = true)]
public int CourseId { get; set; }
public DateTime EnrollDate { get; set; }
public decimal? Score { get; set; }
}
4.7 CodeFirst表创建
4.7.1 创建单表
public class CreateTableExample
{
public void CreateSingleTable()
{
var db = new SqlSugarClient(config);
// 根据实体类创建表
db.CodeFirst.InitTables<User>();
Console.WriteLine("用户表创建成功");
}
public void CreateTableWithBackup()
{
var db = new SqlSugarClient(config);
// 创建表前备份
db.CodeFirst.BackupTable().InitTables<User>();
}
}
4.7.2 批量创建表
public class BatchCreateTables
{
public void CreateMultipleTables()
{
var db = new SqlSugarClient(config);
// 方式1: 指定多个类型
db.CodeFirst.InitTables(
typeof(User),
typeof(Department),
typeof(Employee),
typeof(Product),
typeof(Order)
);
// 方式2: 通过反射获取所有实体类
var types = Assembly.GetExecutingAssembly()
.GetTypes()
.Where(t => t.Namespace == "YourNamespace.Entities")
.ToArray();
db.CodeFirst.InitTables(types);
Console.WriteLine($"成功创建{types.Length}张表");
}
public void CreateTablesWithOptions()
{
var db = new SqlSugarClient(config);
// 设置表创建选项
db.CodeFirst.SetStringDefaultLength(200); // 字符串默认长度
// 只创建不存在的表
db.CodeFirst.InitTables(typeof(User), typeof(Product));
}
}
4.7.3 表存在性检查
public class TableExistenceCheck
{
public void CheckAndCreateTable()
{
var db = new SqlSugarClient(config);
// 检查表是否存在
if (!db.DbMaintenance.IsAnyTable("User", false))
{
db.CodeFirst.InitTables<User>();
Console.WriteLine("创建User表");
}
else
{
Console.WriteLine("User表已存在");
}
}
public void GetTableList()
{
var db = new SqlSugarClient(config);
// 获取所有表名
var tables = db.DbMaintenance.GetTableInfoList(false);
foreach (var table in tables)
{
Console.WriteLine($"表名: {table.Name}, 描述: {table.Description}");
}
}
}
4.8 数据库迁移
4.8.1 表结构同步
public class DatabaseMigration
{
public void SyncTableStructure()
{
var db = new SqlSugarClient(config);
// 对比表结构差异
var diffString = db.CodeFirst.GetDifferenceTables<User>().ToDiffString();
Console.WriteLine(diffString);
// 同步表结构(添加新列、修改列类型等)
db.CodeFirst.SetStringDefaultLength(200)
.InitTables<User>();
}
public void AddColumn()
{
var db = new SqlSugarClient(config);
// 添加列
if (!db.DbMaintenance.IsAnyColumn("User", "Age"))
{
db.DbMaintenance.AddColumn("User", new DbColumnInfo
{
ColumnName = "Age",
DataType = "int",
IsNullable = false,
DefaultValue = "0"
});
}
}
public void UpdateColumn()
{
var db = new SqlSugarClient(config);
// 修改列
db.DbMaintenance.UpdateColumn("User", new DbColumnInfo
{
ColumnName = "Name",
DataType = "varchar(100)",
IsNullable = false
});
}
public void DropColumn()
{
var db = new SqlSugarClient(config);
// 删除列
if (db.DbMaintenance.IsAnyColumn("User", "TempColumn"))
{
db.DbMaintenance.DropColumn("User", "TempColumn");
}
}
}
4.8.2 备份与迁移
public class BackupAndMigration
{
public void BackupTable()
{
var db = new SqlSugarClient(config);
// 备份表
var backupTableName = $"User_Backup_{DateTime.Now:yyyyMMddHHmmss}";
db.DbMaintenance.BackupTable("User", backupTableName);
Console.WriteLine($"表已备份到: {backupTableName}");
}
public void ExportTableStructure()
{
var db = new SqlSugarClient(config);
// 获取建表SQL
var createTableSql = db.DbMaintenance.CreateTableScript<User>();
Console.WriteLine(createTableSql);
// 保存到文件
File.WriteAllText("User_CreateTable.sql", createTableSql);
}
public void MigrateData()
{
var sourceDb = new SqlSugarClient(sourceConfig);
var targetDb = new SqlSugarClient(targetConfig);
// 创建目标表
targetDb.CodeFirst.InitTables<User>();
// 迁移数据
var users = sourceDb.Queryable<User>().ToList();
targetDb.Insertable(users).ExecuteCommand();
Console.WriteLine($"成功迁移{users.Count}条数据");
}
}
4.9 最佳实践
// 1. 使用基类实体
public abstract class BaseEntity
{
[SugarColumn(IsPrimaryKey = true, IsIdentity = true)]
public int Id { get; set; }
[SugarColumn(InsertServerTime = true, IsOnlyIgnoreUpdate = true)]
public DateTime CreateTime { get; set; }
[SugarColumn(UpdateServerTime = true)]
public DateTime UpdateTime { get; set; }
[SugarColumn(IsNullable = true)]
public int? CreateUserId { get; set; }
[SugarColumn(IsNullable = true)]
public int? UpdateUserId { get; set; }
[SugarColumn(DefaultValue = "0")]
public bool IsDeleted { get; set; }
}
public class User : BaseEntity
{
public string Name { get; set; }
public string Email { get; set; }
}
// 2. 实体类分层
namespace YourProject.Entities
{
// 系统模块
namespace System
{
public class User : BaseEntity { }
public class Role : BaseEntity { }
public class Permission : BaseEntity { }
}
// 业务模块
namespace Business
{
public class Order : BaseEntity { }
public class Product : BaseEntity { }
}
}
// 3. 使用数据注解验证
using System.ComponentModel.DataAnnotations;
public class User : BaseEntity
{
[Required(ErrorMessage = "用户名不能为空")]
[StringLength(50, ErrorMessage = "用户名长度不能超过50")]
public string Name { get; set; }
[Required(ErrorMessage = "邮箱不能为空")]
[EmailAddress(ErrorMessage = "邮箱格式不正确")]
public string Email { get; set; }
[Range(1, 150, ErrorMessage = "年龄必须在1-150之间")]
public int Age { get; set; }
}
// 4. 实体类文档注释
/// <summary>
/// 用户实体类
/// </summary>
[SugarTable("sys_user", "系统用户表")]
public class User : BaseEntity
{
/// <summary>
/// 用户名
/// </summary>
[SugarColumn(ColumnDescription = "用户名")]
public string Name { get; set; }
/// <summary>
/// 邮箱
/// </summary>
[SugarColumn(ColumnDescription = "邮箱")]
public string Email { get; set; }
}
// 5. 版本化迁移
public class MigrationVersion
{
private readonly SqlSugarClient _db;
public MigrationVersion(SqlSugarClient db)
{
_db = db;
}
public void ApplyMigrations()
{
var currentVersion = GetCurrentVersion();
if (currentVersion < 1)
{
Migration_V1();
}
if (currentVersion < 2)
{
Migration_V2();
}
}
private int GetCurrentVersion()
{
// 从版本表获取当前版本
return 0;
}
private void Migration_V1()
{
// 初始化表
_db.CodeFirst.InitTables<User>();
_db.CodeFirst.InitTables<Role>();
}
private void Migration_V2()
{
// 添加新字段
_db.DbMaintenance.AddColumn("User", new DbColumnInfo
{
ColumnName = "Phone",
DataType = "varchar(20)"
});
}
}
常见陷阱
- 忘记配置主键: 导致无法正确执行更新和删除操作
- 字段名与数据库关键字冲突: 使用IsIgnore或ColumnName避免
- 导航属性未正确配置: 导致无法正确加载关联数据
- CodeFirst与现有数据库冲突: 使用BackupTable进行备份
- 枚举类型未指定保存方式: 可能导致数据不一致
本章小结
本章详细介绍了SqlSugar的实体类与CodeFirst功能:
- 实体类定义: 掌握了实体类的基本定义和约定
- 特性标注: 学习了各种SqlSugar特性的使用方法
- 数据类型映射: 了解了C#类型与数据库类型的对应关系
- 主键和索引: 掌握了主键和索引的配置方法
- 实体关系: 学习了一对一、一对多、多对多关系的配置
- CodeFirst: 掌握了使用代码创建数据库表的方法
- 数据库迁移: 学习了表结构同步和数据迁移的技巧
- 最佳实践: 总结了实体类设计的最佳实践
通过本章的学习,你应该能够熟练设计实体类并使用CodeFirst功能管理数据库结构。
下一章: 第五章-基础CRUD操作