最近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