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

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

Application
|-- Dtos
|-- Services

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

序號(hào) 分類(lèi) 名稱(chēng) 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í)體間的自動(dòng)映射

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

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

3.1 依賴注入框架

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

3.2 構(gòu)造器注入

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

// AppService使用倉(cāng)儲(chǔ)進(jìn)行數(shù)據(jù)庫(kù)操作,它通過(guò)構(gòu)造函數(shù)注入倉(cāng)儲(chǔ)對(duì)象的引用
// 構(gòu)造函數(shù)自動(dòng)注入我們所需要的類(lèi)或接口
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();  

// 注冊(cè)依賴對(duì)象
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 倉(cāng)儲(chǔ)

2.1.1 查詢

IRepository定義了通用的方法,從數(shù)據(jù)庫(kù)中檢索實(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ù)庫(kù)中沒(méi)有找到這個(gè)實(shí)體,就會(huì)拋出異常。Single方法和Get類(lèi)似,但是它的參數(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ù)給定的條件沒(méi)有查找出實(shí)體或者查出不止一個(gè)實(shí)體,那么Single方法會(huì)拋出異常。

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

Load方法不會(huì)從數(shù)據(jù)庫(kù)中檢索實(shí)體,但是會(huì)創(chuàng)建一個(gè)用于懶加載的代理對(duì)象。如果你只用了Id屬性,那么Entity實(shí)際上并沒(méi)有檢索到。只有你訪問(wèn)實(shí)體的其他屬性,才會(huì)從數(shù)據(jù)庫(kù)中檢索。考慮到性能因素,這個(gè)就可以替換Get方法。這在NHiberbate中也實(shí)現(xiàn)了。如果ORM提供者沒(méi)有實(shí)現(xiàn)它,那么Load方法會(huì)和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ù)庫(kù)中檢索所有的實(shí)體。該方法的重載可以用于過(guò)濾實(shí)體。例子如下:

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

GetAll返回的類(lèi)型是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重寫(xiě)。甚至可以用在一個(gè)連接表達(dá)式中。

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

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

2.1.1.3 自定義返回值

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

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

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

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

在該倉(cāng)儲(chǔ)方法中,因?yàn)閳?zhí)行了給定的lambda(或方法),它是在數(shù)據(jù)庫(kù)連接打開(kāi)的時(shí)候執(zhí)行的。你可以返回實(shí)體列表,單個(gè)實(shí)體,一個(gè)投影或者執(zhí)行了該查詢的其他東西。

2.1.2 插入

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

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方法簡(jiǎn)化了將一個(gè)實(shí)體插入數(shù)據(jù)庫(kù),并將剛剛插入的實(shí)體返回。
InsertAndGetId方法返回了新插入實(shí)體的Id。如果實(shí)體的Id是自動(dòng)增長(zhǎng)的并且需要最新插入實(shí)體的Id,那么該方法很有用。InsertOrUpdate方法通過(guò)檢查Id的值插入或更新給定的實(shí)體。最后,當(dāng)插入或者更新之后,InsertOrUpdateAndGetId返回該實(shí)體的值。

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

2.1.3 更新

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

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

2.1.4 刪除

IRepository定義了從數(shù)據(jù)庫(kù)中刪除一個(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è)要?jiǎng)h除的實(shí)體的Id。

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

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)。因此,倉(cāng)儲(chǔ)方法有異步版本。下面是一個(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支持。如果不支持,異步倉(cāng)儲(chǔ)方法就會(huì)同步進(jìn)行。比如,在EF中,InsertAsync和Insert是等效的,因?yàn)橹钡焦ぷ鲉卧瓿桑―bcontext.SaveChanges),EF才會(huì)將新的實(shí)體寫(xiě)入數(shù)據(jù)庫(kù)。

工作單元

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

下面想象下如下場(chǎng)景,我們數(shù)據(jù)庫(kù)中有多個(gè)表,那樣我們需要為每個(gè)表創(chuàng)建一個(gè)Reporsitory類(lèi)。(好多重復(fù)工作的說(shuō),其實(shí)這不是問(wèn)題)
問(wèn)題是關(guān)于 數(shù)據(jù)上下文(DbContext) 對(duì)象的。如果我們創(chuàng)建多個(gè)Repository類(lèi),是不是每一個(gè)都單獨(dú)的包含一個(gè) 數(shù)據(jù)上下文對(duì)象?我們知道同時(shí)使用多個(gè) 數(shù)據(jù)上下文 會(huì)存在問(wèn)題,那我們?cè)撛趺刺幚砻總€(gè)Repository都擁有自己的數(shù)據(jù)上下文 對(duì)象的問(wèn)題?
來(lái)解決這個(gè)問(wèn)題吧。為什么每個(gè)Repository要擁有一個(gè)數(shù)據(jù)上下文的實(shí)例呢?為什么不在一些地方創(chuàng)建一個(gè)它的實(shí)例,然后在repository被實(shí)例化的時(shí)候作為參數(shù)傳遞進(jìn)去呢?,F(xiàn)在這個(gè)新的類(lèi)被命名為 UnitOfWork ,此類(lèi)將負(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
        {
            // 檢查倉(cāng)儲(chǔ)類(lèi)是否已經(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);
        }
    }
}

倉(cāng)儲(chǔ)

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í)體的列表,支持分頁(yè)
        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í)體的列表,支持分頁(yè)
        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,對(duì)于經(jīng)常使用DbFirst模式的開(kāi)發(fā)者來(lái)說(shuō)已經(jīng)再熟悉不過(guò)了,EntityFramework全靠這員大將。它的作用是代表與數(shù)據(jù)庫(kù)連接的會(huì)話,提供了查詢、狀態(tài)跟蹤、保存等功能。
還有一個(gè)重要的對(duì)象是DbSet,對(duì)實(shí)體類(lèi)型提供了集合操作,比如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è)置禁用一對(duì)多級(jí)聯(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)容合作請(qǐng)聯(lián)系作者
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

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