ABP教程(三)- 开始一个简单的任务管理系统 – 后端编码

上一篇 我们介绍了什么是ABP,这一篇我们通过原作者的”简单任务系统”例子,演示如何运用ABP开发项目

 

创建实体

一般来说任务是需要分配给人来做的,所以我们创建两个实体模型类:Task和Persion


using Abp.Domain.Entities;
using Abp.Domain.Entities.Auditing;
using System.ComponentModel.DataAnnotations.Schema;
using System;

namespace SimpleTaskSystem { public class Task : Entity, IHasCreationTime { [ForeignKey("AssignedPersonId")] public Person AssignedPerson { get; set; } public long? AssignedPersonId { get; set; } public string Description { get; set; } public TaskState State { get; set; } public DateTime CreationTime { get; set; } public Task() { State = TaskState.Active; } } } 

 


using System;
using Abp.Domain.Entities;
using Abp.Domain.Entities.Auditing;

namespace SimpleTaskSystem
{
    public class Person : Entity, IHasCreationTime { public string Name { get; set; } public DateTime CreationTime { get; set; } } } 

 

创建DbContext

使用EntityFramework需要先定义DbContext类,ABP的模板已经创建了DbContext文件,我们只需要把Task和Person类添加到IDbSet


using Abp.EntityFramework;
using System.Data.Entity;

namespace SimpleTaskSystem.EntityFramework
{
    public class SimpleTaskSystemDbContext : AbpDbContext { //TODO: Define an IDbSet for each Entity... //Example: //public virtual IDbSet Users { get; set; } public virtual IDbSet Tasks { get; set; } public virtual IDbSet People { get; set; } /* NOTE: * Setting "Default" to base class helps us when working migration commands on Package Manager Console. * But it may cause problems when working Migrate.exe of EF. If you will apply migrations on command line, do not * pass connection string name to base classes. ABP works either way. */ public SimpleTaskSystemDbContext() : base("Default") { } /* NOTE: * This constructor is used by ABP to pass connection string defined in SimpleTaskSystemDataModule.PreInitialize. * Notice that, actually you will not directly create an instance of SimpleTaskSystemDbContext since ABP automatically handles it. */ public SimpleTaskSystemDbContext(string nameOrConnectionString) : base(nameOrConnectionString) { } } } 

 

通过Database Migrations创建数据库

我们使用EntityFramework的Code First模式创建数据库架构。ABP模板生成的项目已经默认开启了数据迁移功能,我们添加一些默认数据进去。


using System.Data.Entity.Migrations;

namespace SimpleTaskSystem.Migrations
{
    internal sealed class Configuration : DbMigrationsConfiguration { public Configuration() { AutomaticMigrationsEnabled = false; ContextKey = "SimpleTaskSystem"; } protected override void Seed(SimpleTaskSystem.EntityFramework.SimpleTaskSystemDbContext context) { // This method will be called every time after migrating to the latest version. // You can add any seed data here... context.People.AddOrUpdate( p => p.Name, new Person { Name = "张三" }, new Person { Name = "王二" }, new Person { Name = "李四" }, new Person { Name = "老王" } ); } } } 

 

然后打开 程序包管理器控制台 ,选择默认项目并执行命令”Add-Migration InitialCreate”,此时会在Migrations目录下生成一个以 当前时间_InitialCreate.cs 的文件。

然后继续在 程序包管理器控制台 执行 Update-Database,等执行完毕则会在数据库自动创建相应的数据表

定义仓储接口

通过仓储模式,可以更好把业务代码与数据库操作代码更好的分离。我们把仓储的代码写到 Core 项目中


using Abp.Domain.Repositories;
using System.Collections.Generic;

namespace SimpleTaskSystem.Repositorys
{
    public interface ITaskRepository : IRepository<Task, long> { List GetAllWithPeople(long? assignedPersonId, TaskState? state); } } 

 

我们可以为Persion类定义一个仓储,也可以不定义,这里我选择定义,虽然ABP默认提供的仓储在本例中已经够用了,但考虑到以后扩展方便,我们还是也给它定义一个。


using Abp.Domain.Repositories;

namespace SimpleTaskSystem.Repositorys
{
    public interface IPersionRepository : IRepository<Person, long>
    {

    }
}

 

这样后期我们要加一个自定义方法直接加在这里面就行了,不用改动太多。这里也介绍一下ABP自带的仓储方法,我们可以直接使用。

实现仓储类

因为本例用的是EntityFramework,所以我们将在EntityFramework项目中实现上面定义的ITaskRepository仓储接口。如果后期想换个ORM框架,比如NHibernate,我们就只要更换仓储实现的这个项目即可。

TaskRepository.cs


using System.Collections.Generic;
using Abp.EntityFramework;
using SimpleTaskSystem.EntityFramework.Repositories;
using SimpleTaskSystem.Repositorys;
using System.Linq;
using System.Data.Entity;

namespace SimpleTaskSystem.EntityFramework.Repositorys
{
    public class TaskRepository : SimpleTaskSystemRepositoryBase<Task, long>, ITaskRepository
    {
        public TaskRepository(IDbContextProvider dbContextProvider) : base(dbContextProvider)
        {
        }

        public List GetAllWithPeople(long? assignedPersonId, TaskState? state)
        {
            //在仓储方法中,不用处理数据库连接、DbContext和数据事务,ABP框架会自动处理。
            var query = GetAll(); //返回一个 IQueryable接口类型

            //添加一些Where条件 if (assignedPersonId.HasValue) { query = query.Where(task => task.AssignedPerson.Id == assignedPersonId.Value); } if (state.HasValue) { query = query.Where(task => task.State == state); } return query .OrderByDescending(task => task.CreationTime) .Include(task => task.AssignedPerson) .ToList(); } } } 

 

PersionRepository.cs


using SimpleTaskSystem.Repositorys;
using Abp.EntityFramework;

namespace SimpleTaskSystem.EntityFramework.Repositories
{
    public class PersionRepository : SimpleTaskSystemRepositoryBase<Person, long>, IPersionRepository
    {
        public PersionRepository(IDbContextProvider dbContextProvider) : base(dbContextProvider) { } } } 

 

创建服务(Services)

首先在Application项目中定义Task的应用服务层的接口,各dto的类请下载源码查看。

ITaskAppService.cs


using Abp.Application.Services;

namespace SimpleTaskSystem.Services
{
    public interface ITaskAppService : IApplicationService { GetTasksOutput GetTasks(GetTasksInput input); void UpdateTask(UpdateTaskInput input); void CreateTask(CreateTaskInput input); } } 

 

然后,我们写TaskAppService类来实现ITaskAppService接口

TaskAppService.cs


using Abp.Application.Services;
using AutoMapper;
using SimpleTaskSystem.Repositorys;
using System.Collections.Generic;

namespace SimpleTaskSystem.Services { public class TaskAppService : ApplicationService, ITaskAppService { private readonly ITaskRepository _taskRepository; private readonly IPersionRepository _personRepository; /// /// 构造函数自动注入我们所需要的类或接口 ///  public TaskAppService(ITaskRepository taskRepository, IPersionRepository personRepository) { _taskRepository = taskRepository; _personRepository = personRepository; } public void CreateTask(CreateTaskInput input) { Logger.Info("Creating a task for input: " + input); //通过输入参数,创建一个新的Task实体 var task = new Task { Description = input.Description }; if (input.AssignedPersonId.HasValue) { task.AssignedPersonId = input.AssignedPersonId.Value; } //调用仓储基类的Insert方法把实体保存到数据库中 _taskRepository.Insert(task); } public GetTasksOutput GetTasks(GetTasksInput input) { //调用Task仓储的特定方法GetAllWithPeople var tasks = _taskRepository.GetAllWithPeople(input.AssignedPersonId, input.State); //用AutoMapper自动将List转换成List return new GetTasksOutput { Tasks = Mapper.Map<list>(tasks) }; } public void UpdateTask(UpdateTaskInput input) { //可以直接Logger,它在ApplicationService基类中定义的 Logger.Info("Updating a task for input: " + input); //通过仓储基类的通用方法Get,获取指定Id的Task实体对象 var task = _taskRepository.Get(input.Id); //修改task实体的属性值 if (input.State.HasValue) { task.State = input.State.Value; } if (input.AssignedPersonId.HasValue) { task.AssignedPerson = _personRepository.Load(input.AssignedPersonId.Value); } //我们都不需要调用Update方法 //因为应用服务层的方法默认开启了工作单元模式(Unit of Work) //ABP框架会工作单元完成时自动保存对实体的所有更改,除非有异常抛出。有异常时会自动回滚,因为工作单元默认开启数据库事务。 } } } 

 

数据验证

如果应用服务(Application Service)方法的参数对象实现了IInputDto或IValidate接口,ABP会自动进行参数有效性验证。

CreateTaskInput.cs


using Abp.Application.Services.Dto;
using System.ComponentModel.DataAnnotations;

namespace SimpleTaskSystem.Services
{
    public class CreateTaskInput : IInputDto { [Required] public string Description { get; set; } public long? AssignedPersonId { get; set; } } } 

 

如果你想使用自定义验证,你可以实现ICustomValidate 接口

UpdateTaskInput.cs


using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using Abp.Application.Services.Dto;
using Abp.Runtime.Validation;

namespace SimpleTaskSystem.Services { public class UpdateTaskInput : IInputDto, ICustomValidate { public int Id { get; set; } public string Description { get; set; } public long? AssignedPersonId { get; set; } public TaskState? State { get; set; } public void AddValidationErrors(List results) { if (AssignedPersonId == null && State == null) { results.Add(new ValidationResult("AssignedPersonId和State不能同时为空!", new[] { "AssignedPersonId", "State" })); } } } } 

 

创建Web Api服务

ABP默认已经开户了动态API,我们不需要任何设置即可非常轻松地把Application Service的public方法发布成Web Api接口,可以供客户端通过ajax调用。

下一篇我们将在此基础上构建前台页面,实现在浏览器中对任务进行简单的增删改查,静请期待……

本节源码链接: http://pan.baidu.com/s/1jIvZPSM 密码: njk5

转载于:https://www.cnblogs.com/webplus/p/5605975.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值