SmartSql 动态仓储

动态代理仓储

SmartSql源码:https://github.com/Ahoo-Wang/SmartSqlgit

简介

动态代理仓储(SmartSql.DyRepository)组件是SmartSql很是独特的功能,它能简化SmartSql的使用。对业务代码除了配置几乎没有侵入。能够说使用SmartSqlContainer是原始方法,而DyRepository自动帮你实现这些方法。github

DyRepository的表现是只须要定义仓储接口,经过简单配置就能自动实现这些接口并注册到IoC容器中,使用时注入即刻获取实现。原理是经过接口和接口方法的命名规则来获取SmartSql的xml文件中的Scope和SqlId,用接口方法的参数做为Request,经过xml中的sql自动判断是查询仍是执行操做,最后实现对ISmartSqlMapper的调用。sql

适合场景

  1. 使用了仓储模式的架构

仓储模式主要在DDD战术中运用,用来隔离领域和数据库。DyRepository的功能需求主要是在DDD的实践中发现的,目前为止已经知足DDD实践的大部分需求,若是还有其余的相关需求欢迎提出Issue。数据库

  1. 相似SqlHepler的应用

DyRepository能够将任意一个接口实现出查询数据库的工具,CURD方法不在话下。经过接口注入更能发挥解耦的做用。架构

使用介绍

下面会简单演示DyRepository与ISmartSqlMapper的使用对比。app

准备工做

  1. 先建立一个仓储,这个仓储不依赖SmartSql,只是普普统统的仓储接口
//仓储接口,默认模版是I{Scope}Repository,因此这个接口的Scope是Activity
    public interface IActivityRepository
    {
        //接口方法对应SqlId,因此这个方法的SqlId是Insert
        //方法参数对应Request,因此这个方法的Request是activity
        int Insert(Activity activity);

        //值类型的参数会自动封装为一个对象,因此这个方法的Request是new { activityId = activityId }
        Activity Query(long activityId);
    }
  1. 建立配置xml文件SmartSqlMapConfig.xml:
<?xml version="1.0" encoding="utf-8" ?>
<SmartSqlMapConfig xmlns="http://SmartSql.net/schemas/SmartSqlMapConfig.xsd">
  <Settings IsWatchConfigFile="true" IgnoreParameterCase="true"/>
  <Database>
    <!--ParameterPrefix:[SqlServer:@ | MySQL:? |Oracle::] -->
    <DbProvider Name="SqlClientFactory" ParameterPrefix="@" Type="System.Data.SqlClient.SqlClientFactory,System.Data.SqlClient"/>
    <Write Name="WriteDB" ConnectionString="Data Source=.;Initial Catalog=SmartSqlStarterDB;Integrated Security=True"/>
  </Database>
  <SmartSqlMaps>
    <SmartSqlMap Path="Maps" Type="Directory"></SmartSqlMap>
  </SmartSqlMaps>
</SmartSqlMapConfig>
  1. 再建立xml配置文件Activity.xml,放到Maps目录,而且在属性面板设置为“始终复制”:
<?xml version="1.0" encoding="utf-8" ?>
<SmartSqlMap Scope="Activity"  xmlns="http://SmartSql.net/schemas/SmartSqlMap.xsd">
  <Statements>
    <Statement Id="Insert">
      INSERT INTO Activity
      (ActivityId
      ,Name
      ,BeginTime
      ,Address
      ,CreationTime
      ,Deleted)
      VALUES
      (@ActivityId
      ,@Name
      ,@BeginTime
      ,@Address
      ,@CreationTime
      ,@Deleted)
      ;Select Scope_Identity();
    </Statement>

    <Statement Id="Query">
      SELECT * FROM Activity
      WHERE
      ActivityId = @activityId;
    </Statement>
  </Statements>
</SmartSqlMap>

准备工做完成,下面就能够展现两种用法的区别。异步

两种用法

ISmartSqlMapper 用法

若是不用DyRepository,咱们须要用ISmartSqlMapper实现这个仓储。ide

public class ActivityRepository : IActivityRepository
    {
        ISmartSqlMapper SqlMapper = MapperContainer.Instance.GetSqlMapper();

        public int Insert(Activity activity)
        {
            return SqlMapper.ExecuteScalar<int>(new RequestContext()
            {
                Scope = "Activity",
                SqlId = "Insert",
                Request = activity
            });
        }

        public Activity Query(long activityId)
        {
            return SqlMapper.Query<Activity>(new RequestContext()
            {
                Scope = "Activity",
                SqlId = "Query",
                Request = new { activityId = activityId }
            });
        }
    }

再把实现类注册到IoC中:工具

var services = new ServiceCollection();
var services.AddSingleton<IActivityRepository,ActivityRepository>();

DyRepository用法

若是使用DyRepository,咱们不须要再写接口实现,只需配置一下IoC注册便可。this

var services = new ServiceCollection();
    services.AddSmartSqlRepositoryFromAssembly((options) =>
    {
        options.AssemblyString = "SmartSql.Starter.Repository";
    });

注入使用

使用方法就注入接口,再调用接口方法了。

// 假设ActivityService已经注册到IoC容器
    public class ActivityService
    {
        IActivityRepository activityRepository;

        public ActivityService(IActivityRepository activityRepository)
        {
            this.activityRepository = activityRepository;
        }

        public int Create(Activity activity)
        {
            return activityRepository.Insert(activity);
        }

        public int GetById(int id)
        {
            return activityRepository.Insert(id);
        }
    }

总结

经过DyRepository与ISmartSqlMapper的简单对比,咱们就能够看出DyRepository的强大,为咱们省下了不少代码。固然,ISmartSqlMapper天然也有它的灵活性,可以在任何地方使用。可是若是没有其余的特殊需求,在架构方面,由于对业务代码几乎无侵入,DyRepository无疑是最推荐的使用方式。

本文只介绍了DyRepository默认约定的使用方法,其实它还能经过各类配置项去实现更灵活的功能。详情请看下一节《DyRepository配置》。

DyRepository配置

DyRepository的配置分为默认配置、特性配置和注册配置,可是都必须配置IoC注册,由于要都须要建立动态的接口实现到IoC中。

必须的配置:

  1. 单个注册
services.AddRepository<IUserRepository>();
  1. 批量注册
services.AddSmartSqlRepositoryFromAssembly((options) =>
    {
        //仓储接口所在程序集全名
        options.AssemblyString = "SmartSql.Starter.Repository";
    });

可选配置

特性配置指在接口上标注特性来配置DyRepository的配置项,而注册配置是指在IoC注册方法中配置,下面演示一下二者的不一样。

Scope配置

场景

I{Scope}Repository是默认配置的Scope模版,如IUserRepository的Scope就是User。若是是这样的接口命名风格则无需再配置。
而当须要换接口命名风格,如查询User的Dao层名称是IUserDao,则须要配置对应的Scope。

特性配置

[SqlMap(Scope = "User")]
    public interface IUserDao
    {
    }

注册配置

//接口仍是那个接口
    public interface IUserDao
    {
    }

    //IoC配置中,注册单个接口
    services.AddRepository<IUserDao>(scope:"User");
    //或批量注册
    services.AddSmartSqlRepositoryFromAssembly((options) =>
    {
        options.AssemblyString = "SmartSql.Starter.Repository";
        options.ScopeTemplate = "I{Scope}Dao";
    });

注意,AddSmartSqlRepositoryFromAssembly是能够配置屡次的,只要被扫描到的接口不一样,就能够给不一样的接口配置不一样的属性

SqlId配置

SqlId默认是取仓储接口的方法名,只要方法名跟xml中的SqlId同样,则无需任何配置。

场景

由于SmartSql的sql配置是能够动态渲染的,当同一个SqlId传入不一样的参数,能够渲染出不一样的查询条件。例如:

<Statement Id="Query">
      SELECT * FROM User T
      <Where>
        <IsNotEmpty Prepend="And" Property="Email">
          T.Email = @Email
        </IsNotEmpty>
        <IsNotEmpty Prepend="And" Property="UserName">
          T.UserName Like Concat('%',$UserName,'%')
        </IsNotEmpty>
      </Where>
    </Statement>

此时若是只用默认配置,写两个Query(string)方法就会有同方法名同参数类型而没法重载的问题。所以,此时须要接口方法名不一样,而经过配置去指定相同的SqlId。

特性配置

[SqlMap(Scope = "User")]
    public interface IUserRepository
    {
        [Statement(Id = "Query")]
        int QueryByEmail(string email);

        [Statement(Id = "Query")]
        int QueryByUserName(string userName);
    }

注册配置

注册配置中是经过配置一个叫sqlIdNamingConvert的委托参数来实现接口方法名到SqlId的转换方法。

services.AddSmartSqlRepositoryFactory(sqlIdNamingConvert: (type, method) =>
    {
        if (method.Name.StartsWith("QueryBy"))
            return "Query"; //返回的就是SqlId
    });
    services.AddRepositoryFromAssembly((options) =>
    {
        options.AssemblyString = "SmartSql.Starter.Repository";
    })

须要注意的是,这个配置须要把AddSmartSqlRepositoryFactory和AddRepositoryFromAssembly两个方法分开,缘由是前几个配置中的AddSmartSqlRepositoryFromAssembly方法内部调用过AddSmartSqlRepositoryFactory,若是再次调用会形成冲突。

其它配置

场景

若是但愿SmartSql只作接口实现而不侵入接口,以上的注册配置基本就能知足大部分需求。

可是若是须要深刻使用SmartSql,那么利用特性配置和一个泛型接口能获得更多额外的功能。

接口方法指定Sql

即直接给接口方法绑定sql,无需再从xml中配置sql了,但请注意参数前缀仍是须要在对应的配置文件配置。

[Statement(Sql = "Select Top(@taken) T.* From User T With(NoLock);")]
    IEnumerable<User> QueryBySql(int taken);

Statement特性只标记在方法上,还有其余几个参数:

参数 默认值 说明
Scope 当前接口的Scope 对应xml的Scope
Id 方法名 xml对应Statement的Id
Execute ExecuteBehavior.Auto 执行类型,通常默认就好
Sql 配置Sql后会直接执行这个特性上的Sql

指定查询参数

即把接口方法的参数值传递给Sql渲染时指定参数名的参数,例如把id的值传递给@UserId:

IEnumerable<User> Query([Param("UserId")]int id);

泛型接口

继承泛型接口以后,可以直接调用它里面的CURD通用方法。

  1. 同步调用:IRepository<TEntity, TPrimary>
  2. 异步调用:IRepositoryAsync<TEntity, TPrimary>
相关文章
相关标签/搜索