一、引言
接着上一篇的教程,本章我們繼續講SmartSql。今天的主題是動態倉儲。
老規矩,先上一個項目結構
從第二章開始。我們將原來的單一項目做了一個分離。方便之后的更新。
在這個結構中。原本上一章的DataAccess沒有了。取而代之的是Repository。這個就是動態倉儲的項目。接下來我們從這個Repository項目開始說。這也是動態倉儲的核心。
二、Repository項目
1. Nuget依賴
SmartSql有一個獨立的動態倉儲庫,即:SmartSql.DyRepository。如果你想使用動態倉儲,引用它就行啦。
2. 第一個倉儲接口
引用完庫,接下來就是創建我們的第一個倉儲接口—IArticleRepository。廢話不到,先上代碼再一一解釋。

1 using SmartSql.DyRepository; 2 using SmartSql.DyRepository.Annotations; 3 using SmartSqlSampleChapterTwo.Entity; 4 using System.Data; 5
6 namespace SmartSqlSampleChapterTwo.Repository 7 { 8 [SqlMap(Scope = "CustomScope")] 9 public interface IArticleRepository : IRepository<T_Article, long>
10 { 11 [Statement(CommandType = CommandType.Text, Execute = ExecuteBehavior.ExecuteScalar, Id = "Offline")] 12 int OfflineArticle([Param("Id", FieldType = typeof(long))] long articleId); 13
14 [Statement(Sql = "Update T_Article Set Status = 1 Where Id = @Id")] 15 int OnlineArticle([Param("Id")] long article); 16 } 17 }
2.1 默認接口 IRepository
看完代碼是不是發現和上一章的DataAccess有很大的區別,那些CURD的方法都沒有了。
這是SmartSql內置的一些默認接口,它包括以下這些接口,這些接口基本可以滿足大部分普通業務場景了。
1 int Insert(TEntity entity); 2
3 int Update(TEntity entity); 4
5 [Statement(Id = "Update")] 6 int DyUpdate(object dyObj); 7
8 int Delete(object reqParams); 9
10 [Statement(Id = "Delete")] 11 int DeleteById([Param("Id")] TPrimary id); 12
13 TEntity GetEntity(object reqParams); 14
15 [Statement(Id = "GetEntity")] 16 TEntity GetById([Param("Id")] TPrimary id); 17
18 [Statement(Execute = ExecuteBehavior.ExecuteScalar)] 19 int GetRecord(object reqParams); 20
21 IList<TEntity> QueryByPage(object reqParams); 22
23 IList<TEntity> Query(object reqParams); 24
25 [Statement(Execute = ExecuteBehavior.ExecuteScalar)] 26 bool IsExist(object reqParams);
2.2 SqlMap特性
這個特性是用於指定Scope的配置。這個對應於Map中的Scope屬性。這里我定義了“CustomScope”。那對應的Map中也將與之對應。如下圖:
2.3 Statement特性
這個特性略微有點復雜,其中包含了6個屬性,接下來我們一個個看。
2.3.1 Scope
這個特性和SqlMap的Scope作用是一樣的。區別在於Statement的級別更高。
2.3.2 Id
指定此函數所使用的Statement。依據是Id。例:
// 接口定義 [Statement(Id = "TestId")] int CustomStatementId();
<!-- Statement定義 -->
<Statement Id="TestId"> db script... </Statement>
2.3.3 Execute
Execute是一個ExecuteBehavior枚舉,用於指定此函數執行Sql腳本的方式。
Auto | ORM自動識別 |
Execute | 返回影響行數,主要用於執行寫操作。 |
ExecuteScalar | 返回第一行第一列的數據,主要用於返回自增主鍵和獲取結果數 |
Query | 返回List |
QuerySingle | 返回第一行數據 |
GetDataTable | 返回DataTable |
GetDataSet | 返回DataSet |
2.3.4 Sql
特殊場景下,可以直接使用此屬性定義Sql腳本,而不用配置SqlMap。如IArticleRepository的OnlineArticle定義。
2.3.5 CommandType
這個屬性是ADO.NET的CommandType枚舉。作用也完全相同
2.3.6 SourceChoice
指定數據源,可以指定Write或Read。
3. Startup
在上一章節中,我們在Startup中注冊了SmartSql,現在我們要繼續注冊動態倉儲。代碼也很簡單,只要在AddSmart方法完成后繼續調用AddRepositoryFromAssembly即可。如下:
services.AddSmartSql(builder => { builder.UseAlias("SmartSqlSampleChapterTwo"); // 定義實例別名,在多庫場景下適用。 //.UseXmlConfig(ResourceType.File,"MyConfig.xml");
}).AddRepositoryFromAssembly(options => { // SmartSql實例的別名
options.SmartSqlAlias = "SmartSqlSampleChapterTwo"; // 倉儲接口所在的程序集全稱
options.AssemblyString = "SmartSqlSampleChapterTwo.Repository"; // 篩選器,根據接口的Type篩選需要的倉儲
options.Filter = type => type.FullName.Contains("Sample"); // Scope模板,默認是"I{Scope}Repository"
options.ScopeTemplate = "I{Scope}Repository"; });
這個方法中會拋出一個AssemblyAutoRegisterOptions,方便用戶注冊指定的倉儲。
4. Controller的變化
在Sample中,我們直接讓Controller引用了Repository,實際場景中。我們可以在任何需要倉儲的地方引用倉儲。代碼如下:

using Microsoft.AspNetCore.Mvc; using SmartSqlSampleChapterTwo.Entity; using SmartSqlSampleChapterTwo.Repository; using System.Collections.Generic; namespace SmartSqlSampleChapterTwo.Api.Controllers { /// <summary>
///
/// </summary>
[Route("[controller]/[action]")] public class ArticleController : Controller { private readonly IArticleRepository _articleRepository; /// <summary>
/// constructor /// </summary>
/// <param name="articleRepository"></param>
public ArticleController(IArticleRepository articleRepository) { _articleRepository = articleRepository; } /// <summary>
///
/// </summary>
/// <param name="article"></param>
/// <returns></returns>
[HttpPost] public T_Article Add([FromBody] T_Article article) { article.Id = _articleRepository.Insert(article); return article; } /// <summary>
///
/// </summary>
/// <param name="id"></param>
/// <returns></returns>
[HttpGet] public T_Article Get([FromQuery] long id) { return _articleRepository.GetById(id); } /// <summary>
///
/// </summary>
/// <param name="article"></param>
/// <returns></returns>
[HttpPost] public bool Update([FromBody] T_Article article) { return _articleRepository.Update(article) > 0; } /// <summary>
///
/// </summary>
/// <param name="id"></param>
/// <param name="status"></param>
/// <returns></returns>
[HttpPost] public bool UpdateStatus([FromQuery] long id, [FromQuery] int status) { return _articleRepository.DyUpdate(new { Id = id, Status = status }) > 0; } /// <summary>
///
/// </summary>
/// <param name="id"></param>
/// <returns></returns>
[HttpGet] public bool IsExist([FromQuery] long id) { return _articleRepository.IsExist(new { Id = id }); } /// <summary>
///
/// </summary>
/// <param name="key"></param>
/// <returns></returns>
[HttpGet] public IEnumerable<T_Article> Query([FromQuery] string key = "") { return _articleRepository.Query(new { Title = key }); } /// <summary>
///
/// </summary>
/// <param name="id"></param>
/// <returns></returns>
[HttpGet] public int Offline([FromQuery] long id) { return _articleRepository.OfflineArticle(id); } /// <summary>
///
/// </summary>
/// <param name="id"></param>
/// <returns></returns>
[HttpGet] public int Online([FromQuery] long id) { return _articleRepository.OnlineArticle(id); } } }
可以注意到的是,除了把DataAccess變成了Repository。其他的代碼幾乎沒有改動。最后我還添加了倉儲自定義的接口的調用。
5. 結語
今天,我們了解了動態倉儲的使用。它是一個非常方便的特性,可以非常顯著的提升我們寫代碼的效率,減少一定的代碼量,避免了很多“體力活”。讓我們專注於業務!
下期預告:SmartSql中的事務,及AOP的使用