Module-Zero之组织单元(OU)管理【新增】
概览介绍
组织单元(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中的常量。
你可以使用设置管理者修改设置值。
Module-Zero之组织单元(OU)管理【新增】的更多相关文章
- Selenium 2自动化测试实战29(组织单元测试用例和discover更多测试用例)
一.组织单元测试用例 看看unittest单元测试框架是如何扩展和组织新增的测试用例以之前的calculator.py文件为例,为其扩展sub()方法,用来计算两个数相减的结果. #coding:ut ...
- 【SAP业务模式】之ICS(四):组织单元的配置
SAP的ICS业务后台配置主要有以下几个配置点: 1.组织单元的配置(公司代码.销售组织.工厂.采购组织等): 2.主数据的部分: 3.订单和开票的定价过程: 4.开票输出类型: 5.公司间发票的配置 ...
- linux基础-第十六单元 yum管理RPM包
第十六单元 yum管理RPM包 yum的功能 本地yum配置 光盘挂载和镜像挂载 本地yum配置 网络yum配置 网络yum配置 Yum命令的使用 使用yum安装软件 使用yum删除软件 安装组件 删 ...
- RDIFramework.NET V3.3 WinForm版角色授权管理新增角色对操作权限项、模块起止生效日期的设置
在实际应用在我们可能会有这样的需求,某个操作权限项(按钮)或菜单在某个时间范围内可以让指定角色访问.此时通过我们的角色权限扩展设置就可以办到. 在我们框架V3.3 WinForm版全新增加了角色权限扩 ...
- Python模块 --- 最高级别程序组织单元
模块 --- 最高级别程序组织单元 <Python学习手册>笔记 import 导入1个模块 from 获取模块指定变量名 imp.reload 重新载入模块文件代码的方法 模块作用 代码 ...
- 域 搭建OU 组织单元
以这个界面开始操作: 在 baidu.com 右键---新建----组织单位----北京分公司 在 baidu.com 右键---新建----组织单位----北京分公司 在北京分公司 和南京分公司下面 ...
- Web端权限管理新增实用功能:批量增加操作,简单方便快速!
扩展了吉日嘎拉的Web端权限管理功能后,每次添加菜单倒没啥问题,毕竟菜单的数量有限,可是每增加一个模块.功能或者说权限控制点,就得针对各种常规操作,新增很多遍. 浪费时间,还容易出错.新增了一个字典表 ...
- JavaScript学习笔记-商品管理新增/删除/修改功能
<!DOCTYPE html> <html lang="en" xmlns="http://www.w3.org/1999/xhtml"> ...
- RDIFramework.NET V3.3 Web版角色授权管理新增角色对操作权限项、模块起止生效日期的设置
在实际应用在我们可能会有这样的需求,某个操作权限项(按钮)或菜单在某个时间范围内可以让指定角色访问.此时通过我们的角色权限扩展设置就可以办到. 在我们框架V3.3 Web版本全新增加了角色权限扩展设置 ...
随机推荐
- AOP详解
什么是AOP AOP Aspect Oriented Programing 面向切面编程 AOP采取横向抽取机制,取代了传统纵向继承体系重复性代码(性能监视.事务管理.安全检查.缓存) Spring ...
- memcache and redis 的区别
memcache和redis都属于缓存但是memcache的存储大小是收到 限制的memcache的 键值长度是250,内存的大小限制是1M并且memcache不支持数据的持久化缓存 redis支持五 ...
- [spring源码学习]十、IOC源码-conversionService
一.代码示例 1.我们在之前的Person类里新增一个两个属性,分别是客户的兴趣和生日,兴趣爱好有很多,我们使用list进行保存,生日使用日期进行保存 public class Person { pr ...
- XE2 IntraWeb尝试
新建--选择--确定 简单放几个控件在TIWForm1上面,运行,生成一个项目服务器: 复制 URL http://127.0.0.1:8888/$/start 打开网页.
- R语言绘制空间热力图
先上图 R语言的REmap包拥有非常强大的空间热力图以及空间迁移图功能,里面内置了国内外诸多城市坐标数据,使用起来方便快捷. 开始 首先安装相关包 install_packages("dev ...
- php与数据库代码开发规范
php与数据库代码开发规范 1/25/2016 6:00:31 PM php对各类变量命名规范 目录名 文件命名 局部变量命名 使用英文动词名词,用下划线作为单词的分割,所有字母均使用小写 目录 up ...
- 从零开始山寨Caffe·柒:KV数据库
你说你会关系数据库?你说你会Hadoop? 忘掉它们吧,我们既不需要网络支持,也不需要复杂关系模式,只要读写够快就行. ——论数据存储的本质 浅析数据库技术 内存数据库——STL的map容器 关 ...
- 软件工程:vs单元测试
vs单元测试?VS?没装呢... 那么赶紧装个吧,于是跑到这去了: http://www.msdn.hk 我下个免费社区版. 安装过程没有什么需要说明的,傻瓜式安装会吗?当然中间会耗很长时间. 由于以 ...
- Django动态渲染多层菜单
为后续给菜单设置权限管理方便,通过给页面模版菜单动态渲染,通过数据菜单表进行匹配需要渲染的菜单 #Django表结构 class Menus(models.Model): name = models. ...
- SUBLIME 添加PHP控制台
原文地址:http://www.libenfu.com/sublime-%E6%B7%BB%E5%8A%A0php%E6%8E%A7%E5%88%B6%E5%8F%B0/ 点击工具 > 编译系统 ...