- 增加 FreeSql.Provider.Custom 自定义适配访问任何数据库;

This commit is contained in:
2881099 2021-02-05 18:20:38 +08:00
parent 7aedc52cf3
commit 082dcf1fa4
18 changed files with 1509 additions and 193 deletions

View File

@ -512,14 +512,5 @@
<param name="that"></param> <param name="that"></param>
<returns></returns> <returns></returns>
</member> </member>
<member name="M:Microsoft.Extensions.DependencyInjection.FreeSqlRepositoryDependencyInjection.AddFreeRepository(Microsoft.Extensions.DependencyInjection.IServiceCollection,System.Action{FreeSql.FluentDataFilter},System.Reflection.Assembly[])">
<summary>
批量注入 Repository可以参考代码自行调整
</summary>
<param name="services"></param>
<param name="globalDataFilter"></param>
<param name="assemblies"></param>
<returns></returns>
</member>
</members> </members>
</doc> </doc>

View File

@ -91,6 +91,8 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "FreeSql.Provider.KingbaseES
EndProject EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "FreeSql.Provider.Firebird", "Providers\FreeSql.Provider.Firebird\FreeSql.Provider.Firebird.csproj", "{101B11D2-7780-4E14-9B72-77F5D69B3DF9}" Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "FreeSql.Provider.Firebird", "Providers\FreeSql.Provider.Firebird\FreeSql.Provider.Firebird.csproj", "{101B11D2-7780-4E14-9B72-77F5D69B3DF9}"
EndProject EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "FreeSql.Provider.Custom", "Providers\FreeSql.Provider.Custom\FreeSql.Provider.Custom.csproj", "{0DBAA21C-39B2-4AAD-A43D-88E67ED239D1}"
EndProject
Global Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU Debug|Any CPU = Debug|Any CPU
@ -557,6 +559,18 @@ Global
{101B11D2-7780-4E14-9B72-77F5D69B3DF9}.Release|x64.Build.0 = Release|Any CPU {101B11D2-7780-4E14-9B72-77F5D69B3DF9}.Release|x64.Build.0 = Release|Any CPU
{101B11D2-7780-4E14-9B72-77F5D69B3DF9}.Release|x86.ActiveCfg = Release|Any CPU {101B11D2-7780-4E14-9B72-77F5D69B3DF9}.Release|x86.ActiveCfg = Release|Any CPU
{101B11D2-7780-4E14-9B72-77F5D69B3DF9}.Release|x86.Build.0 = Release|Any CPU {101B11D2-7780-4E14-9B72-77F5D69B3DF9}.Release|x86.Build.0 = Release|Any CPU
{0DBAA21C-39B2-4AAD-A43D-88E67ED239D1}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{0DBAA21C-39B2-4AAD-A43D-88E67ED239D1}.Debug|Any CPU.Build.0 = Debug|Any CPU
{0DBAA21C-39B2-4AAD-A43D-88E67ED239D1}.Debug|x64.ActiveCfg = Debug|Any CPU
{0DBAA21C-39B2-4AAD-A43D-88E67ED239D1}.Debug|x64.Build.0 = Debug|Any CPU
{0DBAA21C-39B2-4AAD-A43D-88E67ED239D1}.Debug|x86.ActiveCfg = Debug|Any CPU
{0DBAA21C-39B2-4AAD-A43D-88E67ED239D1}.Debug|x86.Build.0 = Debug|Any CPU
{0DBAA21C-39B2-4AAD-A43D-88E67ED239D1}.Release|Any CPU.ActiveCfg = Release|Any CPU
{0DBAA21C-39B2-4AAD-A43D-88E67ED239D1}.Release|Any CPU.Build.0 = Release|Any CPU
{0DBAA21C-39B2-4AAD-A43D-88E67ED239D1}.Release|x64.ActiveCfg = Release|Any CPU
{0DBAA21C-39B2-4AAD-A43D-88E67ED239D1}.Release|x64.Build.0 = Release|Any CPU
{0DBAA21C-39B2-4AAD-A43D-88E67ED239D1}.Release|x86.ActiveCfg = Release|Any CPU
{0DBAA21C-39B2-4AAD-A43D-88E67ED239D1}.Release|x86.Build.0 = Release|Any CPU
EndGlobalSection EndGlobalSection
GlobalSection(SolutionProperties) = preSolution GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE HideSolutionNode = FALSE
@ -589,6 +603,7 @@ Global
{3D2BD8EC-253A-437F-B4C8-74BC0D91429B} = {2A381C57-2697-427B-9F10-55DA11FD02E4} {3D2BD8EC-253A-437F-B4C8-74BC0D91429B} = {2A381C57-2697-427B-9F10-55DA11FD02E4}
{CDD6A896-F6DF-44CB-B430-06B383916EB0} = {2A381C57-2697-427B-9F10-55DA11FD02E4} {CDD6A896-F6DF-44CB-B430-06B383916EB0} = {2A381C57-2697-427B-9F10-55DA11FD02E4}
{101B11D2-7780-4E14-9B72-77F5D69B3DF9} = {2A381C57-2697-427B-9F10-55DA11FD02E4} {101B11D2-7780-4E14-9B72-77F5D69B3DF9} = {2A381C57-2697-427B-9F10-55DA11FD02E4}
{0DBAA21C-39B2-4AAD-A43D-88E67ED239D1} = {2A381C57-2697-427B-9F10-55DA11FD02E4}
EndGlobalSection EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {089687FD-5D25-40AB-BA8A-A10D1E137F98} SolutionGuid = {089687FD-5D25-40AB-BA8A-A10D1E137F98}

View File

@ -54,6 +54,12 @@ namespace FreeSql
/// <summary> /// <summary>
/// Firebird 是一个跨平台的关系数据库,能作为多用户环境下的数据库服务器运行,也提供嵌入式数据库的实现 /// Firebird 是一个跨平台的关系数据库,能作为多用户环境下的数据库服务器运行,也提供嵌入式数据库的实现
/// </summary> /// </summary>
Firebird Firebird,
/// <summary>
/// 自定义适配器,访问任何数据库<para></para>
/// 注意:该类型不提供 DbFirst/CodeFirst 功能
/// </summary>
Custom
} }
} }

View File

@ -650,6 +650,12 @@
Firebird 是一个跨平台的关系数据库,能作为多用户环境下的数据库服务器运行,也提供嵌入式数据库的实现 Firebird 是一个跨平台的关系数据库,能作为多用户环境下的数据库服务器运行,也提供嵌入式数据库的实现
</summary> </summary>
</member> </member>
<member name="F:FreeSql.DataType.Custom">
<summary>
自定义适配器,访问任何数据库<para></para>
注意:该类型不提供 DbFirst/CodeFirst 功能
</summary>
</member>
<member name="M:FreeSql.AdoNetExtensions.GetIFreeSql(System.Data.IDbConnection)"> <member name="M:FreeSql.AdoNetExtensions.GetIFreeSql(System.Data.IDbConnection)">
<summary> <summary>
获取 IDbConnection 对应的 IFreeSql 实例 获取 IDbConnection 对应的 IFreeSql 实例
@ -3141,177 +3147,6 @@
<param name="parms"></param> <param name="parms"></param>
<returns></returns> <returns></returns>
</member> </member>
<member name="M:FreeSql.IAdo.ExecuteConnectTestAsync(System.Int32,System.Threading.CancellationToken)">
<summary>
测试数据库是否连接正确,本方法执行如下命令:<para></para>
MySql/SqlServer/PostgreSQL/达梦/人大金仓/神通: SELECT 1<para></para>
Oracle: SELECT 1 FROM dual<para></para>
</summary>
<param name="commandTimeout">命令超时设置(秒)</param>
<param name="cancellationToken"></param>
<returns>true: 成功, false: 失败</returns>
</member>
<member name="M:FreeSql.IAdo.ExecuteReaderAsync(System.Func{FreeSql.Internal.Model.FetchCallbackArgs{System.Data.Common.DbDataReader},System.Threading.Tasks.Task},System.Data.CommandType,System.String,System.Data.Common.DbParameter[],System.Threading.CancellationToken)">
<summary>
查询若使用读写分离查询【从库】条件cmdText.StartsWith("SELECT "),否则查询【主库】
</summary>
<param name="readerHander"></param>
<param name="cmdType"></param>
<param name="cmdText"></param>
<param name="cmdParms"></param>
<param name="cancellationToken"></param>
</member>
<member name="M:FreeSql.IAdo.ExecuteReaderAsync(System.Func{FreeSql.Internal.Model.FetchCallbackArgs{System.Data.Common.DbDataReader},System.Threading.Tasks.Task},System.String,System.Object,System.Threading.CancellationToken)">
<summary>
查询ExecuteReaderAsync(dr => {}, "select * from user where age > @age", new { age = 25 })<para></para>
提示parms 参数还可以传 Dictionary&lt;string, object&gt;
</summary>
<param name="readerHander"></param>
<param name="cmdText"></param>
<param name="parms"></param>
<param name="cancellationToken"></param>
</member>
<member name="M:FreeSql.IAdo.ExecuteArrayAsync(System.Data.CommandType,System.String,System.Data.Common.DbParameter[],System.Threading.CancellationToken)">
<summary>
查询
</summary>
<param name="cmdType"></param>
<param name="cmdText"></param>
<param name="cmdParms"></param>
<param name="cancellationToken"></param>
</member>
<member name="M:FreeSql.IAdo.ExecuteArrayAsync(System.String,System.Object,System.Threading.CancellationToken)">
<summary>
查询ExecuteArrayAsync("select * from user where age > @age", new { age = 25 })<para></para>
提示parms 参数还可以传 Dictionary&lt;string, object&gt;
</summary>
<param name="cmdText"></param>
<param name="parms"></param>
<param name="cancellationToken"></param>
<returns></returns>
</member>
<member name="M:FreeSql.IAdo.ExecuteDataSetAsync(System.Data.CommandType,System.String,System.Data.Common.DbParameter[],System.Threading.CancellationToken)">
<summary>
查询
</summary>
<param name="cmdType"></param>
<param name="cmdText"></param>
<param name="cmdParms"></param>
<param name="cancellationToken"></param>
</member>
<member name="M:FreeSql.IAdo.ExecuteDataSetAsync(System.String,System.Object,System.Threading.CancellationToken)">
<summary>
查询ExecuteDataSetAsync("select * from user where age > @age; select 2", new { age = 25 })<para></para>
提示parms 参数还可以传 Dictionary&lt;string, object&gt;
</summary>
<param name="cmdText"></param>
<param name="parms"></param>
<param name="cancellationToken"></param>
<returns></returns>
</member>
<member name="M:FreeSql.IAdo.ExecuteDataTableAsync(System.Data.CommandType,System.String,System.Data.Common.DbParameter[],System.Threading.CancellationToken)">
<summary>
查询
</summary>
<param name="cmdType"></param>
<param name="cmdText"></param>
<param name="cmdParms"></param>
<param name="cancellationToken"></param>
</member>
<member name="M:FreeSql.IAdo.ExecuteDataTableAsync(System.String,System.Object,System.Threading.CancellationToken)">
<summary>
查询ExecuteDataTableAsync("select * from user where age > @age", new { age = 25 })<para></para>
提示parms 参数还可以传 Dictionary&lt;string, object&gt;
</summary>
<param name="cmdText"></param>
<param name="parms"></param>
<param name="cancellationToken"></param>
<returns></returns>
</member>
<member name="M:FreeSql.IAdo.ExecuteNonQueryAsync(System.Data.CommandType,System.String,System.Data.Common.DbParameter[],System.Threading.CancellationToken)">
<summary>
在【主库】执行
</summary>
<param name="cmdType"></param>
<param name="cmdText"></param>
<param name="cmdParms"></param>
<param name="cancellationToken"></param>
</member>
<member name="M:FreeSql.IAdo.ExecuteNonQueryAsync(System.String,System.Object,System.Threading.CancellationToken)">
<summary>
在【主库】执行ExecuteNonQueryAsync("delete from user where age > @age", new { age = 25 })<para></para>
提示parms 参数还可以传 Dictionary&lt;string, object&gt;
</summary>
<param name="cmdText"></param>
<param name="parms"></param>
<param name="cancellationToken"></param>
<returns></returns>
</member>
<member name="M:FreeSql.IAdo.ExecuteScalarAsync(System.Data.CommandType,System.String,System.Data.Common.DbParameter[],System.Threading.CancellationToken)">
<summary>
在【主库】执行
</summary>
<param name="cmdType"></param>
<param name="cmdText"></param>
<param name="cmdParms"></param>
<param name="cancellationToken"></param>
</member>
<member name="M:FreeSql.IAdo.ExecuteScalarAsync(System.String,System.Object,System.Threading.CancellationToken)">
<summary>
在【主库】执行ExecuteScalarAsync("select 1 from user where age > @age", new { age = 25 })<para></para>
提示parms 参数还可以传 Dictionary&lt;string, object&gt;
</summary>
<param name="cmdText"></param>
<param name="parms"></param>
<param name="cancellationToken"></param>
<returns></returns>
</member>
<member name="M:FreeSql.IAdo.QueryAsync``1(System.Data.CommandType,System.String,System.Data.Common.DbParameter[],System.Threading.CancellationToken)">
<summary>
执行SQL返回对象集合QueryAsync&lt;User&gt;("select * from user where age > @age", new SqlParameter { ParameterName = "age", Value = 25 })
</summary>
<typeparam name="T"></typeparam>
<param name="cmdType"></param>
<param name="cmdText"></param>
<param name="cmdParms"></param>
<param name="cancellationToken"></param>
<returns></returns>
</member>
<member name="M:FreeSql.IAdo.QueryAsync``1(System.String,System.Object,System.Threading.CancellationToken)">
<summary>
执行SQL返回对象集合QueryAsync&lt;User&gt;("select * from user where age > @age", new { age = 25 })<para></para>
提示parms 参数还可以传 Dictionary&lt;string, object&gt;
</summary>
<typeparam name="T"></typeparam>
<param name="cmdText"></param>
<param name="parms"></param>
<param name="cancellationToken"></param>
<returns></returns>
</member>
<member name="M:FreeSql.IAdo.QueryAsync``2(System.Data.CommandType,System.String,System.Data.Common.DbParameter[],System.Threading.CancellationToken)">
<summary>
执行SQL返回对象集合Query&lt;User&gt;("select * from user where age > @age; select * from address", new SqlParameter { ParameterName = "age", Value = 25 })
</summary>
<typeparam name="T1"></typeparam>
<typeparam name="T2"></typeparam>
<param name="cmdType"></param>
<param name="cmdText"></param>
<param name="cmdParms"></param>
<param name="cancellationToken"></param>
<returns></returns>
</member>
<member name="M:FreeSql.IAdo.QueryAsync``2(System.String,System.Object,System.Threading.CancellationToken)">
<summary>
执行SQL返回对象集合Query&lt;User, Address&gt;("select * from user where age > @age; select * from address", new { age = 25 })<para></para>
提示parms 参数还可以传 Dictionary&lt;string, object&gt;
</summary>
<typeparam name="T1"></typeparam>
<typeparam name="T2"></typeparam>
<param name="cmdText"></param>
<param name="parms"></param>
<param name="cancellationToken"></param>
<returns></returns>
</member>
<member name="E:FreeSql.IAop.ParseExpression"> <member name="E:FreeSql.IAop.ParseExpression">
<summary> <summary>
可自定义解析表达式 可自定义解析表达式
@ -4145,12 +3980,6 @@
<param name="timeout">超时</param> <param name="timeout">超时</param>
<returns></returns> <returns></returns>
</member> </member>
<member name="M:FreeSql.Internal.ObjectPool.IObjectPool`1.GetAsync">
<summary>
获取资源
</summary>
<returns></returns>
</member>
<member name="M:FreeSql.Internal.ObjectPool.IObjectPool`1.Return(FreeSql.Internal.ObjectPool.Object{`0},System.Boolean)"> <member name="M:FreeSql.Internal.ObjectPool.IObjectPool`1.Return(FreeSql.Internal.ObjectPool.Object{`0},System.Boolean)">
<summary> <summary>
使用完毕后,归还资源 使用完毕后,归还资源
@ -4221,12 +4050,6 @@
</summary> </summary>
<param name="obj">资源对象</param> <param name="obj">资源对象</param>
</member> </member>
<member name="M:FreeSql.Internal.ObjectPool.IPolicy`1.OnGetAsync(FreeSql.Internal.ObjectPool.Object{`0})">
<summary>
从对象池获取对象成功的时候触发,通过该方法统计或初始化对象
</summary>
<param name="obj">资源对象</param>
</member>
<member name="M:FreeSql.Internal.ObjectPool.IPolicy`1.OnReturn(FreeSql.Internal.ObjectPool.Object{`0})"> <member name="M:FreeSql.Internal.ObjectPool.IPolicy`1.OnReturn(FreeSql.Internal.ObjectPool.Object{`0})">
<summary> <summary>
归还对象给对象池的时候触发 归还对象给对象池的时候触发

View File

@ -256,6 +256,11 @@ namespace FreeSql
if (type == null) throwNotFind("FreeSql.Provider.Firebird.dll", "FreeSql.Firebird.FirebirdProvider<>"); if (type == null) throwNotFind("FreeSql.Provider.Firebird.dll", "FreeSql.Firebird.FirebirdProvider<>");
break; break;
case DataType.Custom:
type = Type.GetType("FreeSql.Custom.CustomProvider`1,FreeSql.Provider.Custom")?.MakeGenericType(typeof(TMark));
if (type == null) throwNotFind("FreeSql.Provider.Custom.dll", "FreeSql.Custom.CustomProvider<>");
break;
default: throw new Exception("未指定 UseConnectionString 或者 UseConnectionFactory"); default: throw new Exception("未指定 UseConnectionString 或者 UseConnectionFactory");
} }
} }

View File

@ -0,0 +1,26 @@
using FreeSql.Internal;
using System;
using System.Collections.Generic;
using System.Data;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
namespace FreeSql.Custom
{
class CustomDelete<T1> : Internal.CommonProvider.DeleteProvider<T1>
{
public CustomDelete(IFreeSql orm, CommonUtils commonUtils, CommonExpression commonExpression, object dywhere)
: base(orm, commonUtils, commonExpression, dywhere)
{
}
public override List<T1> ExecuteDeleted() => throw new NotImplementedException("FreeSql.Provider.Custom 未实现该功能");
#if net40
#else
public override Task<List<T1>> ExecuteDeletedAsync(CancellationToken cancellationToken = default) => throw new NotImplementedException("FreeSql.Provider.Custom 未实现该功能");
#endif
}
}

View File

@ -0,0 +1,113 @@
using FreeSql.Internal;
using FreeSql.Internal.ObjectPool;
using System;
using System.Collections.Generic;
using System.Data;
using System.Data.Common;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
namespace FreeSql.Custom
{
class CustomInsert<T1> : Internal.CommonProvider.InsertProvider<T1> where T1 : class
{
CustomUtils _utils;
public CustomInsert(IFreeSql orm, CommonUtils commonUtils, CommonExpression commonExpression)
: base(orm, commonUtils, commonExpression)
{
_utils = _commonUtils as CustomUtils;
}
public override int ExecuteAffrows() => base.SplitExecuteAffrows(_batchValuesLimit > 0 ? _batchValuesLimit : _utils.Adapter.InsertBatchSplitLimit, _batchParameterLimit > 0 ? _batchParameterLimit : 255);
public override long ExecuteIdentity() => base.SplitExecuteIdentity(_batchValuesLimit > 0 ? _batchValuesLimit : _utils.Adapter.InsertBatchSplitLimit, _batchParameterLimit > 0 ? _batchParameterLimit : 255);
public override List<T1> ExecuteInserted() => base.SplitExecuteInserted(_batchValuesLimit > 0 ? _batchValuesLimit : _utils.Adapter.InsertBatchSplitLimit, _batchParameterLimit > 0 ? _batchParameterLimit : 255);
protected override long RawExecuteIdentity()
{
var sql = this.ToSql();
if (string.IsNullOrEmpty(sql)) return 0;
Object<DbConnection> poolConn = null;
var before = new Aop.CurdBeforeEventArgs(_table.Type, _table, Aop.CurdType.Insert, string.Concat(sql, $"; {_utils.Adapter.InsertAfterGetIdentitySql}"), _params);
_orm.Aop.CurdBeforeHandler?.Invoke(this, before);
long ret = 0;
Exception exception = null;
try
{
var conn = _connection;
if (_transaction != null) conn = _transaction.Connection;
if (conn == null)
{
poolConn = _orm.Ado.MasterPool.Get();
conn = poolConn.Value;
}
_orm.Ado.ExecuteNonQuery(conn, _transaction, CommandType.Text, sql, _commandTimeout, _params);
ret = long.TryParse(string.Concat(_orm.Ado.ExecuteScalar(conn, _transaction, CommandType.Text, $" {_utils.Adapter.InsertAfterGetIdentitySql}", _commandTimeout)), out var trylng) ? trylng : 0;
}
catch (Exception ex)
{
exception = ex;
throw ex;
}
finally
{
if (poolConn != null)
_orm.Ado.MasterPool.Return(poolConn);
var after = new Aop.CurdAfterEventArgs(before, exception, ret);
_orm.Aop.CurdAfterHandler?.Invoke(this, after);
}
return ret;
}
protected override List<T1> RawExecuteInserted() => throw new NotImplementedException("FreeSql.Provider.Custom 未实现该功能");
#if net40
#else
public override Task<int> ExecuteAffrowsAsync(CancellationToken cancellationToken = default) => base.SplitExecuteAffrowsAsync(_batchValuesLimit > 0 ? _batchValuesLimit : _utils.Adapter.InsertBatchSplitLimit, _batchParameterLimit > 0 ? _batchParameterLimit : 255, cancellationToken);
public override Task<long> ExecuteIdentityAsync(CancellationToken cancellationToken = default) => base.SplitExecuteIdentityAsync(_batchValuesLimit > 0 ? _batchValuesLimit : _utils.Adapter.InsertBatchSplitLimit, _batchParameterLimit > 0 ? _batchParameterLimit : 255, cancellationToken);
public override Task<List<T1>> ExecuteInsertedAsync(CancellationToken cancellationToken = default) => base.SplitExecuteInsertedAsync(_batchValuesLimit > 0 ? _batchValuesLimit : _utils.Adapter.InsertBatchSplitLimit, _batchParameterLimit > 0 ? _batchParameterLimit : 255, cancellationToken);
async protected override Task<long> RawExecuteIdentityAsync(CancellationToken cancellationToken = default)
{
var sql = this.ToSql();
if (string.IsNullOrEmpty(sql)) return 0;
Object<DbConnection> poolConn = null;
var before = new Aop.CurdBeforeEventArgs(_table.Type, _table, Aop.CurdType.Insert, string.Concat(sql, $"; {_utils.Adapter.InsertAfterGetIdentitySql}"), _params);
_orm.Aop.CurdBeforeHandler?.Invoke(this, before);
long ret = 0;
Exception exception = null;
try
{
var conn = _connection;
if (_transaction != null) conn = _transaction.Connection;
if (conn == null)
{
poolConn = _orm.Ado.MasterPool.Get();
conn = poolConn.Value;
}
await _orm.Ado.ExecuteNonQueryAsync(conn, _transaction, CommandType.Text, sql, _commandTimeout, _params, cancellationToken);
ret = long.TryParse(string.Concat(await _orm.Ado.ExecuteScalarAsync(conn, _transaction, CommandType.Text, $" {_utils.Adapter.InsertAfterGetIdentitySql}", _commandTimeout, null, cancellationToken)), out var trylng) ? trylng : 0;
}
catch (Exception ex)
{
exception = ex;
throw ex;
}
finally
{
if (poolConn != null)
_orm.Ado.MasterPool.Return(poolConn);
var after = new Aop.CurdAfterEventArgs(before, exception, ret);
_orm.Aop.CurdAfterHandler?.Invoke(this, after);
}
return ret;
}
protected override Task<List<T1>> RawExecuteInsertedAsync(CancellationToken cancellationToken = default) => throw new NotImplementedException("FreeSql.Provider.Custom 未实现该功能");
#endif
}
}

View File

@ -0,0 +1,215 @@
using FreeSql.Internal;
using FreeSql.Internal.Model;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Linq.Expressions;
using System.Text;
namespace FreeSql.Custom
{
class CustomSelect<T1> : FreeSql.Internal.CommonProvider.Select1Provider<T1>
{
internal static string ToSqlStatic(CommonUtils _commonUtils, CommonExpression _commonExpression, string _select, bool _distinct, string field, StringBuilder _join, StringBuilder _where, string _groupby, string _having, string _orderby, int _skip, int _limit, List<SelectTableInfo> _tables, List<Dictionary<Type, string>> tbUnions, Func<Type, string, string> _aliasRule, string _tosqlAppendContent, List<GlobalFilter.Item> _whereGlobalFilter, IFreeSql _orm)
{
var _utils = _commonUtils as CustomUtils;
if (_orm.CodeFirst.IsAutoSyncStructure)
_orm.CodeFirst.SyncStructure(_tables.Select(a => a.Table.Type).ToArray());
if (_whereGlobalFilter.Any())
foreach (var tb in _tables.Where(a => a.Type != SelectTableInfoType.Parent))
tb.Cascade = _commonExpression.GetWhereCascadeSql(tb, _whereGlobalFilter, true);
var sb = new StringBuilder();
var tbUnionsGt0 = tbUnions.Count > 1;
for (var tbUnionsIdx = 0; tbUnionsIdx < tbUnions.Count; tbUnionsIdx++)
{
if (tbUnionsIdx > 0) sb.Append("\r\n \r\nUNION ALL\r\n \r\n");
if (tbUnionsGt0) sb.Append(_select).Append(" * from (");
var tbUnion = tbUnions[tbUnionsIdx];
var sbnav = new StringBuilder();
sb.Append(_select);
if (_distinct) sb.Append("DISTINCT ");
if (_limit > 0 && _utils.Adapter.SelectTopStyle == CustomAdapter.SelecTopStyle.Top) sb.Append("TOP ").Append(_skip + _limit).Append(" ");
sb.Append(field);
if (_skip > 0 && _utils.Adapter.SelectTopStyle == CustomAdapter.SelecTopStyle.Top)
throw new NotImplementedException("FreeSql.Provider.Custom 未实现 Skip/Offset 功能,如果需要分页请使用判断上一次 id");
sb.Append(" \r\nFROM ");
var tbsjoin = _tables.Where(a => a.Type != SelectTableInfoType.From).ToArray();
var tbsfrom = _tables.Where(a => a.Type == SelectTableInfoType.From).ToArray();
for (var a = 0; a < tbsfrom.Length; a++)
{
sb.Append(_commonUtils.QuoteSqlName(tbUnion[tbsfrom[a].Table.Type])).Append(" ").Append(_aliasRule?.Invoke(tbsfrom[a].Table.Type, tbsfrom[a].Alias) ?? tbsfrom[a].Alias);
if (tbsjoin.Length > 0)
{
//如果存在 join 查询,则处理 from t1, t2 改为 from t1 inner join t2 on 1 = 1
for (var b = 1; b < tbsfrom.Length; b++)
{
sb.Append(" \r\nLEFT JOIN ").Append(_commonUtils.QuoteSqlName(tbUnion[tbsfrom[b].Table.Type])).Append(" ").Append(_aliasRule?.Invoke(tbsfrom[b].Table.Type, tbsfrom[b].Alias) ?? tbsfrom[b].Alias);
if (string.IsNullOrEmpty(tbsfrom[b].NavigateCondition) && string.IsNullOrEmpty(tbsfrom[b].On) && string.IsNullOrEmpty(tbsfrom[b].Cascade)) sb.Append(" ON 1 = 1");
else
{
var onSql = tbsfrom[b].NavigateCondition ?? tbsfrom[b].On;
sb.Append(" ON ").Append(onSql);
if (string.IsNullOrEmpty(tbsfrom[b].Cascade) == false)
{
if (string.IsNullOrEmpty(onSql)) sb.Append(tbsfrom[b].Cascade);
else sb.Append(" AND ").Append(tbsfrom[b].Cascade);
}
}
}
break;
}
else
{
if (!string.IsNullOrEmpty(tbsfrom[a].NavigateCondition)) sbnav.Append(" AND (").Append(tbsfrom[a].NavigateCondition).Append(")");
if (!string.IsNullOrEmpty(tbsfrom[a].On)) sbnav.Append(" AND (").Append(tbsfrom[a].On).Append(")");
if (a > 0 && !string.IsNullOrEmpty(tbsfrom[a].Cascade)) sbnav.Append(" AND ").Append(tbsfrom[a].Cascade);
}
if (a < tbsfrom.Length - 1) sb.Append(", ");
}
foreach (var tb in tbsjoin)
{
if (tb.Type == SelectTableInfoType.Parent) continue;
switch (tb.Type)
{
case SelectTableInfoType.LeftJoin:
sb.Append(" \r\nLEFT JOIN ");
break;
case SelectTableInfoType.InnerJoin:
sb.Append(" \r\nINNER JOIN ");
break;
case SelectTableInfoType.RightJoin:
sb.Append(" \r\nRIGHT JOIN ");
break;
}
sb.Append(_commonUtils.QuoteSqlName(tbUnion[tb.Table.Type])).Append(" ").Append(_aliasRule?.Invoke(tb.Table.Type, tb.Alias) ?? tb.Alias).Append(" ON ").Append(tb.On ?? tb.NavigateCondition);
if (!string.IsNullOrEmpty(tb.Cascade)) sb.Append(" AND ").Append(tb.Cascade);
if (!string.IsNullOrEmpty(tb.On) && !string.IsNullOrEmpty(tb.NavigateCondition)) sbnav.Append(" AND (").Append(tb.NavigateCondition).Append(")");
}
if (_join.Length > 0) sb.Append(_join);
sbnav.Append(_where);
if (!string.IsNullOrEmpty(_tables[0].Cascade))
sbnav.Append(" AND ").Append(_tables[0].Cascade);
if (sbnav.Length > 0)
{
sb.Append(" \r\nWHERE ").Append(sbnav.Remove(0, 5));
}
if (string.IsNullOrEmpty(_groupby) == false)
{
sb.Append(_groupby);
if (string.IsNullOrEmpty(_having) == false)
sb.Append(" \r\nHAVING ").Append(_having.Substring(5));
}
sb.Append(_orderby);
if (_limit > 0 && _utils.Adapter.SelectTopStyle == CustomAdapter.SelecTopStyle.Limit) sb.Append(" \r\nLIMIT ").Append(_limit);
if (_skip > 0 && _utils.Adapter.SelectTopStyle == CustomAdapter.SelecTopStyle.Limit) sb.Append(" \r\nOFFSET ").Append(_skip);
sbnav.Clear();
if (tbUnionsGt0) sb.Append(") ftb");
}
return sb.Append(_tosqlAppendContent).ToString();
}
public CustomSelect(IFreeSql orm, CommonUtils commonUtils, CommonExpression commonExpression, object dywhere) : base(orm, commonUtils, commonExpression, dywhere) { }
public override ISelect<T1, T2> From<T2>(Expression<Func<ISelectFromExpression<T1>, T2, ISelectFromExpression<T1>>> exp) { this.InternalFrom(exp); var ret = new CustomSelect<T1, T2>(_orm, _commonUtils, _commonExpression, null); CustomSelect<T1>.CopyData(this, (Internal.CommonProvider.Select0Provider)ret, exp?.Parameters); return ret; }
public override ISelect<T1, T2, T3> From<T2, T3>(Expression<Func<ISelectFromExpression<T1>, T2, T3, ISelectFromExpression<T1>>> exp) { this.InternalFrom(exp); var ret = new CustomSelect<T1, T2, T3>(_orm, _commonUtils, _commonExpression, null); CustomSelect<T1>.CopyData(this, (Internal.CommonProvider.Select0Provider)ret, exp?.Parameters); return ret; }
public override ISelect<T1, T2, T3, T4> From<T2, T3, T4>(Expression<Func<ISelectFromExpression<T1>, T2, T3, T4, ISelectFromExpression<T1>>> exp) { this.InternalFrom(exp); var ret = new CustomSelect<T1, T2, T3, T4>(_orm, _commonUtils, _commonExpression, null); CustomSelect<T1>.CopyData(this, (Internal.CommonProvider.Select0Provider)ret, exp?.Parameters); return ret; }
public override ISelect<T1, T2, T3, T4, T5> From<T2, T3, T4, T5>(Expression<Func<ISelectFromExpression<T1>, T2, T3, T4, T5, ISelectFromExpression<T1>>> exp) { this.InternalFrom(exp); var ret = new CustomSelect<T1, T2, T3, T4, T5>(_orm, _commonUtils, _commonExpression, null); CustomSelect<T1>.CopyData(this, (Internal.CommonProvider.Select0Provider)ret, exp?.Parameters); return ret; }
public override ISelect<T1, T2, T3, T4, T5, T6> From<T2, T3, T4, T5, T6>(Expression<Func<ISelectFromExpression<T1>, T2, T3, T4, T5, T6, ISelectFromExpression<T1>>> exp) { this.InternalFrom(exp); var ret = new CustomSelect<T1, T2, T3, T4, T5, T6>(_orm, _commonUtils, _commonExpression, null); CustomSelect<T1>.CopyData(this, (Internal.CommonProvider.Select0Provider)ret, exp?.Parameters); return ret; }
public override ISelect<T1, T2, T3, T4, T5, T6, T7> From<T2, T3, T4, T5, T6, T7>(Expression<Func<ISelectFromExpression<T1>, T2, T3, T4, T5, T6, T7, ISelectFromExpression<T1>>> exp) { this.InternalFrom(exp); var ret = new CustomSelect<T1, T2, T3, T4, T5, T6, T7>(_orm, _commonUtils, _commonExpression, null); CustomSelect<T1>.CopyData(this, (Internal.CommonProvider.Select0Provider)ret, exp?.Parameters); return ret; }
public override ISelect<T1, T2, T3, T4, T5, T6, T7, T8> From<T2, T3, T4, T5, T6, T7, T8>(Expression<Func<ISelectFromExpression<T1>, T2, T3, T4, T5, T6, T7, T8, ISelectFromExpression<T1>>> exp) { this.InternalFrom(exp); var ret = new CustomSelect<T1, T2, T3, T4, T5, T6, T7, T8>(_orm, _commonUtils, _commonExpression, null); CustomSelect<T1>.CopyData(this, (Internal.CommonProvider.Select0Provider)ret, exp?.Parameters); return ret; }
public override ISelect<T1, T2, T3, T4, T5, T6, T7, T8, T9> From<T2, T3, T4, T5, T6, T7, T8, T9>(Expression<Func<ISelectFromExpression<T1>, T2, T3, T4, T5, T6, T7, T8, T9, ISelectFromExpression<T1>>> exp) { this.InternalFrom(exp); var ret = new CustomSelect<T1, T2, T3, T4, T5, T6, T7, T8, T9>(_orm, _commonUtils, _commonExpression, null); CustomSelect<T1>.CopyData(this, (Internal.CommonProvider.Select0Provider)ret, exp?.Parameters); return ret; }
public override ISelect<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10> From<T2, T3, T4, T5, T6, T7, T8, T9, T10>(Expression<Func<ISelectFromExpression<T1>, T2, T3, T4, T5, T6, T7, T8, T9, T10, ISelectFromExpression<T1>>> exp) { this.InternalFrom(exp); var ret = new CustomSelect<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10>(_orm, _commonUtils, _commonExpression, null); CustomSelect<T1>.CopyData(this, (Internal.CommonProvider.Select0Provider)ret, exp?.Parameters); return ret; }
public override ISelect<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11> From<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11>(Expression<Func<ISelectFromExpression<T1>, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, ISelectFromExpression<T1>>> exp) { this.InternalFrom(exp); var ret = new CustomSelect<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11>(_orm, _commonUtils, _commonExpression, null); CustomSelect<T1>.CopyData(this, (Internal.CommonProvider.Select0Provider)ret, exp?.Parameters); return ret; }
public override ISelect<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12> From<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12>(Expression<Func<ISelectFromExpression<T1>, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, ISelectFromExpression<T1>>> exp) { this.InternalFrom(exp); var ret = new CustomSelect<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12>(_orm, _commonUtils, _commonExpression, null); CustomSelect<T1>.CopyData(this, (Internal.CommonProvider.Select0Provider)ret, exp?.Parameters); return ret; }
public override ISelect<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13> From<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13>(Expression<Func<ISelectFromExpression<T1>, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, ISelectFromExpression<T1>>> exp) { this.InternalFrom(exp); var ret = new CustomSelect<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13>(_orm, _commonUtils, _commonExpression, null); CustomSelect<T1>.CopyData(this, (Internal.CommonProvider.Select0Provider)ret, exp?.Parameters); return ret; }
public override ISelect<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14> From<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14>(Expression<Func<ISelectFromExpression<T1>, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, ISelectFromExpression<T1>>> exp) { this.InternalFrom(exp); var ret = new CustomSelect<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14>(_orm, _commonUtils, _commonExpression, null); CustomSelect<T1>.CopyData(this, (Internal.CommonProvider.Select0Provider)ret, exp?.Parameters); return ret; }
public override ISelect<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15> From<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15>(Expression<Func<ISelectFromExpression<T1>, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15, ISelectFromExpression<T1>>> exp) { this.InternalFrom(exp); var ret = new CustomSelect<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15>(_orm, _commonUtils, _commonExpression, null); CustomSelect<T1>.CopyData(this, (Internal.CommonProvider.Select0Provider)ret, exp?.Parameters); return ret; }
public override ISelect<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15, T16> From<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15, T16>(Expression<Func<ISelectFromExpression<T1>, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15, T16, ISelectFromExpression<T1>>> exp) { this.InternalFrom(exp); var ret = new CustomSelect<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15, T16>(_orm, _commonUtils, _commonExpression, null); CustomSelect<T1>.CopyData(this, (Internal.CommonProvider.Select0Provider)ret, exp?.Parameters); return ret; }
public override string ToSql(string field = null) => ToSqlStatic(_commonUtils, _commonExpression, _select, _distinct, field ?? this.GetAllFieldExpressionTreeLevel2().Field, _join, _where, _groupby, _having, _orderby, _skip, _limit, _tables, this.GetTableRuleUnions(), _aliasRule, _tosqlAppendContent, _whereGlobalFilter, _orm);
}
class CustomSelect<T1, T2> : FreeSql.Internal.CommonProvider.Select2Provider<T1, T2> where T2 : class
{
public CustomSelect(IFreeSql orm, CommonUtils commonUtils, CommonExpression commonExpression, object dywhere) : base(orm, commonUtils, commonExpression, dywhere) { }
public override string ToSql(string field = null) => CustomSelect<T1>.ToSqlStatic(_commonUtils, _commonExpression, _select, _distinct, field ?? this.GetAllFieldExpressionTreeLevel2().Field, _join, _where, _groupby, _having, _orderby, _skip, _limit, _tables, this.GetTableRuleUnions(), _aliasRule, _tosqlAppendContent, _whereGlobalFilter, _orm);
}
class CustomSelect<T1, T2, T3> : FreeSql.Internal.CommonProvider.Select3Provider<T1, T2, T3> where T2 : class where T3 : class
{
public CustomSelect(IFreeSql orm, CommonUtils commonUtils, CommonExpression commonExpression, object dywhere) : base(orm, commonUtils, commonExpression, dywhere) { }
public override string ToSql(string field = null) => CustomSelect<T1>.ToSqlStatic(_commonUtils, _commonExpression, _select, _distinct, field ?? this.GetAllFieldExpressionTreeLevel2().Field, _join, _where, _groupby, _having, _orderby, _skip, _limit, _tables, this.GetTableRuleUnions(), _aliasRule, _tosqlAppendContent, _whereGlobalFilter, _orm);
}
class CustomSelect<T1, T2, T3, T4> : FreeSql.Internal.CommonProvider.Select4Provider<T1, T2, T3, T4> where T2 : class where T3 : class where T4 : class
{
public CustomSelect(IFreeSql orm, CommonUtils commonUtils, CommonExpression commonExpression, object dywhere) : base(orm, commonUtils, commonExpression, dywhere) { }
public override string ToSql(string field = null) => CustomSelect<T1>.ToSqlStatic(_commonUtils, _commonExpression, _select, _distinct, field ?? this.GetAllFieldExpressionTreeLevel2().Field, _join, _where, _groupby, _having, _orderby, _skip, _limit, _tables, this.GetTableRuleUnions(), _aliasRule, _tosqlAppendContent, _whereGlobalFilter, _orm);
}
class CustomSelect<T1, T2, T3, T4, T5> : FreeSql.Internal.CommonProvider.Select5Provider<T1, T2, T3, T4, T5> where T2 : class where T3 : class where T4 : class where T5 : class
{
public CustomSelect(IFreeSql orm, CommonUtils commonUtils, CommonExpression commonExpression, object dywhere) : base(orm, commonUtils, commonExpression, dywhere) { }
public override string ToSql(string field = null) => CustomSelect<T1>.ToSqlStatic(_commonUtils, _commonExpression, _select, _distinct, field ?? this.GetAllFieldExpressionTreeLevel2().Field, _join, _where, _groupby, _having, _orderby, _skip, _limit, _tables, this.GetTableRuleUnions(), _aliasRule, _tosqlAppendContent, _whereGlobalFilter, _orm);
}
class CustomSelect<T1, T2, T3, T4, T5, T6> : FreeSql.Internal.CommonProvider.Select6Provider<T1, T2, T3, T4, T5, T6> where T2 : class where T3 : class where T4 : class where T5 : class where T6 : class
{
public CustomSelect(IFreeSql orm, CommonUtils commonUtils, CommonExpression commonExpression, object dywhere) : base(orm, commonUtils, commonExpression, dywhere) { }
public override string ToSql(string field = null) => CustomSelect<T1>.ToSqlStatic(_commonUtils, _commonExpression, _select, _distinct, field ?? this.GetAllFieldExpressionTreeLevel2().Field, _join, _where, _groupby, _having, _orderby, _skip, _limit, _tables, this.GetTableRuleUnions(), _aliasRule, _tosqlAppendContent, _whereGlobalFilter, _orm);
}
class CustomSelect<T1, T2, T3, T4, T5, T6, T7> : FreeSql.Internal.CommonProvider.Select7Provider<T1, T2, T3, T4, T5, T6, T7> where T2 : class where T3 : class where T4 : class where T5 : class where T6 : class where T7 : class
{
public CustomSelect(IFreeSql orm, CommonUtils commonUtils, CommonExpression commonExpression, object dywhere) : base(orm, commonUtils, commonExpression, dywhere) { }
public override string ToSql(string field = null) => CustomSelect<T1>.ToSqlStatic(_commonUtils, _commonExpression, _select, _distinct, field ?? this.GetAllFieldExpressionTreeLevel2().Field, _join, _where, _groupby, _having, _orderby, _skip, _limit, _tables, this.GetTableRuleUnions(), _aliasRule, _tosqlAppendContent, _whereGlobalFilter, _orm);
}
class CustomSelect<T1, T2, T3, T4, T5, T6, T7, T8> : FreeSql.Internal.CommonProvider.Select8Provider<T1, T2, T3, T4, T5, T6, T7, T8> where T2 : class where T3 : class where T4 : class where T5 : class where T6 : class where T7 : class where T8 : class
{
public CustomSelect(IFreeSql orm, CommonUtils commonUtils, CommonExpression commonExpression, object dywhere) : base(orm, commonUtils, commonExpression, dywhere) { }
public override string ToSql(string field = null) => CustomSelect<T1>.ToSqlStatic(_commonUtils, _commonExpression, _select, _distinct, field ?? this.GetAllFieldExpressionTreeLevel2().Field, _join, _where, _groupby, _having, _orderby, _skip, _limit, _tables, this.GetTableRuleUnions(), _aliasRule, _tosqlAppendContent, _whereGlobalFilter, _orm);
}
class CustomSelect<T1, T2, T3, T4, T5, T6, T7, T8, T9> : FreeSql.Internal.CommonProvider.Select9Provider<T1, T2, T3, T4, T5, T6, T7, T8, T9> where T2 : class where T3 : class where T4 : class where T5 : class where T6 : class where T7 : class where T8 : class where T9 : class
{
public CustomSelect(IFreeSql orm, CommonUtils commonUtils, CommonExpression commonExpression, object dywhere) : base(orm, commonUtils, commonExpression, dywhere) { }
public override string ToSql(string field = null) => CustomSelect<T1>.ToSqlStatic(_commonUtils, _commonExpression, _select, _distinct, field ?? this.GetAllFieldExpressionTreeLevel2().Field, _join, _where, _groupby, _having, _orderby, _skip, _limit, _tables, this.GetTableRuleUnions(), _aliasRule, _tosqlAppendContent, _whereGlobalFilter, _orm);
}
class CustomSelect<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10> : FreeSql.Internal.CommonProvider.Select10Provider<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10> where T2 : class where T3 : class where T4 : class where T5 : class where T6 : class where T7 : class where T8 : class where T9 : class where T10 : class
{
public CustomSelect(IFreeSql orm, CommonUtils commonUtils, CommonExpression commonExpression, object dywhere) : base(orm, commonUtils, commonExpression, dywhere) { }
public override string ToSql(string field = null) => CustomSelect<T1>.ToSqlStatic(_commonUtils, _commonExpression, _select, _distinct, field ?? this.GetAllFieldExpressionTreeLevel2().Field, _join, _where, _groupby, _having, _orderby, _skip, _limit, _tables, this.GetTableRuleUnions(), _aliasRule, _tosqlAppendContent, _whereGlobalFilter, _orm);
}
class CustomSelect<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11> : FreeSql.Internal.CommonProvider.Select11Provider<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11> where T2 : class where T3 : class where T4 : class where T5 : class where T6 : class where T7 : class where T8 : class where T9 : class where T10 : class where T11 : class
{
public CustomSelect(IFreeSql orm, CommonUtils commonUtils, CommonExpression commonExpression, object dywhere) : base(orm, commonUtils, commonExpression, dywhere) { }
public override string ToSql(string field = null) => CustomSelect<T1>.ToSqlStatic(_commonUtils, _commonExpression, _select, _distinct, field ?? this.GetAllFieldExpressionTreeLevel2().Field, _join, _where, _groupby, _having, _orderby, _skip, _limit, _tables, this.GetTableRuleUnions(), _aliasRule, _tosqlAppendContent, _whereGlobalFilter, _orm);
}
class CustomSelect<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12> : FreeSql.Internal.CommonProvider.Select12Provider<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12> where T2 : class where T3 : class where T4 : class where T5 : class where T6 : class where T7 : class where T8 : class where T9 : class where T10 : class where T11 : class where T12 : class
{
public CustomSelect(IFreeSql orm, CommonUtils commonUtils, CommonExpression commonExpression, object dywhere) : base(orm, commonUtils, commonExpression, dywhere) { }
public override string ToSql(string field = null) => CustomSelect<T1>.ToSqlStatic(_commonUtils, _commonExpression, _select, _distinct, field ?? this.GetAllFieldExpressionTreeLevel2().Field, _join, _where, _groupby, _having, _orderby, _skip, _limit, _tables, this.GetTableRuleUnions(), _aliasRule, _tosqlAppendContent, _whereGlobalFilter, _orm);
}
class CustomSelect<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13> : FreeSql.Internal.CommonProvider.Select13Provider<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13> where T2 : class where T3 : class where T4 : class where T5 : class where T6 : class where T7 : class where T8 : class where T9 : class where T10 : class where T11 : class where T12 : class where T13 : class
{
public CustomSelect(IFreeSql orm, CommonUtils commonUtils, CommonExpression commonExpression, object dywhere) : base(orm, commonUtils, commonExpression, dywhere) { }
public override string ToSql(string field = null) => CustomSelect<T1>.ToSqlStatic(_commonUtils, _commonExpression, _select, _distinct, field ?? this.GetAllFieldExpressionTreeLevel2().Field, _join, _where, _groupby, _having, _orderby, _skip, _limit, _tables, this.GetTableRuleUnions(), _aliasRule, _tosqlAppendContent, _whereGlobalFilter, _orm);
}
class CustomSelect<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14> : FreeSql.Internal.CommonProvider.Select14Provider<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14> where T2 : class where T3 : class where T4 : class where T5 : class where T6 : class where T7 : class where T8 : class where T9 : class where T10 : class where T11 : class where T12 : class where T13 : class where T14 : class
{
public CustomSelect(IFreeSql orm, CommonUtils commonUtils, CommonExpression commonExpression, object dywhere) : base(orm, commonUtils, commonExpression, dywhere) { }
public override string ToSql(string field = null) => CustomSelect<T1>.ToSqlStatic(_commonUtils, _commonExpression, _select, _distinct, field ?? this.GetAllFieldExpressionTreeLevel2().Field, _join, _where, _groupby, _having, _orderby, _skip, _limit, _tables, this.GetTableRuleUnions(), _aliasRule, _tosqlAppendContent, _whereGlobalFilter, _orm);
}
class CustomSelect<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15> : FreeSql.Internal.CommonProvider.Select15Provider<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15> where T2 : class where T3 : class where T4 : class where T5 : class where T6 : class where T7 : class where T8 : class where T9 : class where T10 : class where T11 : class where T12 : class where T13 : class where T14 : class where T15 : class
{
public CustomSelect(IFreeSql orm, CommonUtils commonUtils, CommonExpression commonExpression, object dywhere) : base(orm, commonUtils, commonExpression, dywhere) { }
public override string ToSql(string field = null) => CustomSelect<T1>.ToSqlStatic(_commonUtils, _commonExpression, _select, _distinct, field ?? this.GetAllFieldExpressionTreeLevel2().Field, _join, _where, _groupby, _having, _orderby, _skip, _limit, _tables, this.GetTableRuleUnions(), _aliasRule, _tosqlAppendContent, _whereGlobalFilter, _orm);
}
class CustomSelect<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15, T16> : FreeSql.Internal.CommonProvider.Select16Provider<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15, T16> where T2 : class where T3 : class where T4 : class where T5 : class where T6 : class where T7 : class where T8 : class where T9 : class where T10 : class where T11 : class where T12 : class where T13 : class where T14 : class where T15 : class where T16 : class
{
public CustomSelect(IFreeSql orm, CommonUtils commonUtils, CommonExpression commonExpression, object dywhere) : base(orm, commonUtils, commonExpression, dywhere) { }
public override string ToSql(string field = null) => CustomSelect<T1>.ToSqlStatic(_commonUtils, _commonExpression, _select, _distinct, field ?? this.GetAllFieldExpressionTreeLevel2().Field, _join, _where, _groupby, _having, _orderby, _skip, _limit, _tables, this.GetTableRuleUnions(), _aliasRule, _tosqlAppendContent, _whereGlobalFilter, _orm);
}
}

View File

@ -0,0 +1,71 @@
using FreeSql.Internal;
using FreeSql.Internal.Model;
using System;
using System.Collections.Generic;
using System.Data;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
namespace FreeSql.Custom
{
class CustomUpdate<T1> : Internal.CommonProvider.UpdateProvider<T1>
{
CustomUtils _utils;
public CustomUpdate(IFreeSql orm, CommonUtils commonUtils, CommonExpression commonExpression, object dywhere)
: base(orm, commonUtils, commonExpression, dywhere)
{
_utils = _commonUtils as CustomUtils;
}
public override int ExecuteAffrows() => base.SplitExecuteAffrows(_batchRowsLimit > 0 ? _batchRowsLimit : _utils.Adapter.UpdateBatchSplitLimit, _batchParameterLimit > 0 ? _batchParameterLimit : 255);
public override List<T1> ExecuteUpdated() => base.SplitExecuteUpdated(_batchRowsLimit > 0 ? _batchRowsLimit : _utils.Adapter.UpdateBatchSplitLimit, _batchParameterLimit > 0 ? _batchParameterLimit : 255);
protected override List<T1> RawExecuteUpdated() => throw new NotImplementedException("FreeSql.Provider.Custom 未实现该功能 未实现该功能");
protected override void ToSqlCase(StringBuilder caseWhen, ColumnInfo[] primarys)
{
if (_table.Primarys.Length == 1)
{
var pk = _table.Primarys.First();
caseWhen.Append(_commonUtils.RereadColumn(pk, _commonUtils.QuoteSqlName(pk.Attribute.Name)));
return;
}
caseWhen.Append("(");
var pkidx = 0;
foreach (var pk in _table.Primarys)
{
if (pkidx > 0) caseWhen.Append(" + '+' + ");
caseWhen.Append(_utils.Adapter.CastSql(_commonUtils.RereadColumn(pk, _commonUtils.QuoteSqlName(pk.Attribute.Name)), _utils.Adapter.MappingDbTypeVarChar));
++pkidx;
}
caseWhen.Append(")");
}
protected override void ToSqlWhen(StringBuilder sb, ColumnInfo[] primarys, object d)
{
if (_table.Primarys.Length == 1)
{
sb.Append(_commonUtils.FormatSql("{0}", _table.Primarys[0].GetDbValue(d)));
return;
}
var pkidx = 0;
foreach (var pk in _table.Primarys)
{
if (pkidx > 0) sb.Append(" + '+' + ");
sb.Append(_utils.Adapter.CastSql(_commonUtils.FormatSql("{0}", pk.GetDbValue(d)), _utils.Adapter.MappingDbTypeVarChar));
++pkidx;
}
}
#if net40
#else
public override Task<int> ExecuteAffrowsAsync(CancellationToken cancellationToken = default) => base.SplitExecuteAffrowsAsync(_batchRowsLimit > 0 ? _batchRowsLimit : _utils.Adapter.UpdateBatchSplitLimit, _batchParameterLimit > 0 ? _batchParameterLimit : 255, cancellationToken);
public override Task<List<T1>> ExecuteUpdatedAsync(CancellationToken cancellationToken = default) => base.SplitExecuteUpdatedAsync(_batchRowsLimit > 0 ? _batchRowsLimit : _utils.Adapter.UpdateBatchSplitLimit, _batchParameterLimit > 0 ? _batchParameterLimit : 255, cancellationToken);
protected override Task<List<T1>> RawExecuteUpdatedAsync(CancellationToken cancellationToken = default) => throw new NotImplementedException("FreeSql.Provider.Custom 未实现该功能 未实现该功能");
#endif
}
}

View File

@ -0,0 +1,173 @@
using FreeSql.Internal;
using FreeSql.Internal.Model;
using System;
using System.Collections.Generic;
using System.Text;
namespace FreeSql.Custom
{
public class CustomAdapter
{
/// <summary>
/// Select TOP 1或 Limit 1 风格
/// </summary>
public virtual SelecTopStyle SelectTopStyle => SelecTopStyle.Top;
public enum SelecTopStyle { Top, Limit }
/// <summary>
/// 插入成功后,获取自增值
/// </summary>
public virtual string InsertAfterGetIdentitySql => "SELECT SCOPE_IDENTITY()";
/// <summary>
/// 批量插入时,自动拆分的每次执行数量
/// </summary>
public virtual int InsertBatchSplitLimit => 255;
/// <summary>
/// 批量更新时,自动拆分的每次执行数量
/// </summary>
public virtual int UpdateBatchSplitLimit => 255;
public virtual string MappingDbTypeBit => "int";
public virtual string MappingDbTypeSmallInt => "smallint";
public virtual string MappingDbTypeInt => "int";
public virtual string MappingDbTypeBigInt => "bigint";
public virtual string MappingDbTypeTinyInt => "tinyint";
public virtual string MappingDbTypeDecimal => "decimal";
public virtual string MappingDbTypeDouble => "float";
public virtual string MappingDbTypeReal => "real";
public virtual string MappingDbTypeDateTime => "datetime";
public virtual string MappingDbTypeVarBinary => "varbinary";
public virtual string MappingDbTypeVarChar => "nvarchar";
public virtual string MappingDbTypeChar => "char";
public virtual string MappingDbTypeText => "nvarchar(max)";
public virtual string MappingDbTypeUniqueIdentifier => "uniqueidentifier";
public virtual char QuoteSqlNameLeft => '[';
public virtual char QuoteSqlNameRight => ']';
public virtual string FieldSql(Type type, string columnName) => columnName;
public virtual string UnicodeStringRawSql(object value, ColumnInfo mapColumn) => value == null ? "NULL" : string.Concat("N'", value.ToString().Replace("'", "''"), "'");
public virtual string DateTimeRawSql(object value)
{
if (value == null) return "NULL";
if (value.Equals(DateTime.MinValue) == true) value = new DateTime(1970, 1, 1);
return string.Concat("'", ((DateTime)value).ToString("yyyy-MM-dd HH:mm:ss"), "'");
}
public virtual string TimeSpanRawSql(object value) => value == null ? "NULL" : ((TimeSpan)value).TotalSeconds.ToString();
public virtual string ByteRawSql(object value)
{
if (value == null) return "NULL";
return $"0x{CommonUtils.BytesSqlRaw(value as byte[])}";
}
public virtual string CastSql(string sql, string to) => $"cast({sql} as {to})";
public virtual string IsNullSql(string sql, object value) => $"isnull({sql}, {value})";
public virtual string ConcatSql(string[] objs, Type[] types)
{
var sb = new StringBuilder();
var news = new string[objs.Length];
for (var a = 0; a < objs.Length; a++)
{
if (types[a] == typeof(string)) news[a] = objs[a];
else if (types[a].NullableTypeOrThis() == typeof(Guid)) news[a] = $"cast({objs[a]} as char(36))";
else news[a] = $"cast({objs[a]} as nvarchar)";
}
return string.Join(" + ", news);
}
public virtual string Mod(string left, string right, Type leftType, Type rightType) => $"{left} % {right}";
public virtual string Div(string left, string right, Type leftType, Type rightType) => $"{left} / {right}";
public virtual string LambdaConvert_ToBoolean(Type type, string operand) => $"(cast({operand} as varchar) not in ('0','false'))";
public virtual string LambdaConvert_ToByte(Type type, string operand) => $"cast({operand} as tinyint)";
public virtual string LambdaConvert_ToChar(Type type, string operand) => $"substring(cast({operand} as varchar),1,1)";
public virtual string LambdaConvert_ToDateTime(Type type, string operand) => $"cast({operand} as datetime)";
public virtual string LambdaConvert_ToDecimal(Type type, string operand) => $"cast({operand} as decimal(36,18))";
public virtual string LambdaConvert_ToDouble(Type type, string operand) => $"cast({operand} as decimal(32,16))";
public virtual string LambdaConvert_ToInt16(Type type, string operand) => $"cast({operand} as smallint)";
public virtual string LambdaConvert_ToInt32(Type type, string operand) => $"cast({operand} as int)";
public virtual string LambdaConvert_ToInt64(Type type, string operand) => $"cast({operand} as bigint)";
public virtual string LambdaConvert_ToSByte(Type type, string operand) => $"cast({operand} as tinyint)";
public virtual string LambdaConvert_ToSingle(Type type, string operand) => $"cast({operand} as decimal(14,7))";
public virtual string LambdaConvert_ToString(Type type, string operand) => type.NullableTypeOrThis() == typeof(Guid) ? $"cast({operand} as varchar(36))" : $"cast({operand} as nvarchar)";
public virtual string LambdaConvert_ToUInt16(Type type, string operand) => $"cast({operand} as smallint)";
public virtual string LambdaConvert_ToUInt32(Type type, string operand) => $"cast({operand} as int)";
public virtual string LambdaConvert_ToUInt64(Type type, string operand) => $"cast({operand} as bigint)";
public virtual string LambdaConvert_ToGuid(Type type, string operand) => $"cast({operand} as uniqueidentifier)";
public virtual string LambdaGuid_NewGuid => "newid()";
public virtual string LambdaRandom_Next => "cast(rand()*1000000000 as int)";
public virtual string LambdaRandom_NextDouble => "rand()";
public virtual string LambdaString_IsNullOrEmpty(string operand) => $"({operand} is null or {operand} = '')";
public virtual string LambdaString_IsNullOrWhiteSpace(string operand) => $"({operand} is null or {operand} = '' or ltrim({operand}) = '')";
public virtual string LambdaString_Length(string operand) => $"len({operand})";
public virtual string LambdaString_ToLower(string operand) => $"lower({operand})";
public virtual string LambdaString_ToUpper(string operand) => $"upper({operand})";
public virtual string LambdaString_Substring(string operand, string startIndex, string length) => string.IsNullOrEmpty(length) ? $"left({operand}, {startIndex})" : $"substring({operand}, {startIndex}, {length})";
public virtual string LambdaString_IndexOf(string operand, string value, string startIndex) => string.IsNullOrEmpty(startIndex) ? $"(charindex({value}, {operand})-1)" : $"(charindex({value}, {operand}, {startIndex})-1)";
public virtual string LambdaString_PadLeft(string operand, string length, string paddingChar) => string.IsNullOrEmpty(paddingChar) ? $"lpad({operand}, {length})" : $"lpad({operand}, {length}, {paddingChar})";
public virtual string LambdaString_PadRight(string operand, string length, string paddingChar) => string.IsNullOrEmpty(paddingChar) ? $"rpad({operand}, {length})" : $"rpad({operand}, {length}, {paddingChar})";
public virtual string LambdaString_Trim(string operand) => $"ltrim(rtrim({operand}))";
public virtual string LambdaString_TrimStart(string operand) => $"ltrim({operand})";
public virtual string LambdaString_TrimEnd(string operand) => $"rtrim({operand})";
public virtual string LambdaString_Replace(string operand, string oldValue, string newValue) => $"replace({operand}, {oldValue}, {newValue})";
public virtual string LambdaString_CompareTo(string operand, string value) => $"({operand} - {value})";
public virtual string LambdaString_Equals(string operand, string value) => $"({operand} = {value})";
public virtual string LambdaDateTime_Now => "getdate()";
public virtual string LambdaDateTime_UtcNow => "getutcdate()";
public virtual string LambdaDateTime_Today => "convert(char(10),getdate(),120)";
public virtual string LambdaDateTime_MinValue => "'1753/1/1 0:00:00'";
public virtual string LambdaDateTime_MaxValue => "'9999/12/31 23:59:59'";
public virtual string LambdaDateTime_Date(string operand) => $"convert(char(10),{operand},120)";
public virtual string LambdaDateTime_TimeOfDay(string operand) => $"datediff(second, convert(char(10),{operand},120), {operand})";
public virtual string LambdaDateTime_DayOfWeek(string operand) => $"(datepart(weekday, {operand})-1)";
public virtual string LambdaDateTime_Day(string operand) => $"datepart(day, {operand})";
public virtual string LambdaDateTime_DayOfYear(string operand) => $"datepart(dayofyear, {operand})";
public virtual string LambdaDateTime_Month(string operand) => $"datepart(month, {operand})";
public virtual string LambdaDateTime_Year(string operand) => $"datepart(year, {operand})";
public virtual string LambdaDateTime_Hour(string operand) => $"datepart(hour, {operand})";
public virtual string LambdaDateTime_Minute(string operand) => $"datepart(minute, {operand})";
public virtual string LambdaDateTime_Second(string operand) => $"datepart(second, {operand})";
public virtual string LambdaDateTime_Millisecond(string operand) => $"(datepart(millisecond, {operand})/1000)";
public virtual string LambdaDateTime_Ticks(string operand) => $"(cast(datediff(second, '1970-1-1', {operand}) as bigint)*10000000+621355968000000000)";
public virtual string LambdaDateTime_DaysInMonth(string year, string month) => $"datepart(day, dateadd(day, -1, dateadd(month, 1, cast({year} as varchar) + '-' + cast({month} as varchar) + '-1')))";
public virtual string LambdaDateTime_IsLeapYear(string year) => $"(({year})%4=0 AND ({year})%100<>0 OR ({year})%400=0)";
public virtual string LambdaDateTime_Add(string operand, string value) => $"dateadd(second, {value}, {operand})";
public virtual string LambdaDateTime_AddDays(string operand, string value) => $"dateadd(day, {value}, {operand})";
public virtual string LambdaDateTime_AddHours(string operand, string value) => $"dateadd(hour, {value}, {operand})";
public virtual string LambdaDateTime_AddMilliseconds(string operand, string value) => $"dateadd(second, ({value})/1000, {operand})";
public virtual string LambdaDateTime_AddMinutes(string operand, string value) => $"dateadd(minute, {value}, {operand})";
public virtual string LambdaDateTime_AddMonths(string operand, string value) => $"dateadd(month, {value}, {operand})";
public virtual string LambdaDateTime_AddSeconds(string operand, string value) => $"dateadd(second, {value}, {operand})";
public virtual string LambdaDateTime_AddTicks(string operand, string value) => $"dateadd(second, ({value})/10000000, {operand})";
public virtual string LambdaDateTime_AddYears(string operand, string value) => $"dateadd(year, {value}, {operand})";
public virtual string LambdaDateTime_Subtract(string operand, string value) => $"datediff(second, {value}, {operand})";
public virtual string LambdaDateTime_SubtractTimeSpan(string operand, string value) => $"dateadd(second, ({value})*-1, {operand})";
public virtual string LambdaDateTime_Equals(string operand, string value) => $"({operand} = {value})";
public virtual string LambdaDateTime_CompareTo(string operand, string value) => $"datediff(second,{value},{operand})";
public virtual string LambdaDateTime_ToString(string operand) => $"convert(varchar, {operand}, 121)";
public virtual string LambdaMath_Abs(string operand) => $"abs({operand})";
public virtual string LambdaMath_Sign(string operand) => $"sign({operand})";
public virtual string LambdaMath_Floor(string operand) => $"floor({operand})";
public virtual string LambdaMath_Ceiling(string operand) => $"ceiling({ operand})";
public virtual string LambdaMath_Round(string operand, string decimals) => $"round({operand}, {decimals})";
public virtual string LambdaMath_Exp(string operand) => $"exp({operand})";
public virtual string LambdaMath_Log(string operand) => $"log({operand})";
public virtual string LambdaMath_Log10(string operand) => $"log10({operand})";
public virtual string LambdaMath_Pow(string operand, string y) => $"power({operand}, {y})";
public virtual string LambdaMath_Sqrt(string operand) => $"sqrt({operand})";
public virtual string LambdaMath_Cos(string operand) => $"cos({operand})";
public virtual string LambdaMath_Sin(string operand) => $"sin({operand})";
public virtual string LambdaMath_Tan(string operand) => $"tan({operand})";
public virtual string LambdaMath_Acos(string operand) => $"acos({operand})";
public virtual string LambdaMath_Asin(string operand) => $"asin({operand})";
public virtual string LambdaMath_Atan(string operand) => $"atan({operand})";
public virtual string LambdaMath_Atan2(string operand, string x) => $"atan2({operand}, {x})";
public virtual string LambdaMath_Truncate(string operand) => $"floor({operand})";
}
}

View File

@ -0,0 +1,82 @@
using FreeSql.Internal;
using FreeSql.Internal.Model;
using FreeSql.Internal.ObjectPool;
using System;
using System.Collections;
using System.Data.Common;
using System.Text;
using System.Threading;
namespace FreeSql.Custom
{
class CustomAdo : FreeSql.Internal.CommonProvider.AdoProvider
{
public CustomAdo() : base(DataType.Custom, null, null) { }
public CustomAdo(CommonUtils util, string masterConnectionString, string[] slaveConnectionStrings, Func<DbConnection> connectionFactory) : base(DataType.Custom, masterConnectionString, slaveConnectionStrings)
{
base._util = util;
if (connectionFactory != null)
{
var pool = new FreeSql.Internal.CommonProvider.DbConnectionPool(DataType.SqlServer, connectionFactory);
MasterPool = pool;
_CreateCommandConnection = pool.TestConnection;
_CreateParameterCommand = CreateCommand();
return;
}
throw new Exception("FreeSql.Provider.CustomAdapter 仅支持 UseConnectionFactory 方式构建 IFreeSql");
}
CustomAdapter Adapter => (_util == null ? FreeSqlCustomAdapterGlobalExtensions.DefaultAdapter : _util._orm.GetCustomAdapter());
public override object AddslashesProcessParam(object param, Type mapType, ColumnInfo mapColumn)
{
if (param == null) return "NULL";
if (mapType != null && mapType != param.GetType() && (param is IEnumerable == false))
param = Utils.GetDataReaderValue(mapType, param);
if (param is bool || param is bool?)
return (bool)param ? 1 : 0;
else if (param is string)
return Adapter.UnicodeStringRawSql(param, mapColumn);
else if (param is char)
return string.Concat("'", param.ToString().Replace("'", "''").Replace('\0', ' '), "'");
else if (param is Enum)
return ((Enum)param).ToInt64();
else if (decimal.TryParse(string.Concat(param), out var trydec))
return param;
else if (param is DateTime || param is DateTime?)
return Adapter.DateTimeRawSql(param);
else if (param is TimeSpan || param is TimeSpan?)
return Adapter.TimeSpanRawSql(param);
else if (param is byte[])
return Adapter.ByteRawSql(param as byte[]);
else if (param is IEnumerable)
return AddslashesIEnumerable(param, mapType, mapColumn);
return string.Concat("'", param.ToString().Replace("'", "''"), "'");
}
DbConnection _CreateCommandConnection;
DbCommand _CreateParameterCommand;
public override DbCommand CreateCommand()
{
if (_CreateCommandConnection != null)
{
var cmd = _CreateCommandConnection.CreateCommand();
cmd.Connection = null;
return cmd;
}
throw new Exception("FreeSql.Provider.CustomAdapter 无法使用 CreateCommand");
}
public DbParameter CreateParameter()
{
return _CreateParameterCommand.CreateParameter();
}
public override void ReturnConnection(IObjectPool<DbConnection> pool, Object<DbConnection> conn, Exception ex)
{
pool.Return(conn);
}
public override DbParameter[] GetDbParamtersByObject(string sql, object obj) => _util.GetDbParamtersByObject(sql, obj);
}
}

View File

@ -0,0 +1,95 @@
using FreeSql.Internal;
using FreeSql.Internal.Model;
using System;
using System.Collections.Generic;
using System.Data;
using System.Data.Common;
using System.Linq;
using System.Text;
using System.Text.RegularExpressions;
namespace FreeSql.Custom
{
class CustomCodeFirst : Internal.CommonProvider.CodeFirstProvider
{
public override bool IsAutoSyncStructure { get => false; set => base.IsAutoSyncStructure = false; }
public override bool IsNoneCommandParameter { get => true; set => base.IsNoneCommandParameter = true; }
public CustomCodeFirst(IFreeSql orm, CommonUtils commonUtils, CommonExpression commonExpression) : base(orm, commonUtils, commonExpression)
{
_utils = _commonUtils as CustomUtils;
}
CustomUtils _utils;
object _dicCsToDbLock = new object();
Dictionary<string, CsToDb<DbType>> _dicCsToDb;
public override DbInfoResult GetDbInfo(Type type)
{
if (_dicCsToDb == null)
{
lock (_dicCsToDbLock)
{
if (_dicCsToDb == null)
{
var reg = new Regex(@"\([^\)]+\)", RegexOptions.IgnoreCase | RegexOptions.Compiled);
Func<string, string> deleteBrackets = str => reg.Replace(str, "");
_dicCsToDb = new Dictionary<string, CsToDb<DbType>>() {
{ typeof(bool).FullName, CsToDb.New(DbType.Boolean, _utils.Adapter.MappingDbTypeBit,$"{_utils.Adapter.MappingDbTypeBit} NOT NULL", null, false, false) },{ typeof(bool?).FullName, CsToDb.New(DbType.Boolean, _utils.Adapter.MappingDbTypeBit,_utils.Adapter.MappingDbTypeBit, null, true, null) },
{ typeof(sbyte).FullName, CsToDb.New(DbType.SByte, _utils.Adapter.MappingDbTypeSmallInt, $"{_utils.Adapter.MappingDbTypeSmallInt} NOT NULL", false, false, 0) },{ typeof(sbyte?).FullName, CsToDb.New(DbType.SByte, _utils.Adapter.MappingDbTypeSmallInt, _utils.Adapter.MappingDbTypeSmallInt, false, true, null) },
{ typeof(short).FullName, CsToDb.New(DbType.Int16, _utils.Adapter.MappingDbTypeSmallInt,$"{_utils.Adapter.MappingDbTypeSmallInt} NOT NULL", false, false, 0) },{ typeof(short?).FullName, CsToDb.New(DbType.Int16, _utils.Adapter.MappingDbTypeSmallInt, _utils.Adapter.MappingDbTypeSmallInt, false, true, null) },
{ typeof(int).FullName, CsToDb.New(DbType.Int32, _utils.Adapter.MappingDbTypeInt, $"{_utils.Adapter.MappingDbTypeInt} NOT NULL", false, false, 0) },{ typeof(int?).FullName, CsToDb.New(DbType.Int32, _utils.Adapter.MappingDbTypeInt, _utils.Adapter.MappingDbTypeInt, false, true, null) },
{ typeof(long).FullName, CsToDb.New(DbType.Int64, _utils.Adapter.MappingDbTypeBigInt,$"{_utils.Adapter.MappingDbTypeBigInt} NOT NULL", false, false, 0) },{ typeof(long?).FullName, CsToDb.New(DbType.Int64, _utils.Adapter.MappingDbTypeBigInt,_utils.Adapter.MappingDbTypeBigInt, false, true, null) },
{ typeof(byte).FullName, CsToDb.New(DbType.Byte, _utils.Adapter.MappingDbTypeTinyInt,$"{_utils.Adapter.MappingDbTypeTinyInt} NOT NULL", true, false, 0) },{ typeof(byte?).FullName, CsToDb.New(DbType.Byte, _utils.Adapter.MappingDbTypeTinyInt,_utils.Adapter.MappingDbTypeTinyInt, true, true, null) },
{ typeof(ushort).FullName, CsToDb.New(DbType.UInt16, _utils.Adapter.MappingDbTypeInt,$"{_utils.Adapter.MappingDbTypeInt} NOT NULL", true, false, 0) },{ typeof(ushort?).FullName, CsToDb.New(DbType.UInt16, _utils.Adapter.MappingDbTypeInt, _utils.Adapter.MappingDbTypeInt, true, true, null) },
{ typeof(uint).FullName, CsToDb.New(DbType.UInt32, _utils.Adapter.MappingDbTypeBigInt, $"{_utils.Adapter.MappingDbTypeBigInt} NOT NULL", true, false, 0) },{ typeof(uint?).FullName, CsToDb.New(DbType.UInt32, _utils.Adapter.MappingDbTypeBigInt, _utils.Adapter.MappingDbTypeBigInt, true, true, null) },
{ typeof(ulong).FullName, CsToDb.New(DbType.UInt64, _utils.Adapter.MappingDbTypeDecimal, $"{_utils.Adapter.MappingDbTypeDecimal}(20,0) NOT NULL", true, false, 0) },{ typeof(ulong?).FullName, CsToDb.New(DbType.UInt64, _utils.Adapter.MappingDbTypeDecimal, $"{_utils.Adapter.MappingDbTypeDecimal}(20,0)", true, true, null) },
{ typeof(double).FullName, CsToDb.New(DbType.Double, _utils.Adapter.MappingDbTypeDouble, $"{_utils.Adapter.MappingDbTypeDouble} NOT NULL", false, false, 0) },{ typeof(double?).FullName, CsToDb.New(DbType.Double, _utils.Adapter.MappingDbTypeDouble, _utils.Adapter.MappingDbTypeDouble, false, true, null) },
{ typeof(float).FullName, CsToDb.New(DbType.Single, _utils.Adapter.MappingDbTypeReal,$"{_utils.Adapter.MappingDbTypeReal} NOT NULL", false, false, 0) },{ typeof(float?).FullName, CsToDb.New(DbType.Single, _utils.Adapter.MappingDbTypeReal,_utils.Adapter.MappingDbTypeReal, false, true, null) },
{ typeof(decimal).FullName, CsToDb.New(DbType.Decimal, _utils.Adapter.MappingDbTypeDecimal, $"{_utils.Adapter.MappingDbTypeDecimal}(10,2) NOT NULL", false, false, 0) },{ typeof(decimal?).FullName, CsToDb.New(DbType.Decimal, _utils.Adapter.MappingDbTypeDecimal, $"{_utils.Adapter.MappingDbTypeDecimal}(10,2)", false, true, null) },
{ typeof(DateTime).FullName, CsToDb.New(DbType.DateTime, _utils.Adapter.MappingDbTypeDateTime, $"{_utils.Adapter.MappingDbTypeDateTime} NOT NULL", false, false, new DateTime(1970,1,1)) },{ typeof(DateTime?).FullName, CsToDb.New(DbType.DateTime, _utils.Adapter.MappingDbTypeDateTime, _utils.Adapter.MappingDbTypeDateTime, false, true, null) },
{ typeof(byte[]).FullName, CsToDb.New(DbType.Binary, _utils.Adapter.MappingDbTypeVarBinary, $"{_utils.Adapter.MappingDbTypeVarBinary}(255)", false, null, new byte[0]) },
{ typeof(string).FullName, CsToDb.New(DbType.String, _utils.Adapter.MappingDbTypeVarChar, $"{_utils.Adapter.MappingDbTypeVarChar}(255)", false, null, "") },
{ typeof(char).FullName, CsToDb.New(DbType.AnsiStringFixedLength, _utils.Adapter.MappingDbTypeChar, $"{_utils.Adapter.MappingDbTypeChar}(1)", false, null, '\0') },
{ typeof(Guid).FullName, CsToDb.New(DbType.Guid, deleteBrackets(_utils.Adapter.MappingDbTypeUniqueIdentifier), $"{_utils.Adapter.MappingDbTypeUniqueIdentifier} NOT NULL", false, false, Guid.Empty) },{ typeof(Guid?).FullName, CsToDb.New(DbType.Guid, deleteBrackets(_utils.Adapter.MappingDbTypeUniqueIdentifier), _utils.Adapter.MappingDbTypeUniqueIdentifier, false, true, null) },
};
}
}
}
if (_dicCsToDb.TryGetValue(type.FullName, out var trydc)) return new DbInfoResult((int)trydc.type, trydc.dbtype, trydc.dbtypeFull, trydc.isnullable, trydc.defaultValue);
if (type.IsArray) return null;
var enumType = type.IsEnum ? type : null;
if (enumType == null && type.IsNullableType())
{
var genericTypes = type.GetGenericArguments();
if (genericTypes.Length == 1 && genericTypes.First().IsEnum) enumType = genericTypes.First();
}
if (enumType != null)
{
var newItem = enumType.GetCustomAttributes(typeof(FlagsAttribute), false).Any() ?
CsToDb.New(DbType.Int64, _utils.Adapter.MappingDbTypeBigInt, $"{_utils.Adapter.MappingDbTypeBigInt}{(type.IsEnum ? " NOT NULL" : "")}", false, type.IsEnum ? false : true, enumType.CreateInstanceGetDefaultValue()) :
CsToDb.New(DbType.Int32, _utils.Adapter.MappingDbTypeInt, $"{_utils.Adapter.MappingDbTypeInt}{(type.IsEnum ? " NOT NULL" : "")}", false, type.IsEnum ? false : true, enumType.CreateInstanceGetDefaultValue());
if (_dicCsToDb.ContainsKey(type.FullName) == false)
{
lock (_dicCsToDbLock)
{
if (_dicCsToDb.ContainsKey(type.FullName) == false)
_dicCsToDb.Add(type.FullName, newItem);
}
}
return new DbInfoResult((int)newItem.type, newItem.dbtype, newItem.dbtypeFull, newItem.isnullable, newItem.defaultValue);
}
return null;
}
protected override string GetComparisonDDLStatements(params TypeAndName[] objects) => throw new NotImplementedException("FreeSql.Provider.Custom 未实现该功能");
}
}

View File

@ -0,0 +1,458 @@
using FreeSql.Internal;
using FreeSql.Internal.Model;
using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Linq.Expressions;
using System.Text;
namespace FreeSql.Custom
{
class CustomExpression : CommonExpression
{
CustomUtils _utils;
public CustomExpression(CommonUtils common) : base(common)
{
_utils = common as CustomUtils;
}
public override string ExpressionLambdaToSqlOther(Expression exp, ExpTSC tsc)
{
Func<Expression, string> getExp = exparg => ExpressionLambdaToSql(exparg, tsc);
switch (exp.NodeType)
{
case ExpressionType.Convert:
var operandExp = (exp as UnaryExpression)?.Operand;
var gentype = exp.Type.NullableTypeOrThis();
if (gentype != operandExp.Type.NullableTypeOrThis())
{
switch (gentype.ToString())
{
case "System.Boolean": return _utils.Adapter.LambdaConvert_ToBoolean(operandExp.Type, getExp(operandExp));
case "System.Byte": return _utils.Adapter.LambdaConvert_ToByte(operandExp.Type, getExp(operandExp));
case "System.Char": return _utils.Adapter.LambdaConvert_ToChar(operandExp.Type, getExp(operandExp));
case "System.DateTime": return _utils.Adapter.LambdaConvert_ToDateTime(operandExp.Type, getExp(operandExp));
case "System.Decimal": return _utils.Adapter.LambdaConvert_ToDecimal(operandExp.Type, getExp(operandExp));
case "System.Double": return _utils.Adapter.LambdaConvert_ToDouble(operandExp.Type, getExp(operandExp));
case "System.Int16": return _utils.Adapter.LambdaConvert_ToInt16(operandExp.Type, getExp(operandExp));
case "System.Int32": return _utils.Adapter.LambdaConvert_ToInt32(operandExp.Type, getExp(operandExp));
case "System.Int64": return _utils.Adapter.LambdaConvert_ToInt64(operandExp.Type, getExp(operandExp));
case "System.SByte": return _utils.Adapter.LambdaConvert_ToSByte(operandExp.Type, getExp(operandExp));
case "System.Single": return _utils.Adapter.LambdaConvert_ToSingle(operandExp.Type, getExp(operandExp));
case "System.String": return _utils.Adapter.LambdaConvert_ToString(operandExp.Type, getExp(operandExp));
case "System.UInt16": return _utils.Adapter.LambdaConvert_ToUInt16(operandExp.Type, getExp(operandExp));
case "System.UInt32": return _utils.Adapter.LambdaConvert_ToUInt32(operandExp.Type, getExp(operandExp));
case "System.UInt64": return _utils.Adapter.LambdaConvert_ToUInt64(operandExp.Type, getExp(operandExp));
case "System.Guid": return _utils.Adapter.LambdaConvert_ToGuid(operandExp.Type, getExp(operandExp));
}
}
break;
case ExpressionType.Call:
var callExp = exp as MethodCallExpression;
switch (callExp.Method.Name)
{
case "Parse":
case "TryParse":
switch (callExp.Method.DeclaringType.NullableTypeOrThis().ToString())
{
case "System.Boolean": return _utils.Adapter.LambdaConvert_ToBoolean(callExp.Method.DeclaringType, getExp(callExp.Arguments[0]));
case "System.Byte": return _utils.Adapter.LambdaConvert_ToByte(callExp.Method.DeclaringType, getExp(callExp.Arguments[0]));
case "System.Char": return _utils.Adapter.LambdaConvert_ToChar(callExp.Method.DeclaringType, getExp(callExp.Arguments[0]));
case "System.DateTime": return _utils.Adapter.LambdaConvert_ToDateTime(callExp.Method.DeclaringType, getExp(callExp.Arguments[0]));
case "System.Decimal": return _utils.Adapter.LambdaConvert_ToDecimal(callExp.Method.DeclaringType, getExp(callExp.Arguments[0]));
case "System.Double": return _utils.Adapter.LambdaConvert_ToDouble(callExp.Method.DeclaringType, getExp(callExp.Arguments[0]));
case "System.Int16": return _utils.Adapter.LambdaConvert_ToInt16(callExp.Method.DeclaringType, getExp(callExp.Arguments[0]));
case "System.Int32": return _utils.Adapter.LambdaConvert_ToInt32(callExp.Method.DeclaringType, getExp(callExp.Arguments[0]));
case "System.Int64": return _utils.Adapter.LambdaConvert_ToInt64(callExp.Method.DeclaringType, getExp(callExp.Arguments[0]));
case "System.SByte": return _utils.Adapter.LambdaConvert_ToSByte(callExp.Method.DeclaringType, getExp(callExp.Arguments[0]));
case "System.Single": return _utils.Adapter.LambdaConvert_ToSingle(callExp.Method.DeclaringType, getExp(callExp.Arguments[0]));
case "System.UInt16": return _utils.Adapter.LambdaConvert_ToUInt16(callExp.Method.DeclaringType, getExp(callExp.Arguments[0]));
case "System.UInt32": return _utils.Adapter.LambdaConvert_ToUInt32(callExp.Method.DeclaringType, getExp(callExp.Arguments[0]));
case "System.UInt64": return _utils.Adapter.LambdaConvert_ToUInt64(callExp.Method.DeclaringType, getExp(callExp.Arguments[0]));
case "System.Guid": return _utils.Adapter.LambdaConvert_ToGuid(callExp.Method.DeclaringType, getExp(callExp.Arguments[0]));
}
return null;
case "NewGuid":
switch (callExp.Method.DeclaringType.NullableTypeOrThis().ToString())
{
case "System.Guid": return _utils.Adapter.LambdaGuid_NewGuid;
}
return null;
case "Next":
if (callExp.Object?.Type == typeof(Random)) return _utils.Adapter.LambdaRandom_Next;
return null;
case "NextDouble":
if (callExp.Object?.Type == typeof(Random)) return _utils.Adapter.LambdaRandom_NextDouble;
return null;
case "Random":
if (callExp.Method.DeclaringType.IsNumberType()) return _utils.Adapter.LambdaRandom_NextDouble;
return null;
case "ToString":
if (callExp.Object != null) return callExp.Arguments.Count == 0 ? _utils.Adapter.LambdaConvert_ToString(callExp.Object.Type, getExp(callExp.Object)) : null;
return null;
}
var objExp = callExp.Object;
var objType = objExp?.Type;
if (objType?.FullName == "System.Byte[]") return null;
var argIndex = 0;
if (objType == null && callExp.Method.DeclaringType == typeof(Enumerable))
{
objExp = callExp.Arguments.FirstOrDefault();
objType = objExp?.Type;
argIndex++;
if (objType == typeof(string))
{
switch (callExp.Method.Name)
{
case "First":
case "FirstOrDefault":
return _utils.Adapter.LambdaString_Substring(getExp(callExp.Arguments[0]), "1", "1");
}
}
}
if (objType == null) objType = callExp.Method.DeclaringType;
if (objType != null || objType.IsArrayOrList())
{
if (argIndex >= callExp.Arguments.Count) break;
tsc.SetMapColumnTmp(null);
var args1 = getExp(callExp.Arguments[argIndex]);
var oldMapType = tsc.SetMapTypeReturnOld(tsc.mapTypeTmp);
var oldDbParams = tsc.SetDbParamsReturnOld(null);
var left = objExp == null ? null : getExp(objExp);
tsc.SetMapColumnTmp(null).SetMapTypeReturnOld(oldMapType);
tsc.SetDbParamsReturnOld(oldDbParams);
switch (callExp.Method.Name)
{
case "Contains":
//判断 in //在各大 Provider AdoProvider 中已约定500元素分割, 3空格\r\n4空格
return $"(({args1}) in {left.Replace(", \r\n \r\n", $") \r\n OR ({args1}) in (")})";
}
}
break;
case ExpressionType.NewArrayInit:
var arrExp = exp as NewArrayExpression;
var arrSb = new StringBuilder();
arrSb.Append("(");
for (var a = 0; a < arrExp.Expressions.Count; a++)
{
if (a > 0) arrSb.Append(",");
arrSb.Append(getExp(arrExp.Expressions[a]));
}
if (arrSb.Length == 1) arrSb.Append("NULL");
return arrSb.Append(")").ToString();
case ExpressionType.ListInit:
var listExp = exp as ListInitExpression;
var listSb = new StringBuilder();
listSb.Append("(");
for (var a = 0; a < listExp.Initializers.Count; a++)
{
if (listExp.Initializers[a].Arguments.Any() == false) continue;
if (a > 0) listSb.Append(",");
listSb.Append(getExp(listExp.Initializers[a].Arguments.FirstOrDefault()));
}
if (listSb.Length == 1) listSb.Append("NULL");
return listSb.Append(")").ToString();
case ExpressionType.New:
var newExp = exp as NewExpression;
if (typeof(IList).IsAssignableFrom(newExp.Type))
{
if (newExp.Arguments.Count == 0) return "(NULL)";
if (typeof(IEnumerable).IsAssignableFrom(newExp.Arguments[0].Type) == false) return "(NULL)";
return getExp(newExp.Arguments[0]);
}
return null;
}
return null;
}
public override string ExpressionLambdaToSqlMemberAccessString(MemberExpression exp, ExpTSC tsc)
{
if (exp.Expression == null)
{
switch (exp.Member.Name)
{
case "Empty": return "''";
}
return null;
}
var left = ExpressionLambdaToSql(exp.Expression, tsc);
switch (exp.Member.Name)
{
case "Length": return _utils.Adapter.LambdaString_Length(left);
}
return null;
}
public override string ExpressionLambdaToSqlMemberAccessDateTime(MemberExpression exp, ExpTSC tsc)
{
if (exp.Expression == null)
{
switch (exp.Member.Name)
{
case "Now": return _utils.Adapter.LambdaDateTime_Now;
case "UtcNow": return _utils.Adapter.LambdaDateTime_UtcNow;
case "Today": return _utils.Adapter.LambdaDateTime_Today;
case "MinValue": return _utils.Adapter.LambdaDateTime_MinValue;
case "MaxValue": return _utils.Adapter.LambdaDateTime_MaxValue;
}
return null;
}
var left = ExpressionLambdaToSql(exp.Expression, tsc);
switch (exp.Member.Name)
{
case "Date": return _utils.Adapter.LambdaDateTime_Date(left);
case "TimeOfDay": return _utils.Adapter.LambdaDateTime_TimeOfDay(left);
case "DayOfWeek": return _utils.Adapter.LambdaDateTime_DayOfWeek(left);
case "Day": return _utils.Adapter.LambdaDateTime_Day(left);
case "DayOfYear": return _utils.Adapter.LambdaDateTime_DayOfYear(left);
case "Month": return _utils.Adapter.LambdaDateTime_Month(left);
case "Year": return _utils.Adapter.LambdaDateTime_Year(left);
case "Hour": return _utils.Adapter.LambdaDateTime_Hour(left);
case "Minute": return _utils.Adapter.LambdaDateTime_Minute(left);
case "Second": return _utils.Adapter.LambdaDateTime_Second(left);
case "Millisecond": return _utils.Adapter.LambdaDateTime_Millisecond(left);
case "Ticks": return _utils.Adapter.LambdaDateTime_Ticks(left);
}
return null;
}
public override string ExpressionLambdaToSqlMemberAccessTimeSpan(MemberExpression exp, ExpTSC tsc)
{
if (exp.Expression == null)
{
switch (exp.Member.Name)
{
case "Zero": return "0";
case "MinValue": return "-922337203685477580"; //微秒 Ticks / 10
case "MaxValue": return "922337203685477580";
}
return null;
}
var left = ExpressionLambdaToSql(exp.Expression, tsc);
switch (exp.Member.Name)
{
case "Days": return _utils.Adapter.LambdaMath_Floor($"({left})/{60 * 60 * 24}");
case "Hours": return _utils.Adapter.LambdaMath_Floor($"({left})/{60 * 60}%24");
case "Milliseconds": return $"({_utils.Adapter.CastSql(left, _utils.Adapter.MappingDbTypeBigInt)}*1000)";
case "Minutes": return _utils.Adapter.LambdaMath_Floor($"({left})/60%60");
case "Seconds": return $"(({left})%60)";
case "Ticks": return $"({_utils.Adapter.CastSql(left, _utils.Adapter.MappingDbTypeBigInt)}*10000000)";
case "TotalDays": return $"(({left})/{60 * 60 * 24})";
case "TotalHours": return $"(({left})/{60 * 60})";
case "TotalMilliseconds": return $"({_utils.Adapter.CastSql(left, _utils.Adapter.MappingDbTypeBigInt)}*1000)";
case "TotalMinutes": return $"(({left})/60)";
case "TotalSeconds": return $"({left})";
}
return null;
}
public override string ExpressionLambdaToSqlCallString(MethodCallExpression exp, ExpTSC tsc)
{
Func<Expression, string> getExp = exparg => ExpressionLambdaToSql(exparg, tsc);
if (exp.Object == null)
{
switch (exp.Method.Name)
{
case "IsNullOrEmpty": return _utils.Adapter.LambdaString_IsNullOrEmpty(getExp(exp.Arguments[0]));
case "IsNullOrWhiteSpace": return _utils.Adapter.LambdaString_IsNullOrWhiteSpace(getExp(exp.Arguments[0]));
case "Concat": return _common.StringConcat(exp.Arguments.Select(a => getExp(a)).ToArray(), exp.Arguments.Select(a => a.Type).ToArray());
}
}
else
{
var left = getExp(exp.Object);
switch (exp.Method.Name)
{
case "StartsWith":
case "EndsWith":
case "Contains":
var args0Value = getExp(exp.Arguments[0]);
if (args0Value == "NULL") return $"({left}) IS NULL";
if (exp.Method.Name == "StartsWith") return $"({left}) LIKE {(args0Value.EndsWith("'") ? args0Value.Insert(args0Value.Length - 1, "%") : $"({_common.StringConcat(new string[] { args0Value, "'%'" }, new[] { typeof(int), typeof(string) })})")}";
if (exp.Method.Name == "EndsWith") return $"({left}) LIKE {(args0Value.StartsWith("'") ? args0Value.Insert(1, "%") : $"({_common.StringConcat(new string[] { "'%'", args0Value }, new[] { typeof(string), typeof(int) })})")}";
if (args0Value.StartsWith("'") && args0Value.EndsWith("'")) return $"({left}) LIKE {args0Value.Insert(1, "%").Insert(args0Value.Length, "%")}";
return $"({left}) LIKE ({_common.StringConcat(new string[] { "'%'", args0Value, "'%'" }, new[] { typeof(string), typeof(int), typeof(string)})})";
case "ToLower": return _utils.Adapter.LambdaString_ToLower(left);
case "ToUpper": return _utils.Adapter.LambdaString_ToUpper(left);
case "Substring":
var substrArgs1 = getExp(exp.Arguments[0]);
if (long.TryParse(substrArgs1, out var testtrylng1)) substrArgs1 = (testtrylng1 + 1).ToString();
else substrArgs1 += "+1";
if (exp.Arguments.Count == 1) return _utils.Adapter.LambdaString_Substring(left, substrArgs1, null);
return _utils.Adapter.LambdaString_Substring(left, substrArgs1, getExp(exp.Arguments[1]));
case "IndexOf":
var indexOfFindStr = getExp(exp.Arguments[0]);
if (exp.Arguments.Count > 1 && exp.Arguments[1].Type.FullName == "System.Int32")
{
var locateArgs1 = getExp(exp.Arguments[1]);
if (long.TryParse(locateArgs1, out var testtrylng2)) locateArgs1 = (testtrylng2 + 1).ToString();
else locateArgs1 += "+1";
return _utils.Adapter.LambdaString_IndexOf(left, indexOfFindStr, locateArgs1);
}
return _utils.Adapter.LambdaString_IndexOf(left, indexOfFindStr, null);
case "PadLeft":
if (exp.Arguments.Count == 1) return _utils.Adapter.LambdaString_PadLeft(left, getExp(exp.Arguments[0]), null);
return _utils.Adapter.LambdaString_PadLeft(left, getExp(exp.Arguments[0]), getExp(exp.Arguments[1]));
case "PadRight":
if (exp.Arguments.Count == 1) return _utils.Adapter.LambdaString_PadRight(left, getExp(exp.Arguments[0]), null);
return _utils.Adapter.LambdaString_PadRight(left, getExp(exp.Arguments[0]), getExp(exp.Arguments[1]));
case "Trim": return _utils.Adapter.LambdaString_Trim(left);
case "TrimStart": return _utils.Adapter.LambdaString_TrimStart(left);
case "TrimEnd": return _utils.Adapter.LambdaString_TrimEnd(left);
case "Replace": return _utils.Adapter.LambdaString_Replace(left, getExp(exp.Arguments[0]), getExp(exp.Arguments[1]));
case "CompareTo": return _utils.Adapter.LambdaString_CompareTo(left, getExp(exp.Arguments[0]));
case "Equals": return _utils.Adapter.LambdaString_Equals(left, getExp(exp.Arguments[0]));
}
}
return null;
}
public override string ExpressionLambdaToSqlCallMath(MethodCallExpression exp, ExpTSC tsc)
{
Func<Expression, string> getExp = exparg => ExpressionLambdaToSql(exparg, tsc);
switch (exp.Method.Name)
{
case "Abs": return _utils.Adapter.LambdaMath_Abs(getExp(exp.Arguments[0]));
case "Sign": return _utils.Adapter.LambdaMath_Sign(getExp(exp.Arguments[0]));
case "Floor": return _utils.Adapter.LambdaMath_Floor(getExp(exp.Arguments[0]));
case "Ceiling": return _utils.Adapter.LambdaMath_Ceiling(getExp(exp.Arguments[0]));
case "Round":
if (exp.Arguments.Count > 1 && exp.Arguments[1].Type.FullName == "System.Int32") return _utils.Adapter.LambdaMath_Round(getExp(exp.Arguments[0]), getExp(exp.Arguments[1]));
return _utils.Adapter.LambdaMath_Round(getExp(exp.Arguments[0]), "0");
case "Exp": return _utils.Adapter.LambdaMath_Exp(getExp(exp.Arguments[0]));
case "Log": return _utils.Adapter.LambdaMath_Log(getExp(exp.Arguments[0]));
case "Log10": return _utils.Adapter.LambdaMath_Log10(getExp(exp.Arguments[0]));
case "Pow": return _utils.Adapter.LambdaMath_Pow(getExp(exp.Arguments[0]), getExp(exp.Arguments[1]));
case "Sqrt": return _utils.Adapter.LambdaMath_Sqrt(getExp(exp.Arguments[0]));
case "Cos": return _utils.Adapter.LambdaMath_Cos(getExp(exp.Arguments[0]));
case "Sin": return _utils.Adapter.LambdaMath_Sin(getExp(exp.Arguments[0]));
case "Tan": return _utils.Adapter.LambdaMath_Tan(getExp(exp.Arguments[0]));
case "Acos": return _utils.Adapter.LambdaMath_Acos(getExp(exp.Arguments[0]));
case "Asin": return _utils.Adapter.LambdaMath_Asin(getExp(exp.Arguments[0]));
case "Atan": return _utils.Adapter.LambdaMath_Atan(getExp(exp.Arguments[0]));
case "Atan2": return _utils.Adapter.LambdaMath_Atan2(getExp(exp.Arguments[0]), getExp(exp.Arguments[1]));
case "Truncate": return _utils.Adapter.LambdaMath_Truncate(getExp(exp.Arguments[0]));
}
return null;
}
public override string ExpressionLambdaToSqlCallDateTime(MethodCallExpression exp, ExpTSC tsc)
{
Func<Expression, string> getExp = exparg => ExpressionLambdaToSql(exparg, tsc);
if (exp.Object == null)
{
switch (exp.Method.Name)
{
case "Compare": return _utils.Adapter.LambdaDateTime_CompareTo(getExp(exp.Arguments[0]), getExp(exp.Arguments[1]));
case "DaysInMonth": return _utils.Adapter.LambdaDateTime_DaysInMonth(getExp(exp.Arguments[0]), getExp(exp.Arguments[1]));
case "Equals": return _utils.Adapter.LambdaDateTime_Equals(getExp(exp.Arguments[0]), getExp(exp.Arguments[1]));
case "IsLeapYear": return _utils.Adapter.LambdaDateTime_IsLeapYear(getExp(exp.Arguments[0]));
case "Parse": return _utils.Adapter.LambdaConvert_ToDateTime(exp.Arguments[0].Type, getExp(exp.Arguments[0]));
case "ParseExact":
case "TryParse":
case "TryParseExact": return _utils.Adapter.LambdaConvert_ToDateTime(exp.Arguments[0].Type, getExp(exp.Arguments[0]));
}
}
else
{
var left = getExp(exp.Object);
var args1 = exp.Arguments.Count == 0 ? null : getExp(exp.Arguments[0]);
switch (exp.Method.Name)
{
case "Add": return _utils.Adapter.LambdaDateTime_Add(left, args1);
case "AddDays": return _utils.Adapter.LambdaDateTime_AddDays(left, args1);
case "AddHours": return _utils.Adapter.LambdaDateTime_AddHours(left, args1);
case "AddMilliseconds": return _utils.Adapter.LambdaDateTime_AddMilliseconds(left, args1);
case "AddMinutes": return _utils.Adapter.LambdaDateTime_AddMinutes(left, args1);
case "AddMonths": return _utils.Adapter.LambdaDateTime_AddMonths(left, args1);
case "AddSeconds": return _utils.Adapter.LambdaDateTime_AddSeconds(left, args1);
case "AddTicks": return _utils.Adapter.LambdaDateTime_AddTicks(left, args1);
case "AddYears": return _utils.Adapter.LambdaDateTime_AddYears(left, args1);
case "Subtract":
switch ((exp.Arguments[0].Type.IsNullableType() ? exp.Arguments[0].Type.GetGenericArguments().FirstOrDefault() : exp.Arguments[0].Type).FullName)
{
case "System.DateTime": return _utils.Adapter.LambdaDateTime_Subtract(left, args1);
case "System.TimeSpan": return _utils.Adapter.LambdaDateTime_SubtractTimeSpan(left, args1);
}
break;
case "Equals": return _utils.Adapter.LambdaDateTime_Equals(left, args1);
case "CompareTo": return _utils.Adapter.LambdaDateTime_CompareTo(left, args1);
case "ToString": return exp.Arguments.Count == 0 ? _utils.Adapter.LambdaDateTime_ToString(left) : null;
}
}
return null;
}
public virtual string LambdaDateSpan_Add(string operand, string value) => $"({operand}+{value})";
public virtual string LambdaDateSpan_Subtract(string operand, string value) => $"({operand}-({value}))";
public virtual string LambdaDateSpan_Equals(string oldvalue, string newvalue) => $"({oldvalue} = {newvalue})";
public virtual string LambdaDateSpan_CompareTo(string oldvalue, string newvalue) => $"({oldvalue}-({newvalue}))";
public override string ExpressionLambdaToSqlCallTimeSpan(MethodCallExpression exp, ExpTSC tsc)
{
Func<Expression, string> getExp = exparg => ExpressionLambdaToSql(exparg, tsc);
if (exp.Object == null)
{
switch (exp.Method.Name)
{
case "Compare": return $"({getExp(exp.Arguments[0])}-({getExp(exp.Arguments[1])}))";
case "Equals": return $"({getExp(exp.Arguments[0])} = {getExp(exp.Arguments[1])})";
case "FromDays": return $"(({getExp(exp.Arguments[0])})*{60 * 60 * 24})";
case "FromHours": return $"(({getExp(exp.Arguments[0])})*{60 * 60})";
case "FromMilliseconds": return $"(({getExp(exp.Arguments[0])})/1000)";
case "FromMinutes": return $"(({getExp(exp.Arguments[0])})*60)";
case "FromSeconds": return $"({getExp(exp.Arguments[0])})";
case "FromTicks": return $"(({getExp(exp.Arguments[0])})/10000000)";
case "Parse": return _utils.Adapter.LambdaConvert_ToInt64(exp.Arguments[0].Type, getExp(exp.Arguments[0]));
case "ParseExact":
case "TryParse":
case "TryParseExact": return _utils.Adapter.LambdaConvert_ToInt64(exp.Arguments[0].Type, getExp(exp.Arguments[0]));
}
}
else
{
var left = getExp(exp.Object);
var args1 = exp.Arguments.Count == 0 ? null : getExp(exp.Arguments[0]);
switch (exp.Method.Name)
{
case "Add": return $"({left}+{args1})";
case "Subtract": return $"({left}-({args1}))";
case "Equals": return $"({left} = {args1})";
case "CompareTo": return $"({left}-({args1}))";
case "ToString": return _utils.Adapter.LambdaConvert_ToString(exp.Type, left);
}
}
return null;
}
public override string ExpressionLambdaToSqlCallConvert(MethodCallExpression exp, ExpTSC tsc)
{
Func<Expression, string> getExp = exparg => ExpressionLambdaToSql(exparg, tsc);
if (exp.Object == null)
{
switch (exp.Method.Name)
{
case "ToBoolean": return _utils.Adapter.LambdaConvert_ToBoolean(exp.Arguments[0].Type, getExp(exp.Arguments[0]));
case "ToByte": return _utils.Adapter.LambdaConvert_ToByte(exp.Arguments[0].Type, getExp(exp.Arguments[0]));
case "ToChar": return _utils.Adapter.LambdaConvert_ToChar(exp.Arguments[0].Type, getExp(exp.Arguments[0]));
case "ToDateTime": return _utils.Adapter.LambdaConvert_ToDateTime(exp.Arguments[0].Type, getExp(exp.Arguments[0]));
case "ToDecimal": return _utils.Adapter.LambdaConvert_ToDecimal(exp.Arguments[0].Type, getExp(exp.Arguments[0]));
case "ToDouble": return _utils.Adapter.LambdaConvert_ToDouble(exp.Arguments[0].Type, getExp(exp.Arguments[0]));
case "ToInt16": return _utils.Adapter.LambdaConvert_ToInt16(exp.Arguments[0].Type, getExp(exp.Arguments[0]));
case "ToInt32": return _utils.Adapter.LambdaConvert_ToInt32(exp.Arguments[0].Type, getExp(exp.Arguments[0]));
case "ToInt64": return _utils.Adapter.LambdaConvert_ToInt64(exp.Arguments[0].Type, getExp(exp.Arguments[0]));
case "ToSByte": return _utils.Adapter.LambdaConvert_ToSByte(exp.Arguments[0].Type, getExp(exp.Arguments[0]));
case "ToSingle": return _utils.Adapter.LambdaConvert_ToSingle(exp.Arguments[0].Type, getExp(exp.Arguments[0]));
case "ToString": return _utils.Adapter.LambdaConvert_ToString(exp.Arguments[0].Type, getExp(exp.Arguments[0]));
case "ToUInt16": return _utils.Adapter.LambdaConvert_ToUInt16(exp.Arguments[0].Type, getExp(exp.Arguments[0]));
case "ToUInt32": return _utils.Adapter.LambdaConvert_ToUInt32(exp.Arguments[0].Type, getExp(exp.Arguments[0]));
case "ToUInt64": return _utils.Adapter.LambdaConvert_ToUInt64(exp.Arguments[0].Type, getExp(exp.Arguments[0]));
}
}
return null;
}
}
}

View File

@ -0,0 +1,91 @@
using FreeSql.Custom;
using FreeSql.Internal;
using FreeSql.Internal.CommonProvider;
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Data;
using System.Data.Common;
using System.Linq;
using System.Threading;
namespace FreeSql.Custom
{
public class CustomProvider<TMark> : BaseDbProvider, IFreeSql<TMark>
{
public override ISelect<T1> CreateSelectProvider<T1>(object dywhere) => new CustomSelect<T1>(this, this.InternalCommonUtils, this.InternalCommonExpression, dywhere);
public override IInsert<T1> CreateInsertProvider<T1>() => new CustomInsert<T1>(this, this.InternalCommonUtils, this.InternalCommonExpression);
public override IUpdate<T1> CreateUpdateProvider<T1>(object dywhere) => new CustomUpdate<T1>(this, this.InternalCommonUtils, this.InternalCommonExpression, dywhere);
public override IDelete<T1> CreateDeleteProvider<T1>(object dywhere) => new CustomDelete<T1>(this, this.InternalCommonUtils, this.InternalCommonExpression, dywhere);
public override IInsertOrUpdate<T1> CreateInsertOrUpdateProvider<T1>() => throw new NotImplementedException("FreeSql.Provider.Custom 未实现该功能");
public override IDbFirst DbFirst => throw new NotImplementedException("FreeSql.Provider.Custom 未实现该功能");
public CustomProvider(string masterConnectionString, string[] slaveConnectionString, Func<DbConnection> connectionFactory = null)
{
this.InternalCommonUtils = new CustomUtils(this);
this.InternalCommonExpression = new CustomExpression(this.InternalCommonUtils);
this.Ado = new CustomAdo(this.InternalCommonUtils, masterConnectionString, slaveConnectionString, connectionFactory);
this.Aop = new AopProvider();
this.CodeFirst = new CustomCodeFirst(this, this.InternalCommonUtils, this.InternalCommonExpression);
var _utils = InternalCommonUtils as CustomUtils;
//处理 MaxLength
this.Aop.ConfigEntityProperty += new EventHandler<Aop.ConfigEntityPropertyEventArgs>((s, e) =>
{
object[] attrs = null;
try
{
attrs = e.Property.GetCustomAttributes(false).ToArray(); //.net core 反射存在版本冲突问题,导致该方法异常
}
catch { }
var maxlenAttr = attrs.Where(a => {
return ((a as Attribute)?.TypeId as Type)?.Name == "MaxLengthAttribute";
}).FirstOrDefault();
if (maxlenAttr != null)
{
var lenProp = maxlenAttr.GetType().GetProperties().Where(a => a.PropertyType.IsNumberType()).FirstOrDefault();
if (lenProp != null && int.TryParse(string.Concat(lenProp.GetValue(maxlenAttr, null)), out var tryval))
{
if (tryval != 0)
{
switch (this.Ado.DataType)
{
case DataType.Sqlite:
e.ModifyResult.DbType = tryval > 0 ? $"{_utils.Adapter.MappingDbTypeVarChar}({tryval})" : _utils.Adapter.MappingDbTypeText;
break;
}
}
}
}
});
}
~CustomProvider() => this.Dispose();
int _disposeCounter;
public override void Dispose()
{
if (Interlocked.Increment(ref _disposeCounter) != 1) return;
try
{
(this.Ado as AdoProvider)?.Dispose();
}
finally
{
FreeSqlCustomAdapterGlobalExtensions._dicCustomAdater.TryRemove(Ado.Identifier, out var tryada);
}
}
}
}
public static class FreeSqlCustomAdapterGlobalExtensions
{
internal static CustomAdapter DefaultAdapter = new CustomAdapter();
internal static ConcurrentDictionary<Guid, CustomAdapter> _dicCustomAdater = new ConcurrentDictionary<Guid, CustomAdapter>();
public static void SetCustomAdapter(this IFreeSql that, CustomAdapter adapter) => _dicCustomAdater.AddOrUpdate(that.Ado.Identifier, adapter, (fsql, old) => adapter);
internal static CustomAdapter GetCustomAdapter(this IFreeSql that) => _dicCustomAdater.TryGetValue(that.Ado.Identifier, out var tryada) ? tryada : DefaultAdapter;
}

View File

@ -0,0 +1,85 @@
using FreeSql.Internal;
using FreeSql.Internal.Model;
using System;
using System.Collections.Generic;
using System.Data;
using System.Data.Common;
using System.Globalization;
namespace FreeSql.Custom
{
public class CustomUtils : CommonUtils
{
public CustomUtils(IFreeSql orm) : base(orm) { }
public CustomAdapter Adapter => _orm.GetCustomAdapter();
public override DbParameter AppendParamter(List<DbParameter> _params, string parameterName, ColumnInfo col, Type type, object value)
{
if (string.IsNullOrEmpty(parameterName)) parameterName = $"p_{_params?.Count}";
if (value?.Equals(DateTime.MinValue) == true) value = new DateTime(1970, 1, 1);
var ret = (_orm.Ado as CustomAdo)?.CreateParameter();
ret.ParameterName = QuoteParamterName(parameterName);
ret.Value = value;
var tp = _orm.CodeFirst.GetDbInfo(type)?.type;
if (tp != null) ret.DbType = (DbType)tp.Value;
_params?.Add(ret);
return ret;
}
public override DbParameter[] GetDbParamtersByObject(string sql, object obj) =>
Utils.GetDbParamtersByObject<DbParameter>(sql, obj, null, (name, type, value) =>
{
if (value?.Equals(DateTime.MinValue) == true) value = new DateTime(1970, 1, 1);
var ret = (_orm.Ado as CustomAdo)?.CreateParameter();
ret.ParameterName = QuoteParamterName(name);
ret.Value = value;
var tp = _orm.CodeFirst.GetDbInfo(type)?.type;
if (tp != null) ret.DbType = (DbType)tp.Value;
return ret;
});
static FreeSql.Custom.CustomAdo _customAdo = new FreeSql.Custom.CustomAdo();
public override string FormatSql(string sql, params object[] args) => _customAdo.Addslashes(sql, args);
public override string QuoteSqlName(params string[] name)
{
if (name.Length == 1)
{
var nametrim = name[0].Trim();
if (nametrim.StartsWith("(") && nametrim.EndsWith(")"))
return nametrim; //原生SQL
if (nametrim.StartsWith(Adapter.QuoteSqlNameLeft.ToString()) && nametrim.EndsWith(Adapter.QuoteSqlNameRight.ToString()))
return nametrim;
return $"{Adapter.QuoteSqlNameLeft}{nametrim.TrimStart(Adapter.QuoteSqlNameLeft).TrimEnd(Adapter.QuoteSqlNameRight).Replace(".", $"{Adapter.QuoteSqlNameRight}.{Adapter.QuoteSqlNameLeft}")}{Adapter.QuoteSqlNameRight}";
}
return $"{Adapter.QuoteSqlNameLeft}{string.Join($"{Adapter.QuoteSqlNameRight}.{Adapter.QuoteSqlNameLeft}", name)}{Adapter.QuoteSqlNameRight}";
}
public override string TrimQuoteSqlName(string name)
{
var nametrim = name.Trim();
if (nametrim.StartsWith("(") && nametrim.EndsWith(")"))
return nametrim; //原生SQL
//return $"{nametrim.TrimStart('[').TrimEnd(']').Replace("].[", ".").Replace(".[", ".")}";
return $"{nametrim.TrimStart(Adapter.QuoteSqlNameLeft).TrimEnd(Adapter.QuoteSqlNameRight).Replace($"{Adapter.QuoteSqlNameRight}.{Adapter.QuoteSqlNameLeft}", ".").Replace($".{Adapter.QuoteSqlNameLeft}", ".")}";
}
public override string[] SplitTableName(string name) => GetSplitTableNames(name, Adapter.QuoteSqlNameLeft, Adapter.QuoteSqlNameRight, 2);
public override string QuoteParamterName(string name) => $"@{name}";
public override string IsNull(string sql, object value) => Adapter.IsNullSql(sql, value);
public override string StringConcat(string[] objs, Type[] types) => Adapter.ConcatSql(objs, types);
public override string Mod(string left, string right, Type leftType, Type rightType) => Adapter.Mod(left, right, leftType, rightType);
public override string Div(string left, string right, Type leftType, Type rightType) => Adapter.Div(left, right, leftType, rightType);
public override string Now => Adapter.LambdaDateTime_Now;
public override string NowUtc => Adapter.LambdaDateTime_UtcNow;
public override string QuoteWriteParamterAdapter(Type type, string paramterName) => paramterName;
protected override string QuoteReadColumnAdapter(Type type, Type mapType, string columnName) => Adapter.FieldSql(type, columnName);
public override string GetNoneParamaterSqlValue(List<DbParameter> specialParams, string specialParamFlag, ColumnInfo col, Type type, object value)
{
if (value == null) return "NULL";
if (type.IsNumberType()) return string.Format(CultureInfo.InvariantCulture, "{0}", value);
if (type == typeof(byte[])) return Adapter.ByteRawSql(value);
return FormatSql("{0}", value, 1);
}
}
}

View File

@ -0,0 +1,37 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFrameworks>netstandard2.0;net45;net40</TargetFrameworks>
<Version>2.3.0-preview20210206</Version>
<GeneratePackageOnBuild>true</GeneratePackageOnBuild>
<Authors>FreeSql;ncc;YeXiangQin</Authors>
<Description>FreeSql 数据库自定义适配,访问所有数据库</Description>
<PackageProjectUrl>https://github.com/2881099/FreeSql</PackageProjectUrl>
<RepositoryUrl>https://github.com/2881099/FreeSql</RepositoryUrl>
<RepositoryType>git</RepositoryType>
<PackageLicenseExpression>MIT</PackageLicenseExpression>
<PackageTags>FreeSql;ORM</PackageTags>
<PackageId>$(AssemblyName)</PackageId>
<PackageIcon>logo.png</PackageIcon>
<Title>$(AssemblyName)</Title>
<IsPackable>true</IsPackable>
<GenerateAssemblyInfo>true</GenerateAssemblyInfo>
<SignAssembly>true</SignAssembly>
<AssemblyOriginatorKeyFile>key.snk</AssemblyOriginatorKeyFile>
<DelaySign>false</DelaySign>
</PropertyGroup>
<ItemGroup>
<None Include="../../logo.png" Pack="true" PackagePath="\" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\..\FreeSql\FreeSql.csproj" />
</ItemGroup>
<PropertyGroup Condition="'$(TargetFramework)' == 'net40'">
<DefineConstants>net40</DefineConstants>
</PropertyGroup>
</Project>

Binary file not shown.

View File

@ -0,0 +1,30 @@
FreeSql.Provider.Custom 实现自定义适配器,访问所有数据库。
# 通用实现
通用实现为了让用户自己适配更多的数据库,比如连接 mssql 2000、db2 等数据库,牺牲了一些功能:
- 不支持 CodeFirst 自动迁移
- 不支持 DbFirst 接口方法的实现
- 不支持 原来的分页方法,需要自行判断 id 进行分页
- 只支持较少的基础类型bool,sbyte,short,int,long,byte,ushort,uint,ulong,double,float,decimal,DateTime,byte[],string,Guid
使用者只需求重写类 FreeSql.Custom.CustomAdapter 就可以自定义访问不同的数据库。
我们默认做了一套 sqlserver 的语法和映射适配,代码在 [CustomAdapter.cs](https://github.com/2881099/FreeSql/blob/master/Providers/FreeSql.Provider.Custom/CustomAdapter.cs),请查看代码了解。
```csharp
class Mssql2000Adapter : FreeSql.Custom.CustomAdapter
{
public override string InsertAfterGetIdentitySql => "SELECT SCOPE_IDENTITY()";
//可以重写更多的设置
}
static IFreeSql fsql = new FreeSql.FreeSqlBuilder()
.UseConnectionString(FreeSql.DataType.Custom, () => new SqlConnection(@"Data Source=..."))
.Build(); //be sure to define as singleton mode
fsql.SetCustomAdapter(new Mssql2000Adapter());
```
适配好新的 CustomAdapter 后,请在 FreeSqlBuilder.Build 之后调用 IFreeSql.SetCustomAdapter 方法生效。