前言
大家好,我是Rector
又是星期五,很興奮,很高興,很high...啦啦啦。。。
Rector在圖享網又和大家見面啦!!!上一篇《[一步一步創建ASP.NET MVC5程序[Repository+Autofac+Automapper+SqlSugar](五)][1]》,我們完成了:
- AutoMapper是什么簡述
- 安裝AutoMapper
- AutoMapper的配置
- AutoMapper的應用
通過前面幾篇文章的學習,本系列【一步一步創建ASP.NET MVC5程序[Repository+Autofac+Automapper+SqlSugar]】中主要涉及到的技術和組件已基本介紹到位了。接下來的系列文章主要會以知識技術整合,提升,重構等為中心來展開,通過解決項目實戰遇到的各種問題來幫助大家有目,有方向性地學習,以達到提升大家的ASP.NENT MVC 5開發技能的效果。
本文知識要點
今天要給大家分享的是本系列[一步一步創建ASP.NET MVC5程序]的 進階知識:
- 泛型倉儲
為什么使用泛型倉儲
說到為什么使用泛型倉儲,我們不得不回到我們的項目,以項目設計來驅動,說明為什么是泛型倉儲,用泛型倉儲有哪些好處。
回到項目本身
在v1.5版本中,我們已經實現了倉儲層和服務層。其中,倉儲層是我們直接訪問數據庫的層,可以通過倉儲層對數據庫進行任何有權限的操作,包括增,刪,改,查。我們的PostRepository博文倉儲實現類已經實現了其接口中的增,刪,改,查操作,IPostRepository接口:
using System.Collections.Generic;
using TsBlog.Domain.Entities;
namespace TsBlog.Repositories
{
public interface IPostRepository
{
/// <summary>
/// 根據ID查詢單條數據
/// </summary>
/// <param name="id">ID</param>
/// <returns></returns>
Post FindById(int id);
/// <summary>
/// 查詢所有數據(無分頁,大數量時請慎用)
/// </summary>
/// <returns></returns>
IEnumerable<Post> FindAll();
/// <summary>
/// 寫入實體數據
/// </summary>
/// <param name="entity">博文實體類</param>
/// <returns></returns>
int Insert(Post entity);
/// <summary>
/// 更新實體數據
/// </summary>
/// <param name="entity">博文實體類</param>
/// <returns></returns>
bool Update(Post entity);
/// <summary>
/// 根據實體刪除一條數據
/// </summary>
/// <param name="entity">博文實體類</param>
/// <returns></returns>
bool Delete(Post entity);
/// <summary>
/// 刪除指定ID的數據
/// </summary>
/// <param name="id">主鍵ID</param>
/// <returns></returns>
bool DeleteById(object id);
/// <summary>
/// 刪除指定ID集合的數據(批量刪除)
/// </summary>
/// <param name="ids">主鍵ID集合</param>
/// <returns></returns>
bool DeleteByIds(object[] ids);
}
}
看着這個接口類文件現在想一下,如果我們再在數據庫新增一個用戶表(User),然后在領域項目【TsBlog.Domain】中對應創建領域實體(User),那么按照本系列以前添加倉儲和服務層接口的步驟,我們是不是還需要在倉儲中創建一個IUserRepository.cs,如果IUserRepository也包括了增,刪,改,查方法,那么我們是不是需要把IPostRepository中的所有接口方法復制到IUserRepository.cs文件中呢?同時,其實現也要同樣的復制。
如果我們又添加在數據庫新增了多張表,對應的倉儲接口和實現是不是又要重復以上的操作呢?ctrl+c , ctrl+v !!! 如果是這樣,還不如使用代碼生成器來得快。
看到這里,希望有開發經驗的開發者們不要笑話。回想一下當初筆者在初入.NET開發的時候也是這么干的,復制,粘貼,代碼生成器都用過。隨着時間和經驗的積累,你也會變得更好,前提是少用或者不用復制,粘貼來實現編碼功能,即使是網上找的實現方法,也要自己動手敲一遍。
以上兩段話跑題了,我們還是切回正題,上面提到的問題其實是有辦法來避免重復工作,減輕我們的工作量的,即使用泛型倉儲。
泛型倉儲的實現
首先,打開項目【TsBlog.Repositories】,創建接口文件 IRepository.cs,在其中編寫通用的查詢接口方法:
using System;
using System.Collections.Generic;
using System.Linq.Expressions;
namespace TsBlog.Repositories
{
/// <summary>
/// 倉儲通用接口類
/// </summary>
/// <typeparam name="T">泛型實體類</typeparam>
public interface IRepository<T> where T : class, new()
{
/// <summary>
/// 根據主值查詢單條數據
/// </summary>
/// <param name="pkValue">主鍵值</param>
/// <returns>泛型實體</returns>
T FindById(object pkValue);
/// <summary>
/// 查詢所有數據(無分頁,請慎用)
/// </summary>
/// <returns></returns>
IEnumerable<T> FindAll();
/// <summary>
/// 根據條件查詢數據
/// </summary>
/// <param name="predicate">條件表達式樹</param>
/// <param name="orderBy">排序</param>
/// <returns>泛型實體集合</returns>
IEnumerable<T> FindListByClause(Expression<Func<T, bool>> predicate, string orderBy);
/// <summary>
/// 根據條件查詢數據
/// </summary>
/// <param name="predicate">條件表達式樹</param>
/// <returns></returns>
T FindByClause(Expression<Func<T, bool>> predicate);
/// <summary>
/// 寫入實體數據
/// </summary>
/// <param name="entity">實體類</param>
/// <returns></returns>
long Insert(T entity);
/// <summary>
/// 更新實體數據
/// </summary>
/// <param name="entity"></param>
/// <returns></returns>
bool Update(T entity);
/// <summary>
/// 刪除數據
/// </summary>
/// <param name="entity">實體類</param>
/// <returns></returns>
bool Delete(T entity);
/// <summary>
/// 刪除數據
/// </summary>
/// <param name="where">過濾條件</param>
/// <returns></returns>
bool Delete(Expression<Func<T, bool>> @where);
/// <summary>
/// 刪除指定ID的數據
/// </summary>
/// <param name="id"></param>
/// <returns></returns>
bool DeleteById(object id);
/// <summary>
/// 刪除指定ID集合的數據(批量刪除)
/// </summary>
/// <param name="ids"></param>
/// <returns></returns>
bool DeleteByIds(object[] ids);
}
}
創建泛型基類 GenericRepository.cs :
using System;
using System.Collections.Generic;
using System.Linq.Expressions;
namespace TsBlog.Repositories
{
public abstract class GenericRepository<T> : IRepository<T> where T : class, new()
{
#region Implementation of IRepository<T>
/// <summary>
/// 根據主值查詢單條數據
/// </summary>
/// <param name="pkValue">主鍵值</param>
/// <returns>泛型實體</returns>
public T FindById(object pkValue)
{
using (var db = DbFactory.GetSqlSugarClient())
{
var entity = db.Queryable<T>().InSingle(pkValue);
return entity;
}
}
/// <summary>
/// 查詢所有數據(無分頁,請慎用)
/// </summary>
/// <returns></returns>
public IEnumerable<T> FindAll()
{
using (var db = DbFactory.GetSqlSugarClient())
{
var list = db.Queryable<T>().ToList();
return list;
}
}
/// <summary>
/// 根據條件查詢數據
/// </summary>
/// <param name="predicate">條件表達式樹</param>
/// <param name="orderBy">排序</param>
/// <returns>泛型實體集合</returns>
public IEnumerable<T> FindListByClause(Expression<Func<T, bool>> predicate, string orderBy)
{
using (var db = DbFactory.GetSqlSugarClient())
{
var entities = db.Queryable<T>().Where(predicate).ToList();
return entities;
}
}
/// <summary>
/// 根據條件查詢數據
/// </summary>
/// <param name="predicate">條件表達式樹</param>
/// <returns></returns>
public T FindByClause(Expression<Func<T, bool>> predicate)
{
using (var db = DbFactory.GetSqlSugarClient())
{
var entity = db.Queryable<T>().First(predicate);
return entity;
}
}
/// <summary>
/// 寫入實體數據
/// </summary>
/// <param name="entity">實體類</param>
/// <returns></returns>
public long Insert(T entity)
{
using (var db = DbFactory.GetSqlSugarClient())
{
//返回插入數據的標識字段值
var i = db.Insertable(entity).ExecuteReturnBigIdentity();
return i;
}
}
/// <summary>
/// 更新實體數據
/// </summary>
/// <param name="entity"></param>
/// <returns></returns>
public bool Update(T entity)
{
using (var db = DbFactory.GetSqlSugarClient())
{
//這種方式會以主鍵為條件
var i = db.Updateable(entity).ExecuteCommand();
return i > 0;
}
}
/// <summary>
/// 刪除數據
/// </summary>
/// <param name="entity">實體類</param>
/// <returns></returns>
public bool Delete(T entity)
{
using (var db = DbFactory.GetSqlSugarClient())
{
var i = db.Deleteable(entity).ExecuteCommand();
return i > 0;
}
}
/// <summary>
/// 刪除數據
/// </summary>
/// <param name="where">過濾條件</param>
/// <returns></returns>
public bool Delete(Expression<Func<T, bool>> @where)
{
using (var db = DbFactory.GetSqlSugarClient())
{
var i = db.Deleteable<T>(@where).ExecuteCommand();
return i > 0;
}
}
/// <summary>
/// 刪除指定ID的數據
/// </summary>
/// <param name="id"></param>
/// <returns></returns>
public bool DeleteById(object id)
{
using (var db = DbFactory.GetSqlSugarClient())
{
var i = db.Deleteable<T>(id).ExecuteCommand();
return i > 0;
}
}
/// <summary>
/// 刪除指定ID集合的數據(批量刪除)
/// </summary>
/// <param name="ids"></param>
/// <returns></returns>
public bool DeleteByIds(object[] ids)
{
using (var db = DbFactory.GetSqlSugarClient())
{
var i = db.Deleteable<T>().In(ids).ExecuteCommand();
return i > 0;
}
}
#endregion
}
}
現在,倉儲接口和泛型倉儲基類已創建好了,接下來我們重構 IPostRepository 和 PostRepository,使他們分別繼承自 IRepository 和 GenericRepository。
IPostRepository.cs
using TsBlog.Domain.Entities;
namespace TsBlog.Repositories
{
public interface IPostRepository :IRepository<Post>
{
}
}
PostRepository.cs
using TsBlog.Domain.Entities;
namespace TsBlog.Repositories
{
/// <summary>
/// POST表的數據庫操作類
/// </summary>
public class PostRepository : GenericRepository<Post>
{
}
}
IPostRepository 和 PostRepository 是不是一下簡潔了很多,但實現的方法還是和重構前是一樣的。
怎么樣,如果我們再新增用戶表的倉儲接口和倉儲實現是不是非常簡單了呢?再也不用為重復的增,刪,改,查操作來復制,粘貼了。
配置基於接口的依賴注入
在項目【TsBlog.Repositories】中添加接口類 IDependency.cs :
namespace TsBlog.Repositories
{
/// <summary>
/// 依賴注入的接口約束
/// </summary>
public interface IDependency
{
}
}
在泛型倉儲抽象基類 GenericRepository.cs 中添加 IDependency 接口約束 :
public abstract class GenericRepository<T> : IDependency, IRepository<T> where T : class, new()
打開項目【TsBlog.Frontend】中的 Global.asax 重新配置 AutofacRegister 方法,如下:
private void AutofacRegister()
{
var builder = new ContainerBuilder();
//注冊MvcApplication程序集中所有的控制器
builder.RegisterControllers(typeof(MvcApplication).Assembly);
//注冊倉儲層服務
//builder.RegisterType<PostRepository>().As<IPostRepository>();
//注冊基於接口約束的實體
var assembly = AppDomain.CurrentDomain.GetAssemblies();
builder.RegisterAssemblyTypes(assembly)
.Where(
t => t.GetInterfaces()
.Any(i => i.IsAssignableFrom(typeof(IDependency)))
)
.AsImplementedInterfaces()
.InstancePerDependency();
//注冊服務層服務
builder.RegisterType<PostService>().As<IPostService>();
//注冊過濾器
builder.RegisterFilterProvider();
var container = builder.Build();
//設置依賴注入解析器
DependencyResolver.SetResolver(new AutofacDependencyResolver(container));
}
按F5運行,是否報錯了?
是的,因為我們剛才修改了泛型倉儲中Insert的返回類型,所以,修改 IPostService.cs中的Insert的返回類型為long:
long Insert(Post entity);
修改后的 IPostService.cs:
using System.Collections.Generic;
using TsBlog.Domain.Entities;
namespace TsBlog.Services
{
public interface IPostService
{
/// <summary>
/// 根據ID查詢單條數據
/// </summary>
/// <param name="id">ID</param>
/// <returns></returns>
Post FindById(int id);
/// <summary>
/// 查詢所有數據(無分頁,大數量時請慎用)
/// </summary>
/// <returns></returns>
IEnumerable<Post> FindAll();
/// <summary>
/// 寫入實體數據
/// </summary>
/// <param name="entity">博文實體類</param>
/// <returns></returns>
long Insert(Post entity);
/// <summary>
/// 更新實體數據
/// </summary>
/// <param name="entity">博文實體類</param>
/// <returns></returns>
bool Update(Post entity);
/// <summary>
/// 根據實體刪除一條數據
/// </summary>
/// <param name="entity">博文實體類</param>
/// <returns></returns>
bool Delete(Post entity);
/// <summary>
/// 刪除指定ID的數據
/// </summary>
/// <param name="id">主鍵ID</param>
/// <returns></returns>
bool DeleteById(object id);
/// <summary>
/// 刪除指定ID集合的數據(批量刪除)
/// </summary>
/// <param name="ids">主鍵ID集合</param>
/// <returns></returns>
bool DeleteByIds(object[] ids);
}
}
再修改 PostService.cs中的Insert的返回類型為long:
public long Insert(Post entity)
{
return _postRepository.Insert(entity);
}
修改后的 PostService.cs:
using System.Collections.Generic;
using TsBlog.Domain.Entities;
using TsBlog.Repositories;
namespace TsBlog.Services
{
public class PostService : IPostService
{
private readonly IRepository<Post> _postRepository;
public PostService(IRepository<Post> postRepository)
{
_postRepository = postRepository;
}
public bool Delete(Post entity)
{
return _postRepository.Delete(entity);
}
public bool DeleteById(object id)
{
return _postRepository.DeleteById(id);
}
public bool DeleteByIds(object[] ids)
{
return _postRepository.DeleteByIds(ids);
}
public IEnumerable<Post> FindAll()
{
return _postRepository.FindAll();
}
public Post FindById(int id)
{
return _postRepository.FindById(id);
}
public long Insert(Post entity)
{
return _postRepository.Insert(entity);
}
public bool Update(Post entity)
{
return _postRepository.Update(entity);
}
}
}
請注意:在 PostRepository.cs中還沒有繼承至 IPostRepository.cs ,所以,在 PostService.cs 的構造函數中我們暫時使用泛型接口 IRepository
:
private readonly IRepository
public PostService(IRepository
{
_postRepository = postRepository;
}
下一篇將解決這個問題
再次按F5運行,打開頁面[http://localhost:54739/home/post],熟悉你頁面又回來了,哈哈。。。
![create-aspnet-mvc-5-web-application-repository-autofac-automapper-sqlsugar-step-by-step-06][2]
本文的源碼托管地址:https://github.com/lampo1024/TsBlog/releases/tag/v1.6
本文學習到此結束,本系列未完待續,我們下期再見……
如果你喜歡Rector的本系列文章,請為我點個大大的贊。
本文來源 [圖享網][3] 《[一步一步創建ASP.NET MVC5程序\[Repository+Autofac+Automapper+SqlSugar\](六)][4]》
我的博客即將搬運同步至騰訊雲+社區,邀請大家一同入駐:https://cloud.tencent.com/developer/support-plan
[1]: http://2sharings.com/2017/create-aspnet-mvc-5-web-application-repository-autofac-automapper-sqlsugar-step-by-step-05
[2]: http://img.2sharings.com/uploads/2017/12/create-aspnet-mvc-5-web-application-repository-autofac-automapper-sqlsugar-step-by-step-05-05.png
[3]: http://2sharings.com/
[4]: http://2sharings.com/2017/create-aspnet-mvc-5-web-application-repository-autofac-automapper-sqlsugar-step-by-step-06