SmartSql = MyBatis + Cache(Memory | Redis) + R/W Splitting +Dynamic Repository + Diagnostics ...... ...
一、引言
接著上一篇的教程,本章我們繼續講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 }
IArticleRepository
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);
}
}
}
ArticleController
可以註意到的是,除了把DataAccess變成了Repository。其他的代碼幾乎沒有改動。最後我還添加了倉儲自定義的介面的調用。
5. 結語
今天,我們瞭解了動態倉儲的使用。它是一個非常方便的特性,可以非常顯著的提升我們寫代碼的效率,減少一定的代碼量,避免了很多“體力活”。讓我們專註於業務!
下期預告:SmartSql中的事務,及AOP的使用