SmartSql使用教程(2)—使用動態代理實現CURD

Noah.Ji發表於2019-05-17

一、引言

  接著上一篇的教程,本章我們繼續講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指令碼的方式。

ExecuteBehavior
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的使用

 

相關文章