在ABP中AppUserThe data fields of the table are limited,Now there is a scene that is docking with the applet,需要在AppUser表中添加一个OpenId字段.The problem that a small partner encountered in the group today is based onABP的AppUserAfter the object is expanded,User queries are no problem,But additions and updates will be reported"XXX field is required"的问题.本文以AppUser表扩展OpenIdfield as an example.

一.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; } // WeChat application unique identifier
public string OpenId { get; set; } private AppUser()
{
}
}

因为AppUserInherited from aggregate root,The aggregate root is implemented by defaultIHasExtraProperties接口,Otherwise if you want to extend the entity,Then the entity implementation is requiredIHasExtraProperties接口才行.

二.Entity extension management

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和IdentityUsershare the same table
b.ToTable(AbpIdentityDbProperties.DbTablePrefix + "Users"); b.ConfigureByConvention();
b.ConfigureAbpUser(); b.Property(x => x.OpenId).HasMaxLength(128).HasDefaultValue("").IsRequired().HasColumnName(nameof(AppUser.OpenId));
}); builder.ConfigureBaseService();
}
}

四.Database migrations and updates

1.数据库迁移

dotnet ef migrations add add_appuser_openid

2.数据库更新

dotnet ef database update

3.Operate on extra properties

After database migration and update,在AbpUsersThere will be one more in the databaseOpenId字段,Then you can pass it in the backendSetProperty或者GetPropertyto manipulate additional properties:

// 设置额外属性
var user = await _identityUserRepository.GetAsync(userId);
user.SetProperty("Title", "My custom title value!");
await _identityUserRepository.UpdateAsync(user); // Get extra properties
var user = await _identityUserRepository.GetAsync(userId);
return user.GetProperty<string>("Title");

But what about the front end,主要是通过ExtraPropertiesfield thisjsontype to manipulate additional properties.

五.Application layer addition and modification operations

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()函数

Used in the above add and update operation codeUpdateUserByInput()函数如下:

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();
}
}

  The advantage of entity extension is that there is no need to inherit entities,Or modify the entity to extend the entity,It can be said to be very flexible,But entity expansion is not suitable for complex scenarios,Such as creating indexes and foreign keys with extra properties、Write with extra propertiesSQL或LINQ等.遇到这种情况该怎么办呢?One way is to directly reference the source code and add fields.

参考文献:

[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

基于ABP的AppUserMore related articles on object extensions

  1. ABP(现代ASP.NET样板开发框架)系列之16、ABP应用层——数据传输对象(DTOs)

    点这里进入ABP系列文章总目录 基于DDD的现代ASP.NET开发框架--ABP系列之16.ABP应用层——数据传输对象(DTOs) ABP是“ASP.NET Boilerplate Project ...

  2. ABP应用层——数据传输对象(DTOs)

    ABP应用层——数据传输对象(DTOs) 基于DDD的现代ASP.NET开发框架--ABP系列之16.ABP应用层——数据传输对象(DTOs) ABP是“ASP.NET Boilerplate Pro ...

  3. 基于 abp vNext 和 .NET Core 开发博客项目 - 定时任务最佳实战(三)

    上一篇(https://www.cnblogs.com/meowv/p/12974439.html)完成了全网各大平台的热点新闻数据的抓取,本篇继续围绕抓取完成后的操作做一个提醒.当每次抓取完数据后, ...

  4. 基于 abp vNext 和 .NET Core 开发博客项目 - 博客接口实战篇(一)

    系列文章 基于 abp vNext 和 .NET Core 开发博客项目 - 使用 abp cli 搭建项目 基于 abp vNext 和 .NET Core 开发博客项目 - 给项目瘦身,让它跑起来 ...

  5. 基于 abp vNext 和 .NET Core 开发博客项目 - 博客接口实战篇(二)

    系列文章 基于 abp vNext 和 .NET Core 开发博客项目 - 使用 abp cli 搭建项目 基于 abp vNext 和 .NET Core 开发博客项目 - 给项目瘦身,让它跑起来 ...

  6. 循序渐进VUE+Element 前端应用开发(23)--- 基于ABP实现前后端的附件上传,图片或者附件展示管理

    在我们一般系统中,往往都会涉及到附件的处理,有时候附件是图片文件,有时候是Excel.Word等文件,一般也就是可以分为图片附件和其他附件了,图片附件可以进行裁剪管理.多个图片上传管理,及图片预览操作 ...

  7. 基于ABP落地领域驱动设计-01.全景图

    什么是领域驱动设计? 领域驱动设计(简称:DDD)是一种针对复杂需求的软件开发方法.将软件实现与不断发展的模型联系起来,专注于核心领域逻辑,而不是基础设施细节.DDD适用于复杂领域和大规模应用,而不是 ...

  8. 基于ABP落地领域驱动设计-02.聚合和聚合根的最佳实践和原则

    目录 前言 聚合 聚合和聚合根原则 包含业务原则 单个单元原则 事务边界原则 可序列化原则 聚合和聚合根最佳实践 只通过ID引用其他聚合 用于 EF Core 和 关系型数据库 保持聚合根足够小 聚合 ...

  9. 基于ABP落地领域驱动设计-03.仓储和规约最佳实践和原则

    目录 系列文章 仓储 仓储的通用原则 仓储中不包含领域逻辑 规约 在实体中使用规约 在仓储中使用规约 组合规约 学习帮助 围绕DDD和ABP Framework两个核心技术,后面还会陆续发布核心构件实 ...

  10. 基于ABP落地领域驱动设计-04.领域服务和应用服务的最佳实践和原则

    目录 系列文章 领域服务 应用服务 学习帮助 系列文章 基于ABP落地领域驱动设计-00.目录和前言 基于ABP落地领域驱动设计-01.全景图 基于ABP落地领域驱动设计-02.聚合和聚合根的最佳实践 ...

随机推荐

  1. ADProcessing of converted digital quantities

    The maximum value of the analog input voltage is assumed to be 5V,A/DThe conversion device is 8位转换. [The resolution of this converter is 1/2n=0.3906%.] [The minimum value that can distinguish the input analog voltage change is 5*0.3906%=19.5mv.] Then analog voltage and digital input ...

  2. js密码的校验(判断字符类型、统计字符类型个数)

    /** *判断字符类型 */ function CharMode(iN) { if (iN >= 48 && iN <= 57) //数字 return 1; if (iN ...

  3. Go 语言多维数组

    Go 语言支持多维数组,以下为常用的多维数组声明方式: var variable_name [SIZE1][SIZE2]...[SIZEN] variable_type 以下实例声明了三维的整型数组: ...

  4. session的部分理解

    定义 Session:在计算机中,尤其是在网络应用中,称为“会话控制”.Session 对象存储特定用户会话所需的属性及配置信息.这样,当用户在应用程序的 Web 页之间跳转时,存储在 Session ...

  5. appnium启动报错Encountered internal error running command: Error: Error occured while starting App. Original error: Permission to start activity denied.

    说明写错了activity 首先查看一下activity,使用命令 打开被测app,输入命令adb shell dumpsys window | findstr mCurrentFocus 看似这个a ...

  6. LINUX LVMand snapshot volume configuration and management

    Refer to this article for details: http://www.cnblogs.com/zhaojiedi1992/p/zhaojiedi_linux_042_lvm.html 1.LVM是什么 逻辑卷管理LVM是一个多 ...

  7. wpf(布局与Canvas )

    WPF的布局有控件都在System.Windows.Controls.Panel这个基类下面,常见的布局控件: . canvas: Canvas是最基本的面板,它不会自动调整内部元素的排列及大小,它仅 ...

  8. json字符串与json对象转换

    从网上找的几种常用的转换方法,测试结果如下: 1.json字符串——>json对象 /* test 1 */ var str = '{"a":1,"b": ...

  9. Spark SQLthe overall implementation logic

    1.sqlModule resolution of the statement When we write a query statement,一般包含三个部分,select部分,from数据源部分,whereRestrictions section,The contents of these three parts are insqlhas a special name: 当我们写sql时,如上图所示, ...

  10. Linux知识(2)----中文输入法安装

    Ubantu14.04在English的环境下,没有中文输入法,自带的ibus不完整.现在基于ibus框架,有几个比较好用的输入法,如sunpingyin和google pinying,还有五笔的输入 ...