首先我们先来设计下用户模块,简单用户模块设计涵盖两个类,用户表以及角色表。如下图:
我们在Core项目中增加一个文件夹Domain,在Domain增加Customers文件夹,添加一个枚举PasswordFormat并且继承Int。
/// <summary>
/// 密码加密的格式枚举
/// </summary>
public enum PasswordFormat:int
{
/// <summary>
/// 不加密
/// </summary>
Clear = 0,
/// <summary>
/// Hashed加密法
/// </summary>
Hashed = 1,
/// <summary>
/// Encrypted加密法
/// </summary>
Encrypted = 2,
}
然后增加CustomerRole实体继承Entity,Entity是Abp的实体基类,它有很多重要的功能,我们的主键设置为Int型,所以不需要类型约束,如果你的主键是Guid型,那么请继承Entity《GUID》就好了。实体中有些属性需要约束长度以及为空项,所以我在Login上面增加属性约束[Required, MaxLength(50), MinLength(5)],这样就表示该属性为必填项,并且长度限制为5-50个字符。
增加Customer类继承Entity,并且实现IHasCreationTime,IHasModificationTime,这两个接口的含义是需要增加创建的时间以及最后的修改时间,我们只需要实现该接口并且,修改其属性为默认属性就好了
/// <summary>
/// 最后修改时间(不需要处理)
/// </summary>
public DateTime? LastModificationTime { get; set; }
/// <summary>
/// 创建时间(不需要处理)
/// </summary>
public DateTime CreationTime { get; set; }
用户实体中我增加了一个加密方式PasswordFormatId,但是他是int型,并且我刚刚写了个枚举,那么我的实现机制是
/// <summary>
/// 加密方式(不映射)
/// </summary>
[NotMapped]
public virtual PasswordFormat PasswordFormat
{
get { return (PasswordFormat)PasswordFormatId; }
set { this.PasswordFormatId = (int)value; }
}
[NotMapped]属性是不映射到数据库的意思。
ok实体我们写好了,那么我们要把该实体关联到ef让ef框架生成实体对应的数据库表。Blog_Solution.EntityFramework项目下的EntityFramework文件夹中Blog_SolutionDbContext类,打开后我们看到很多英文注释,仔细看一下在类中最上面有一段注释是这样写的:
//TODO: Define an IDbSet for each Entity...
//Example:
//public virtual IDbSet<User> Users { get; set; }
例子:在这里定义你的实体。ok 我增加两个实体
//Customers
public virtual IDbSet<CustomerRole> CustomerRole { get; set; }
public virtual IDbSet<Customer> Customer { get; set; }
其他的地方不动,我们先不去生成数据库,先把服务层写好。
Blog_Solution.Application项目中增加文件夹Customers,新建一个接口ICustomerRoleService并且继承接口IApplicationService(它是用来做注入用的,如果你不继承该接口,那么项目就不会注入该服务),写好我们对应的函数:
/// <summary>
/// 获取所有权限
/// </summary>
/// <param name="keywords">关键字</param>
/// <param name="showHidden">是否显示隐藏的值</param>
/// <param name="isAdmin">是否管理员</param>
/// <param name="parentIds">父节点</param>
/// <param name="pageIndex"></param>
/// <param name="pageSize"></param>
/// <returns></returns>
IPagedResult<CustomerRole> GetAllRoles(string keywords = "", bool showHidden = false, bool? isAdmin = null, List<int> parentIds = null, int pageIndex = 0, int pageSize = int.MaxValue);
/// <summary>
/// 获取用户角色
/// </summary>
/// <param name="customerRoleId"></param>
/// <returns></returns>
CustomerRole GetCustomerRoleById(int customerRoleId);
/// <summary>
/// 新增角色
/// </summary>
/// <param name="role"></param>
void InsertCustomerRole(CustomerRole role);
/// <summary>
/// 更新角色
/// </summary>
/// <param name="role"></param>
void UpdateCustomerRole(CustomerRole role);
/// <summary>
/// 删除角色
/// </summary>
/// <param name="customerRoleId"></param>
void DeleteCustomerRole(int customerRoleId);
/// <summary>
/// 删除角色
/// </summary>
/// <param name="role"></param>
void DeleteCustomerRole(CustomerRole role);
这个接口中,我们有一个函数是获取所有角色,我的返回对象是IPagedResult《T》,那好,我在该项目新增一个类PagedResult实现IPagedResult接口并且序列化该类:
/// <summary>
/// 分页查询实现类
/// </summary>
/// <typeparam name="T">T对象为实体对象的继承类</typeparam>
[Serializable]
public class PagedResult<T> : IPagedResult<T> where T : Entity
{
/// <summary>
/// 实例化
/// </summary>
/// <param name="source">数据源</param>
/// <param name="pageIndex">当前页</param>
/// <param name="pageSize">页大小</param>
public PagedResult(IQueryable<T> source, int pageIndex, int pageSize)
{
int total = source.Count();
this.TotalCount = total;
this.Items = source.Skip(pageIndex).Take(pageSize).ToList();
}
/// <summary>
/// 实例化
/// </summary>
/// <param name="source">数据源</param>
/// <param name="pageIndex">当前页</param>
/// <param name="pageSize">页大小</param>
public PagedResult(IList<T> source, int pageIndex, int pageSize)
{
int total = source.Count();
this.TotalCount = total;
this.Items = source.Skip(pageIndex).Take(pageSize).ToList();
}
/// <summary>
/// 数据集
/// </summary>
public IReadOnlyList<T> Items { get; set; }
/// <summary>
/// 总个数
/// </summary>
public int TotalCount { get; set; }
}
这样在用户角色服务实现类就可以实现该方法了。
我们在创建一个用户服务接口ICustomerService并且继承IApplicationService:
public interface ICustomerService: IApplicationService
{
/// <summary>
/// 新增用户
/// </summary>
/// <param name="customer"></param>
void InsertCustomer(Customer customer);
/// <summary>
/// 更新用户
/// </summary>
/// <param name="input"></param>
void UpdateCustomer(Customer input);
/// <summary>
/// 根据主键获取用户
/// </summary>
/// <param name="customerId"></param>
/// <returns></returns>
Customer GetCustomerById(int customerId);
/// <summary>
/// 根据登录名获取用户
/// </summary>
/// <param name="loginName"></param>
/// <returns></returns>
Customer GetCustomerByLoginName(string loginName);
/// <summary>
/// 根据邮箱获取用户
/// </summary>
/// <param name="email"></param>
/// <returns></returns>
Customer GetCustomerByEmail(string email);
/// <summary>
/// 根据手机获取用户
/// </summary>
/// <param name="mobile"></param>
/// <returns></returns>
Customer GetCustomerByMobile(string mobile);
/// <summary>
/// 获取所有用户
/// </summary>
/// <param name="createdFrom"></param>
/// <param name="createdTo"></param>
/// <param name="customerRoleIds"></param>
/// <param name="email"></param>
/// <param name="loginName"></param>
/// <param name="mobile"></param>
/// <param name="pageIndex"></param>
/// <param name="pageSize"></param>
/// <returns></returns>
IPagedResult<Customer> GetAllCustomers(DateTime? createdFrom = null,
DateTime? createdTo = null,int[] customerRoleIds = null,
string email = null, string loginName = null, string mobile = null,
int pageIndex = 0, int pageSize = int.MaxValue);
}
这样服务模块就建好了。
反过头我们来创建数据库。首先去web项目中配置你的数据库连接字符串
<connectionStrings>
<add name="Default" connectionString="Server=localhost; Database=Blog_Solution; Trusted_Connection=True;" providerName="System.Data.SqlClient" />
</connectionStrings>
我没有变更,这样可以连接我的数据库。
其次,我们重新生成下Solution。然后打开Nuget管理器控制台如下图:
如果你不知道如何打开该界面,Visual Studio ->工具 ->Nuget包管理器->程序包管理器控制台。然后注意下默认项目选择为EntityFramework。在PM输入命令 Add-Migration Create_Customer 后回车。稍等片刻Blog_Solution.EntityFramework项目中的Migrations文件夹会新增一个命名为日期开头后缀_Create_Customers.cs的文件,该文件中有两个表数据新建,查看你的属性是不是需要更改,如果不需要更改那么我们在Nuget控制台继续操作,Update-Database回车。查看下你的数据库吧,是不是也是下图这个样子
剩下的内容就是控制器了,我只在这里标识下角色控制器。首先,我们要针对实体在页面上页面实体(这就是OO的概念,我针对不同的层级有不同的对象,多态和继承的表现)。Models文件夹中增加Customers文件夹,然后新增页面实体CustomerRoleModel 继承自EntityDto(这里是为了映射一会再讲)。代码如下:
[AutoMap(typeof(CustomerRole))]
public class CustomerRoleModel:EntityDto
{
public CustomerRoleModel() {
this.AvailableParentRole = new List<SelectListItem>();
}
/// <summary>
/// 是否启用
/// </summary>
[Required]
public bool Enabled { get; set; }
/// <summary>
/// 角色名称
/// </summary>
[Required, MaxLength(20)]
public string RoleName { get; set; }
/// <summary>
/// 排序
/// </summary>
[UIHint("DisplayOrder")]
public int DisplayOrder { get; set; }
/// <summary>
/// 是否后台用户
/// </summary>
public bool IsAdmin { get; set; }
/// <summary>
/// 父节点
/// </summary>
[Required]
public int ParentId { get; set; }
/// <summary>
/// 是否默认注册用户
/// </summary>
public bool IsDefault { get; set; }
public IList<SelectListItem> AvailableParentRole { get; set; }
为什么上面要写 [AutoMap(typeof(CustomerRole))]也是为了映射稍后作答。
看我的控制器吧:
public class CustomerRoleController : Blog_SolutionControllerBase
{
#region Fields && Ctor
private readonly ICustomerRoleService _roleService;
/// <summary>
/// 构造,因为有注入所以不用担心
/// </summary>
/// <param name="roleService"></param>
public CustomerRoleController(ICustomerRoleService roleService)
{
this._roleService = roleService;
}
#endregion
#region Utilities
//组建用户角色实体
[NonAction]
private void PrepareCustomerRoleModel(CustomerRoleModel model)
{
var parentRoles = _roleService.GetAllRoles(showHidden: true,
parentIds: new List<int> { 0 }
);
if (model == null)
model = new CustomerRoleModel();
model.AvailableParentRole.Add(new SelectListItem
{
Selected = model.ParentId == 0,
Text = "*角色",
Value = "0",
});
foreach (var item in parentRoles.Items)
{
model.AvailableParentRole.Add(new SelectListItem {
Selected = model.ParentId == item.Id,
Text = item.RoleName,
Value = item.Id.ToString(),
});
}
}
#endregion
/// <summary>
/// 列表页面
/// </summary>
/// <returns></returns>
#region Method
public ActionResult List()
{
var model = new CustomerRoleListModel();
return View(model);
}
/// <summary>
/// 列表请求的数据(我用的是Kendoui大家可以试试很好用)
/// </summary>
/// <param name="command"></param>
/// <param name="model"></param>
/// <returns></returns>
[HttpPost]
public ActionResult List(DataSourceRequest command ,CustomerRoleListModel model)
{
var datas = _roleService.GetAllRoles(keywords: model.Keywords,
showHidden: true,
pageIndex: command.Page - 1,
pageSize: command.PageSize);
var data = new DataSourceResult {
Data = datas.Items,
Total = datas.TotalCount
};
return AbpJson(data);
}
/// <summary>
/// 新增页面
/// </summary>
/// <returns></returns>
public ActionResult Create()
{
var model = new CustomerRoleModel();
PrepareCustomerRoleModel(model);
return View(model);
}
/// <summary>
/// 新增逻辑
/// </summary>
/// <param name="model"></param>
/// <returns></returns>
[HttpPost]
public ActionResult Create(CustomerRoleModel model)
{
if (ModelState.IsValid)
{
//这里就是页面实体映射的关键,我可以把页面的实体转换为数据库的实体在进行操作
//但是还需要一小步在web项目中的App_Start文件夹中有个Blog_SolutionWebModule类,我们要注意下
//去看看就知道了
var entity = model.MapTo<CustomerRole>();
_roleService.InsertCustomerRole(entity);
return RedirectToAction("List");
}
PrepareCustomerRoleModel(model);
return View(model);
}
#endregion
}
项目里面的注释很清楚,不解释了。好了,删除和编辑你们看着办吧,还有View里面我为了重用性,把公用的页面做了一个分布页~你们可以看看。
项目地址https://github.com/5ina/BlogSolution 欢迎一起来搞~
扫一扫添加MrColor的公众号,每天都有新文章!
交流群:68848430这个群是朋友的。我每天都在欢迎大家进来讨论