基于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.pswp.cn/news/283792.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/283792.shtml
英文地址,請注明出處:http://en.pswp.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;后在美國發展、并在日本得以發揚…