领域驱动设计 C#实现 问题 设计 解决方案

1 应用层(Application)

Application
|-- Dtos
|-- Services

1.1数据传输对象

序号 分类 名称 CRUD
1 InputDto CreateDictCategoryInput C
2 InputDto GetAllDictCategoryInput R
3 InputDto GetDictCategoryInfoInput R
4 InputDto UpdateDictCategoryInput U
5 InputDto DeleteDictCategoryInput D
6 OutputDto DictCategoryOutput R
7 OutputDto GetAllDictCategoryOutput R

1.1.1 CreateDictCategoryInput

using System;

namespace Boer.Cloud.Bas.Application.DictCategoryMgr.Dtos
{
    public class CreateDictCategoryInput
    {
        public string CategoryName { get; set; }
        public string ParentCategoryId { get; set; }
        public string CategoryDesc { get; set; }
        public DateTime? CreationTime { get; set; }
        public string CreatorUserId { get; set; }
        public DateTime? LastModificationTime { get; set; }
        public string LastModifierUserId { get; set; }
        public DateTime? DeletionTime { get; set; }
        public string DeleterUserId { get; set; }
        public int? IsDeleted { get; set; }
        public int? Status { get; set; }
        public int? DisOrder { get; set; }
    }
}

1.1.2 GetAllDictCategoryInput

namespace Boer.Cloud.Bas.Application.DictCategoryMgr.Dtos
{
    public class GetAllDictCategoryInput
    {
        public string Token { get; set; }
    }
}

1.1.3 GetDictCategoryInfoInput

namespace Boer.Cloud.Bas.Application.DictCategoryMgr.Dtos
{
    public class GetDictCategoryInfoInput
    {
        public string CategoryId { get; set; }
    }
}

1.1.4 UpdateDictCategoryInput

namespace Boer.Cloud.Bas.Application.DictCategoryMgr.Dtos
{
    public class UpdateDictCategoryInput : CreateDictCategoryInput
    {
        public string CategoryId { get; set; }
    }
}

1.1.5 DeleteDictCategoryInput

namespace Boer.Cloud.Bas.Application.DictCategoryMgr.Dtos
{
    public class DeleteDictCategoryInput
    {
        public string CategoryId { get; set; }
    }
}

1.1.6 DictCategoryOutput

namespace Boer.Cloud.Bas.Application.DictCategoryMgr.Dtos
{
    public class DictCategoryOutput : UpdateDictCategoryInput { }
}

1.1.7 GetAllDictCategoryOutput

using System.Collections.Generic;

namespace Boer.Cloud.Bas.Application.DictCategoryMgr.Dtos
{
    public class GetAllDictCategoryOutput
    {
        public List<DictCategoryOutput> DictCategories { get; set; }
    }
}

2 DTO和实体间的自动映射

2.1 CreateMap

CreateMap<CreateDictCategoryInput, DictCategory>();
CreateMap<UpdateDictCategoryInput, DictCategory>();
CreateMap<DeleteDictCategoryInput, DictCategory>();
CreateMap<DictCategory, DictCategoryOutput>();

2.2 Map

var entity = Mapper.Map<CreateDictCategoryInput, DictCategory>(model);
var entity = Mapper.Map<UpdateDictCategoryInput, DictCategory>(model);
var entity = Mapper.Map<DeleteDictCategoryInput, DictCategory>(model);

jsonMsg.Result = Mapper.Map<DictCategory, DictCategoryOutput>(entity);
jsonMsg.Result = Mapper.Map<List<DictCategoryOutput>>(entity);

3 依赖注入

维基百科说:“依赖注入是一种软件设计模式,在这种模式下,一个或更多的依赖(或服务)被注入(或者通过引用传递)到一个独立的对象(或客户端)中,然后成为了该客户端状态的一部分。该模式分离了客户端依赖本身行为的创建,这使得程序设计变得松耦合,并遵循了依赖反转和单一职责原则。与服务定位器模式形成直接对比的是,它允许客户端了解客户端如何使用该系统找到依赖”。

3.1 依赖注入框架

微软提供的Unity,引用Microsoft.Practices.Unity.dll
和Microsoft.Practices.Unity.Configuration.dll

3.2 构造器注入

构造器注入(Constructor Injection):IoC容器会智能地选择选择和调用适合的构造函数以创建依赖的对象。如果被选择的构造函数具有相应的参数,IoC容器在调用构造函数之前解析注册的依赖关系并自行获得相应参数对象。

// AppService使用仓储进行数据库操作,它通过构造函数注入仓储对象的引用
// 构造函数自动注入我们所需要的类或接口
private readonly IUnitOfWork _uow = null;
private readonly IBasPolicy _policy = null;

public DictCategoryAppService(IUnitOfWork uow, IBasPolicy policy)
{
    this._uow = uow;
    this._policy = policy;
}

调用代码

// 创建容器
var container = new UnityContainer();  

// 注册依赖对象
container.RegisterType<IDictCategoryAppService, DictCategoryAppService>(new HierarchicalLifetimeManager());
container.RegisterType<IUnitOfWork, Boer.Cloud.Bas.Domain.UnitOfWork.UnitOfWork>(new HierarchicalLifetimeManager());
container.RegisterType<IBasPolicy, BasPolicy>(new HierarchicalLifetimeManager());

2 领域层

2.1 仓储

2.1.1 查询

IRepository定义了通用的方法,从数据库中检索实体。

2.1.1.1 获得单个实体

TEntity Get(TPrimaryKey id);
Task<TEntity> GetAsync(TPrimaryKey id);
TEntity Single(Expression<Func<TEntity, bool>> predicate);
Task<TEntity> SingleAsync(Expression<Func<TEntity, bool>> predicate);
TEntity FirstOrDefault(TPrimaryKey id);
Task<TEntity> FirstOrDefaultAsync(TPrimaryKey id);
TEntity FirstOrDefault(Expression<Func<TEntity, bool>> predicate);
Task<TEntity> FirstOrDefaultAsync(Expression<Func<TEntity, bool>> predicate);
TEntity Load(TPrimaryKey id);

Get方法用于获得一个给定主键(Id)的实体。如果在数据库中没有找到这个实体,就会抛出异常。Single方法和Get类似,但是它的参数是一个表达式而不是一个Id。因此,你可以使用Lambda表达式获得一个实体。样例用法:

var person = _personRepository.Get(42);
var person = _personRepository.Single(p => p.Name == "Halil İbrahim Kalkan");

注意:如果根据给定的条件没有查找出实体或者查出不止一个实体,那么Single方法会抛出异常。

FirstOrDefault是相似的,但是如果根据给的的Id或者表达式没有找到实体,那么就会返回null。如果对于给定的条件存在不止一个实体,那么会返回找到的第一个实体。

Load方法不会从数据库中检索实体,但是会创建一个用于懒加载的代理对象。如果你只用了Id属性,那么Entity实际上并没有检索到。只有你访问实体的其他属性,才会从数据库中检索。考虑到性能因素,这个就可以替换Get方法。这在NHiberbate中也实现了。如果ORM提供者没有实现它,那么Load方法会和Get方法一样地工作。

一些方法有用于async编程模型的异步(async)版本。

2.1.1.2 获得实体的列表

List<TEntity> GetAllList();
Task<List<TEntity>> GetAllListAsync();
List<TEntity> GetAllList(Expression<Func<TEntity, bool>> predicate);
Task<List<TEntity>> GetAllListAsync(Expression<Func<TEntity, bool>> predicate);
IQueryable<TEntity> GetAll();

GetAllList从数据库中检索所有的实体。该方法的重载可以用于过滤实体。例子如下:

var allPeople = _personRepository.GetAllList();
var somePeople = _personRepository.GetAllList(person => person.IsActive && person.Age > 42);

GetAll返回的类型是IQueryable。因此,你可以在此方法之后添加Linq方法。例子如下:

//Example 1
var query = from person in _personRepository.GetAll()
            where person.IsActive
            orderby person.Name
            select person;
var people = query.ToList();

//Example 2:
List<Person> personList2 = _personRepository.GetAll().Where(p => p.Name.Contains("H")).OrderBy(p => p.Name).Skip(40).Take(20).ToList();

有了GetAll方法,几乎所有的查询都可以使用Linq重写。甚至可以用在一个连接表达式中。

关于IQueryable
脱离了仓储方法调用GetAll()方法时,数据库连接必须要打开。这是因为IQueryable的延迟执行。直到调用ToList()方法或者在foreach循环中使用IQueryable(或者访问查询到的元素)时,才会执行数据库查询操作。因此,当调用ToList()方法时。数据库连接必须打开。这可以通过ABP中的UnitOfWork特性标记调用者方法来实现。注意:应用服务方法默认已经是UnitOfWork,因此,即使没有为应用服务层方法添加UnitOfWork特性,GetAll()方法也会正常工作。

这些方法也存在用于异步编程模型的asyn版本。

2.1.1.3 自定义返回值

也存在提供了IQueryable的额外方法,在调用的方法中不需要使用UnitOfWork。

T Query<T>(Func<IQueryable<TEntity>, T> queryMethod);

Query方法接受一个接收IQueryable的lambda(或方法),并返回任何对象的类型。例子如下:

var people = _personRepository.Query(q => q.Where(p => p.Name.Contains("H")).OrderBy(p => p.Name).ToList());

在该仓储方法中,因为执行了给定的lambda(或方法),它是在数据库连接打开的时候执行的。你可以返回实体列表,单个实体,一个投影或者执行了该查询的其他东西。

2.1.2 插入

IRepository接口定义了将一个实体插入数据库的简单方法:

TEntity Insert(TEntity entity);
Task<TEntity> InsertAsync(TEntity entity);
TPrimaryKey InsertAndGetId(TEntity entity);
Task<TPrimaryKey> InsertAndGetIdAsync(TEntity entity);
TEntity InsertOrUpdate(TEntity entity);
Task<TEntity> InsertOrUpdateAsync(TEntity entity);
TPrimaryKey InsertOrUpdateAndGetId(TEntity entity);
Task<TPrimaryKey> InsertOrUpdateAndGetIdAsync(TEntity entity);

Insert方法简化了将一个实体插入数据库,并将刚刚插入的实体返回。
InsertAndGetId方法返回了新插入实体的Id。如果实体的Id是自动增长的并且需要最新插入实体的Id,那么该方法很有用。InsertOrUpdate方法通过检查Id的值插入或更新给定的实体。最后,当插入或者更新之后,InsertOrUpdateAndGetId返回该实体的值。

所有的方法都存在用于异步编程模型的async版本。

2.1.3 更新

IRepository定义了一个方法来更新数据库中已存在的实体。它可以获得要更新的实体并返回相同的实体对象。

TEntity Update(TEntity entity);
Task<TEntity> UpdateAsync(TEntity entity);

2.1.4 删除

IRepository定义了从数据库中删除一个已存在的实体的方法。

void Delete(TEntity entity);
Task DeleteAsync(TEntity entity);
void Delete(TPrimaryKey id);
Task DeleteAsync(TPrimaryKey id);
void Delete(Expression<Func<TEntity, bool>> predicate);
Task DeleteAsync(Expression<Func<TEntity, bool>> predicate);

第一个方法接受一个已存在的实体,第二个方法接受一个要删除的实体的Id。

最后一个方法接受一个删除符合给定条件的所有实体的方法。注意,匹配给定谓词的所有实体都会从数据库中检索到然后被删除。因此,小心使用它,如果给定的条件存在太多的实体,那么可能会造成性能问题。

2.1.5 其他

IRepository也提供了获得表中实体数量的方法。

int Count();
Task<int> CountAsync();
int Count(Expression<Func<TEntity, bool>> predicate);
Task<int> CountAsync(Expression<Func<TEntity, bool>> predicate);
long LongCount();
Task<long> LongCountAsync();
long LongCount(Expression<Func<TEntity, bool>> predicate);
Task<long> LongCountAsync(Expression<Func<TEntity, bool>> predicate);

2.1.6 关于异步方法

支持异步编程模型(APM)。因此,仓储方法有异步版本。下面是一个使用了异步模型的应用服务方法样例:

public class PersonAppService : AbpWpfDemoAppServiceBase, IPersonAppService
{
    private readonly IRepository<Person> _personRepository;

    public PersonAppService(IRepository<Person> personRepository)
    {
        _personRepository = personRepository;
    }

    public async Task<GetPeopleOutput> GetAllPeople()
    {
        var people = await _personRepository.GetAllListAsync();
            
        return new GetPeopleOutput
        {
            People = Mapper.Map<List<PersonDto>>(people)
        };
    }
}

GetAllPeople方法是异步的,并使用了具有await关键字的GetAllListAsync方法。

也许不是所有的ORM框架都支持Async,但是EntityFramework支持。如果不支持,异步仓储方法就会同步进行。比如,在EF中,InsertAsync和Insert是等效的,因为直到工作单元完成(Dbcontext.SaveChanges),EF才会将新的实体写入数据库。

工作单元

如何处理多个Repository库?

下面想象下如下场景,我们数据库中有多个表,那样我们需要为每个表创建一个Reporsitory类。(好多重复工作的说,其实这不是问题)
问题是关于 数据上下文(DbContext) 对象的。如果我们创建多个Repository类,是不是每一个都单独的包含一个 数据上下文对象?我们知道同时使用多个 数据上下文 会存在问题,那我们该怎么处理每个Repository都拥有自己的数据上下文 对象的问题?
来解决这个问题吧。为什么每个Repository要拥有一个数据上下文的实例呢?为什么不在一些地方创建一个它的实例,然后在repository被实例化的时候作为参数传递进去呢。现在这个新的类被命名为 UnitOfWork ,此类将负责创建数据上下文实例并移交到控制器的所有repository实例。

IUnitOfWork.cs

using Boer.Cloud.Bas.Domain.Repositories;
using System;

namespace Boer.Cloud.Bas.Domain.UnitOfWork
{
    public interface IUnitOfWork : IDisposable
    {
        IBasRepositoryBase<T> Repository<T>() where T : class;
        void SaveChanges();
    }
}

UnitOfWork.cs

using Boer.Cloud.Bas.Domain.Repositories;
using Boer.Cloud.Bas.EntityFramework;
using Boer.Cloud.Bas.EntityFramework.Repositories;
using System;
using System.Collections.Generic;
using System.Linq;

namespace Boer.Cloud.Bas.Domain.UnitOfWork
{
    public class UnitOfWork : IUnitOfWork
    {
        private BasDbContext dbContext = null;

        public UnitOfWork()
        {
            dbContext = new BasDbContext();
        }

        public Dictionary<Type, object> repositories = new Dictionary<Type, object>();

        public IBasRepositoryBase<T> Repository<T>() where T : class
        {
            // 检查仓储类是否已经创建,如果存在将返回一个实例,
            // 否则将创建一个新的实例。
            if (repositories.Keys.Contains(typeof(T)) == true)
            {
                return repositories[typeof(T)] as IBasRepositoryBase<T>;
            }
            IBasRepositoryBase<T> repo = new BasRepositoryBase<T>(dbContext);
            repositories.Add(typeof(T), repo);
            return repo;
        }

        public void SaveChanges()
        {
            dbContext.SaveChanges();
        }

        private bool disposed = false;
        protected virtual void Dispose(bool disposing)
        {
            if (!this.disposed)
            {
                if (disposing)
                {
                    dbContext.Dispose();
                }
            }
            this.disposed = true;
        }

        public void Dispose()
        {
            Dispose(true);
            GC.SuppressFinalize(this);
        }
    }
}

仓储

IBasRepositoryBase.cs

using System;
using System.Collections.Generic;
using System.Linq;
using System.Linq.Expressions;
using System.Threading.Tasks;

namespace Boer.Cloud.Bas.Domain.Repositories
{
    public interface IBasRepositoryBase<T> where T : class
    {
        void OnBeforeInsert(T entity);
        void OnAfterInsert(T entity);
        void OnBeforeUpdate(T entity);
        void OnAfterUpdate(T entity);
        void OnBeforeDelete(T entity);
        void OnAfterDelete(T entity);

        #region 获得实体的列表
        List<T> GetAllList();
        Task<List<T>> GetAllListAsync();
        Task<List<T>> GetAllListAsync(Expression<Func<T, bool>> predicate);
        IQueryable<T> GetAll();
        IEnumerable<T> GetAll(Expression<Func<T, bool>> predicate = null);
        #endregion

        #region 获取实体的列表,支持分页
        IEnumerable<T> Get(string orderBy, int pageIndex, int pageSize);
        IEnumerable<T> Get(Expression<Func<T, bool>> predicate, string orderBy, int pageIndex, int pageSize);
        #endregion

        #region 获得单个实体
        T Single(Expression<Func<T, bool>> predicate);
        Task<T> SingleAsync(Expression<Func<T, bool>> predicate);
        T FirstOrDefault(Expression<Func<T, bool>> predicate);
        Task<T> FirstOrDefaultAsync(Expression<Func<T, bool>> predicate);
        #endregion

        #region 插入
        T Insert(T entity);
        Task<T> InsertAsync(T entity);
        #endregion

        #region 更新
        T Update(T entity);
        Task<T> UpdateAsync(T entity);
        #endregion

        #region 删除
        void Delete(T entity);
        Task DeleteAsync(T entity);
        void Delete(Expression<Func<T, bool>> predicate);
        Task DeleteAsync(Expression<Func<T, bool>> predicate);
        #endregion

        #region 其他
        int Count();
        Task<int> CountAsync();
        int Count(Expression<Func<T, bool>> predicate);
        Task<int> CountAsync(Expression<Func<T, bool>> predicate);
        long LongCount();
        Task<long> LongCountAsync();
        long LongCount(Expression<Func<T, bool>> predicate);
        Task<long> LongCountAsync(Expression<Func<T, bool>> predicate);
        #endregion

    }
}

BasRepositoryBase.cs

using Boer.Cloud.Bas.Domain.Repositories;
using System;
using System.Collections.Generic;
using System.Data.Entity;
using System.Linq;
using System.Linq.Dynamic;
using System.Linq.Expressions;
using System.Threading.Tasks;

namespace Boer.Cloud.Bas.EntityFramework.Repositories
{
    public class BasRepositoryBase<T> : IBasRepositoryBase<T> where T : class
    {
        private BasDbContext dbContext = null;

        public virtual DbSet<T> Table { get { return dbContext.Set<T>(); } }

        public BasRepositoryBase(BasDbContext _dbContext)
        {
            dbContext = _dbContext;
        }

        public virtual void OnBeforeInsert(T entity){ }
        public virtual void OnAfterInsert(T entity) { }
        public virtual void OnBeforeUpdate(T entity) { }
        public virtual void OnAfterUpdate(T entity) { }
        public virtual void OnBeforeDelete(T entity) { }
        public virtual void OnAfterDelete(T entity) { }

        #region 获得实体的列表
        public IQueryable<T> GetAll()
        {
            return Table;
        }

        public List<T> GetAllList()
        {
            return GetAll().ToList();
        }

        public async Task<List<T>> GetAllListAsync()
        {
            return await GetAll().ToListAsync();
        }

        public async Task<List<T>> GetAllListAsync(Expression<Func<T, bool>> predicate)
        {
            return await GetAll().Where(predicate).ToListAsync();
        }

        public IEnumerable<T> GetAll(Expression<Func<T, bool>> predicate = null)
        {
            if (predicate != null)
            {
                return Table.Where(predicate);
            }
            return Table.AsEnumerable();
        }
        #endregion

        #region 获取实体的列表,支持分页
        public IEnumerable<T> Get(string orderBy, int pageIndex, int pageSize)
        {
            return
                GetAll()
                .OrderBy(orderBy)
                .Skip((pageIndex - 1) * pageSize)
                .Take(pageSize)
                .AsEnumerable();
        }

        public IEnumerable<T> Get(Expression<Func<T, bool>> predicate,
            string orderBy, int pageIndex, int pageSize)
        {
            return
                GetAll().Where(predicate)
                .OrderBy(orderBy)
                .Skip((pageIndex - 1) * pageSize)
                .Take(pageSize)
                .AsEnumerable();
        }
        #endregion

        #region 获得单个实体
        public T Single(Expression<Func<T, bool>> predicate)
        {
            return GetAll().Single(predicate);
        }

        public async Task<T> SingleAsync(Expression<Func<T, bool>> predicate)
        {
            return await GetAll().SingleAsync(predicate);
        }

        public T FirstOrDefault(Expression<Func<T, bool>> predicate)
        {
            return GetAll().FirstOrDefault(predicate);
        }

        public async Task<T> FirstOrDefaultAsync(Expression<Func<T, bool>> predicate)
        {
            return await GetAll().FirstOrDefaultAsync(predicate);
        }
        #endregion

        #region 插入
        public T Insert(T entity)
        {
            return Table.Add(entity);
        }

        public Task<T> InsertAsync(T entity)
        {
            return Task.FromResult(Table.Add(entity));
        }
        #endregion

        #region 更新
        public T Update(T entity)
        {
            AttachIfNot(entity);
            dbContext.Entry(entity).State = EntityState.Modified;
            return entity;
        }

        public Task<T> UpdateAsync(T entity)
        {
            AttachIfNot(entity);
            dbContext.Entry(entity).State = EntityState.Modified;
            return Task.FromResult(entity);
        }
        #endregion

        #region 删除
        public void Delete(T entity)
        {
            AttachIfNot(entity);

            Table.Remove(entity);
        }

        public Task DeleteAsync(T entity)
        {
            Delete(entity);
            return Task.FromResult(0);
        }

        public void Delete(Expression<Func<T, bool>> predicate)
        {
            foreach (var entity in GetAll().Where(predicate).ToList())
            {
                Delete(entity);
            }
        }

        public async Task DeleteAsync(Expression<Func<T, bool>> predicate)
        {
            Delete(predicate);
        }

        #endregion

        #region 其他
        public int Count()
        {
            return GetAll().Count();
        }

        public async Task<int> CountAsync()
        {
            return await GetAll().CountAsync();
        }

        public int Count(Expression<Func<T, bool>> predicate)
        {
            return GetAll().Where(predicate).Count();
        }

        public async Task<int> CountAsync(Expression<Func<T, bool>> predicate)
        {
            return await GetAll().Where(predicate).CountAsync();
        }

        public long LongCount()
        {
            return GetAll().LongCount();
        }

        public async Task<long> LongCountAsync()
        {
            return await GetAll().LongCountAsync();
        }

        public long LongCount(Expression<Func<T, bool>> predicate)
        {
            return GetAll().Where(predicate).LongCount();
        }

        public async Task<long> LongCountAsync(Expression<Func<T, bool>> predicate)
        {
            return await GetAll().Where(predicate).LongCountAsync();
        }

        #endregion

        protected virtual void AttachIfNot(T entity)
        {
            if (!Table.Local.Contains(entity))
            {
                Table.Attach(entity);
            }
        }
    }
}

创建DbContext

提到DbContext,对于经常使用DbFirst模式的开发者来说已经再熟悉不过了,EntityFramework全靠这员大将。它的作用是代表与数据库连接的会话,提供了查询、状态跟踪、保存等功能。
还有一个重要的对象是DbSet,对实体类型提供了集合操作,比如Add、Attach、Remove。继承了DbQuery,所以可以提供查询功能。

BasDbContext.cs

using Boer.Cloud.Bas.Domain.Entities;
using Boer.Cloud.Bas.EntityFramework.Mapping;
using Boer.Cloud.Core.Helper;
using System;
using System.Data.Entity;
using System.Data.Entity.ModelConfiguration.Conventions;
using System.Diagnostics;

namespace Boer.Cloud.Bas.EntityFramework
{
    public class BasDbContext : DbContext
    {
        public BasDbContext()
            : base("name=DefaultDBConnection")
        {
            Database.SetInitializer<BasDbContext>(null);
            this.Database.Log = new Action<string>(q => Debug.WriteLine(q));
        }

        #region Property

        public virtual IDbSet<AreaCategory> AreaCategories { get; set; }
        public virtual IDbSet<DictCategory> DictCategories { get; set; }
        public virtual IDbSet<Dict> Dicts { get; set; }

        #endregion

        protected override void OnModelCreating(DbModelBuilder modelBuilder)
        {
            // 设置禁用一对多级联删除
            modelBuilder.Conventions.Remove<OneToManyCascadeDeleteConvention>();
            // 设置Schema
            modelBuilder.HasDefaultSchema(Config.GetValue("DefaultSchema", "BOER"));

            #region BasMapping

            modelBuilder.Configurations.Add(new AreaCategoryMap());
            modelBuilder.Configurations.Add(new DictCategoryMap());
            modelBuilder.Configurations.Add(new DictMap());

            #endregion
        }
    }
}

应用服务

IAreaCategoryAppService.cs

using Boer.Cloud.Bas.Application.AreaCategoryMgr.Dtos;
using Boer.Cloud.Core.Dto;
using System.Threading.Tasks;

namespace Boer.Cloud.Bas.Application.AreaCategoryMgr
{
    public interface IAreaCategoryAppService
    {
        Task<JsonMessage> Create(CreateAreaCategoryInput model);
        Task<JsonMessage> Update(UpdateAreaCategoryInput model);
        Task<JsonMessage> Delete(DeleteAreaCategoryInput model);
        Task<JsonMessage> GetInfo(GetAreaCategoryInfoInput model);
        JsonMessage GetAll(GetAllAreaCategoryInput model);
    }
}

AreaCategoryAppService.cs

using AutoMapper;
using Boer.Cloud.Bas.Application.AreaCategoryMgr.Dtos;
using Boer.Cloud.Bas.Domain.Entities;
using Boer.Cloud.Bas.Domain.Policies;
using Boer.Cloud.Bas.Domain.UnitOfWork;
using Boer.Cloud.Core.Dto;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;

namespace Boer.Cloud.Bas.Application.AreaCategoryMgr
{
    public class AreaCategoryAppService : IAreaCategoryAppService
    {
        private readonly IUnitOfWork _uow = null;
        private readonly IBasPolicy _policy = null;

        public AreaCategoryAppService(IUnitOfWork uow, IBasPolicy policy)
        {
            this._uow = uow;
            this._policy = policy;
        }

        public async Task<JsonMessage> Create(CreateAreaCategoryInput model)
        {
            var entity = Mapper.Map<CreateAreaCategoryInput, AreaCategory>(model);
            entity.AreaId = Guid.NewGuid().ToString("N").ToUpper();

            await _uow.Repository<AreaCategory>().InsertAsync(entity);
            _uow.SaveChanges();

            return _policy.GetErrorMsgByErrCode(0);
        }

        public async Task<JsonMessage> Update(UpdateAreaCategoryInput model)
        {
            if (string.IsNullOrEmpty(model.AreaId))
                return _policy.GetErrorMsgByErrCode(20601003);

            var entity = Mapper.Map<UpdateAreaCategoryInput, AreaCategory>(model);

            await _uow.Repository<AreaCategory>().UpdateAsync(entity);
            _uow.SaveChanges();

            return _policy.GetErrorMsgByErrCode(0);
        }

        public async Task<JsonMessage> Delete(DeleteAreaCategoryInput model)
        {
            if (string.IsNullOrEmpty(model.AreaId))
                return _policy.GetErrorMsgByErrCode(20601003);

            if (_policy.IsExistsByParentAreaId(model.AreaId))
                return _policy.GetErrorMsgByErrCode(20601004);

            if (_policy.IsNullByAreaCategories(model.AreaId))
                return _policy.GetErrorMsgByErrCode(20601002);

            await _uow.Repository<AreaCategory>().DeleteAsync(b => b.AreaId == model.AreaId);
            _uow.SaveChanges();

            return _policy.GetErrorMsgByErrCode(0);
        }

        public async Task<JsonMessage> GetInfo(GetAreaCategoryInfoInput model)
        {
            if (string.IsNullOrEmpty(model.AreaId))
                return _policy.GetErrorMsgByErrCode(20601003);

            if (_policy.IsNullByAreaCategories(model.AreaId))
                return _policy.GetErrorMsgByErrCode(20601002);

            var entity = await _uow.Repository<AreaCategory>().SingleAsync(b => b.AreaId == model.AreaId);

            JsonMessage jsonMsg = _policy.GetErrorMsgByErrCode(0);
            jsonMsg.Result = Mapper.Map<AreaCategory, AreaCategoryOutput>(entity);
            return jsonMsg;
        }

        public JsonMessage GetAll(GetAllAreaCategoryInput model)
        {
            var entity = _uow.Repository<AreaCategory>().GetAll().OrderBy(item => item.AreaCode).ToList();

            JsonMessage jsonMsg = _policy.GetErrorMsgByErrCode(0);
            jsonMsg.Result = Mapper.Map<List<AreaCategoryOutput>>(entity);
            return jsonMsg;
        }
    }
}

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 158,425评论 4 361
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 67,058评论 1 291
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 108,186评论 0 243
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 43,848评论 0 204
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,249评论 3 286
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,554评论 1 216
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,830评论 2 312
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,536评论 0 197
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,239评论 1 241
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,505评论 2 244
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 32,004评论 1 258
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,346评论 2 253
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 32,999评论 3 235
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,060评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,821评论 0 194
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,574评论 2 271
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,480评论 2 267

推荐阅读更多精彩内容