最近SmartSql被正式引入到了NCC,藉着這個契機寫一個使用教程系列git
SmartSql = MyBatis + Cache(Memory | Redis) + R/W Splitting +Dynamic Repository + Diagnostics ......github
簡潔、高效、高性能、擴展性、監控、漸進式開發!sql
SmartSql 借鑑了 MyBatis 的思想,使用 XML 來管理 SQL ,而且提供了若干個篩選器標籤來消除代碼層面的各類 if/else 的判斷分支。數據庫
SmartSql將管理你的 SQL ,而且經過篩選標籤來維護原本你在代碼層面的各類條件判斷,使你的代碼更加優美。json
DotNet 體系下大都是 Linq 系的 ORM,Linq 很好,消除了開發人員對 SQL 的依賴。 但卻忽視了一點,SQL 自己並不複雜,並且在複雜查詢場景當中開發人員很難經過編寫Linq來生成良好性能的SQL,相信使用過EF的同窗必定有這樣的體驗:「我想好了Sql怎麼寫,而後再來寫Linq,完了可能還要再查看一下Linq輸出的Sql是什麼樣的「。這是很是糟糕的體驗。要想對Sql作絕對的優化,那麼開發者必須對Sql有絕對的控制權。另外Sql自己很簡單,爲什麼要增長一層翻譯器呢?緩存
知道了SmartSql是什麼,那接下來咱們開始建立一個項目從0開始使用SmartSql寫一個簡單的CURD接口服務。app
先上一個項目結構,而後咱們一一分析他們的做用ide
這裏我用的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() )
SmartSql的庫能夠直接在Nuget上找到,但由於.NetCoreMVC的項目如今自帶了DI依賴注入的關係,咱們只須要直接引用SmartSql.DI.Extension就能夠了。測試
項目的依賴性包括了
1. AspNetCore基礎庫
2. SmartSql.DI.Extension(咱們的主角)
3. Swashbuckle.AspNetCore(方便咱們接口測試)
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>
1 <SmartSqlMap Scope="Article" xmlns="http://SmartSql.net/schemas/SmartSqlMap.xsd">
2 ... 3 </SmartSqlMap>
這裏的關鍵在於Scope,這個屬性是用於定位Map的。
<!--新增-->
<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>
<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配置中。咱們使用了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>
注入SmartSql
// register smartsql
services.AddSmartSql(builder => { builder.UseAlias("SmartSqlSampleChapterOne"); // 定義實例別名,在多庫場景下適用。 //.UseXmlConfig(ResourceType.File,"MyConfig.xml");
});
在2.2中咱們把基礎配置文件命名爲SmartSqlMapConfig。這個是默認文件名,咱們也能夠像上面的註釋代碼同樣。自定義配置文件的名稱。
其實到了這一步一切都順其天然了。我感受沒有什麼能夠多講了。直接上代碼了!
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 }
有了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<T_Article> Query([FromQuery] string key = "") { return _articleDataAccess.Query(new { Title = key }); } } }
前面咱們已經把SmartSql注入到了DI。如今咱們再完善一下它,把Mvc和Swagger也注入進去。
1 using Microsoft.AspNetCore.Builder; 2 using Microsoft.AspNetCore.Hosting; 3 using Microsoft.Extensions.Configuration; 4 using Microsoft.Extensions.DependencyInjection; 5 using Microsoft.Extensions.Logging; 6 using Swashbuckle.AspNetCore.Swagger; 7 using System; 8 using System.IO; 9 using SmartSql.ConfigBuilder; 10 using SmartSqlSampleChapterOne.DataAccess; 11
12 namespace SmartSqlSampleChapterOne 13 { 14 public class Startup 15 { 16 public Startup(IConfiguration configuration) 17 { 18 Configuration = configuration; 19 } 20
21 public IConfiguration Configuration { get; } 22 // This method gets called by the runtime. Use this method to add services to the container. 23 // For more information on how to configure your application, visit https://go.microsoft.com/fwlink/?LinkID=398940
24 public void ConfigureServices(IServiceCollection services) 25 { 26 services.AddMvc(); 27
28 services.AddLogging(logging =>
29 { 30 logging.SetMinimumLevel(LogLevel.Trace); 31 logging.AddConsole(); 32 }); 33
34 // register smartsql
35 services.AddSmartSql(builder =>
36 { 37 builder.UseAlias("SmartSqlSampleChapterOne"); // 定義實例別名,在多庫場景下適用。 38 //.UseXmlConfig(ResourceType.File,"MyConfig.xml");
39 }); 40
41 // register data access
42 services.AddSingleton<ArticleDataAccess>(); 43
44 // register swagger
45 services.AddSwaggerGen(c =>
46 { 47 c.SwaggerDoc("SmartSqlSampleChapterOne", new Info 48 { 49 Title = "SmartSqlSample.ChapterOne", 50 Version = "v1", 51 Description = "SmartSqlSample.ChapterOne"
52 }); 53 var filePath = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "SmartSqlSampleChapterOne.xml"); 54 if (File.Exists(filePath)) c.IncludeXmlComments(filePath); 55 }); 56
57 } 58
59 // This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
60 public void Configure(IApplicationBuilder app, IHostingEnvironment env) 61 { 62 if (env.IsDevelopment()) app.UseDeveloperExceptionPage(); 63 app.UseMvc(); 64
65 app.UseSwagger(c => { }); 66 app.UseSwaggerUI(c => { c.SwaggerEndpoint("/swagger/SmartSqlSampleChapterOne/swagger.json", "SmartSqlSampleChapterOne"); }); 67 } 68 } 69 }
好了!至此項目的大部分元素都作了一個簡單介紹。咱們來看看最終的運行結果吧。
接口預覽
添加接口
獲取接口
查詢接口
本篇文章簡單介紹了一下如何使用SmartSql從無到有,完成一個單表的CURD接口實現。但其實SmartSql是一個很是強大的ORM,它還有許多特性沒有展開。再接下來的系列文章中。我會一一爲你們介紹。
下期預告:使用動態代理實現CURD