基于ABP的AppUser对象扩展

虚幻大学 xuhss 198℃ 0评论

? 优质资源分享 ?

学习路线指引(点击解锁) 知识定位 人群定位
? Python实战微信订餐小程序 ? 进阶级 本课程是python flask+微信小程序的完美结合,从项目搭建到腾讯云部署上线,打造一个全栈订餐系统。
?Python量化交易实战? 入门级 手把手带你打造一个易扩展、更安全、效率更高的量化交易系统

  在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
                .MapEfCorePropertystring>(nameof(AppUser.OpenId), (entityBuilder, propertyBuilder) =>
 {
 propertyBuilder.HasMaxLength(128);
 propertyBuilder.HasDefaultValue("");
 propertyBuilder.IsRequired();
 }
 );
 });
 }
}

三.数据库上下文

BaseServiceDbContext.cs位于BaseService.EntityFrameworkCore项目中,如下:

[ConnectionStringName("Default")]
public class BaseServiceDbContext : AbpDbContext
{
 ......

 public BaseServiceDbContext(DbContextOptions options): base(options)
 {
 }

 protected override void OnModelCreating(ModelBuilder builder)
 {
 base.OnModelCreating(builder);

 builder.Entity(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 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(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 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(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

转载请注明:xuhss » 基于ABP的AppUser对象扩展

喜欢 (0)

您必须 登录 才能发表评论!