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