DDD Code First 迁移数据实现EF CORE的软删除,值对象迁移配置
感谢Jeffcky大佬的博客:
EntityFramework Core 2.0全局过滤 (HasQueryFilter) https://www.cnblogs.com/CreateMyself/p/8491058.html什么是值对象
没有唯一的标识,固定不变的,表示一个具体的概念,用来描述一个东西的特征,代表是什么,使用时直接添加或替换,值对象在迁移时,会以字段的形式迁移到数据库中软删除
定义删除的接口public interface ISoftDelete { bool IsDeleted { get; set; } }
创建模型实现ISoftDelete接口
public class UserInfo : IAggregationRoot, ISoftDelete { public Guid Id { get; set; } public string UserName { get; private set; } public string UserPassword { get; private set; } public string UserPhone { get; private set; } public Address Address { get; private set; } public bool IsDeleted { get; set; } } [Owned] public class Address:IValueObject { public string Province { get;private set; } public string City { get; private set; } public string County { get; private set; } public string AddressDetails { get; private set; } }
Lamda的扩展以及Code First 迁移配置
protected override void OnModelCreating(ModelBuilder modelBuilder) { //设置软删除 foreach (var entityType in modelBuilder.Model.GetEntityTypes()) { var parameter = Expression.Parameter(entityType.ClrType); //查询类上面是否有Owned(值对象)的特性 var ownedModelType = parameter.Type; var ownedAttribute = Attribute.GetCustomAttribute(ownedModelType, typeof(OwnedAttribute)); if (ownedAttribute == null) { var propertyMethodInfo = typeof(EF).GetMethod("Property").MakeGenericMethod(typeof(bool)); var isDeletedProperty = Expression.Call(propertyMethodInfo, parameter, Expression.Constant("IsDeleted")); BinaryExpression compareExpression = Expression.MakeBinary(ExpressionType.Equal, isDeletedProperty, Expression.Constant(false)); var lambda = Expression.Lambda(compareExpression, parameter); modelBuilder.Entity(entityType.ClrType).HasQueryFilter(lambda); } } }
在这里需要过滤掉值对象的类,在值对象的类上面声明一个特性,通过该特性过滤掉该值对象, 如果该类是值对象就直接跳过,不过滤值对象EF CORE会给值对象附加一个IsDeleted的字段,EF CORE执行中会报错,提示找不到该字段
Owned是EF CORE 配置值对象的特性,可以去自定义特性,在每一个值对象上面声明,在OnModelCreating 过滤掉包含这个特性的类
最终实现的代码:
public async Task>> GetUserList(SearchUserDto input)
{
Expression> where = e => e.IsDisable == false;
if (!string.IsNullOrEmpty(input.SearchName))
{
where = where.And(e => e.UserName.Contains(input.SearchName));
}
if (!string.IsNullOrEmpty(input.SearchPwd))
{
where = where.And(e => e.UserPhone.Contains(input.SearchPwd));
}
var userList = await _userRepository.LoadEntityListAsync(where, e => e.UserName, "asc", input.PageIndex, input.Pagesize);
var total = await _userRepository.GetEntitiesCountAsync(where);
var userDtoList = userList.MapToList<UserInfo, UserDto>();
HeaderResult<List<UserDto>> result = new HeaderResult<List<UserDto>>
{
IsSucceed = true,
Result = userDtoList,
Total = total
};
return result;
}
</pre>
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· go语言实现终端里的倒计时
· 如何编写易于单元测试的代码
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· 周边上新:园子的第一款马克杯温暖上架
· 分享 3 个 .NET 开源的文件压缩处理库,助力快速实现文件压缩解压功能!
· Ollama——大语言模型本地部署的极速利器
· DeepSeek如何颠覆传统软件测试?测试工程师会被淘汰吗?
· 使用C#创建一个MCP客户端