基于ABP的AppUser对象扩展

  在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

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/283792.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

html (align 、placeholder )

onblur 事件会在对象失去焦点时发生。 onkeyup 事件会在键盘按键被松开时发生。 ----------------------------------------------------------------------------------------------------------- align 属性规定单元格中内容的水平对齐方式。 <td align"value"&…

4种分布式session解决方案

cookie和session的区别和联系 cookie是本地客户端用来存储少量数据信息的&#xff0c;保存在客户端&#xff0c;用户能够很容易的获取&#xff0c;安全性不高&#xff0c;存储的数据量小 session是服务器用来存储部分数据信息&#xff0c;保存在服务器&#xff0c;用户不容易获…

L2-020. 功夫传人

一门武功能否传承久远并被发扬光大&#xff0c;是要看缘分的。一般来说&#xff0c;师傅传授给徒弟的武功总要打个折扣&#xff0c;于是越往后传&#xff0c;弟子们的功夫就越弱…… 直到某一支的某一代突然出现一个天分特别高的弟子&#xff08;或者是吃到了灵丹、挖到了特别的…

找数组里没出现的数

题目&#xff1a;给定整数的数组&#xff0c;其中1≤A [1]≤ N&#xff08;N数组的大小&#xff09;&#xff0c;一些元素出现两次以及其他出现一次。找到不出现在这个数组中的[1&#xff0c;n ]包含的所有元素。 思路&#xff1a;map的思想。。。。 public List<Integer>…

Blazor University (43)JavaScript 互操作 —— 类型安全

原文链接&#xff1a;https://blazor-university.com/javascript-interop/calling-dotnet-from-javascript/type-safety/类型安全在从 JavaScript 调用 .NET[1] 部分中&#xff0c;您可能已经注意到我们的 JavaScript 的第 6 行在将随机生成的数字传递给 .NET 之前调用了 toStr…

分享 60 个神级 VS Code 插件

文章来源&#xff1a;juejin.cn/post/6994327298740600839 本文不做任何编辑器的比较&#xff0c;只是我本人日常使用 vscode 进行开发&#xff0c;并且比较喜欢折腾 vscode &#xff0c;会到处找这一些好玩的插件&#xff0c;于是越攒越多&#xff0c;今天给大家推荐一下我收…

URL结构分析

http://bh-lay.com/blog/14b531db64a

PHP 基础篇 - PHP 中 DES 加解密详解

2019独角兽企业重金招聘Python工程师标准>>> 一、简介 DES 是对称性加密里面常见一种&#xff0c;全称为 Data Encryption Standard&#xff0c;即数据加密标准&#xff0c;是一种使用密钥加密的块算法。密钥长度是64位(bit)&#xff0c;超过位数密钥被忽略。所谓对…

PerfView专题 (第一篇): 如何寻找热点函数

一&#xff1a;背景 准备开个系列来聊一下 PerfView 这款工具&#xff0c;熟悉我的朋友都知道我喜欢用 WinDbg&#xff0c;这东西虽然很牛&#xff0c;但也不是万能的&#xff0c;也有一些场景他解决不了或者很难解决&#xff0c;这时候借助一些其他的工具来辅助&#xff0c;是…

3四则运算软件2016011992

使用JAVA编程语言&#xff0c;独立完成一个3到5个运算符的四则运算练习的命令行软件开发 基本功能要求&#xff1a; 程序可接收一个输入参数n&#xff0c;然后随机产生n道加减乘除&#xff08;分别使用符号-*来表示&#xff09;练习题&#xff0c;每个数字在 0 和 100 之间…

JAVA高并发多线程必须懂的50个问题

下面是Java线程相关的热门面试题&#xff0c;你可以用它来好好准备面试。 1) 什么是线程&#xff1f; 线程是操作系统能够进行运算调度的最小单位&#xff0c;它被包含在进程之中&#xff0c;是进程中的实际运作单位。程序员可以通过它进行多处理器编程&#xff0c;你可以使用…

Centos7设置IP为固定值

1.进入到系统的IP地址保存文件所在目录 [rootlocalhost ~]# cd /etc/sysconfig/network-scripts 2.修改保存IP信息的文件 [rootlocalhost ~]# vim ifcfg-eth0 &#xff08;你机器上的名字有可能不是这个&#xff0c;但是是以ifcfg-eth开头的文件&#xff09; 保存后退出 3.重启…

为 EditorConfig 文件开启错误编译失败

前言上次&#xff0c;我们介绍了 EditorConfig 文件可以自定义代码样式规则。但是&#xff0c;当我们想设置代码样式严重性&#xff0c;比如不允许编译成功时&#xff0c;又踩了不少坑。修改无效想把 var 首选项&#xff0c;从“首选"var" 仅重构”&#xff0c;改成“…

【.NET特供-第三季】ASP.NET MVC系列:传统WebForm站点和MVC站点执行机制对照

本文以图形化的方式&#xff0c;从‘执行机制’方面对照传统WebForm站点和MVC站点。请參看下面图形&#xff1a; 一、执行机制 当我们訪问一个站点的时候&#xff0c;浏览器和server都是做了哪些动作呢&#xff1f; &#xff08;本文仅仅是提供一个简单的执行过程&#xff0c;有…

hdoj1045 Fire Net(二分图最大匹配)

题意&#xff1a;给出一个图&#xff0c;其中有 . 和 X 两种&#xff0c;. 为通路&#xff0c;X表示墙&#xff0c;在其中放炸弹&#xff0c;然后炸弹不能穿过墙&#xff0c;问你最多在图中可以放多少个炸弹&#xff1f; 这个题建图有点复杂orz。 建图&#xff0c;首先把每一行…

c++的命名空间

一.C的命名原则namespace是指标识符的各种可见范围&#xff0c;c的所有标识符都被定义在一个名为std的namespace中。1.<iostream>和<iostream.h>是两个不同的文件&#xff0c;后缀为.h的头文件c标准已经明确提出不支持了&#xff0c;早些的实现将标准库功能定义在全…

投阿里被拒,说跳槽太频繁!三年两个工作,问题真的那么大吗?

什么样的跳槽频率才不算频繁&#xff1f;一位网友发问&#xff1a;投阿里被拒&#xff0c;理由是跳槽太频繁&#xff0c;不合适。三年两个工作&#xff0c;问题真的那么大吗&#xff1f;网友说&#xff0c;阿里对稳定性要求非常高&#xff0c;三年两跳和五年三跳都是红线&#…

Linux下防御DDOS攻击的操作梳理

DDOS的全称是Distributed Denial of Service&#xff0c;即"分布式拒绝服务攻击"&#xff0c;是指击者利用大量“肉鸡”对攻击目标发动大量的正常或非正常请求、耗尽目标主机资源或网络资源&#xff0c;从而使被攻击的主机不能为合法用户提供服务。 DDOS攻击的本质是…

为什么信息化 ≠ 数字化?终于有人讲明白了

作者&#xff1a;石秀峰 来源&#xff1a;谈数据&#xff08;ID&#xff1a;learning-bigdata&#xff09; 近期&#xff0c;我一做数字化咨询的朋友&#xff08;化名老王&#xff09;遇到了一个头痛的问题&#xff1a;话说老王的团队近期接了一个大单——一大型制造业的数字化…

JAVA代码—算法基础:数独问题(Sodoku Puzzles)

JAVA代码—算法基础&#xff1a;数独问题&#xff08;Sodoku Puzzles&#xff09; 数独问题&#xff08;Sodoku Puzzles&#xff09; 数独游戏&#xff08;日语&#xff1a;数独 すうどく&#xff09;是一种源自18世纪末的瑞士的游戏&#xff0c;后在美国发展、并在日本得以发扬…