欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

SmartSql使用教程(2)—使用动态代理实现CURD

程序员文章站 2022-06-28 20:23:19
SmartSql = MyBatis + Cache(Memory | Redis) + R/W Splitting +Dynamic Repository + Diagnostics ...... ......

一、引言

  接着上一篇的教程,本章我们继续讲smartsql。今天的主题是动态仓储。

  老规矩,先上一个项目结构

SmartSql使用教程(2)—使用动态代理实现CURD

  从第二章开始。我们将原来的单一项目做了一个分离。方便之后的更新。

  在这个结构中。原本上一章的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 }

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中也将与之对应。如下图:

  SmartSql使用教程(2)—使用动态代理实现CURD

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);
        }
    }
}

  可以注意到的是,除了把dataaccess变成了repository。其他的代码几乎没有改动。最后我还添加了仓储自定义的接口的调用。

5. 结语

  今天,我们了解了动态仓储的使用。它是一个非常方便的特性,可以非常显著的提升我们写代码的效率,减少一定的代码量,避免了很多“体力活”。让我们专注于业务!

示例代码链接在这里

 

下期预告:smartsql中的事务,及aop的使用