領(lǐng)域驅(qū)動設(shè)計(jì) C#實(shí)現(xiàn) 問題 設(shè)計(jì) 解決方案

1 應(yīng)用層(Application)

Application
|-- Dtos
|-- Services

1.1數(shù)據(jù)傳輸對象

序號 分類 名稱 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和實(shí)體間的自動映射

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 依賴注入

維基百科說:“依賴注入是一種軟件設(shè)計(jì)模式,在這種模式下,一個(gè)或更多的依賴(或服務(wù))被注入(或者通過引用傳遞)到一個(gè)獨(dú)立的對象(或客戶端)中寞缝,然后成為了該客戶端狀態(tài)的一部分剩晴。該模式分離了客戶端依賴本身行為的創(chuàng)建,這使得程序設(shè)計(jì)變得松耦合鲤桥,并遵循了依賴反轉(zhuǎn)和單一職責(zé)原則箫锤。與服務(wù)定位器模式形成直接對比的是泞歉,它允許客戶端了解客戶端如何使用該系統(tǒng)找到依賴”。

3.1 依賴注入框架

微軟提供的Unity宇弛,引用Microsoft.Practices.Unity.dll
和Microsoft.Practices.Unity.Configuration.dll

3.2 構(gòu)造器注入

構(gòu)造器注入(Constructor Injection):IoC容器會智能地選擇選擇和調(diào)用適合的構(gòu)造函數(shù)以創(chuàng)建依賴的對象鸡典。如果被選擇的構(gòu)造函數(shù)具有相應(yīng)的參數(shù),IoC容器在調(diào)用構(gòu)造函數(shù)之前解析注冊的依賴關(guān)系并自行獲得相應(yīng)參數(shù)對象枪芒。

// AppService使用倉儲進(jìn)行數(shù)據(jù)庫操作轿钠,它通過構(gòu)造函數(shù)注入倉儲對象的引用
// 構(gòu)造函數(shù)自動注入我們所需要的類或接口
private readonly IUnitOfWork _uow = null;
private readonly IBasPolicy _policy = null;

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

調(diào)用代碼

// 創(chuàng)建容器
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 領(lǐng)域?qū)?/h1>

2.1 倉儲

2.1.1 查詢

IRepository定義了通用的方法,從數(shù)據(jù)庫中檢索實(shí)體病苗。

2.1.1.1 獲得單個(gè)實(shí)體

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方法用于獲得一個(gè)給定主鍵(Id)的實(shí)體疗垛。如果在數(shù)據(jù)庫中沒有找到這個(gè)實(shí)體,就會拋出異常硫朦。Single方法和Get類似贷腕,但是它的參數(shù)是一個(gè)表達(dá)式而不是一個(gè)Id。因此咬展,你可以使用Lambda表達(dá)式獲得一個(gè)實(shí)體泽裳。樣例用法:

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

注意:如果根據(jù)給定的條件沒有查找出實(shí)體或者查出不止一個(gè)實(shí)體,那么Single方法會拋出異常破婆。

FirstOrDefault是相似的涮总,但是如果根據(jù)給的的Id或者表達(dá)式?jīng)]有找到實(shí)體,那么就會返回null祷舀。如果對于給定的條件存在不止一個(gè)實(shí)體瀑梗,那么會返回找到的第一個(gè)實(shí)體烹笔。

Load方法不會從數(shù)據(jù)庫中檢索實(shí)體,但是會創(chuàng)建一個(gè)用于懶加載的代理對象抛丽。如果你只用了Id屬性谤职,那么Entity實(shí)際上并沒有檢索到。只有你訪問實(shí)體的其他屬性亿鲜,才會從數(shù)據(jù)庫中檢索允蜈。考慮到性能因素蒿柳,這個(gè)就可以替換Get方法饶套。這在NHiberbate中也實(shí)現(xiàn)了。如果ORM提供者沒有實(shí)現(xiàn)它垒探,那么Load方法會和Get方法一樣地工作凤跑。

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

2.1.1.2 獲得實(shí)體的列表

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從數(shù)據(jù)庫中檢索所有的實(shí)體叛复。該方法的重載可以用于過濾實(shí)體仔引。例子如下:

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重寫撬码。甚至可以用在一個(gè)連接表達(dá)式中儿倒。

關(guān)于IQueryable
脫離了倉儲方法調(diào)用GetAll()方法時(shí),數(shù)據(jù)庫連接必須要打開呜笑。這是因?yàn)镮Queryable的延遲執(zhí)行夫否。直到調(diào)用ToList()方法或者在foreach循環(huán)中使用IQueryable(或者訪問查詢到的元素)時(shí),才會執(zhí)行數(shù)據(jù)庫查詢操作叫胁。因此凰慈,當(dāng)調(diào)用ToList()方法時(shí)。數(shù)據(jù)庫連接必須打開驼鹅。這可以通過ABP中的UnitOfWork特性標(biāo)記調(diào)用者方法來實(shí)現(xiàn)微谓。注意:應(yīng)用服務(wù)方法默認(rèn)已經(jīng)是UnitOfWork,因此输钩,即使沒有為應(yīng)用服務(wù)層方法添加UnitOfWork特性豺型,GetAll()方法也會正常工作。

這些方法也存在用于異步編程模型的asyn版本买乃。

2.1.1.3 自定義返回值

也存在提供了IQueryable的額外方法姻氨,在調(diào)用的方法中不需要使用UnitOfWork。

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

Query方法接受一個(gè)接收IQueryable的lambda(或方法)剪验,并返回任何對象的類型肴焊。例子如下:

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

在該倉儲方法中前联,因?yàn)閳?zhí)行了給定的lambda(或方法),它是在數(shù)據(jù)庫連接打開的時(shí)候執(zhí)行的抖韩。你可以返回實(shí)體列表蛀恩,單個(gè)實(shí)體疫铜,一個(gè)投影或者執(zhí)行了該查詢的其他東西茂浮。

2.1.2 插入

IRepository接口定義了將一個(gè)實(shí)體插入數(shù)據(jù)庫的簡單方法:

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方法簡化了將一個(gè)實(shí)體插入數(shù)據(jù)庫,并將剛剛插入的實(shí)體返回壳咕。
InsertAndGetId方法返回了新插入實(shí)體的Id席揽。如果實(shí)體的Id是自動增長的并且需要最新插入實(shí)體的Id那伐,那么該方法很有用品嚣。InsertOrUpdate方法通過檢查Id的值插入或更新給定的實(shí)體。最后癌淮,當(dāng)插入或者更新之后竟稳,InsertOrUpdateAndGetId返回該實(shí)體的值属桦。

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

2.1.3 更新

IRepository定義了一個(gè)方法來更新數(shù)據(jù)庫中已存在的實(shí)體他爸。它可以獲得要更新的實(shí)體并返回相同的實(shí)體對象聂宾。

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

2.1.4 刪除

IRepository定義了從數(shù)據(jù)庫中刪除一個(gè)已存在的實(shí)體的方法。

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

第一個(gè)方法接受一個(gè)已存在的實(shí)體诊笤,第二個(gè)方法接受一個(gè)要刪除的實(shí)體的Id系谐。

最后一個(gè)方法接受一個(gè)刪除符合給定條件的所有實(shí)體的方法。注意讨跟,匹配給定謂詞的所有實(shí)體都會從數(shù)據(jù)庫中檢索到然后被刪除纪他。因此,小心使用它晾匠,如果給定的條件存在太多的實(shí)體茶袒,那么可能會造成性能問題。

2.1.5 其他

IRepository也提供了獲得表中實(shí)體數(shù)量的方法凉馆。

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 關(guān)于異步方法

支持異步編程模型(APM)弹谁。因此,倉儲方法有異步版本句喜。下面是一個(gè)使用了異步模型的應(yīng)用服務(wù)方法樣例:

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關(guān)鍵字的GetAllListAsync方法。

也許不是所有的ORM框架都支持Async咳胃,但是EntityFramework支持植康。如果不支持,異步倉儲方法就會同步進(jìn)行展懈。比如销睁,在EF中供璧,InsertAsync和Insert是等效的,因?yàn)橹钡焦ぷ鲉卧瓿桑―bcontext.SaveChanges)冻记,EF才會將新的實(shí)體寫入數(shù)據(jù)庫睡毒。

工作單元

如何處理多個(gè)Repository庫?

下面想象下如下場景冗栗,我們數(shù)據(jù)庫中有多個(gè)表演顾,那樣我們需要為每個(gè)表創(chuàng)建一個(gè)Reporsitory類。(好多重復(fù)工作的說隅居,其實(shí)這不是問題)
問題是關(guān)于 數(shù)據(jù)上下文(DbContext) 對象的钠至。如果我們創(chuàng)建多個(gè)Repository類,是不是每一個(gè)都單獨(dú)的包含一個(gè) 數(shù)據(jù)上下文對象胎源?我們知道同時(shí)使用多個(gè) 數(shù)據(jù)上下文 會存在問題棉钧,那我們該怎么處理每個(gè)Repository都擁有自己的數(shù)據(jù)上下文 對象的問題?
來解決這個(gè)問題吧涕蚤。為什么每個(gè)Repository要擁有一個(gè)數(shù)據(jù)上下文的實(shí)例呢宪卿?為什么不在一些地方創(chuàng)建一個(gè)它的實(shí)例,然后在repository被實(shí)例化的時(shí)候作為參數(shù)傳遞進(jìn)去呢⊥蛘ぃ現(xiàn)在這個(gè)新的類被命名為 UnitOfWork 佑钾,此類將負(fù)責(zé)創(chuàng)建數(shù)據(jù)上下文實(shí)例并移交到控制器的所有repository實(shí)例。

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
        {
            // 檢查倉儲類是否已經(jīng)創(chuàng)建申钩,如果存在將返回一個(gè)實(shí)例次绘,
            // 否則將創(chuàng)建一個(gè)新的實(shí)例。
            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 獲得實(shí)體的列表
        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 獲取實(shí)體的列表撒遣,支持分頁
        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 獲得單個(gè)實(shí)體
        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 獲得實(shí)體的列表
        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 獲取實(shí)體的列表邮偎,支持分頁
        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 獲得單個(gè)實(shí)體
        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);
            }
        }
    }
}

創(chuàng)建DbContext

提到DbContext,對于經(jīng)常使用DbFirst模式的開發(fā)者來說已經(jīng)再熟悉不過了,EntityFramework全靠這員大將义黎。它的作用是代表與數(shù)據(jù)庫連接的會話禾进,提供了查詢、狀態(tài)跟蹤廉涕、保存等功能泻云。
還有一個(gè)重要的對象是DbSet,對實(shí)體類型提供了集合操作狐蜕,比如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)
        {
            // 設(shè)置禁用一對多級聯(lián)刪除
            modelBuilder.Conventions.Remove<OneToManyCascadeDeleteConvention>();
            // 設(shè)置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
        }
    }
}

應(yīng)用服務(wù)

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

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市廉白,隨后出現(xiàn)的幾起案子个初,更是在濱河造成了極大的恐慌,老刑警劉巖猴蹂,帶你破解...
    沈念sama閱讀 217,509評論 6 504
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件院溺,死亡現(xiàn)場離奇詭異,居然都是意外死亡磅轻,警方通過查閱死者的電腦和手機(jī)珍逸,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,806評論 3 394
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來瓢省,“玉大人弄息,你說我怎么就攤上這事痊班∏诨椋” “怎么了?”我有些...
    開封第一講書人閱讀 163,875評論 0 354
  • 文/不壞的土叔 我叫張陵涤伐,是天一觀的道長馒胆。 經(jīng)常有香客問我,道長凝果,這世上最難降的妖魔是什么祝迂? 我笑而不...
    開封第一講書人閱讀 58,441評論 1 293
  • 正文 為了忘掉前任,我火速辦了婚禮器净,結(jié)果婚禮上型雳,老公的妹妹穿的比我還像新娘。我一直安慰自己山害,他們只是感情好纠俭,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,488評論 6 392
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著浪慌,像睡著了一般冤荆。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上权纤,一...
    開封第一講書人閱讀 51,365評論 1 302
  • 那天钓简,我揣著相機(jī)與錄音,去河邊找鬼汹想。 笑死外邓,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的古掏。 我是一名探鬼主播损话,決...
    沈念sama閱讀 40,190評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼冗茸!你這毒婦竟也來了席镀?” 一聲冷哼從身側(cè)響起匹中,我...
    開封第一講書人閱讀 39,062評論 0 276
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎豪诲,沒想到半個(gè)月后顶捷,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,500評論 1 314
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡屎篱,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,706評論 3 335
  • 正文 我和宋清朗相戀三年服赎,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片交播。...
    茶點(diǎn)故事閱讀 39,834評論 1 347
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡重虑,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出秦士,到底是詐尸還是另有隱情缺厉,我是刑警寧澤,帶...
    沈念sama閱讀 35,559評論 5 345
  • 正文 年R本政府宣布隧土,位于F島的核電站提针,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏曹傀。R本人自食惡果不足惜辐脖,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,167評論 3 328
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望皆愉。 院中可真熱鬧嗜价,春花似錦、人聲如沸幕庐。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,779評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽翔脱。三九已至奴拦,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間届吁,已是汗流浹背错妖。 一陣腳步聲響...
    開封第一講書人閱讀 32,912評論 1 269
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留疚沐,地道東北人暂氯。 一個(gè)月前我還...
    沈念sama閱讀 47,958評論 2 370
  • 正文 我出身青樓,卻偏偏與公主長得像亮蛔,于是被迫代替她去往敵國和親痴施。 傳聞我的和親對象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,779評論 2 354

推薦閱讀更多精彩內(nèi)容