前言 大家好,我是Rector 又是星期五,很興奮,很高興,很high...啦啦啦。。。 Rector在圖享網又和大家見面啦!!!上一篇《 "一步一步創建ASP.NET MVC5程式\[Repository+Autofac+Automapper+SqlSugar\" ][1]》,我們完成了: Aut ...
前言
大家好,我是Rector
又是星期五,很興奮,很高興,很high...啦啦啦。。。
Rector在圖享網又和大家見面啦!!!上一篇《一步一步創建ASP.NET MVC5程式[Repository+Autofac+Automapper+SqlSugar](五)》,我們完成了:
- 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<Post> _postRepository; public PostService(IRepository<Post> postRepository) { _postRepository = postRepository; }
下一篇將解決這個問題
再次按F5運行,打開頁面[http://localhost:54739/home/post],熟悉你頁面又回來了,哈哈。。。
本文的源碼托管地址:https://github.com/lampo1024/TsBlog/releases/tag/v1.6
本文學習到此結束,本系列未完待續,我們下期再見……
如果你喜歡Rector的本系列文章,請為我點個大大的贊。
本文來源 圖享網 《一步一步創建ASP.NET MVC5程式[Repository+Autofac+Automapper+SqlSugar](六)》