当前位置:网站首页>基于ABP的AppUser对象扩展
基于ABP的AppUser对象扩展
2022-08-09 23:32:00 【阿升】
在ABP中AppUser表的数据字段是有限的,现在有个场景是和小程序对接,需要在AppUser表中添加一个OpenId字段。今天有个小伙伴在群中遇到的问题是基于ABP的AppUser对象扩展后,用户查询是没有问题的,但是增加和更新就会报"XXX field is required"的问题。本文以AppUser表扩展OpenId字段为例进行介绍。
一.AppUser实体表
AppUser.cs位于BaseService.Domain项目中,如下:
public class AppUser : FullAuditedAggregateRoot<Guid>, IUser
{
public virtual Guid? TenantId { get; private set; }
public virtual string UserName { get; private set; }
public virtual string Name { get; private set; }
public virtual string Surname { get; private set; }
public virtual string Email { get; private set; }
public virtual bool EmailConfirmed { get; private set; }
public virtual string PhoneNumber { get; private set; }
public virtual bool PhoneNumberConfirmed { get; private set; }
// 微信应用唯一标识
public string OpenId { get; set; }
private AppUser()
{
}
}
因为AppUser继承自聚合根,而聚合根默认都实现了IHasExtraProperties接口,否则如果想对实体进行扩展,那么需要实体实现IHasExtraProperties接口才行。
二.实体扩展管理
BaseEfCoreEntityExtensionMappings.cs位于BaseService.EntityFrameworkCore项目中,如下:
public class BaseEfCoreEntityExtensionMappings
{
private static readonly OneTimeRunner OneTimeRunner = new OneTimeRunner();
public static void Configure()
{
BaseServiceModuleExtensionConfigurator.Configure();
OneTimeRunner.Run(() =>
{
ObjectExtensionManager.Instance
.MapEfCoreProperty<IdentityUser, string>(nameof(AppUser.OpenId), (entityBuilder, propertyBuilder) =>
{
propertyBuilder.HasMaxLength(128);
propertyBuilder.HasDefaultValue("");
propertyBuilder.IsRequired();
}
);
});
}
}
三.数据库上下文
BaseServiceDbContext.cs位于BaseService.EntityFrameworkCore项目中,如下:
[ConnectionStringName("Default")]
public class BaseServiceDbContext : AbpDbContext<BaseServiceDbContext>
{
......
public BaseServiceDbContext(DbContextOptions<BaseServiceDbContext> options): base(options)
{
}
protected override void OnModelCreating(ModelBuilder builder)
{
base.OnModelCreating(builder);
builder.Entity<AppUser>(b =>
{
// AbpUsers和IdentityUser共享相同的表
b.ToTable(AbpIdentityDbProperties.DbTablePrefix + "Users");
b.ConfigureByConvention();
b.ConfigureAbpUser();
b.Property(x => x.OpenId).HasMaxLength(128).HasDefaultValue("").IsRequired().HasColumnName(nameof(AppUser.OpenId));
});
builder.ConfigureBaseService();
}
}
四.数据库迁移和更新
1.数据库迁移
dotnet ef migrations add add_appuser_openid
2.数据库更新
dotnet ef database update
3.对额外属性操作
数据库迁移和更新后,在AbpUsers数据库中就会多出来一个OpenId字段,然后在后端中就可以通过SetProperty或者GetProperty来操作额外属性了:
// 设置额外属性
var user = await _identityUserRepository.GetAsync(userId);
user.SetProperty("Title", "My custom title value!");
await _identityUserRepository.UpdateAsync(user);
// 获取额外属性
var user = await _identityUserRepository.GetAsync(userId);
return user.GetProperty<string>("Title");
但是在前端呢,主要是通过ExtraProperties字段这个json类型来操作额外属性的。
五.应用层增改操作
UserAppService.cs位于BaseService.Application项目中,如下:
1.增加操作
[Authorize(IdentityPermissions.Users.Create)]
public async Task<IdentityUserDto> Create(BaseIdentityUserCreateDto input)
{
var user = new IdentityUser(
GuidGenerator.Create(),
input.UserName,
input.Email,
CurrentTenant.Id
);
input.MapExtraPropertiesTo(user);
(await UserManager.CreateAsync(user, input.Password)).CheckErrors();
await UpdateUserByInput(user, input);
var dto = ObjectMapper.Map<IdentityUser, IdentityUserDto>(user);
foreach (var id in input.JobIds)
{
await _userJobsRepository.InsertAsync(new UserJob(CurrentTenant.Id, user.Id, id));
}
foreach (var id in input.OrganizationIds)
{
await _userOrgsRepository.InsertAsync(new UserOrganization(CurrentTenant.Id, user.Id, id));
}
await CurrentUnitOfWork.SaveChangesAsync();
return dto;
}
2.更新操作
[Authorize(IdentityPermissions.Users.Update)]
public async Task<IdentityUserDto> UpdateAsync(Guid id, BaseIdentityUserUpdateDto input)
{
UserManager.UserValidators.Clear();
var user = await UserManager.GetByIdAsync(id);
user.ConcurrencyStamp = input.ConcurrencyStamp;
(await UserManager.SetUserNameAsync(user, input.UserName)).CheckErrors();
await UpdateUserByInput(user, input);
input.MapExtraPropertiesTo(user);
(await UserManager.UpdateAsync(user)).CheckErrors();
if (!input.Password.IsNullOrEmpty())
{
(await UserManager.RemovePasswordAsync(user)).CheckErrors();
(await UserManager.AddPasswordAsync(user, input.Password)).CheckErrors();
}
var dto = ObjectMapper.Map<IdentityUser, IdentityUserDto>(user);
dto.SetProperty("OpenId", input.ExtraProperties["OpenId"]);
await _userJobsRepository.DeleteAsync(_ => _.UserId == id);
if (input.JobIds != null)
{
foreach (var jid in input.JobIds)
{
await _userJobsRepository.InsertAsync(new UserJob(CurrentTenant.Id, id, jid));
}
}
await _userOrgsRepository.DeleteAsync(_ => _.UserId == id);
if (input.OrganizationIds != null)
{
foreach (var oid in input.OrganizationIds)
{
await _userOrgsRepository.InsertAsync(new UserOrganization(CurrentTenant.Id, id, oid));
}
}
await CurrentUnitOfWork.SaveChangesAsync();
return dto;
}
3.UpdateUserByInput()函数
上述增加和更新操作代码中用到的UpdateUserByInput()函数如下:
protected virtual async Task UpdateUserByInput(IdentityUser user, IdentityUserCreateOrUpdateDtoBase input)
{
if (!string.Equals(user.Email, input.Email, StringComparison.InvariantCultureIgnoreCase))
{
(await UserManager.SetEmailAsync(user, input.Email)).CheckErrors();
}
if (!string.Equals(user.PhoneNumber, input.PhoneNumber, StringComparison.InvariantCultureIgnoreCase))
{
(await UserManager.SetPhoneNumberAsync(user, input.PhoneNumber)).CheckErrors();
}
(await UserManager.SetLockoutEnabledAsync(user, input.LockoutEnabled)).CheckErrors();
user.Name = input.Name;
user.Surname = input.Surname;
user.SetProperty("OpenId", input.ExtraProperties["OpenId"]);
if (input.RoleNames != null)
{
(await UserManager.SetRolesAsync(user, input.RoleNames)).CheckErrors();
}
}
实体扩展的好处是不用继承实体,或者修改实体就可以对实体进行扩展,可以说是非常的灵活,但是实体扩展并不适用于复杂的场景,比如使用额外属性创建索引和外键、使用额外属性编写SQL或LINQ等。遇到这种情况该怎么办呢?有种方法是直接引用源码和添加字段。
参考文献:
[1]自定义应用模块:https://docs.abp.io/zh-Hans/abp/6.0/Customizing-Application-Modules-Guide
[2]自定义应用模块-扩展实体:https://docs.abp.io/zh-Hans/abp/6.0/Customizing-Application-Modules-Extending-Entities
[3]自定义应用模块-重写服务:https://docs.abp.io/zh-Hans/abp/6.0/Customizing-Application-Modules-Overriding-Services
[4]ABP-MicroService:https://github.com/WilliamXu96/ABP-MicroService
边栏推荐
猜你喜欢
信息系统项目管理师核心考点(六十四)信息安全基础知识重要概念
Creo5.0 introductory tutorial free material
AUTOCAD——形位公差如何标注、CAD打断于点的操作
YOLOV5 study notes (7) - training your own data set
【集训DAY3】挖金矿【二分答案】
巴比特 | 元宇宙每日必读:国内首个数字人产业专项支持政策发布,2025年北京数字人产业规模将破500亿元...
[SUCTF 2019]CheckIn (.htaccess和.user.ini)
源码编译安装LAMP和LNMP
Wireshark classic practice and interview 13-point summary
工程 (七) ——PolarSeg点云语义分割
随机推荐
Distributed database problem (2): data replication
GoLang 使用 goroutine 停止的几种办法
【Infiltration tool】Browser data export tool
WPF DataGrid using data templates
CAD 连接两个相交线
Why don't suggest you run in Docker Mysql?
Cmake 用法记录
LeetCode常见题型——链表
知行合一的时候
ECCV 2022 | 微软开源TinyViT :搞定小模型的预训练能力
经济衰退即将来临前CIO控制成本的七种方法
JVM Memory and Garbage Collection - 10. Direct Memory
selenium和驱动安装
Alibaba Cloud SMS Service Activation
第十二,十三章 mysql数据类型,视图的课后练习
ES6 Beginner to Mastery #15: Generator Usage
The technical aspects of the byte have been passed, and the salary has been negotiated for 20K*13, but the result is still being brushed. I asked the HR why...
【SSL集训DAY2】有趣的数【数位DP】
deepstream学习笔记(三):deepstream-imagedata-multistream解析与接入适配yolov5模型测试
如何抑制告警风暴?