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
倉儲模式主要在DDD戰術中運用,用來隔離領域和數據庫。DyRepository的功能需求主要是在DDD的實踐中發現的,目前爲止已經知足DDD實踐的大部分需求,若是還有其餘的相關需求歡迎提出Issue。數據庫
DyRepository能夠將任意一個接口實現出查詢數據庫的工具,CURD方法不在話下。經過接口注入更能發揮解耦的做用。架構
下面會簡單演示DyRepository與ISmartSqlMapper的使用對比。app
//倉儲接口,默認模版是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); }
<?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>
<?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>
準備工做完成,下面就能夠展現兩種用法的區別。異步
若是不用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,咱們不須要再寫接口實現,只需配置一下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的配置分爲默認配置、特性配置和註冊配置,可是都必須配置IoC註冊,由於要都須要建立動態的接口實現到IoC中。
services.AddRepository<IUserRepository>();
services.AddSmartSqlRepositoryFromAssembly((options) => { //倉儲接口所在程序集全名 options.AssemblyString = "SmartSql.Starter.Repository"; });
特性配置指在接口上標註特性來配置DyRepository的配置項,而註冊配置是指在IoC註冊方法中配置,下面演示一下二者的不一樣。
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默認是取倉儲接口的方法名,只要方法名跟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,無需再從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通用方法。
IRepository<TEntity, TPrimary>
IRepositoryAsync<TEntity, TPrimary>