SmartSql使用教程(1)——初探,建立一個簡單的CURD介面服務

来源:https://www.cnblogs.com/noahji/archive/2019/05/13/10846215.html
-Advertisement-
Play Games

SmartSql = MyBatis + Cache(Memory | Redis) + R/W Splitting +Dynamic Repository + Diagnostics ...... ...


一、引言

最近SmartSql被正式引入到了NCC,藉著這個契機寫一個使用教程系列

 

二、SmartSql簡介[摘自官方文檔]

1. SmartSql是什麼?

SmartSql = MyBatis + Cache(Memory | Redis) + R/W Splitting +Dynamic Repository + Diagnostics ......

2. SmartSql的特性

簡潔、高效、高性能、擴展性、監控、漸進式開發!

3. 她是如何工作的?

  SmartSql 借鑒了 MyBatis 的思想,使用 XML 來管理 SQL ,並且提供了若幹個篩選器標簽來消除代碼層面的各種 if/else 的判斷分支。

  SmartSql將管理你的 SQL ,並且通過篩選標簽來維護本來你在代碼層面的各種條件判斷,使你的代碼更加優美。

4. 為什麼選擇SmartSql?

  DotNet 體系下大都是 Linq 系的 ORM,Linq 很好,消除了開發人員對 SQL 的依賴。 但卻忽視了一點,SQL 本身並不複雜,而且在複雜查詢場景當中開發人員很難通過編寫Linq來生成良好性能的SQL,相信使用過EF的同學一定有這樣的體驗:“我想好了Sql怎麼寫,然後再來寫Linq,完了可能還要再查看一下Linq輸出的Sql是什麼樣的“。這是非常糟糕的體驗。要想對Sql做絕對的優化,那麼開發者必須對Sql有絕對的控制權。另外Sql本身很簡單,為何要增加一層翻譯器呢?

 

三、開始SmartSql之旅

  知道了SmartSql是什麼,那接下來我們開始創建一個項目從0開始使用SmartSql寫一個簡單的CURD介面服務。

  先上一個項目結構,然後我們一一分析他們的作用

 

1. 創建DB

  這裡我用的DB是MSSql,直接貼腳本了。

Create Database SmartSqlSample
GO
Use SmartSqlSample
GO
Create Table T_Article (
    Id bigint not null primary key identity(1,1),
    Title nvarchar(255) not null,
    Content nvarchar(max) null,
    Author nvarchar(255) null,
    Status int not null,
    CreateTime datetime not null default getdate(),
    ModifiedTime datetime not null default getdate()
)
Init腳本

2. SmartSql 基礎配置

2.1 添加Nuget依賴

  SmartSql的庫可以直接在Nuget上找到,但因為.NetCoreMVC的項目現在自帶了DI依賴註入的關係,我們只需要直接引用SmartSql.DI.Extension就可以了。

  項目的依賴性包括了

  1. AspNetCore基礎庫

  2. SmartSql.DI.Extension(我們的主角)

  3. Swashbuckle.AspNetCore(方便我們介面測試)

 

2.2 添加SmartSql配置文件

  SmartSql是一個基於Xml配置的ORM。這點和Mybatis沒有什麼不同。如果你熟悉Mybatis,相信你很快就能適應SmartSql。如果你以前沒接觸過類似的ORM。那請跟著這個教程,一步一步瞭解SmartSql的強大。

  SmartSqlMapConfig.xml,SmartSql的起點。

 1 <?xml version="1.0" encoding="utf-8" ?>
 2 <!--
 3 //*******************************
 4 // Create By Noah.Ji
 5 // Date 2019-05-10
 6 // Github : https://github.com/noahjzc/SmartSqlSample
 7 //*******************************-->
 8 <SmartSqlMapConfig xmlns="http://SmartSql.net/schemas/SmartSqlMapConfig.xsd">
 9   <!-- 允許使用緩存(以後章節細講) -->
10   <Settings IsCacheEnabled="true" />
11   <!-- 屬性、特性配置節點,這裡只配置一個連接字元串 -->
12   <Properties>
13     <Property Name="ConnectionString" Value="Data Source=localhost;database=SmartSqlSample;uid=sa;pwd=123456" />
14     <Property Name="ReadOneConnectionString" Value="Data Source=123.123.123.123;database=SmartSqlSample;uid=sa;pwd=123456" />
15   </Properties>
16   <!-- 資料庫配置 Start -->
17   <Database>
18     <DbProvider Name="SqlServer" />
19     <Write Name="Sample-Write" ConnectionString="${ConnectionString}" />
20     <!-- 多讀節點配置 -->
21     <!--
22     <Read Name="Sample-Node-1" ConnectionString="${ReadOneConnectionString}" Weight="60"/>
23     <Read Name="Sample-Node-2" ConnectionString="Data Source=456.456.456.456;database=SmartSqlSample;uid=sa;pwd=123456" Weight="40"/>
24     -->
25   </Database>
26   <!-- 資料庫配置 End -->
27   <!-- 數據Map配置 Start -->
28   <SmartSqlMaps>
29     <!-- 文件夾 -->
30     <SmartSqlMap Path="Maps" Type="Directory"></SmartSqlMap>
31 
32     <!-- 文件夾及子集(遞歸獲取文件夾下所有Map文件) -->
33     <!--<SmartSqlMap Path="Maps" Type="DirectoryWithAllSub"></SmartSqlMap>-->
34 
35     <!-- 單個文件 -->
36     <!--<SmartSqlMap Path="Maps/T_Article.xml" Type="File"></SmartSqlMap>-->
37 
38     <!-- 嵌入式資源 -->
39     <!--<SmartSqlMap Path="SmartSqlSampleChapterOne.Maps.T_Article.xml, SmartSqlSampleChapterOne" Type="Embedded"></SmartSqlMap>-->
40 
41     <!-- http資源 -->
42     <!--<SmartSqlMap Type="Uri" Path="https://smartsql.net/Maps/T_Article.xml" />-->
43   </SmartSqlMaps>
44   <!-- 數據Map配置 End -->
45 </SmartSqlMapConfig>

2.3 表Map配置

2.3.1 Root節點

1 <SmartSqlMap Scope="Article" xmlns="http://SmartSql.net/schemas/SmartSqlMap.xsd">
2 ...
3 </SmartSqlMap>

這裡的關鍵在於Scope,這個屬性是用於定位Map的。

2.3.2 CUD配置

<!--新增-->
<Statement Id="Insert">
  INSERT INTO T_Article
  (Title
  ,Content
  ,Author
  ,Status
  ,CreateTime
  ,ModifiedTime
  )
  VALUES
  (@Title
  ,@Content
  ,@Author
  ,@Status
  ,@CreateTime
  ,GetDate()
  );
  SELECT Scope_Identity();
</Statement>
<!--刪除-->
<Statement Id="Delete">
  DELETE T_Article WHERE Id = @Id
</Statement>
<!--更新-->
<Statement Id="Update">
  UPDATE T_Article
  <Set>
    ModifiedTime = GetDate()
    <IsProperty Prepend="," Property="Title">
      Title = @Title
    </IsProperty>
    <IsProperty Prepend="," Property="Content">
      Content = @Content
    </IsProperty>
    <IsProperty Prepend="," Property="Author">
      Author = @Author
    </IsProperty>
    <IsProperty Prepend="," Property="Status">
      Status = @Status
    </IsProperty>
    <IsProperty Prepend="," Property="CreateTime">
      CreateTime = @CreateTime
    </IsProperty>
  </Set>
  Where id=@Id
</Statement>
CUD配置

2.3.3 通用查詢節點

<Statement Id="QueryParams">
  <Where>
    <IsGreaterEqual Prepend="And" Property="Id" CompareValue="0">
      T.Id = @Id
    </IsGreaterEqual>
    <IsNotEmpty Prepend="And" Property="Title">
      T.Title Like '%'+@Title+'%'
    </IsNotEmpty>
    <IsNotEmpty Prepend="And" Property="Ids">
      T.Id IN @Ids
    </IsNotEmpty>
  </Where>
</Statement>
通用查詢節點

這個Statement節點其實和別的節點沒什麼區別。SmartSql允許Statement的嵌套。使用規則如下麵這段配置

<Statement Id="Query">
  SELECT T.* FROM T_Article T
  <Include RefId="QueryParams" />
  <Switch Prepend="Order By" Property="OrderBy">
    <Default>
      T.id Desc
    </Default>
  </Switch>
  <IsNotEmpty Prepend="Limit" Property="Taken">@Taken</IsNotEmpty>
</Statement>
Query

在這段Query配置中。我們使用了Include標簽來引入上面定義好的Id為QueryParams的Statement,這樣就做到了查詢配置的通用性。例如我還可以將QueryParams配置到分頁和查詢結果數的配置中。如下:

<!--獲取分頁數據-->
<Statement Id="QueryByPage">
  SELECT T.* FROM T_Article As T
  <Include RefId="QueryParams" />
  <Switch Prepend="Order By" Property="OrderBy">
    <Default>
      T.Id Desc
    </Default>
  </Switch>
  Offset ((@PageIndex-1)*@PageSize) Rows Fetch Next @PageSize Rows Only;
</Statement>

<!--獲取記錄數-->
<Statement Id="GetRecord">
  SELECT Count(1) FROM T_Article T
  <Include RefId="QueryParams" />
</Statement>
分頁及結果數查詢

2.4 Startup

註入SmartSql

// register smartsql
services.AddSmartSql(builder =>
{
    builder.UseAlias("SmartSqlSampleChapterOne");       // 定義實例別名,在多庫場景下適用。
    //.UseXmlConfig(ResourceType.File,"MyConfig.xml");
});

在2.2中我們把基礎配置文件命名為SmartSqlMapConfig。這個是預設文件名,我們也可以像上面的註釋代碼一樣。自定義配置文件的名稱。

 

3. 讓配置工作起來

其實到了這一步一切都順其自然了。我感覺沒有什麼可以多講了。直接上代碼了!

  1 using Microsoft.Extensions.DependencyInjection;
  2 using SmartSql;
  3 using SmartSqlSampleChapterOne.Entity;
  4 using System;
  5 using System.Collections.Generic;
  6 
  7 namespace SmartSqlSampleChapterOne.DataAccess
  8 {
  9     /// <summary>
 10     /// 
 11     /// </summary>
 12     public class ArticleDataAccess
 13     {
 14         private readonly ISqlMapper _sqlMapper;
 15 
 16         /// <summary>
 17         /// 
 18         /// </summary>
 19         /// <param name="sp"></param>
 20         public ArticleDataAccess(IServiceProvider sp)
 21         {
 22             _sqlMapper = sp.GetSmartSql("SmartSqlSampleChapterOne").SqlMapper;
 23         }
 24 
 25         /// <summary>
 26         /// Insert
 27         /// </summary>
 28         /// <param name="article"></param>
 29         /// <returns></returns>
 30         public long Insert(T_Article article)
 31         {
 32             return _sqlMapper.ExecuteScalar<long>(new RequestContext
 33             {
 34                 Scope = "Article",
 35                 SqlId = "Insert",
 36                 Request = article
 37             });
 38         }
 39 
 40         /// <summary>
 41         /// Update
 42         /// </summary>
 43         /// <param name="article"></param>
 44         /// <returns></returns>
 45         public int Update(T_Article article)
 46         {
 47             return _sqlMapper.Execute(new RequestContext
 48             {
 49                 Scope = "Article",
 50                 SqlId = "Update",
 51                 Request = article
 52             });
 53         }
 54 
 55         /// <summary>
 56         /// DyUpdate
 57         /// </summary>
 58         /// <param name="updateObj"></param>
 59         /// <returns></returns>
 60         public int DyUpdate(object updateObj)
 61         {
 62             return _sqlMapper.Execute(new RequestContext
 63             {
 64                 Scope = "Article",
 65                 SqlId = "Update",
 66                 Request = updateObj
 67             });
 68         }
 69 
 70         /// <summary>
 71         /// Delete
 72         /// </summary>
 73         /// <param name="id"></param>
 74         /// <returns></returns>
 75         public int Delete(long id)
 76         {
 77             return _sqlMapper.Execute(new RequestContext
 78             {
 79                 Scope = "Article",
 80                 SqlId = "Delete",
 81                 Request = new { Id = id }
 82             });
 83         }
 84 
 85         /// <summary>
 86         /// GetById
 87         /// </summary>
 88         /// <param name="id"></param>
 89         /// <returns></returns>
 90         public T_Article GetById(long id)
 91         {
 92             return _sqlMapper.QuerySingle<T_Article>(new RequestContext
 93             {
 94                 Scope = "Article",
 95                 SqlId = "GetEntity",
 96                 Request = new { Id = id }
 97             });
 98         }
 99 
100         /// <summary>
101         /// Query
102         /// </summary>
103         /// <param name="queryParams"></param>
104         /// <returns></returns>
105         public IEnumerable<T_Article> Query(object queryParams)
106         {
107             return _sqlMapper.Query<T_Article>(new RequestContext
108             {
109                 Scope = "Article",
110                 SqlId = "Query",
111                 Request = queryParams
112             });
113         }
114 
115         /// <summary>
116         /// GetRecord
117         /// </summary>
118         /// <param name="queryParams"></param>
119         /// <returns></returns>
120         public int GetRecord(object queryParams)
121         {
122             return _sqlMapper.ExecuteScalar<int>(new RequestContext
123             {
124                 Scope = "Article",
125                 SqlId = "GetRecord",
126                 Request = queryParams
127             });
128         }
129 
130         /// <summary>
131         /// IsExist
132         /// </summary>
133         /// <param name="queryParams"></param>
134         /// <returns></returns>
135         public bool IsExist(object queryParams)
136         {
137             return _sqlMapper.QuerySingle<bool>(new RequestContext
138             {
139                 Scope = "Article",
140                 SqlId = "IsExist",
141                 Request = queryParams
142             });
143         }
144     }
145 }
ArticleDataAccess

 

4. 最後一步

4.1 ArticleController

有了DataAccess我們可以輕鬆的操作資料庫了。最後一步我們建立一個Controller,對外暴露一些介面吧。

using Microsoft.AspNetCore.Mvc;
using SmartSqlSampleChapterOne.DataAccess;
using SmartSqlSampleChapterOne.Entity;
using System.Collections.Generic;

namespace SmartSqlSampleChapterOne.Controllers
{
    /// <summary>
    /// 
    /// </summary>
    [Route("[controller]/[action]")]
    public class ArticleController : Controller
    {
        private readonly ArticleDataAccess _articleDataAccess;

        /// <summary>
        /// constructor
        /// </summary>
        /// <param name="articleDataAccess"></param>
        public ArticleController(ArticleDataAccess articleDataAccess)
        {
            _articleDataAccess = articleDataAccess;
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="article"></param>
        /// <returns></returns>
        [HttpPost]
        public T_Article Add([FromBody] T_Article article)
        {
            article.Id = _articleDataAccess.Insert(article);
            return article;
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="id"></param>
        /// <returns></returns>
        [HttpGet]
        public T_Article Get([FromQuery] long id)
        {
            return _articleDataAccess.GetById(id);
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="article"></param>
        /// <returns></returns>
        [HttpPost]
        public bool Update([FromBody] T_Article article)
        {
            return _articleDataAccess.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 _articleDataAccess.DyUpdate(new
            {
                Id = id,
                Status = status
            }) > 0;
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="id"></param>
        /// <returns></returns>
        [HttpGet]
        public bool IsExist([FromQuery] long id)
        {
            return _articleDataAccess.IsExist(new
            {
                Id = id
            });
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="key"></param>
        /// <returns></returns>
        [HttpGet]
        public IEnumerable<

您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • Python面向對象之文件操作 , 內容 文件的概念,文件的基本操作,文件/目錄的常用管理操作,文本文件的編碼格式。其中 文件的概念 包括 文件的概念和作用,文件的存儲方式;文件的基本操作 包括 文件操作步驟,操作文件的方法/函數,read方法,open函數,readline按行讀取文件內容;文件/... ...
  • 前面介紹了線程的基本用法,按理說足夠一般的場合使用了,只是每次開闢新線程,都得單獨定義專門的線程類,著實開銷不小。註意到新線程內部真正需要開發者重寫的僅有run方法,其實就是一段代碼塊,分線程啟動之後也單單執行該代碼段而已。因而完全可以把這段代碼抽出來,把它定義為類似方法的一串任務代碼,這樣能夠像調 ...
  • 終於A了這道題啊(坑啊) 教練說:這道題不能用map吧,複雜度不一個O(nlogn)嗎 於是我就一直想不出來,然後看題解代碼,一看就是map... 所以我就在想,那複雜度是不是也不是O(nlogn)呢 教練看了半天,說:好像確實不是誒 原來阻擋我的最大障礙是教練啊!!!(當時只給題面,也不知道時限) ...
  • 一個模塊的 API層(Web層),主要負責如下幾個方面的工作:接收 前端層 提交的數據查詢請求,使用 服務層 提供的 IQueryable 查詢數據源,查詢出需要的數據返回前端。接收 前端層 提交的業務處理請求,調用 服務層 的服務,處理業務需求,並將操作結果返回前端。使用MVC的 Area-Co... ...
  • Ocelot .Net Core開源網關 作者:markjiang7m2 原文地址: 源碼地址:https://gitee.com/Sevenm2/OcelotDemo 今天要給大家介紹的Ocelot是一個基於 .net core的開源WebAPI服務網關項目,它的功能非常強大,包括了路由、請求聚合 ...
  • 本文講述使用window服務創建定時任務 1.如圖,新建項目,windows桌面->windows服務 2.如圖,右鍵,添加安裝程式 3.在下圖安裝程式 serviceInstaller1 上右鍵,修改serviceName和Description 4.如圖,在 serviceProcessInst ...
  • .net core 設置讀取JSON配置文件 appsettings.json Startup.cs 中 類庫中 使用 這種方法可以保證可以修改正在運行的dotnet core 程式,不需要重啟程式 使用Newtonsoft.Json 查詢/修改,以及修改 appsettings.json 文件 R ...
  • 主要是通過修改HOSTS來,解決GitHub載入和下載慢問題。 ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...