AspnetBoilerplate (ABP) Organization Units 組織結構管理


ABP是一個成熟的.NET框架,功能完善。目前由於項目需要正在自學中。

ABP對於組織節點管理這一基本上每個項目都要反復重復開發的內容,進行了自己的實現。

主要包括這些常用功能:

  • 多租戶
  • 樹結構管理的實體
  • 與用戶系統集成的查詢

下面我們根據官方文檔以及DEMO去學習這個功能。

不過需要注意的是,ABP默認沒有提供展示層的實現,這一塊就需要自己實現了。

官方文檔理解

 OrganizationUnit 實體定義

  • TenantId: 租戶ID,如果為null則是host的組織節點。(具體概念參閱多租戶)
  • ParentId: 父節點Id,如果為null則是根節點。
  • Code: 一個拼接的虛擬路徑字符串代碼,在租戶內唯一。
  • DisplayName: 顯示名稱

Organization Tree

模型定義中的ParentId使得這個數據結構定義了一個典型的父子樹。

  • 這個樹允許有多個根節點
  • 樹的最大深度是OrganizationUnit.MaxDepth,值為16
  • 每一級子節點的數目也有限制,主要是由於后面要提到的OU Code定義決定的。

OU Code

OU Code由OrganizationUnit Manager自動維護,它是類似於"00001.00042.00005"的字符串。它可以用於遞歸查詢。

這種字段在樹結構中是很必須的,如果沒有它,樹查詢會變成效率的殺手。有了這類虛擬路徑,可以通過分隔符分解后批量查詢。

Abp對OU Code有以下規則:

  •  在一個租戶中唯一
  • 子節點的Code需要以父節點的Code開頭
  • Code的長度,由層級深度決定
  • OU Code可以被改變,例如移動節點
  • 我們需要使用Id作為OU引用的字段,而不是Code

OrganizationUnit Manager

  • OrganizationUnitManager 通過依賴注入引入,一般用於:
  • 增、刪、改OU
  • 移動OU
  • 讀取OU信息,以及OU的items

Multi-Tenancy

OrganizationUnitManager 一次只能操作一個租戶,默認租戶為當前租戶。

樣例代碼分析

首先創建一個實體,派生自IMustHaveTenant , IMustHaveOrganizationUnit

 

public class Product : Entity, IMustHaveTenant, IMustHaveOrganizationUnit
{
    public virtual int TenantId { get; set; }

    public virtual long OrganizationUnitId { get; set; }
    
    public virtual string Name { get; set; }

    public virtual float Price { get; set; }
}

  

實現Service:

public class ProductManager : IDomainService
{
	//實體倉儲,實體繼承自IMustHaveOrganizationUnit
	private readonly IRepository<Product> _productRepository;
	//OU倉儲,通過此倉儲讀取OU
	private readonly IRepository<OrganizationUnit, long> _organizationUnitRepository;
	//用戶數據Manager
	private readonly UserManager _userManager;

	//構造函數,DI注入
	public ProductManager(
		IRepository<Product> productRepository, 
		IRepository<OrganizationUnit, long> organizationUnitRepository, 
		UserManager userManager)
	{
		_productRepository = productRepository;
		_organizationUnitRepository = organizationUnitRepository;
		_userManager = userManager;
	}

	//根據組織節點,獲取關聯的Product
	public List<Product> GetProductsInOu(long organizationUnitId)
	{
		return _productRepository.GetAllList(p => p.OrganizationUnitId == organizationUnitId);
	}
	
	//根據組織節點Id查詢所有的Products,包含子Product
	[UnitOfWork]//UnitOfWork支持事務
	public virtual List<Product> GetProductsInOuIncludingChildren(long organizationUnitId)
	{
		//根據組織節點id,獲取code
		var code = _organizationUnitRepository.Get(organizationUnitId).Code;

		//查詢組織節點開頭的所有節點,這樣避免了遞歸查詢,提升了效率,也是Code定義的目的所在
		var query =
			from product in _productRepository.GetAll()
			join organizationUnit in _organizationUnitRepository.GetAll() on product.OrganizationUnitId equals organizationUnit.Id
			where organizationUnit.Code.StartsWith(code)
			select product;

		return query.ToList();
	}

	//根據用戶查詢Product
	//查詢用戶關聯的組織節點,再根據組織節點,查詢關聯的Product
	public async Task<List<Product>> GetProductsForUserAsync(long userId)
	{
		var user = await _userManager.GetUserByIdAsync(userId);
		var organizationUnits = await _userManager.GetOrganizationUnitsAsync(user);
		var organizationUnitIds = organizationUnits.Select(ou => ou.Id);

		return await _productRepository.GetAllListAsync(p => organizationUnitIds.Contains(p.OrganizationUnitId));
	}

	//同上個函數類似,查詢中加入了子節點
	[UnitOfWork]
	public virtual async Task<List<Product>> GetProductsForUserIncludingChildOusAsync(long userId)
	{
		var user = await _userManager.GetUserByIdAsync(userId);
		var organizationUnits = await _userManager.GetOrganizationUnitsAsync(user);
		var organizationUnitCodes = organizationUnits.Select(ou => ou.Code);

		var query =
			from product in _productRepository.GetAll()
			join organizationUnit in _organizationUnitRepository.GetAll() on product.OrganizationUnitId equals organizationUnit.Id
			where organizationUnitCodes.Any(code => organizationUnit.Code.StartsWith(code))
			select product;

		return query.ToList();
	}
}

  

  

通過這段源碼我們發現,其實在Abp模板中Zero模塊已經默認添加了用戶與組織節點的關聯,如下圖:

 

OrganizationUnits表是一個父子樹結構,表達了我們系統中所有需要以父子樹表達的邏輯結構。

實體表User,Product通過一張關聯表與組織節點關聯,關聯關系如E-R圖所示。

在數據庫中,abp並沒有創建外鍵聯系,這應該是為了高復用OU表。

其他設置

你可以通過 AbpZeroSettingNames.OrganizationUnits.MaxUserMembershipCount 來設置一個用戶的最大OU關聯數。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM