初識ABP vNext(5):ABP擴充套件實體

xhznl發表於2020-08-21

Tips:本篇已加入系列文章閱讀目錄,可點選檢視更多相關文章。

前言

上一篇實現了前端vue部分的使用者登入和選單許可權控制,但是有一些問題需要解決,比如使用者頭像、使用者介紹欄位目前還沒有,下面就來完善一下。

開始

因為使用者實體是ABP模板自動生成的,其中的屬性都預先定義好了,但是ABP是允許我們擴充套件模組實體的,我們可以通過擴充套件使用者實體來增加使用者頭像和使用者介紹欄位。

擴充套件實體

ABP支援多種擴充套件實體的方式:

  1. 將所有擴充套件屬性以json格式儲存在同一個資料庫欄位中
  2. 將每個擴充套件屬性儲存在獨立的資料庫欄位中
  3. 建立一個新的實體類對映到原有實體的同一個資料庫表中
  4. 建立一個新的實體類對映到獨立的資料庫表中

這裡選擇第2種方式就好,它們的具體區別請見官網:擴充套件實體

src\Xhznl.HelloAbp.Domain\Users\AppUser.cs:

/// <summary>
/// 頭像
/// </summary>
public string Avatar { get; set; }

/// <summary>
/// 個人介紹
/// </summary>
public string Introduction { get; set; }

src\Xhznl.HelloAbp.EntityFrameworkCore\EntityFrameworkCore\HelloAbpDbContext.cs:

builder.Entity<AppUser>(b =>
{
    。。。。。。
        
    b.Property(x => x.Avatar).IsRequired(false).HasMaxLength(AppUserConsts.MaxAvatarLength).HasColumnName(nameof(AppUser.Avatar));
    b.Property(x => x.Introduction).IsRequired(false).HasMaxLength(AppUserConsts.MaxIntroductionLength).HasColumnName(nameof(AppUser.Introduction));
});

src\Xhznl.HelloAbp.EntityFrameworkCore\EntityFrameworkCore\HelloAbpEfCoreEntityExtensionMappings.cs:

OneTimeRunner.Run(() =>
{
    ObjectExtensionManager.Instance
        .MapEfCoreProperty<IdentityUser, string>(
            nameof(AppUser.Avatar),
            b => { b.HasMaxLength(AppUserConsts.MaxAvatarLength); }
        )
        .MapEfCoreProperty<IdentityUser, string>(
            nameof(AppUser.Introduction),
            b => { b.HasMaxLength(AppUserConsts.MaxIntroductionLength); }
        );
});

src\Xhznl.HelloAbp.Application.Contracts\HelloAbpDtoExtensions.cs:

OneTimeRunner.Run(() =>
{
    ObjectExtensionManager.Instance
        .AddOrUpdateProperty<string>(
            new[]
            {
                typeof(IdentityUserDto),
                typeof(IdentityUserCreateDto),
                typeof(IdentityUserUpdateDto),
                typeof(ProfileDto),
                typeof(UpdateProfileDto)
            },
            "Avatar"
        )
        .AddOrUpdateProperty<string>(
            new[]
            {
                typeof(IdentityUserDto),
                typeof(IdentityUserCreateDto),
                typeof(IdentityUserUpdateDto),
                typeof(ProfileDto),
                typeof(UpdateProfileDto)
            },
            "Introduction"
        );
});

注意最後一步,Dto也需要新增擴充套件屬性,不然就算你實體中已經有了新欄位,但介面依然獲取不到。

然後就是新增遷移更新資料庫了:

Add-Migration Added_AppUser_Properties

Update-Database 也可以不用update,執行DbMigrator專案來更新

檢視資料庫,AppUsers表已經生成這2個欄位了:

目前還沒做設定介面,我先手動給2個初始值:

再次請求/api/identity/my-profile介面,已經返回了這2個擴充套件欄位:

修改一下前端部分:

src\store\modules\user.js:

// get user info
getInfo({ commit }) {
  return new Promise((resolve, reject) => {
    getInfo()
      .then(response => {
        const data = response;
        if (!data) {
          reject("Verification failed, please Login again.");
        }
        const { name, extraProperties } = data;
        commit("SET_NAME", name);
        commit("SET_AVATAR", extraProperties.Avatar);
        commit("SET_INTRODUCTION", extraProperties.Introduction);
        resolve(data);
      })
      .catch(error => {
        reject(error);
      });
  });
},

重新整理介面,右上角的使用者頭像就回來了:

路由整理

刪除掉vue-element-admin多餘的路由,並新增ABP模板自帶的身份認證管理和租戶管理。

src\router\index.js:

/* Router Modules */
import identityRouter from "./modules/identity";
import tenantRouter from "./modules/tenant";

export const asyncRoutes = [
  /** when your routing map is too long, you can split it into small modules **/
  identityRouter,
  tenantRouter,
  // 404 page must be placed at the end !!!
  { path: "*", redirect: "/404", hidden: true }
];

src\router\modules\identity.js:

/** When your routing table is too long, you can split it into small modules **/

import Layout from "@/layout";

const identityRouter = {
  path: "/identity",
  component: Layout,
  redirect: "noRedirect",
  name: "Identity",
  meta: {
    title: "identity",
    icon: "user"
  },
  children: [
    {
      path: "roles",
      component: () => import("@/views/identity/roles"),
      name: "Roles",
      meta: { title: "roles", policy: "AbpIdentity.Roles" }
    },
    {
      path: "users",
      component: () => import("@/views/identity/users"),
      name: "Users",
      meta: { title: "users", policy: "AbpIdentity.Users" }
    }
  ]
};
export default identityRouter;

src\router\modules\tenant.js:

/** When your routing table is too long, you can split it into small modules **/

import Layout from "@/layout";

const tenantRouter = {
  path: "/tenant",
  component: Layout,
  redirect: "/tenant/tenants",
  alwaysShow: true,
  name: "Tenant",
  meta: {
    title: "tenant",
    icon: "tree"
  },
  children: [
    {
      path: "tenants",
      component: () => import("@/views/tenant/tenants"),
      name: "Tenants",
      meta: { title: "tenants", policy: "AbpTenantManagement.Tenants" }
    }
  ]
};
export default tenantRouter;

執行效果:

對應ABP模板介面:

最後

本篇介紹了ABP擴充套件實體的基本使用,並且整理了前端部分的系統選單,但是選單的文字顯示不對。下一篇將介紹ABP本地化,讓系統文字支援多國語言。

相關文章