Module-Zero之組織單元(OU)管理【新增】


返回《Module Zero學習目錄》


概覽介紹

組織單元(Organization Unit【簡稱OU】)可以有層次地給用戶和實體分組。

OrganizationUnit實體

一個OU是通過OrganizationUnit實體表示的。該實體的基本屬性如下:

  • TenantId:該OU的租戶Id。對於租主的OU可以為null。
  • ParentId:父OU的Id。如果該OU是根OU,那么可以是null。
  • Code:對於每個租戶都唯一的有層次的字符串碼。
  • DisplayName:OU的顯示名稱。

OrganizationUnit實體的主鍵(Id)是long類型的,OrganizationUnit實體是從提供了審計信息的FullAuditedEntity派生的,而且實現了 ISoftDelete接口(因此,OU是不能從數據庫中真正刪除的,只是軟刪除)。

組織樹(Organization Tree)

因為一個OU可以有一個父親,所以一個租戶的所有OU是在一個樹形結構中的。這棵樹有一些規則:

  • 可以有不止一個根(根的ParentId為null)。
  • 根的最大深度定義為OrganizationUnit.MaxDepth常量,值為16。
  • 一個OU的第一層的孩子數量是有限制的(因為OU代碼單元長度是固定的,下面有解釋)。

OU代碼

OU代碼是OrganizationUnit管理者自動生成、維護的,它是一個字符串,有點像"00001.00042.00005"

這個代碼可以輕松地查詢一個OU的所有孩子(遞歸地查詢)的數據庫數據,該代碼的一些規則如下:

  • 對於租戶是唯一的。
  • 相同OU的所有孩子的代碼以父OU代碼作為開頭
  • 基於OU在樹中的層級,它會有一個固定長度。
  • 雖然OU代碼是唯一的,但如果你移動了一個OU,那么它是可修改的。因此,我們應該通過Id來引用一個OU,而不是代碼(Code)。

OrganizationUnit管理者

OrganizationUnitManager類可以被注入,用於管理OU。公共用例是:

  • 創建,更新或刪除一個OU
  • 在OU樹中移動一個OU
  • 獲取關於OU樹和OU項的信息

多租戶

OrganizationUnitManager是為單租戶設計的,默認對 當前的租戶有效。

公共用例

這里,我們會看到OU的公共用例。你可以點擊這里找到樣例的源代碼。

創建屬於OU的實體

OU最明顯的用法是將一個實體賦予一個OU。讓我們看一個樣板實體:

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

我們創建了OrganizationUnitId屬性將一個實體賦予一個OU。 IMustHaveOrganizationUnit定義了OrganizationUnitId屬性。我們不必實現該接口,但是建議提供標准化。除此之外,還有一個IMayHaveOrganizationId,該接口提供了一個nullable(可空)的OrganizationUnitId屬性。

現在,我們可以將一個Product關聯到一個OU,並且查詢一個特定OU的產品。

注意:Product實體有 TenantId(它是IMustHaveTenant接口中定義的屬性)屬性來區分多租戶應用中不同租戶的產品(請看多租戶博客)。如果你的應用不是多租戶,那么你不需要這個接口和屬性。

獲取一個組織單元中的實體

獲取一個OU中的Products很簡單,來看一下領域服務這個例子:

public class ProductManager : IDomainService
{
    private readonly IRepository<Product> _productRepository;

    public ProductManager(IRepository<Product> productRepository)
    {
        _productRepository = productRepository;
    }

    public List<Product> GetProductsInOu(long organizationUnitId)
    {
        return _productRepository.GetAllList(p => p.OrganizationUnitId == organizationUnitId);
    }
}

我們可以對Product.OrganizationUnitId簡單地寫一個斷言,如上所示。

獲取一個包括子組織單元的組織單元的實體

我們可能想獲取一個包括子組織單元的組織單元的Products。在這種情況下,OU Code(代碼)可以幫到我們:

public class ProductManager : IDomainService
{
    private readonly IRepository<Product> _productRepository;
    private readonly IRepository<OrganizationUnit, long> _organizationUnitRepository;

    public ProductManager(
        IRepository<Product> productRepository, 
        IRepository<OrganizationUnit, long> organizationUnitRepository)
    {
        _productRepository = productRepository;
        _organizationUnitRepository = organizationUnitRepository;
    }

    [UnitOfWork]
    public virtual List<Product> GetProductsInOuIncludingChildren(long organizationUnitId)
    {
        var code = _organizationUnitRepository.Get(organizationUnitId).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();
    }
}

首先,我們獲得給定OU的Code。然后,我們創建了一個具有join和StartsWith(code)條件(在sql中StartsWith創建一個Like查詢)的LINQ。這樣,我們就可以有層次低獲得一個OU的products。

為用戶過濾實體

我們可能獲取在OU中的一個特定用戶的所有Products,看下面的樣例代碼:

public class ProductManager : IDomainService
{
    private readonly IRepository<Product> _productRepository;
    private readonly UserManager _userManager;

    public ProductManager(
        IRepository<Product> productRepository, 
        UserManager userManager)
    {
        _productRepository = productRepository;
        _organizationUnitRepository = organizationUnitRepository;
        _userManager = userManager;
    }

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

我們先找到該用戶OU的Id,然后獲取Products時使用了Contains條件。當然,我們可以創建一個具有join的LINQ查詢來獲得相同的列表。

我們可能想要獲取包括子OU的用戶OU的Products:

public class ProductManager : IDomainService
{
    private readonly IRepository<Product> _productRepository;
    private readonly IRepository<OrganizationUnit, long> _organizationUnitRepository;
    private readonly UserManager _userManager;

    public ProductManager(
        IRepository<Product> productRepository, 
        IRepository<OrganizationUnit, long> organizationUnitRepository, 
        UserManager userManager)
    {
        _productRepository = productRepository;
        _organizationUnitRepository = organizationUnitRepository;
        _userManager = userManager;
    }

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

我們將具有StartsWith條件的Any聯合到了一個LINQ join語句中。

當然,也可能有更復雜的需求,但是所有的需求都可以使用LINQ或SQL完成。

設置

你可以注入然后使用IOrganizationUnitSettings接口來獲取OU的設置值。當前,只有一個你可以更改的設置:

  • MaxUserMembershipCount:一個用戶最大允許的關系數量。默認值是int.MaxValue,它允許用戶同時成為無限OU的成員。設置名稱是一個定義在AbpZeroSettingNames.OrganizationUnits.MaxUserMembershipCount中的常量。

你可以使用設置管理者修改設置值。


免責聲明!

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



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