initial commit

This commit is contained in:
tk
2024-11-13 18:18:28 +08:00
commit 013f35e296
1500 changed files with 443723 additions and 0 deletions

View File

@ -0,0 +1,17 @@
using System;
using System.Collections.Generic;
using System.Text;
namespace FreeSql.DataAnnotations
{
[AttributeUsage(AttributeTargets.Property)]
public class ClickHousePartitionAttribute : Attribute
{
public ClickHousePartitionAttribute(string format = "toYYYYMM({0})")
{
Format = format;
}
public string Format { get; set; }
}
}

View File

@ -0,0 +1,91 @@
using ClickHouse.Client.ADO;
using FreeSql.Internal;
using FreeSql.Internal.CommonProvider;
using FreeSql.Internal.Model;
using FreeSql.Internal.ObjectPool;
using System;
using System.Collections;
using System.Data.Common;
using System.Linq;
using System.Threading;
namespace FreeSql.ClickHouse
{
class ClickHouseAdo : FreeSql.Internal.CommonProvider.AdoProvider
{
public ClickHouseAdo() : base(DataType.ClickHouse, null, null) { }
public ClickHouseAdo(CommonUtils util, string masterConnectionString, string[] slaveConnectionStrings, Func<DbConnection> connectionFactory) : base(DataType.ClickHouse, masterConnectionString, slaveConnectionStrings)
{
base._util = util;
if (connectionFactory != null)
{
var pool = new FreeSql.Internal.CommonProvider.DbConnectionPool(DataType.ClickHouse, connectionFactory);
ConnectionString = pool.TestConnection?.ConnectionString;
MasterPool = pool;
return;
}
var isAdoPool = masterConnectionString?.StartsWith("AdoConnectionPool,") ?? false;
if (isAdoPool) masterConnectionString = masterConnectionString.Substring("AdoConnectionPool,".Length);
if (!string.IsNullOrEmpty(masterConnectionString))
MasterPool = isAdoPool ?
new DbConnectionStringPool(base.DataType, CoreStrings.S_MasterDatabase, () => new ClickHouseConnection(masterConnectionString)) as IObjectPool<DbConnection> :
new ClickHouseConnectionPool(CoreStrings.S_MasterDatabase, masterConnectionString, null, null);
slaveConnectionStrings?.ToList().ForEach(slaveConnectionString =>
{
var slavePool = isAdoPool ?
new DbConnectionStringPool(base.DataType, $"{CoreStrings.S_SlaveDatabase}{SlavePools.Count + 1}", () => new ClickHouseConnection(slaveConnectionString)) as IObjectPool<DbConnection> :
new ClickHouseConnectionPool($"{CoreStrings.S_SlaveDatabase}{SlavePools.Count + 1}", slaveConnectionString, () => Interlocked.Decrement(ref slaveUnavailables), () => Interlocked.Increment(ref slaveUnavailables));
SlavePools.Add(slavePool);
});
}
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 ? "true" : "false"; //不需要转0/1
else if (param is string)
return string.Concat("'", param.ToString().Replace("'", "''").Replace("\\", "\\\\"), "'"); //只有 mysql 需要处理反斜杠
else if (param is char)
return string.Concat("'", param.ToString().Replace("'", "''").Replace("\\", "\\\\").Replace('\0', ' '), "'");
else if (param is Enum)
return AddslashesTypeHandler(param.GetType(), param) ?? string.Concat("'", param.ToString().Replace("'", "''").Replace("\\", "\\\\"), "'"); //((Enum)val).ToInt64();
else if (decimal.TryParse(string.Concat(param), out var trydec))
return param;
else if (param is DateTime)
return AddslashesTypeHandler(typeof(DateTime), param) ?? string.Concat("'", ((DateTime)param).ToString("yyyy-MM-dd HH:mm:ss"), "'");
else if (param is DateTime?)
return AddslashesTypeHandler(typeof(DateTime?), param) ?? string.Concat("'", ((DateTime)param).ToString("yyyy-MM-dd HH:mm:ss"), "'");
else if (param is TimeSpan || param is TimeSpan?)
return ((TimeSpan)param).Ticks / 10;
else if (param is byte[])
return $"0x{CommonUtils.BytesSqlRaw(param as byte[])}";
else if (param is IEnumerable)
return AddslashesIEnumerable(param, mapType, mapColumn);
return string.Concat("'", param.ToString().Replace("'", "''").Replace("\\", "\\\\"), "'");
}
public override DbCommand CreateCommand()
{
System.Data.IDbCommand command = new ClickHouseCommand();
return (DbCommand)command;
}
public override void ReturnConnection(IObjectPool<DbConnection> pool, Object<DbConnection> conn, Exception ex)
{
var rawPool = pool as ClickHouseConnectionPool;
if (rawPool != null) rawPool.Return(conn, ex);
else pool.Return(conn);
}
public override DbParameter[] GetDbParamtersByObject(string sql, object obj) => _util.GetDbParamtersByObject(sql, obj);
}
}

View File

@ -0,0 +1,250 @@
using FreeSql.Internal.ObjectPool;
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Data;
using System.Data.Common;
using System.Text.RegularExpressions;
using System.Threading.Tasks;
using ClickHouse.Client.ADO;
namespace FreeSql.ClickHouse
{
class ClickHouseConnectionPool : ObjectPool<DbConnection>
{
internal Action availableHandler;
internal Action unavailableHandler;
public ClickHouseConnectionPool(string name, string connectionString, Action availableHandler, Action unavailableHandler) : base(null)
{
this.availableHandler = availableHandler;
this.unavailableHandler = unavailableHandler;
var policy = new ClickHouseConnectionPoolPolicy
{
_pool = this,
Name = name
};
this.Policy = policy;
policy.ConnectionString = connectionString;
}
public void Return(Object<DbConnection> obj, Exception exception, bool isRecreate = false)
{
if (exception != null && exception is ClickHouseException)
{
if (obj.Value.Ping() == false)
base.SetUnavailable(exception, obj.LastGetTimeCopy);
}
base.Return(obj, isRecreate);
}
}
public class ClickHouseException : Exception
{
public int Code;
public string Name;
public string ServerStackTrace;
public ClickHouseException() { }
public ClickHouseException(string message) : base(message) { }
public ClickHouseException(string message, Exception innerException) : base(message, innerException) { }
}
class ClickHouseConnectionPoolPolicy : IPolicy<DbConnection>
{
internal ClickHouseConnectionPool _pool;
public string Name { get; set; } = $"ClickHouse ClickHouseConnection {CoreStrings.S_ObjectPool}";
public int PoolSize { get; set; } = 100;
public TimeSpan SyncGetTimeout { get; set; } = TimeSpan.FromSeconds(10);
public TimeSpan IdleTimeout { get; set; } = TimeSpan.FromSeconds(20);
public int AsyncGetCapacity { get; set; } = 10000;
public bool IsThrowGetTimeoutException { get; set; } = true;
public bool IsAutoDisposeWithSystem { get; set; } = true;
public int CheckAvailableInterval { get; set; } = 2;
public int Weight { get; set; } = 1;
static ConcurrentDictionary<string, int> dicConnStrIncr = new ConcurrentDictionary<string, int>(StringComparer.CurrentCultureIgnoreCase);
private string _connectionString;
public string ConnectionString
{
get => _connectionString;
set
{
_connectionString = value ?? "";
var minPoolSize = 0;
var pattern = @"Min\s*pool\s*size\s*=\s*(\d+)";
var m = Regex.Match(_connectionString, pattern, RegexOptions.IgnoreCase);
if (m.Success)
{
minPoolSize = int.Parse(m.Groups[1].Value);
_connectionString = Regex.Replace(_connectionString, pattern, "", RegexOptions.IgnoreCase);
}
pattern = @"Max\s*pool\s*size\s*=\s*(\d+)";
m = Regex.Match(_connectionString, pattern, RegexOptions.IgnoreCase);
if (m.Success)
{
PoolSize = int.Parse(m.Groups[1].Value);
_connectionString = Regex.Replace(_connectionString, pattern, "", RegexOptions.IgnoreCase);
}
pattern = @"Connection\s*LifeTime\s*=\s*(\d+)";
m = Regex.Match(_connectionString, pattern, RegexOptions.IgnoreCase);
if (m.Success)
{
IdleTimeout = TimeSpan.FromSeconds(int.Parse(m.Groups[1].Value));
_connectionString = Regex.Replace(_connectionString, pattern, "", RegexOptions.IgnoreCase);
}
FreeSql.Internal.CommonUtils.PrevReheatConnectionPool(_pool, minPoolSize);
}
}
public bool OnCheckAvailable(Object<DbConnection> obj)
{
if (obj.Value == null) return false;
if (obj.Value.State == ConnectionState.Closed) obj.Value.Open();
return obj.Value.Ping(true);
}
public DbConnection OnCreate()
{
var conn = new ClickHouseConnection(_connectionString);
return conn;
}
public void OnDestroy(DbConnection obj)
{
if (obj.State != ConnectionState.Closed) obj.Close();
obj.Dispose();
}
public void OnGet(Object<DbConnection> obj)
{
if (_pool.IsAvailable)
{
if (obj.Value == null)
{
_pool.SetUnavailable(new Exception(CoreStrings.S_ConnectionStringError), obj.LastGetTimeCopy);
throw new Exception(CoreStrings.S_ConnectionStringError_Check(this.Name));
}
if (obj.Value.State != ConnectionState.Open || DateTime.Now.Subtract(obj.LastReturnTime).TotalSeconds > 60 && obj.Value.Ping() == false)
{
try
{
obj.Value.Open();
}
catch (Exception ex)
{
if (_pool.SetUnavailable(ex, obj.LastGetTimeCopy) == true)
throw new Exception($"【{this.Name}】Block access and wait for recovery: {ex.Message}");
throw ex;
}
}
}
}
#if net40
#else
async public Task OnGetAsync(Object<DbConnection> obj)
{
if (_pool.IsAvailable)
{
if (obj.Value == null)
{
_pool.SetUnavailable(new Exception(CoreStrings.S_ConnectionStringError), obj.LastGetTimeCopy);
throw new Exception(CoreStrings.S_ConnectionStringError_Check(this.Name));
}
if (obj.Value.State != ConnectionState.Open || DateTime.Now.Subtract(obj.LastReturnTime).TotalSeconds > 60 && (await obj.Value.PingAsync()) == false)
{
try
{
await obj.Value.OpenAsync();
}
catch (Exception ex)
{
if (_pool.SetUnavailable(ex, obj.LastGetTimeCopy) == true)
throw new Exception($"【{this.Name}】Block access and wait for recovery: {ex.Message}");
throw ex;
}
}
}
}
#endif
public void OnGetTimeout()
{
}
public void OnReturn(Object<DbConnection> obj)
{
//if (obj?.Value != null && obj.Value.State != ConnectionState.Closed) try { obj.Value.Close(); } catch { }
}
public void OnAvailable()
{
_pool.availableHandler?.Invoke();
}
public void OnUnavailable()
{
_pool.unavailableHandler?.Invoke();
}
}
static class DbConnectionExtensions
{
static DbCommand PingCommand(DbConnection conn)
{
var cmd = conn.CreateCommand();
cmd.CommandTimeout = 5;
cmd.CommandText = "select 1";
return cmd;
}
public static bool Ping(this DbConnection that, bool isThrow = false)
{
try
{
PingCommand(that).ExecuteNonQuery();
return true;
}
catch
{
if (that.State != ConnectionState.Closed) try { that.Close(); } catch { }
if (isThrow) throw;
return false;
}
}
#if net40
#else
async public static Task<bool> PingAsync(this DbConnection that, bool isThrow = false)
{
try
{
await PingCommand(that).ExecuteNonQueryAsync();
return true;
}
catch
{
if (that.State != ConnectionState.Closed) try { that.Close(); } catch { }
if (isThrow) throw;
return false;
}
}
#endif
}
}

View File

@ -0,0 +1,681 @@
using FreeSql.Internal;
using FreeSql.Internal.Model;
using System;
using System.Collections;
using System.Collections.Generic;
using System.Data;
using System.Linq;
using System.Text;
using System.Text.RegularExpressions;
using System.Data.Common;
using System.Reflection;
using FreeSql.Internal.ObjectPool;
using ClickHouse.Client.ADO;
using FreeSql.DataAnnotations;
namespace FreeSql.ClickHouse
{
class ClickHouseCodeFirst : Internal.CommonProvider.CodeFirstProvider
{
public ClickHouseCodeFirst(IFreeSql orm, CommonUtils commonUtils, CommonExpression commonExpression) : base(orm,
commonUtils, commonExpression)
{
}
static object _dicCsToDbLock = new object();
static Dictionary<string, CsToDb<DbType>> _dicCsToDb = new Dictionary<string, CsToDb<DbType>>()
{
{ typeof(bool).FullName, CsToDb.New(DbType.SByte, "Bool", "Bool", null, false, false) },
{ typeof(bool?).FullName, CsToDb.New(DbType.SByte, "Bool", "Nullable(Bool)", null, true, null) },
{ typeof(sbyte).FullName, CsToDb.New(DbType.SByte, "Int8", "Int8", false, false, 0) },
{ typeof(sbyte?).FullName, CsToDb.New(DbType.SByte, "Int8", "Nullable(Int8)", false, true, null) },
{ typeof(short).FullName, CsToDb.New(DbType.Int16, "Int16", "Int16", false, false, 0) },
{ typeof(short?).FullName, CsToDb.New(DbType.Int16, "Int16", "Nullable(Int16)", false, true, null) },
{ typeof(int).FullName, CsToDb.New(DbType.Int32, "Int32", "Int32", false, false, 0) },
{ typeof(int?).FullName, CsToDb.New(DbType.Int32, "Int32", "Nullable(Int32)", false, true, null) },
{ typeof(long).FullName, CsToDb.New(DbType.Int64, "Int64", "Int64", false, false, 0) },
{ typeof(long?).FullName, CsToDb.New(DbType.Int64, "Int64", "Nullable(Int64)", false, true, null) },
{ typeof(byte).FullName, CsToDb.New(DbType.Byte, "UInt8", "UInt8", true, false, 0) },
{ typeof(byte?).FullName, CsToDb.New(DbType.Byte, "UInt8", "Nullable(UInt8)", true, true, null) },
{ typeof(ushort).FullName, CsToDb.New(DbType.UInt16, "UInt16", "UInt16", true, false, 0) },
{ typeof(ushort?).FullName, CsToDb.New(DbType.UInt16, "UInt16", "Nullable(UInt16)", true, true, null) },
{ typeof(uint).FullName, CsToDb.New(DbType.UInt32, "UInt32", "UInt32", true, false, 0) },
{ typeof(uint?).FullName, CsToDb.New(DbType.UInt32, "UInt32", "Nullable(UInt32)", true, true, null) },
{ typeof(ulong).FullName, CsToDb.New(DbType.UInt64, "UInt64", "UInt64", true, false, 0) },
{ typeof(ulong?).FullName, CsToDb.New(DbType.UInt64, "UInt64", "Nullable(UInt64)", true, true, null) },
{ typeof(double).FullName, CsToDb.New(DbType.Double, "Float64", "Float64", false, false, 0) },
{ typeof(double?).FullName, CsToDb.New(DbType.Double, "Float64", "Nullable(Float64)", false, true, null) },
{ typeof(float).FullName, CsToDb.New(DbType.Single, "Float32", "Float32", false, false, 0) },
{ typeof(float?).FullName, CsToDb.New(DbType.Single, "Float32", "Nullable(Float32)", false, true, null) },
{
typeof(decimal).FullName,
CsToDb.New(DbType.Decimal, "Decimal(38, 19)", "Decimal(38, 19)", false, false,
0) //Nullable(Decimal(38, 19))
},
{
typeof(decimal?).FullName,
CsToDb.New(DbType.Decimal, "Nullable(Decimal(38, 19))", "Nullable(Decimal(38, 19))", false, true, null)
},
{
typeof(DateTime).FullName,
CsToDb.New(DbType.DateTime, "DateTime('Asia/Shanghai')", "DateTime('Asia/Shanghai')", false, false,
new DateTime(1970, 1, 1))
},
{
typeof(DateTime?).FullName,
CsToDb.New(DbType.DateTime, "DateTime('Asia/Shanghai')", "Nullable(DateTime('Asia/Shanghai'))", false,
true, null)
},
{ typeof(string).FullName, CsToDb.New(DbType.String, "String", "String", false, null, "") },
{ typeof(char).FullName, CsToDb.New(DbType.String, "String", "String", false, false, "") },
{ typeof(char?).FullName, CsToDb.New(DbType.Single, "String", "Nullable(String)", false, true, null) },
{ typeof(Guid).FullName, CsToDb.New(DbType.String, "String", "String", false, false, Guid.Empty) },
{ typeof(Guid?).FullName, CsToDb.New(DbType.String, "String", "Nullable(String)", false, true, null) },
};
public override DbInfoResult GetDbInfo(Type type)
{
if (_dicCsToDb.TryGetValue(type.FullName, out var trydc))
return new DbInfoResult((int)trydc.type, trydc.dbtype, trydc.dbtypeFull, trydc.isnullable,
trydc.defaultValue);
//判断是否是集合
var isCollection = IsArray(type);
if (isCollection.Item1)
{
var genericType = isCollection.Item2;
var genericTypeName = genericType?.FullName;
var tryGetValue = _dicCsToDb.TryGetValue(genericTypeName, out var value);
if (tryGetValue)
{
var arrayDbType = $"Array({value.dbtype})";
var defaultArray = new ArrayList(0);
return new DbInfoResult(Convert.ToInt32(DbType.Object), arrayDbType, arrayDbType, false, defaultArray);
}
}
return null;
}
private Tuple<bool, Type> IsArray(Type type)
{
var flag = false;
Type resultType = null;
if (type.IsArray)
{
flag = true;
resultType = type.GetElementType();
}
return new Tuple<bool, Type>(flag, resultType);
}
private Tuple<bool, Type> IsCollection(Type type)
{
var flag = false;
Type resultType = null;
var interfaces = type.GetInterfaces();
if (interfaces.Any(t => t.Name == "IList"))
flag = true;
if (interfaces.Any(t => t.Name == "ICollection"))
flag = true;
if (interfaces.Any(t => t.Name == "IEnumerable"))
flag = true;
if (type.Name == "Array")
{
flag = true;
resultType = typeof(string);
}
if (type.Name == "ArrayList")
{
flag = true;
resultType = typeof(string);
}
//是否是泛型
if (type.GetGenericArguments().Any())
{
var first = type.GetGenericArguments().First();
resultType = first;
}
return new Tuple<bool, Type>(flag, resultType);
}
protected override string GetComparisonDDLStatements(params TypeSchemaAndName[] objects)
{
Object<DbConnection> conn = null;
string database = null;
try
{
conn = _orm.Ado.MasterPool.Get(TimeSpan.FromSeconds(5));
database = conn.Value.Database;
var sb = new StringBuilder();
foreach (var obj in objects)
{
if (sb.Length > 0)
sb.Append("\r\n");
var tb = obj.tableSchema;
if (tb == null)
throw new Exception(CoreStrings.S_Type_IsNot_Migrable(obj.tableSchema.Type.FullName));
if (tb.Columns.Any() == false)
throw new Exception(CoreStrings.S_Type_IsNot_Migrable_0Attributes(obj.tableSchema.Type.FullName));
var tbname = _commonUtils.SplitTableName(tb.DbName);
if (tbname?.Length == 1)
tbname = new[] { database, tbname[0] };
var tboldname = _commonUtils.SplitTableName(tb.DbOldName); //旧表名
if (tboldname?.Length == 1)
tboldname = new[] { database, tboldname[0] };
if (string.IsNullOrEmpty(obj.tableName) == false)
{
var tbtmpname = _commonUtils.SplitTableName(obj.tableName);
if (tbtmpname?.Length == 1)
tbtmpname = new[] { database, tbtmpname[0] };
if (tbname[0] != tbtmpname[0] || tbname[1] != tbtmpname[1])
{
tbname = tbtmpname;
tboldname = null;
}
}
if (string.Compare(tbname[0], database, true) != 0 && LocalExecuteScalar(database,
_commonUtils.FormatSql(" select 1 from system.databases d where name={0}", tbname[0])) ==
null) //创建数据库
sb.Append($"CREATE DATABASE IF NOT EXISTS ").Append(_commonUtils.QuoteSqlName(tbname[0]))
.Append(" ENGINE=Ordinary;\r\n");
var sbalter = new StringBuilder();
var istmpatler = false; //创建临时表,导入数据,删除旧表,修改
if (LocalExecuteScalar(tbname[0],
_commonUtils.FormatSql(" SELECT 1 FROM system.tables t WHERE database ={0} and name ={1}",
tbname)) == null)
{
//表不存在
if (tboldname != null)
{
if (string.Compare(tboldname[0], tbname[0], true) != 0 && LocalExecuteScalar(database,
_commonUtils.FormatSql(" select 1 from system.databases where name={0}",
tboldname[0])) == null ||
LocalExecuteScalar(tboldname[0],
_commonUtils.FormatSql(
" SELECT 1 FROM system.tables WHERE database={0} and name={1}", tboldname)) ==
null)
//数据库或表不存在
tboldname = null;
}
if (tboldname == null)
{
//创建表
var createTableName = _commonUtils.QuoteSqlName(tbname[0], tbname[1]);
sb.Append("CREATE TABLE IF NOT EXISTS ").Append(createTableName).Append(" ( ");
foreach (var tbcol in tb.ColumnsByPosition)
{
//如果这里是主键就是不为Nullable
tbcol.Attribute.DbType =
CkNullableAdapter(tbcol.Attribute.DbType, tbcol.Attribute.IsPrimary);
tbcol.Attribute.DbType = CkIntAdapter(tbcol.Attribute.DbType);
sb.Append(" \r\n ").Append(_commonUtils.QuoteSqlName(tbcol.Attribute.Name)).Append(" ")
.Append(tbcol.Attribute.DbType);
if (string.IsNullOrEmpty(tbcol.Comment) == false)
sb.Append(" COMMENT ").Append(_commonUtils.FormatSql("{0}", tbcol.Comment));
sb.Append(",");
}
foreach (var uk in tb.Indexes)
{
sb.Append(" \r\n ");
sb.Append("INDEX ")
.Append(_commonUtils.QuoteSqlName(ReplaceIndexName(uk.Name, tbname[1])));
sb.Append(" (");
foreach (var tbcol in uk.Columns)
{
sb.Append(_commonUtils.QuoteSqlName(tbcol.Column.Attribute.Name));
sb.Append(", ");
}
sb.Remove(sb.Length - 2, 2).Append(") ");
sb.Append("TYPE set(8192) GRANULARITY 5,");
}
//sb.Remove(sb.Length - 1, 1);
if (tb.Primarys.Any())
{
var primaryKeys = string.Join(",",
tb.Primarys.Select(p => _commonUtils.QuoteSqlName(p.Attribute.Name)));
sb.Append(" \r\n PRIMARY KEY ");
sb.Append($"( {primaryKeys} ) ");
}
sb.Append("\r\n) ");
sb.Append("\r\nENGINE = MergeTree()");
if (tb.Primarys.Any())
{
var primaryKeys = string.Join(",",
tb.Primarys.Select(p => _commonUtils.QuoteSqlName(p.Attribute.Name)));
sb.Append(" \r\nORDER BY ");
sb.Append($"( {primaryKeys} ) ");
}
//查找属性是否标记了分区特性
var partitionColumnInfos = tb.Properties.Where(
c => c.Value.GetCustomAttribute<ClickHousePartitionAttribute>() != null).ToList();
if (partitionColumnInfos != null && partitionColumnInfos.Any())
{
var partitionProperty = partitionColumnInfos.First();
var partitionColumnInfo = tb.Columns.FirstOrDefault(pair =>
pair.Value.CsName == partitionProperty.Value.Name);
var partitionName = _commonUtils.QuoteSqlName(partitionColumnInfo.Value.Attribute.Name);
var partitionAttribute = partitionProperty.Value
.GetCustomAttribute<ClickHousePartitionAttribute>();
sb.Append($" \r\nPARTITION BY {string.Format(partitionAttribute.Format, partitionName)}");
}
//if (string.IsNullOrEmpty(tb.Comment) == false)
// sb.Append(" Comment=").Append(_commonUtils.FormatSql("{0}", tb.Comment));
sb.Append(" \r\nSETTINGS index_granularity = 8192;\r\n");
continue;
}
//如果新表,旧表在一个数据库下,直接修改表名
if (string.Compare(tbname[0], tboldname[0], true) == 0)
sbalter.Append("RENAME TABLE ")
.Append(_commonUtils.QuoteSqlName(tboldname[0], tboldname[1]))
.Append(" TO ").Append(_commonUtils.QuoteSqlName(tbname[0], tbname[1]))
.Append(";\r\n");
else
{
//如果新表,旧表不在一起,创建新表,导入数据,删除旧表
istmpatler = true;
}
}
else
tboldname = null; //如果新表已经存在,不走改表名逻辑
//对比字段,只可以修改类型、增加字段、有限的修改字段名;保证安全不删除字段
var sql = _commonUtils.FormatSql(@"
select
a.name,
a.type,
if(ilike(a.`type`, 'Nullable(%S%)'),'is_nullable','0'),
a.comment as comment,
a.is_in_partition_key,
a.is_in_sorting_key,
a.is_in_primary_key,
a.is_in_sampling_key
from system.columns a
where a.database in ({0}) and a.table in ({1})", tboldname ?? tbname);
var ds = _orm.Ado.ExecuteArray(CommandType.Text, sql);
var tbstruct = ds.ToDictionary(a => string.Concat(a[0]), a =>
{
return new
{
column = string.Concat(a[0]),
sqlType = (string)a[1],
is_nullable = a[1]?.ToString().Contains("Nullable"),
is_identity = false,
comment = string.Concat(a[3]),
is_primary = string.Concat(a[6]) == "1",
};
}, StringComparer.CurrentCultureIgnoreCase);
if (istmpatler == false)
{
var existsPrimary = tbstruct.Any(o => o.Value.is_primary);
//对比列
foreach (var tbcol in tb.ColumnsByPosition)
{
//表中有这个字段
var condition1 = tbstruct.TryGetValue(tbcol.Attribute.Name, out var tbstructcol);
var condition2 = string.IsNullOrEmpty(tbcol.Attribute.OldName) == false;
if (condition1 ||
condition2 && tbstruct.TryGetValue(tbcol.Attribute.OldName, out tbstructcol))
{
var isCommentChanged = tbstructcol.comment != (tbcol.Comment ?? "");
var ckDbType = CkNullableAdapter(tbcol.Attribute.DbType, tbcol.Attribute.IsPrimary);
ckDbType = CkIntAdapter(ckDbType);
var typeCondition1 = RemoveSpaceComparison(tbstructcol.sqlType, ckDbType) == false;
var typeCondition2 = tbcol.Attribute.IsNullable != tbstructcol.is_nullable;
if (typeCondition1 || typeCondition1 || isCommentChanged)
{
sbalter.Append("ALTER TABLE ")
.Append(_commonUtils.QuoteSqlName($"{tbname[0]}.{tbname[1]}"))
.Append(" MODIFY COLUMN ").Append(_commonUtils.QuoteSqlName(tbstructcol.column))
.Append(tbcol.Attribute.IsNullable &&
tbcol.Attribute.DbType.Contains("Nullable") == false
? $"Nullable({tbcol.Attribute.DbType.Split(' ').First()})"
: tbcol.Attribute.DbType.Split(' ').First())
.Append(";\r\n");
}
if (isCommentChanged)
sbalter.Append("ALTER TABLE ")
.Append(_commonUtils.QuoteSqlName($"{tbname[0]}.{tbname[1]}"))
.Append(" COMMENT COLUMN ")
.Append(_commonUtils.QuoteSqlName(tbstructcol.column))
.Append(_commonUtils.FormatSql("{0}", tbcol.Comment ?? "")).Append(";\r\n");
if (string.Compare(tbstructcol.column, tbcol.Attribute.OldName, true) == 0)
sbalter.Append("ALTER TABLE ")
.Append(_commonUtils.QuoteSqlName($"{tbname[0]}.{tbname[1]}"))
.Append(" RENAME COLUMN ").Append(_commonUtils.QuoteSqlName(tbstructcol.column))
.Append(" TO ").Append(_commonUtils.QuoteSqlName(tbcol.Attribute.Name))
.Append(";\r\n");
continue;
}
//添加列
sbalter.Append("ALTER TABLE ").Append(_commonUtils.QuoteSqlName(tbname[0], tbname[1]))
.Append(" ADD Column ").Append(_commonUtils.QuoteSqlName(tbcol.Attribute.Name))
.Append(" ")
.Append(tbcol.Attribute.DbType);
if (tbcol.Attribute.IsNullable == false && tbcol.DbDefaultValue != "NULL" &&
tbcol.Attribute.IsIdentity == false)
sbalter.Append(" DEFAULT ").Append(tbcol.DbDefaultValue);
if (string.IsNullOrEmpty(tbcol.Comment) == false)
sbalter.Append(" COMMENT ").Append(_commonUtils.FormatSql("{0}", tbcol.Comment ?? ""));
sbalter.Append(";\r\n");
}
var indexSelectSql = _commonUtils.FormatSql(
@"SELECT name,expr FROM system.data_skipping_indices WHERE database={0}",
tboldname ?? tbname);
var indexCollect = _orm.Ado.Query<ClickHouseTableIndex>(CommandType.Text, indexSelectSql);
//对比索引
foreach (var uk in tb.Indexes)
{
if (string.IsNullOrEmpty(uk.Name) || uk.Columns.Any() == false)
continue;
var ukname = ReplaceIndexName(uk.Name, tbname[1]);
//先判断表中有没此字段的索引
if (indexCollect.Any(c =>
RemoveSpaceComparison(c.expr,
string.Join(",", uk.Columns.Select(i => i.Column.CsName)))))
{
//有这个字段的索引,但是名称不一样 修改名 , ClickHouse不支持修改列
//if (!indexCollect.Where(c => c.name == uk.Name).Any())
//{
//
// sbalter.Append("ALTER TABLE ")
// .Append(_commonUtils.QuoteSqlName(tbname[0], tbname[1]))
// .Append(" DROP INDEX ").Append(ukname).Append(" ").Append(";\r\n");
// //添加
// sbalter.Append("ALTER TABLE ")
// .Append(_commonUtils.QuoteSqlName(tbname[0], tbname[1]))
// .Append(" ADD INDEX ").Append(ukname).Append(" (");
// foreach (var tbcol in uk.Columns)
// {
// sbalter.Append(_commonUtils.QuoteSqlName(tbcol.Column.Attribute.Name));
// sbalter.Append(", ");
// }
// sbalter.Remove(sbalter.Length - 2, 2).Append(") TYPE set(8192) GRANULARITY 5")
// .Append(";\r\n");
//}
}
else
{
//创建索引
sbalter.Append("ALTER TABLE ").Append(_commonUtils.QuoteSqlName(tbname[0], tbname[1]))
.Append(" ADD INDEX ").Append(ukname).Append(" (");
foreach (var tbcol in uk.Columns)
{
sbalter.Append(_commonUtils.QuoteSqlName(tbcol.Column.Attribute.Name));
sbalter.Append(", ");
}
sbalter.Remove(sbalter.Length - 2, 2).Append(") TYPE set(8192) GRANULARITY 5")
.Append(";\r\n");
}
}
}
if (istmpatler == false)
{
sb.Append(sbalter);
Console.WriteLine(sb.ToString());
continue;
}
//创建临时表,数据导进临时表,然后删除原表,将临时表改名为原表名
var tablename = tboldname == null
? _commonUtils.QuoteSqlName(tbname[0], tbname[1])
: _commonUtils.QuoteSqlName(tboldname[0], tboldname[1]);
var tmptablename = _commonUtils.QuoteSqlName(tbname[0], $"FreeSqlTmp_{tbname[1]}");
//创建临时表
sb.Append("CREATE TABLE IF NOT EXISTS ").Append(tmptablename).Append(" ( ");
foreach (var tbcol in tb.ColumnsByPosition)
{
tbcol.Attribute.DbType = tbcol.Attribute.DbType.Replace(" NOT NULL", "");
sb.Append(" \r\n ").Append(_commonUtils.QuoteSqlName(tbcol.Attribute.Name)).Append(" ")
.Append(tbcol.Attribute.DbType);
if (string.IsNullOrEmpty(tbcol.Comment) == false)
sb.Append(" COMMENT ").Append(_commonUtils.FormatSql("{0}", tbcol.Comment));
sb.Append(",");
}
foreach (var uk in tb.Indexes)
{
sb.Append(" \r\n ");
sb.Append("INDEX ").Append(_commonUtils.QuoteSqlName(ReplaceIndexName(uk.Name, tbname[1])))
.Append("(");
foreach (var tbcol in uk.Columns)
{
sb.Append(_commonUtils.QuoteSqlName(tbcol.Column.Attribute.Name));
sb.Append("TYPE set(8192) GRANULARITY 5, ");
}
sb.Remove(sb.Length - 2, 2).Append("),");
}
sb.Remove(sb.Length - 1, 1);
sb.Append("\r\n) ");
sb.Append("\r\nENGINE = MergeTree()");
if (tb.Primarys.Any())
{
var primaryKeys = string.Join(",",
tb.Primarys.Select(p => _commonUtils.QuoteSqlName(p.Attribute.Name)));
sb.Append(" \r\nORDER BY ( ");
sb.Append(primaryKeys);
sb.Append(" )");
sb.Append(" \r\nPRIMARY KEY ");
sb.Append($"({primaryKeys}) ");
}
sb.Remove(sb.Length - 1, 1);
//if (string.IsNullOrEmpty(tb.Comment) == false)
// sb.Append(" Comment=").Append(_commonUtils.FormatSql("{0}", tb.Comment));
sb.Append(" SETTINGS index_granularity = 8192;\r\n");
sb.Append("INSERT INTO ").Append(tmptablename).Append(" SELECT ");
foreach (var tbcol in tb.ColumnsByPosition)
{
var insertvalue = "NULL";
if (tbstruct.TryGetValue(tbcol.Attribute.Name, out var tbstructcol) ||
string.IsNullOrEmpty(tbcol.Attribute.OldName) == false &&
tbstruct.TryGetValue(tbcol.Attribute.OldName, out tbstructcol))
{
insertvalue = _commonUtils.QuoteSqlName(tbstructcol.column);
if (tbcol.Attribute.DbType.StartsWith(tbstructcol.sqlType,
StringComparison.CurrentCultureIgnoreCase) == false)
{
//insertvalue = $"cast({insertvalue} as {tbcol.Attribute.DbType.Split(' ').First()})";
}
if (tbcol.Attribute.IsNullable != tbstructcol.is_nullable)
insertvalue = $"ifnull({insertvalue},{tbcol.DbDefaultValue})";
}
else if (tbcol.Attribute.IsNullable == false)
if (tbcol.DbDefaultValue != "NULL")
insertvalue = tbcol.DbDefaultValue;
sb.Append(insertvalue).Append(", ");
}
sb.Remove(sb.Length - 2, 2).Append(" FROM ").Append(tablename).Append(";\r\n");
sb.Append("DROP TABLE ").Append(tablename).Append(";\r\n");
sb.Append("RENAME TABLE ").Append(tmptablename).Append(" TO ")
.Append(_commonUtils.QuoteSqlName(tbname[0], tbname[1])).Append(";\r\n");
}
var res = sb.Length == 0 ? null : sb.ToString();
return res;
}
finally
{
try
{
if (string.IsNullOrEmpty(database) == false)
conn.Value.ChangeDatabase(database);
_orm.Ado.MasterPool.Return(conn);
}
catch
{
_orm.Ado.MasterPool.Return(conn, true);
}
}
object LocalExecuteScalar(string db, string sql)
{
if (string.Compare(database, db) != 0)
conn.Value.ChangeDatabase(db);
try
{
using (var cmd = conn.Value.CreateCommand())
{
cmd.CommandText = sql;
cmd.CommandType = CommandType.Text;
var before = new Aop.CommandBeforeEventArgs(cmd);
this._orm?.Aop.CommandBeforeHandler?.Invoke(this._orm, before);
Exception afterException = null;
try
{
return cmd.ExecuteScalar();
}
catch (Exception ex)
{
afterException = ex;
throw;
}
finally
{
this._orm?.Aop.CommandAfterHandler?.Invoke(this._orm,
new Aop.CommandAfterEventArgs(before, afterException, null));
}
}
}
finally
{
if (string.Compare(database, db) != 0)
conn.Value.ChangeDatabase(database);
}
}
string CkNullableAdapter(string dbType, bool isPrimary)
{
if (isPrimary)
{
if (dbType.Contains("Nullable"))
{
var res = dbType.Replace("Nullable(", "")
.Replace(")", "")
.Replace(" NOT NULL", "");
return res;
}
return dbType;
}
return dbType.Replace(" NOT NULL", "");
}
string CkIntAdapter(string dbType)
{
var result = dbType;
if (dbType.Contains("Array"))
return dbType;
if (dbType.ToLower().Contains("int64"))
{
if (dbType.Contains("Nullable"))
{
result = "Nullable(Int64)";
}
else
{
result = "Int64";
}
}
else if (dbType.ToLower().Contains("int"))
{
if (dbType.Contains("Nullable"))
{
result = "Nullable(Int32)";
}
else
{
result = "Int32";
}
}
return result;
}
//去除空格后比较
bool RemoveSpaceComparison(string a, string b)
{
a = Regex.Replace(a, @"\s", "").ToLower();
b = Regex.Replace(b, @"\s", "").ToLower();
return a == b;
}
}
public override int ExecuteDDLStatements(string ddl)
{
if (string.IsNullOrEmpty(ddl))
return 0;
var scripts = ddl.Split(new string[] { ";\r\n" }, StringSplitOptions.None)
.Where(a => string.IsNullOrEmpty(a.Trim()) == false).ToArray();
if (scripts.Any() == false)
return 0;
var affrows = 0;
foreach (var script in scripts)
affrows += base.ExecuteDDLStatements(script);
return affrows;
}
}
internal class ClickHouseTableIndex
{
public string name { get; set; }
public string expr { get; set; }
}
}

View File

@ -0,0 +1,473 @@
using FreeSql.DatabaseModel;
using FreeSql.Internal;
using FreeSql.Internal.Model;
using System;
using System.Collections.Generic;
using System.Data;
using System.Linq;
using System.Text;
using System.Text.RegularExpressions;
using ClickHouse.Client.ADO;
namespace FreeSql.ClickHouse
{
class ClickHouseDbFirst : IDbFirst
{
IFreeSql _orm;
protected CommonUtils _commonUtils;
protected CommonExpression _commonExpression;
public ClickHouseDbFirst(IFreeSql orm, CommonUtils commonUtils, CommonExpression commonExpression)
{
_orm = orm;
_commonUtils = commonUtils;
_commonExpression = commonExpression;
}
public int GetDbType(DbColumnInfo column) => (int)GetClickHouseDbType(column);
DbType GetClickHouseDbType(DbColumnInfo column)
{
if (column.DbTypeText == "Nullable")
{
column.DbTypeText = column.DbTypeTextFull;
//(?<=\()(\S +)(?=\))
}
switch (column.DbTypeText?.ToLower())
{
case "bit":
case "tinyint":
case "bool":
case "sbyte":
case "int8":
case "nullable(int8)": return DbType.SByte;
case "byte":
case "uint8":
case "nullable(uint8)": return DbType.Byte;
case "smallint":
case "int16":
case "nullable(int16)": return DbType.Int16;
case "uint16":
case "nullable(uint16)": return DbType.UInt16;
case "int32":
case "int":
case "nullable(int32)": return DbType.Int32;
case "uint":
case "uint32":
case "nullable(uint32)": return DbType.UInt32;
case "bigint":
case "int64":
case "long":
case "nullable(int64)": return DbType.Int64;
case "uint64":
case "ulong":
case "nullable(uint64)": return DbType.UInt64;
case "real":
case "Float64":
case "double":
case "nullable(float64)": return DbType.Double;
case "Float32":
case "float":
case "nullable(float32)": return DbType.Single;
case "decimal":
case "decimal128":
case "nullable(decimal128)": return DbType.Decimal;
case "date":
case "nullable(date)": return DbType.Date;
case "datetime":
case "nullable(datetime)": return DbType.DateTime;
case "datetime64":
case "nullable(datetime64)": return DbType.DateTime;
case "tinytext":
case "text":
case "mediumtext":
case "longtext":
case "char":
case "string":
case "nullable(string)":
case "varchar": return DbType.String;
default:
{
if (column.DbTypeText?.ToLower().Contains("datetime") == true)
return DbType.DateTime;
return DbType.String;
}
}
}
static readonly Dictionary<int, DbToCs> _dicDbToCs = new Dictionary<int, DbToCs>() {
{ (int)DbType.SByte, new DbToCs("(sbyte?)", "sbyte.Parse({0})", "{0}.ToString()", "sbyte?", typeof(sbyte), typeof(sbyte?), "{0}.Value", "GetByte") },
{ (int)DbType.Int16, new DbToCs("(short?)", "short.Parse({0})", "{0}.ToString()", "short?", typeof(short), typeof(short?), "{0}.Value", "GetInt16") },
{ (int)DbType.Int32, new DbToCs("(int?)", "int.Parse({0})", "{0}.ToString()", "int?", typeof(int), typeof(int?), "{0}.Value", "GetInt32") },
{ (int)DbType.Int64, new DbToCs("(long?)", "long.Parse({0})", "{0}.ToString()", "long?", typeof(long), typeof(long?), "{0}.Value", "GetInt64") },
{ (int)DbType.Byte, new DbToCs("(byte?)", "byte.Parse({0})", "{0}.ToString()", "byte?", typeof(byte), typeof(byte?), "{0}.Value", "GetByte") },
{ (int)DbType.UInt16, new DbToCs("(ushort?)", "ushort.Parse({0})", "{0}.ToString()", "ushort?", typeof(ushort), typeof(ushort?), "{0}.Value", "GetInt16") },
{ (int)DbType.UInt32, new DbToCs("(uint?)", "uint.Parse({0})", "{0}.ToString()", "uint?", typeof(uint), typeof(uint?), "{0}.Value", "GetInt32") },
{ (int)DbType.UInt64, new DbToCs("(ulong?)", "ulong.Parse({0})", "{0}.ToString()", "ulong?", typeof(ulong), typeof(ulong?), "{0}.Value", "GetInt64") },
{ (int)DbType.Double, new DbToCs("(double?)", "double.Parse({0})", "{0}.ToString()", "double?", typeof(double), typeof(double?), "{0}.Value", "GetDouble") },
{ (int)DbType.Single, new DbToCs("(float?)", "float.Parse({0})", "{0}.ToString()", "float?", typeof(float), typeof(float?), "{0}.Value", "GetFloat") },
{ (int)DbType.Decimal, new DbToCs("(decimal?)", "decimal.Parse({0})", "{0}.ToString()", "decimal?", typeof(decimal), typeof(decimal?), "{0}.Value", "GetDecimal") },
{ (int)DbType.Date, new DbToCs("(DateTime?)", "new DateTime(long.Parse({0}))", "{0}.Ticks.ToString()", "DateTime?", typeof(DateTime), typeof(DateTime?), "{0}.Value", "GetDateTime") },
{ (int)DbType.Date, new DbToCs("(DateTime?)", "new DateTime(long.Parse({0}))", "{0}.Ticks.ToString()", "DateTime?", typeof(DateTime), typeof(DateTime?), "{0}.Value", "GetDateTime") },
{ (int)DbType.DateTime, new DbToCs("(DateTime?)", "new DateTime(long.Parse({0}))", "{0}.Ticks.ToString()", "DateTime?", typeof(DateTime), typeof(DateTime?), "{0}.Value", "GetDateTime") },
{ (int)DbType.DateTime2, new DbToCs("(DateTime?)", "new DateTime(long.Parse({0}))", "{0}.Ticks.ToString()", "DateTime?", typeof(DateTime), typeof(DateTime?), "{0}.Value", "GetDateTime") },
{ (int)DbType.Guid, new DbToCs("(Guid?)", "Guid.Parse({0})", "{0}.ToString()", "Guid?", typeof(Guid), typeof(Guid?), "{0}", "GetString") },
{ (int)DbType.String, new DbToCs("", "{0}.Replace(StringifySplit, \"|\")", "{0}.Replace(\"|\", StringifySplit)", "string", typeof(string), typeof(string), "{0}", "GetString") },
};
public string GetCsConvert(DbColumnInfo column) => _dicDbToCs.TryGetValue(column.DbType, out var trydc) ? (column.IsNullable ? trydc.csConvert : trydc.csConvert.Replace("?", "")) : null;
public string GetCsParse(DbColumnInfo column) => _dicDbToCs.TryGetValue(column.DbType, out var trydc) ? trydc.csParse : null;
public string GetCsStringify(DbColumnInfo column) => _dicDbToCs.TryGetValue(column.DbType, out var trydc) ? trydc.csStringify : null;
public string GetCsType(DbColumnInfo column) => _dicDbToCs.TryGetValue(column.DbType, out var trydc) ? (column.IsNullable ? trydc.csType : trydc.csType.Replace("?", "")) : null;
public Type GetCsTypeInfo(DbColumnInfo column) => _dicDbToCs.TryGetValue(column.DbType, out var trydc) ? trydc.csTypeInfo : null;
public string GetCsTypeValue(DbColumnInfo column) => _dicDbToCs.TryGetValue(column.DbType, out var trydc) ? trydc.csTypeValue : null;
public string GetDataReaderMethod(DbColumnInfo column) => _dicDbToCs.TryGetValue(column.DbType, out var trydc) ? trydc.dataReaderMethod : null;
public List<string> GetDatabases()
{
var sql = @" select name from system.databases where name not in ('system', 'default')";
var ds = _orm.Ado.ExecuteArray(CommandType.Text, sql);
return ds.Select(a => a.FirstOrDefault()?.ToString()).ToList();
}
public bool ExistsTable(string name, bool ignoreCase)
{
if (string.IsNullOrEmpty(name)) return false;
var tbname = _commonUtils.SplitTableName(name);
if (tbname?.Length == 1)
{
var database = "";
using (var conn = _orm.Ado.MasterPool.Get(TimeSpan.FromSeconds(5)))
{
database = conn.Value.Database;
}
tbname = new[] { database, tbname[0] };
}
if (ignoreCase) tbname = tbname.Select(a => a.ToLower()).ToArray();
var sql = $" SELECT 1 FROM information_schema.tables WHERE {(ignoreCase ? "lower(table_schema)" : "table_schema")} = {_commonUtils.FormatSql("{0}", tbname[0])} and {(ignoreCase ? "lower(table_name)" : "table_name")} = {_commonUtils.FormatSql("{0}", tbname[1])}";
return string.Concat(_orm.Ado.ExecuteScalar(CommandType.Text, sql)) == "1";
}
public DbTableInfo GetTableByName(string name, bool ignoreCase = true) => GetTables(null, name, ignoreCase)?.FirstOrDefault();
public List<DbTableInfo> GetTablesByDatabase(params string[] database) => GetTables(database, null, false);
public List<DbTableInfo> GetTables(string[] database, string tablename, bool ignoreCase)
{
var loc1 = new List<DbTableInfo>();
var loc2 = new Dictionary<string, DbTableInfo>(StringComparer.CurrentCultureIgnoreCase);
var loc3 = new Dictionary<string, Dictionary<string, DbColumnInfo>>(StringComparer.CurrentCultureIgnoreCase);
string[] tbname = null;
if (string.IsNullOrEmpty(tablename) == false)
{
tbname = _commonUtils.SplitTableName(tablename);
if (tbname?.Length == 1)
{
using (var conn = _orm.Ado.MasterPool.Get(TimeSpan.FromSeconds(5)))
{
if (string.IsNullOrEmpty(conn.Value.Database)) return loc1;
tbname = new[] { conn.Value.Database, tbname[0] };
}
}
if (ignoreCase) tbname = tbname.Select(a => a.ToLower()).ToArray();
database = new[] { tbname[0] };
}
else if (database == null || database.Any() == false)
{
using (var conn = _orm.Ado.MasterPool.Get())
{
if (string.IsNullOrEmpty(conn.Value.Database)) return loc1;
database = new[] { conn.Value.Database };
}
}
var databaseIn = string.Join(",", database.Select(a => _commonUtils.FormatSql("{0}", a)));
var sql = $@"
select
concat(a.table_schema, '.', a.table_name) 'id',
a.table_schema 'schema',
a.table_name 'table',
a.table_comment,
a.table_type 'type'
from information_schema.tables a
where {(ignoreCase ? "lower(a.table_schema)" : "a.table_schema")} in ({databaseIn}){(tbname == null ? "" : $" and {(ignoreCase ? "lower(a.table_name)" : "a.table_name")}={_commonUtils.FormatSql("{0}", tbname[1])}")}";
var ds = _orm.Ado.ExecuteArray(CommandType.Text, sql);
if (ds == null) return loc1;
var loc6 = new List<string[]>();
var loc66 = new List<string[]>();
var loc6_1000 = new List<string>();
var loc66_1000 = new List<string>();
foreach (var row in ds)
{
var table_id = string.Concat(row[0]);
var schema = string.Concat(row[1]);
var table = string.Concat(row[2]);
var comment = string.Concat(row[3]);
var type = string.Concat(row[4]) == "VIEW" ? DbTableType.VIEW : DbTableType.TABLE;
if (database.Length == 1)
{
table_id = table_id.Substring(table_id.IndexOf('.') + 1);
schema = "";
}
loc2.Add(table_id, new DbTableInfo { Id = table_id, Schema = schema, Name = table, Comment = comment, Type = type });
loc3.Add(table_id, new Dictionary<string, DbColumnInfo>(StringComparer.CurrentCultureIgnoreCase));
switch (type)
{
case DbTableType.TABLE:
case DbTableType.VIEW:
loc6_1000.Add(table.Replace("'", "''"));
if (loc6_1000.Count >= 500)
{
loc6.Add(loc6_1000.ToArray());
loc6_1000.Clear();
}
break;
case DbTableType.StoreProcedure:
loc66_1000.Add(table.Replace("'", "''"));
if (loc66_1000.Count >= 500)
{
loc66.Add(loc66_1000.ToArray());
loc66_1000.Clear();
}
break;
}
}
if (loc6_1000.Count > 0) loc6.Add(loc6_1000.ToArray());
if (loc66_1000.Count > 0) loc66.Add(loc66_1000.ToArray());
if (loc6.Count == 0) return loc1;
var loc8 = new StringBuilder().Append("(");
for (var loc8idx = 0; loc8idx < loc6.Count; loc8idx++)
{
if (loc8idx > 0) loc8.Append(" OR ");
loc8.Append("a.table_name in (");
for (var loc8idx2 = 0; loc8idx2 < loc6[loc8idx].Length; loc8idx2++)
{
if (loc8idx2 > 0) loc8.Append(",");
loc8.Append($"'{loc6[loc8idx][loc8idx2]}'");
}
loc8.Append(")");
}
loc8.Append(")");
sql = $@"
select
concat(a.table_schema, '.', a.table_name),
a.column_name,
a.data_type,
ifnull(a.character_maximum_length, 0) 'len',
a.column_type,
case when a.is_nullable = 'YES' then 1 else 0 end 'is_nullable',
case when locate('auto_increment', a.extra) > 0 then 1 else 0 end 'is_identity',
a.column_comment 'comment',
a.column_default 'default_value'
from information_schema.columns a
where {(ignoreCase ? "lower(a.table_schema)" : "a.table_schema")} in ({databaseIn}) and {loc8}
";
ds = _orm.Ado.ExecuteArray(CommandType.Text, sql);
if (ds == null) return loc1;
var position = 0;
foreach (var row in ds)
{
string table_id = string.Concat(row[0]);
string column = string.Concat(row[1]);
string type = string.Concat(row[2]);
//long max_length = long.Parse(string.Concat(row[3]));
string sqlType = string.Concat(row[4]);
var m_len = Regex.Match(sqlType, @"\w+\((\d+)");
int max_length = m_len.Success ? int.Parse(m_len.Groups[1].Value) : -1;
bool is_nullable = string.Concat(row[5]) == "1";
bool is_identity = string.Concat(row[6]) == "1";
string comment = string.Concat(row[7]);
string defaultValue = string.Concat(row[8]);
if (max_length == 0) max_length = -1;
if (database.Length == 1)
{
table_id = table_id.Substring(table_id.IndexOf('.') + 1);
}
loc3[table_id].Add(column, new DbColumnInfo
{
Name = column,
MaxLength = max_length,
IsIdentity = is_identity,
IsNullable = is_nullable,
IsPrimary = false,
DbTypeText = type,
DbTypeTextFull = sqlType,
Table = loc2[table_id],
Comment = comment,
DefaultValue = defaultValue,
Position = ++position
});
loc3[table_id][column].DbType = this.GetDbType(loc3[table_id][column]);
loc3[table_id][column].CsType = this.GetCsTypeInfo(loc3[table_id][column]);
}
sql = $@"
select
concat(a.table_schema, '.', a.table_name) 'table_id',
a.column_name,
a.index_name 'index_id',
case when a.non_unique = 0 then 1 else 0 end 'IsUnique',
case when a.index_name = 'PRIMARY' then 1 else 0 end 'IsPrimaryKey',
0 'IsClustered',
0 'IsDesc'
from information_schema.statistics a
where {(ignoreCase ? "lower(a.table_schema)" : "a.table_schema")} in ({databaseIn}) and {loc8}
";
ds = _orm.Ado.ExecuteArray(CommandType.Text, sql);
if (ds == null) return loc1;
var indexColumns = new Dictionary<string, Dictionary<string, DbIndexInfo>>(StringComparer.CurrentCultureIgnoreCase);
var uniqueColumns = new Dictionary<string, Dictionary<string, DbIndexInfo>>(StringComparer.CurrentCultureIgnoreCase);
foreach (var row in ds)
{
string table_id = string.Concat(row[0]);
string column = string.Concat(row[1]);
string index_id = string.Concat(row[2]);
bool is_unique = string.Concat(row[3]) == "1";
bool is_primary_key = string.Concat(row[4]) == "1";
bool is_clustered = string.Concat(row[5]) == "1";
bool is_desc = string.Concat(row[6]) == "1";
if (database.Length == 1)
table_id = table_id.Substring(table_id.IndexOf('.') + 1);
if (loc3.ContainsKey(table_id) == false || loc3[table_id].ContainsKey(column) == false) continue;
var loc9 = loc3[table_id][column];
if (loc9.IsPrimary == false && is_primary_key) loc9.IsPrimary = is_primary_key;
Dictionary<string, DbIndexInfo> loc10 = null;
DbIndexInfo loc11 = null;
if (!indexColumns.TryGetValue(table_id, out loc10))
indexColumns.Add(table_id, loc10 = new Dictionary<string, DbIndexInfo>(StringComparer.CurrentCultureIgnoreCase));
if (!loc10.TryGetValue(index_id, out loc11))
loc10.Add(index_id, loc11 = new DbIndexInfo());
loc11.Columns.Add(new DbIndexColumnInfo { Column = loc9, IsDesc = is_desc });
if (is_unique && !is_primary_key)
{
if (!uniqueColumns.TryGetValue(table_id, out loc10))
uniqueColumns.Add(table_id, loc10 = new Dictionary<string, DbIndexInfo>(StringComparer.CurrentCultureIgnoreCase));
if (!loc10.TryGetValue(index_id, out loc11))
loc10.Add(index_id, loc11 = new DbIndexInfo());
loc11.Columns.Add(new DbIndexColumnInfo { Column = loc9, IsDesc = is_desc });
}
}
foreach (string table_id in indexColumns.Keys)
{
foreach (var column in indexColumns[table_id])
loc2[table_id].IndexesDict.Add(column.Key, column.Value);
}
foreach (string table_id in uniqueColumns.Keys)
{
foreach (var column in uniqueColumns[table_id])
{
column.Value.Columns.Sort((c1, c2) => c1.Column.Name.CompareTo(c2.Column.Name));
loc2[table_id].UniquesDict.Add(column.Key, column.Value);
}
}
if (tbname == null)
{
sql = $@"
select
concat(a.constraint_schema, '.', a.table_name) 'table_id',
a.column_name,
a.constraint_name 'FKId',
concat(a.referenced_table_schema, '.', a.referenced_table_name) 'ref_table_id',
1 'IsForeignKey',
a.referenced_column_name 'ref_column'
from information_schema.key_column_usage a
where {(ignoreCase ? "lower(a.constraint_schema)" : "a.constraint_schema")} in ({databaseIn}) and {loc8} and not isnull(position_in_unique_constraint)
";
ds = _orm.Ado.ExecuteArray(CommandType.Text, sql);
if (ds == null) return loc1;
var fkColumns = new Dictionary<string, Dictionary<string, DbForeignInfo>>(StringComparer.CurrentCultureIgnoreCase);
foreach (var row in ds)
{
string table_id = string.Concat(row[0]);
string column = string.Concat(row[1]);
string fk_id = string.Concat(row[2]);
string ref_table_id = string.Concat(row[3]);
bool is_foreign_key = string.Concat(row[4]) == "1";
string referenced_column = string.Concat(row[5]);
if (database.Length == 1)
{
table_id = table_id.Substring(table_id.IndexOf('.') + 1);
ref_table_id = ref_table_id.Substring(ref_table_id.IndexOf('.') + 1);
}
if (loc3.ContainsKey(table_id) == false || loc3[table_id].ContainsKey(column) == false) continue;
var loc9 = loc3[table_id][column];
if (loc2.ContainsKey(ref_table_id) == false) continue;
var loc10 = loc2[ref_table_id];
var loc11 = loc3[ref_table_id][referenced_column];
Dictionary<string, DbForeignInfo> loc12 = null;
DbForeignInfo loc13 = null;
if (!fkColumns.TryGetValue(table_id, out loc12))
fkColumns.Add(table_id, loc12 = new Dictionary<string, DbForeignInfo>(StringComparer.CurrentCultureIgnoreCase));
if (!loc12.TryGetValue(fk_id, out loc13))
loc12.Add(fk_id, loc13 = new DbForeignInfo { Table = loc2[table_id], ReferencedTable = loc10 });
loc13.Columns.Add(loc9);
loc13.ReferencedColumns.Add(loc11);
}
foreach (var table_id in fkColumns.Keys)
foreach (var fk in fkColumns[table_id])
loc2[table_id].ForeignsDict.Add(fk.Key, fk.Value);
}
foreach (var table_id in loc3.Keys)
{
foreach (var loc5 in loc3[table_id].Values)
{
loc2[table_id].Columns.Add(loc5);
if (loc5.IsIdentity) loc2[table_id].Identitys.Add(loc5);
if (loc5.IsPrimary) loc2[table_id].Primarys.Add(loc5);
}
}
foreach (var loc4 in loc2.Values)
{
//if (loc4.Primarys.Count == 0 && loc4.UniquesDict.Count > 0)
//{
// foreach (var loc5 in loc4.UniquesDict.First().Value.Columns)
// {
// loc5.Column.IsPrimary = true;
// loc4.Primarys.Add(loc5.Column);
// }
//}
loc4.Primarys.Sort((c1, c2) => c1.Name.CompareTo(c2.Name));
loc4.Columns.Sort((c1, c2) =>
{
int compare = c2.IsPrimary.CompareTo(c1.IsPrimary);
if (compare == 0)
{
bool b1 = loc4.ForeignsDict.Values.Where(fk => fk.Columns.Where(c3 => c3.Name == c1.Name).Any()).Any();
bool b2 = loc4.ForeignsDict.Values.Where(fk => fk.Columns.Where(c3 => c3.Name == c2.Name).Any()).Any();
compare = b2.CompareTo(b1);
}
if (compare == 0) compare = c1.Name.CompareTo(c2.Name);
return compare;
});
loc1.Add(loc4);
}
loc1.Sort((t1, t2) =>
{
var ret = t1.Schema.CompareTo(t2.Schema);
if (ret == 0) ret = t1.Name.CompareTo(t2.Name);
return ret;
});
loc2.Clear();
loc3.Clear();
return loc1;
}
public List<DbEnumInfo> GetEnumsByDatabase(params string[] database)
{
return new List<DbEnumInfo>();
}
}
}

View File

@ -0,0 +1,621 @@
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.Reflection;
using System.Text;
using System.Text.RegularExpressions;
namespace FreeSql.ClickHouse
{
class ClickHouseExpression : CommonExpression
{
public ClickHouseExpression(CommonUtils common) : base(common) { }
public override string ExpressionLambdaToSqlOther(Expression exp, ExpTSC tsc)
{
Func<Expression, string> getExp = exparg => ExpressionLambdaToSql(exparg, tsc);
switch (exp.NodeType)
{
case ExpressionType.ArrayLength:
var arrOper = (exp as UnaryExpression)?.Operand;
if (arrOper.Type == typeof(byte[])) return $"length({getExp(arrOper)})";
break;
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 $"({getExp(operandExp)} not in ('0','false'))";
case "System.Byte": return $"cast({getExp(operandExp)} as Int8)";
case "System.Char": return $"substr(cast({getExp(operandExp)} as String), 1, 1)";
case "System.DateTime": return ExpressionConstDateTime(operandExp) ?? $"cast({getExp(operandExp)} as DateTime)";
case "System.Decimal": return $"cast({getExp(operandExp)} as Decimal128(19))";
case "System.Double": return $"cast({getExp(operandExp)} as Float64)";
case "System.Int16": return $"cast({getExp(operandExp)} as Int16)";
case "System.Int32": return $"cast({getExp(operandExp)} as Int32)";
case "System.Int64": return $"cast({getExp(operandExp)} as Int64)";
case "System.SByte": return $"cast({getExp(operandExp)} as UInt8)";
case "System.Single": return $"cast({getExp(operandExp)} as Float32)";
case "System.String": return $"cast({getExp(operandExp)} as String)";
case "System.UInt16": return $"cast({getExp(operandExp)} as UInt16)";
case "System.UInt32": return $"cast({getExp(operandExp)} as UInt32)";
case "System.UInt64": return $"cast({getExp(operandExp)} as UInt64)";
case "System.Guid": return $"substr(cast({getExp(operandExp)} as String), 1, 36)";
}
}
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 $"({getExp(callExp.Arguments[0])} not in ('0','false'))";
case "System.Byte": return $"cast({getExp(callExp.Arguments[0])} as Int8)";
case "System.Char": return $"substr(cast({getExp(callExp.Arguments[0])} as String), 1, 1)";
case "System.DateTime": return ExpressionConstDateTime(callExp.Arguments[0]) ?? $"cast({getExp(callExp.Arguments[0])} as DateTime)";
case "System.Decimal": return $"cast({getExp(callExp.Arguments[0])} as Decimal128(19))";
case "System.Double": return $"cast({getExp(callExp.Arguments[0])} as Float64)";
case "System.Int16": return $"cast({getExp(callExp.Arguments[0])} as Int16)";
case "System.Int32": return $"cast({getExp(callExp.Arguments[0])} as Int32)";
case "System.Int64": return $"cast({getExp(callExp.Arguments[0])} as Int64)";
case "System.SByte": return $"cast({getExp(callExp.Arguments[0])} as UInt8)";
case "System.Single": return $"cast({getExp(callExp.Arguments[0])} as Float32)";
case "System.UInt16": return $"cast({getExp(callExp.Arguments[0])} as UInt16)";
case "System.UInt32": return $"cast({getExp(callExp.Arguments[0])} as UInt32)";
case "System.UInt64": return $"cast({getExp(callExp.Arguments[0])} as UInt64)";
case "System.Guid": return $"substr(cast({getExp(callExp.Arguments[0])} as String), 1, 36)";
}
return null;
case "NewGuid":
return null;
case "Next":
if (callExp.Object?.Type == typeof(Random)) return "cast(rand()*1000000000 as Int64)";
return null;
case "NextDouble":
if (callExp.Object?.Type == typeof(Random)) return "rand()";
return null;
case "Random":
if (callExp.Method.DeclaringType.IsNumberType()) return "rand()";
return null;
case "ToString":
if (callExp.Object != null)
{
if (callExp.Object.Type.NullableTypeOrThis().IsEnum)
{
tsc.SetMapColumnTmp(null);
var oldMapType = tsc.SetMapTypeReturnOld(typeof(string));
var enumStr = ExpressionLambdaToSql(callExp.Object, tsc);
tsc.SetMapColumnTmp(null).SetMapTypeReturnOld(oldMapType);
return enumStr;
}
var value = ExpressionGetValue(callExp.Object, out var success);
if (success) return formatSql(value, typeof(string), null, null);
return callExp.Arguments.Count == 0 ? $"cast({getExp(callExp.Object)} as String)" : 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 $"substr({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 = objExp?.NodeType == ExpressionType.MemberAccess ? tsc.SetDbParamsReturnOld(null) : null; //#900 UseGenerateCommandParameterWithLambda(true) 子查询 bug、以及 #1173 参数化 bug
//tsc.isNotSetMapColumnTmp = true;
var left = objExp == null ? null : getExp(objExp);
//tsc.isNotSetMapColumnTmp = false;
//tsc.SetMapColumnTmp(null).SetMapTypeReturnOld(oldMapType);
//if (oldDbParams != null) tsc.SetDbParamsReturnOld(oldDbParams);
switch (callExp.Method.Name)
{
case "Count":
left = objExp == null ? null : getExp(objExp);
if (left.StartsWith("(") || left.EndsWith(")")) left = $"array[{left.TrimStart('(').TrimEnd(')')}]";
return $"(case when {left} is null then 0 else length({left}) end)";
case "Any":
left = objExp == null ? null : getExp(objExp);
if (left.StartsWith("(") || left.EndsWith(")")) left = $"array[{left.TrimStart('(').TrimEnd(')')}]";
return $"(case when {left} is null then 0 else length({left}) end > 0)";
case "Contains":
tsc.SetMapColumnTmp(null);
var args1 = getExp(callExp.Arguments[argIndex]);
var oldMapType = tsc.SetMapTypeReturnOld(tsc.mapTypeTmp);
var oldDbParams = objExp?.NodeType == ExpressionType.MemberAccess ? tsc.SetDbParamsReturnOld(null) : null; //#900 UseGenerateCommandParameterWithLambda(true) 子查询 bug、以及 #1173 参数化 bug
tsc.isNotSetMapColumnTmp = true;
left = objExp == null ? null : getExp(objExp);
tsc.isNotSetMapColumnTmp = false;
tsc.SetMapColumnTmp(null).SetMapTypeReturnOld(oldMapType);
if (oldDbParams != null) tsc.SetDbParamsReturnOld(oldDbParams);
//判断 in 或 hasAny
if (left.StartsWith("array[") && left.EndsWith("]"))
return $"({args1}) in ({left.Substring(6, left.Length - 7)})";
if (left.StartsWith("(") && left.EndsWith(")")) //在各大 Provider AdoProvider 中已约定500元素分割, 3空格\r\n4空格
return $"(({args1}) in {left.Replace(", \r\n \r\n", $") \r\n OR ({args1}) in (")})";
if (args1.StartsWith("(") && args1.EndsWith(")")) args1 = $"[{args1.TrimStart('(').TrimEnd(')')}]";
else args1 = $"[{args1}]";
return $"(hasAny({left}, {args1}))";
case "Concat":
left = objExp == null ? null : getExp(objExp);
if (left.StartsWith("(") || left.EndsWith(")")) left = $"array[{left.TrimStart('(').TrimEnd(')')}]";
var right2 = getExp(callExp.Arguments[argIndex]);
if (right2.StartsWith("(") || right2.EndsWith(")")) right2 = $"array[{right2.TrimStart('(').TrimEnd(')')}]";
return $"(arrayConcat({left} || {right2}))";
}
}
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(",");
if (a % 500 == 499) arrSb.Append(" \r\n \r\n"); //500元素分割, 3空格\r\n4空格
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 $"char_length({left})";
}
return null;
}
public override string ExpressionLambdaToSqlMemberAccessDateTime(MemberExpression exp, ExpTSC tsc)
{
if (exp.Expression == null)
{
switch (exp.Member.Name)
{
case "Now": return _common.Now;
case "UtcNow": return _common.NowUtc;
case "Today": return "curdate()";
case "MinValue": return "cast('0001/1/1 0:00:00' as DateTime)";
case "MaxValue": return "cast('9999/12/31 23:59:59' as DateTime)";
}
return null;
}
var left = ExpressionLambdaToSql(exp.Expression, tsc);
if ((exp.Expression as MemberExpression)?.Expression.NodeType == ExpressionType.Constant)
left = $"toDateTime({left})";
//IsDate(left);
switch (exp.Member.Name)
{
case "Date": return $"toDate({left})";
case "TimeOfDay": return $"dateDiff(second, toDate({left}), toDateTime({left}))*1000000";
case "DayOfWeek": return $"(toDayOfWeek({left})-1)";
case "Day": return $"toDayOfMonth({left})";
case "DayOfYear": return $"toDayOfYear({left})";
case "Month": return $"toMonth({left})";
case "Year": return $"toYear({left})";
case "Hour": return $"toHour({left})";
case "Minute": return $"toMinute({left})";
case "Second": return $"toSecond({left})";
case "Millisecond": return $"(toSecond({left})/1000)";
case "Ticks": return $"(dateDiff(second, toDate('0001-1-1'), toDateTime({left}))*10000000+621355968000000000)";
}
return null;
}
public bool IsInt(string _string)
{
if (string.IsNullOrEmpty(_string))
return false;
int i = 0;
return int.TryParse(_string, out i);
}
public bool IsDate(string date)
{
if (string.IsNullOrEmpty(date))
return true;
return DateTime.TryParse(date, out var time);
}
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 $"intDiv(({left})/{60 * 60 * 24})";
case "Hours": return $"intDiv(({left})/{60 * 60}%24)";
case "Milliseconds": return $"(cast({left} as Int64)*1000)";
case "Minutes": return $"intDiv(({left})/60%60)";
case "Seconds": return $"(({left})%60)";
case "Ticks": return $"(intDiv({left} as Int64)*10000000)";
case "TotalDays": return $"(({left})/{60 * 60 * 24})";
case "TotalHours": return $"(({left})/{60 * 60})";
case "TotalMilliseconds": return $"(cast({left} as Int64)*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":
var arg1 = getExp(exp.Arguments[0]);
return $"({arg1} is null or {arg1} = '')";
case "IsNullOrWhiteSpace":
var arg2 = getExp(exp.Arguments[0]);
return $"({arg2} is null or {arg2} = '' or ltrim({arg2}) = '')";
case "Concat":
if (exp.Arguments.Count == 1 && exp.Arguments[0].NodeType == ExpressionType.NewArrayInit && exp.Arguments[0] is NewArrayExpression concatNewArrExp)
return _common.StringConcat(concatNewArrExp.Expressions.Select(a => getExp(a)).ToArray(), null);
return _common.StringConcat(exp.Arguments.Select(a => getExp(a)).ToArray(), null);
case "Format":
if (exp.Arguments[0].NodeType != ExpressionType.Constant) throw new Exception(CoreStrings.Not_Implemented_Expression_ParameterUseConstant(exp,exp.Arguments[0]));
if (exp.Arguments.Count == 1) return ExpressionLambdaToSql(exp.Arguments[0], tsc);
var expArgsHack = exp.Arguments.Count == 2 && exp.Arguments[1].NodeType == ExpressionType.NewArrayInit ?
(exp.Arguments[1] as NewArrayExpression).Expressions : exp.Arguments.Where((a, z) => z > 0);
//3个 {} 时Arguments 解析出来是分开的
//4个 {} 时Arguments[1] 只能解析这个出来,然后里面是 NewArray []
var expArgs = expArgsHack.Select(a => $"',{_common.IsNull(ExpressionLambdaToSql(a, tsc), "''")},'").ToArray();
return $"concat({string.Format(ExpressionLambdaToSql(exp.Arguments[0], tsc), expArgs)})";
case "Join":
if (exp.IsStringJoin(out var tolistObjectExp, out var toListMethod, out var toListArgs1))
{
var newToListArgs0 = Expression.Call(tolistObjectExp, toListMethod,
Expression.Lambda(
Expression.Call(
typeof(SqlExtExtensions).GetMethod("StringJoinClickHouseGroupConcat"),
Expression.Convert(toListArgs1.Body, typeof(object)),
Expression.Convert(exp.Arguments[0], typeof(object))),
toListArgs1.Parameters));
var newToListSql = getExp(newToListArgs0);
return newToListSql;
}
break;
}
}
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 $"positionCaseInsensitive({left}, {args0Value}) = 1";
if (exp.Method.Name == "EndsWith") return $"({left}) LIKE {(args0Value.StartsWith("'") ? args0Value.Insert(1, "%") : $"concat('%', {args0Value})")}";
return $"positionCaseInsensitive({left}, {args0Value}) > 0";
case "ToLower": return $"lower({left})";
case "ToUpper": return $"upper({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 $"substr({left}, {substrArgs1})";
return $"substr({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 $"(locate({indexOfFindStr}, {left}, {locateArgs1})-1)";
}
return $"(locate({indexOfFindStr}, {left})-1)";
case "PadLeft":
if (exp.Arguments.Count == 1) return $"lpad({left}, {getExp(exp.Arguments[0])})";
return $"lpad({left}, {getExp(exp.Arguments[0])}, {getExp(exp.Arguments[1])})";
case "PadRight":
if (exp.Arguments.Count == 1) return $"rpad({left}, {getExp(exp.Arguments[0])})";
return $"rpad({left}, {getExp(exp.Arguments[0])}, {getExp(exp.Arguments[1])})";
case "Trim":
case "TrimStart":
case "TrimEnd":
if (exp.Arguments.Count == 0)
{
if (exp.Method.Name == "Trim") return $"trim({left})";
if (exp.Method.Name == "TrimStart") return $"ltrim({left})";
if (exp.Method.Name == "TrimEnd") return $"rtrim({left})";
}
foreach (var argsTrim02 in exp.Arguments)
{
var argsTrim01s = new[] { argsTrim02 };
if (argsTrim02.NodeType == ExpressionType.NewArrayInit)
{
var arritem = argsTrim02 as NewArrayExpression;
argsTrim01s = arritem.Expressions.ToArray();
}
foreach (var argsTrim01 in argsTrim01s)
{
if (exp.Method.Name == "Trim") left = $"trim({getExp(argsTrim01)} from {left})";
if (exp.Method.Name == "TrimStart") left = $"trim(leading {getExp(argsTrim01)} from {left})";
if (exp.Method.Name == "TrimEnd") left = $"trim(trailing {getExp(argsTrim01)} from {left})";
}
}
return left;
case "Replace": return $"replace({left}, {getExp(exp.Arguments[0])}, {getExp(exp.Arguments[1])})";
case "CompareTo": return $"strcmp({left}, {getExp(exp.Arguments[0])})";
case "Equals": return $"({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 $"abs({getExp(exp.Arguments[0])})";
case "Sign": return $"sign({getExp(exp.Arguments[0])})";
case "Floor": return $"floor({getExp(exp.Arguments[0])})";
case "Ceiling": return $"ceiling({getExp(exp.Arguments[0])})";
case "Round":
if (exp.Arguments.Count > 1 && exp.Arguments[1].Type.FullName == "System.Int32") return $"round({getExp(exp.Arguments[0])}, {getExp(exp.Arguments[1])})";
return $"round({getExp(exp.Arguments[0])})";
case "Exp": return $"exp({getExp(exp.Arguments[0])})";
case "Log": return $"log({getExp(exp.Arguments[0])})";
case "Log10": return $"log10({getExp(exp.Arguments[0])})";
case "Pow": return $"pow({getExp(exp.Arguments[0])}, {getExp(exp.Arguments[1])})";
case "Sqrt": return $"sqrt({getExp(exp.Arguments[0])})";
case "Cos": return $"cos({getExp(exp.Arguments[0])})";
case "Sin": return $"sin({getExp(exp.Arguments[0])})";
case "Tan": return $"tan({getExp(exp.Arguments[0])})";
case "Acos": return $"acos({getExp(exp.Arguments[0])})";
case "Asin": return $"asin({getExp(exp.Arguments[0])})";
case "Atan": return $"atan({getExp(exp.Arguments[0])})";
case "Atan2": return $"atan2({getExp(exp.Arguments[0])}, {getExp(exp.Arguments[1])})";
case "Truncate": return $"truncate({getExp(exp.Arguments[0])}, 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 $"({getExp(exp.Arguments[0])} - ({getExp(exp.Arguments[1])}))";
case "DaysInMonth": return $"toDayOfMonth(subtractDays(addMonths(toStartOfMonth(concat({getExp(exp.Arguments[0])}, '-', {getExp(exp.Arguments[1])}, '-01')), 1), 1))";
case "Equals": return $"({getExp(exp.Arguments[0])} = {getExp(exp.Arguments[1])})";
case "IsLeapYear":
var isLeapYearArgs1 = getExp(exp.Arguments[0]);
return $"(({isLeapYearArgs1})%4=0 AND ({isLeapYearArgs1})%100<>0 OR ({isLeapYearArgs1})%400=0)";
case "Parse": return ExpressionConstDateTime(exp.Arguments[0]) ?? $"cast({getExp(exp.Arguments[0])} as DateTime)";
case "ParseExact":
case "TryParse":
case "TryParseExact": return ExpressionConstDateTime(exp.Arguments[0]) ?? $"cast({getExp(exp.Arguments[0])} as DateTime)";
}
}
else
{
var left = getExp(exp.Object);
var args1 = exp.Arguments.Count == 0 ? null : getExp(exp.Arguments[0]);
switch (exp.Method.Name)
{
case "Add": return $"addSeconds(toDateTime({left}), {args1})";
case "AddDays": return $"addDays(toDateTime({left}), {args1})";
case "AddHours": return $"addHours(toDateTime({left}), {args1})";
case "AddMilliseconds": return $"addSeconds(toDateTime({left}), {args1}/1000)";
case "AddMinutes": return $"addMinutes(toDateTime({left}),{args1})";
case "AddMonths": return $"addMonths(toDateTime({left}),{args1})";
case "AddSeconds": return $"addSeconds(toDateTime({left}),{args1})";
case "AddTicks": return $"addSeconds(toDateTime({left}), {args1}/10000000)";
case "AddYears": return $"addYears(toDateTime({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 $"dateDiff(second, {args1}, toDateTime({left}))";
case "System.TimeSpan": return $"addSeconds(toDateTime({left}),(({args1})*-1))";
}
break;
case "Equals": return $"({left} = {args1})";
case "CompareTo": return $"dateDiff(second,{args1},toDateTime({left}))";
case "ToString":
if (exp.Arguments.Count == 0) return $"date_format({left},'%Y-%m-%d %H:%M:%S.%f')";
switch (args1)
{
case "'yyyy-MM-dd HH:mm:ss'": return $"formatDateTime(toDateTime({left}),'%Y-%m-%d %H:%M:%S')";
case "'yyyy-MM-dd HH:mm'": return $"formatDateTime(toDateTime({left}),'%Y-%m-%d %H:%M')";
case "'yyyy-MM-dd HH'": return $"formatDateTime(toDateTime({left}),'%Y-%m-%d %H')";
case "'yyyy-MM-dd'": return $"formatDateTime(toDateTime({left}),'%Y-%m-%d')";
case "'yyyy-MM'": return $"formatDateTime(toDateTime({left}),'%Y-%m')";
case "'yyyyMMddHHmmss'": return $"formatDateTime(toDateTime({left}),'%Y%m%d%H%M%S')";
case "'yyyyMMddHHmm'": return $"formatDateTime(toDateTime({left}),'%Y%m%d%H%M')";
case "'yyyyMMddHH'": return $"formatDateTime(toDateTime({left}),'%Y%m%d%H')";
case "'yyyyMMdd'": return $"formatDateTime(toDateTime({left}),'%Y%m%d')";
case "'yyyyMM'": return $"formatDateTime(toDateTime({left}),'%Y%m')";
case "'yyyy'": return $"formatDateTime(toDateTime({left}),'%Y')";
case "'HH:mm:ss'": return $"formatDateTime(toDateTime({left}),'%H:%M:%S')";
}
args1 = Regex.Replace(args1, "(yyyy|yy|MM|M|dd|d|HH|H|hh|h|mm|ss|tt)", m =>
{
switch (m.Groups[1].Value)
{
case "yyyy": return $"%Y";
case "yy": return $"%y";
case "MM": return $"%_a1";
case "M": return $"%c";
case "dd": return $"%d";
case "d": return $"%e";
case "HH": return $"%H";
case "H": return $"%k";
case "hh": return $"%h";
case "h": return $"%l";
case "mm": return $"%i";
case "ss": return $"%_a2";
case "tt": return $"%p";
}
return m.Groups[0].Value;
});
var argsFinds = new[] { "%Y", "%y", "%_a1", "%c", "%d", "%e", "%H", "%k", "%h", "%l", "%M", "%_a2", "%p" };
var argsSpts = Regex.Split(args1, "(m|s|t)");
for (var a = 0; a < argsSpts.Length; a++)
{
switch (argsSpts[a])
{
case "m": argsSpts[a] = $"case when substr(formatDateTime(toDateTime({left}),'%M'),1,1) = '0' then substr(formatDateTime(toDateTime({left}),'%M'),2,1) else formatDateTime(toDateTime({left}),'%M') end"; break;
case "s": argsSpts[a] = $"case when substr(formatDateTime(toDateTime({left}),'%S'),1,1) = '0' then substr(formatDateTime(toDateTime({left}),'%S'),2,1) else formatDateTime(toDateTime({left}),'%S') end"; break;
case "t": argsSpts[a] = $"trim(trailing 'M' from formatDateTime(toDateTime({left}),'%p'))"; break;
default:
var argsSptsA = argsSpts[a];
if (argsSptsA.StartsWith("'")) argsSptsA = argsSptsA.Substring(1);
if (argsSptsA.EndsWith("'")) argsSptsA = argsSptsA.Remove(argsSptsA.Length - 1);
argsSpts[a] = argsFinds.Any(m => argsSptsA.Contains(m)) ? $"formatDateTime(toDateTime({left}),'{argsSptsA}')" : $"'{argsSptsA}'";
break;
}
}
if (argsSpts.Length > 0) args1 = $"concat({string.Join(", ", argsSpts.Where(a => a != "''"))})";
return args1.Replace("%_a1", "%m").Replace("%_a2", "%S");
}
}
return null;
}
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])})*{(long)1000000 * 60 * 60 * 24})";
case "FromHours": return $"(({getExp(exp.Arguments[0])})*{(long)1000000 * 60 * 60})";
case "FromMilliseconds": return $"(({getExp(exp.Arguments[0])})*1000)";
case "FromMinutes": return $"(({getExp(exp.Arguments[0])})*{(long)1000000 * 60})";
case "FromSeconds": return $"(({getExp(exp.Arguments[0])})*1000000)";
case "FromTicks": return $"(({getExp(exp.Arguments[0])})/10)";
case "Parse": return $"cast({getExp(exp.Arguments[0])} as Int64)";
case "ParseExact":
case "TryParse":
case "TryParseExact": return $"cast({getExp(exp.Arguments[0])} as Int64)";
}
}
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 $"cast({left} as String)";
}
}
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 $"({getExp(exp.Arguments[0])} not in ('0','false'))";
case "ToByte": return $"cast({getExp(exp.Arguments[0])} as Int8)";
case "ToChar": return $"substr(cast({getExp(exp.Arguments[0])} as String), 1, 1)";
case "ToDateTime": return ExpressionConstDateTime(exp.Arguments[0]) ?? $"cast({getExp(exp.Arguments[0])} as DateTime)";
case "ToDecimal": return $"cast({getExp(exp.Arguments[0])} as Decimal128(19))";
case "ToDouble": return $"cast({getExp(exp.Arguments[0])} as Float64)";
case "ToInt16": return $"cast({getExp(exp.Arguments[0])} as Int16)";
case "ToInt32": return $"cast({getExp(exp.Arguments[0])} as Int32)";
case "ToInt64": return $"cast({getExp(exp.Arguments[0])} as Int64)";
case "ToSByte": return $"cast({getExp(exp.Arguments[0])} as UInt8)";
case "ToSingle": return $"cast({getExp(exp.Arguments[0])} as Float32)";
case "ToString": return $"cast({getExp(exp.Arguments[0])} as String)";
case "ToUInt16": return $"cast({getExp(exp.Arguments[0])} as UInt16)";
case "ToUInt32": return $"cast({getExp(exp.Arguments[0])} as UInt32)";
case "ToUInt64": return $"cast({getExp(exp.Arguments[0])} as UInt64)";
}
}
return null;
}
}
}

View File

@ -0,0 +1,94 @@
using FreeSql;
using FreeSql.ClickHouse.Curd;
using FreeSql.Internal.CommonProvider;
using System;
using System.Collections.Generic;
using System.Linq.Expressions;
using System.Threading;
using System.Threading.Tasks;
using FreeSql.DataAnnotations;
public static partial class FreeSqlClickHouseGlobalExtensions
{
/// <summary>
/// 特殊处理类似 string.Format 的使用方法,防止注入,以及 IS NULL 转换
/// </summary>
/// <param name="that"></param>
/// <param name="args"></param>
/// <returns></returns>
public static string FormatClickHouse(this string that, params object[] args) =>
_clickHouseAdo.Addslashes(that, args);
static FreeSql.ClickHouse.ClickHouseAdo _clickHouseAdo = new FreeSql.ClickHouse.ClickHouseAdo();
/// <summary>
/// Clickhouse limit by
/// </summary>
public static ISelect<T> LimitBy<T>(this ISelect<T> that, Expression<Func<T, object>> selector, int limit,
int offset = 0)
{
if (limit <= 0 && offset <= 0) return that;
var s0p = that as ClickHouseSelect<T>;
var oldOrderBy = s0p._orderby;
s0p._orderby = "";
try
{
s0p.InternalOrderBy(selector);
s0p._limitBy = $"LIMIT {(offset > 0 ? $"{offset}, " : "")}{limit} BY {s0p._orderby}";
}
finally
{
s0p._orderby = oldOrderBy;
}
return that;
}
/// <summary>
/// Clickhouse 采样子句
/// </summary>
public static ISelect<T> Sample<T>(this ISelect<T> that, decimal k, int n, decimal m)
{
var s0p = that as ClickHouseSelect<T>;
if (k > 0)
if (m > 0)
s0p._sample = $"SAMPLE {k} OFFSET {m}";
else
s0p._sample = $"SAMPLE {k}";
else if (n > 0)
s0p._sample = $"SAMPLE {k}";
return that;
}
/// <summary>
/// 批量快速插入
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="that"></param>
/// <returns></returns>
public static async Task<int> ExecuteClickHouseBulkCopyAsync<T>(this IInsert<T> that) where T : class
{
try
{
var insert = that as ClickHouseInsert<T>;
await insert.InternalBulkCopyAsync();
}
catch (Exception e)
{
throw e;
}
return 0;
}
/// <summary>
/// 批量快速插入
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="insert"></param>
/// <returns></returns>
public static int ExecuteClickHouseBulkCopy<T>(this IInsert<T> insert) where T : class
{
return ExecuteClickHouseBulkCopyAsync(insert).ConfigureAwait(false).GetAwaiter().GetResult();
}
}

View File

@ -0,0 +1,42 @@
using FreeSql.Internal;
using FreeSql.Internal.CommonProvider;
using FreeSql.ClickHouse.Curd;
using System;
using System.Data.Common;
using System.Linq.Expressions;
using System.Threading;
namespace FreeSql.ClickHouse
{
public class ClickHouseProvider<TMark> : BaseDbProvider, IFreeSql<TMark>
{
public override ISelect<T1> CreateSelectProvider<T1>(object dywhere) => new ClickHouseSelect<T1>(this, this.InternalCommonUtils, this.InternalCommonExpression, dywhere);
public override IInsert<T1> CreateInsertProvider<T1>() => new ClickHouseInsert<T1>(this, this.InternalCommonUtils, this.InternalCommonExpression);
public override IUpdate<T1> CreateUpdateProvider<T1>(object dywhere) => new ClickHouseUpdate<T1>(this, this.InternalCommonUtils, this.InternalCommonExpression, dywhere);
public override IDelete<T1> CreateDeleteProvider<T1>(object dywhere) => new ClickHouseDelete<T1>(this, this.InternalCommonUtils, this.InternalCommonExpression, dywhere);
public override IInsertOrUpdate<T1> CreateInsertOrUpdateProvider<T1>()
{
throw new NotImplementedException();
}
public ClickHouseProvider(string masterConnectionString, string[] slaveConnectionString, Func<DbConnection> connectionFactory = null)
{
this.InternalCommonUtils = new ClickHouseUtils(this);
this.InternalCommonExpression = new ClickHouseExpression(this.InternalCommonUtils);
this.Ado = new ClickHouseAdo(this.InternalCommonUtils, masterConnectionString, slaveConnectionString, connectionFactory);
this.Aop = new AopProvider();
this.DbFirst = new ClickHouseDbFirst(this, this.InternalCommonUtils, this.InternalCommonExpression);
this.CodeFirst = new ClickHouseCodeFirst(this, this.InternalCommonUtils, this.InternalCommonExpression);
}
~ClickHouseProvider() => this.Dispose();
int _disposeCounter;
public override void Dispose()
{
if (Interlocked.Increment(ref _disposeCounter) != 1) return;
(this.Ado as AdoProvider)?.Dispose();
}
}
}

View File

@ -0,0 +1,179 @@
using FreeSql.Internal;
using FreeSql.Internal.Model;
using ClickHouse.Client.ADO;
using System;
using System.Collections.Generic;
using System.Data.Common;
using System.Globalization;
using System.Data;
using System.Text.Json;
using ClickHouse.Client.ADO.Parameters;
using System.Text.RegularExpressions;
using System.Text;
namespace FreeSql.ClickHouse
{
internal class ClickHouseUtils : CommonUtils
{
public ClickHouseUtils(IFreeSql orm) : base(orm)
{
}
public override DbParameter AppendParamter(List<DbParameter> _params, string parameterName, ColumnInfo col, Type type, object value)
{
if (value is string str)
value = str?.Replace("\t", "\\t")
.Replace("\r\n", "\\r\\n")
.Replace("\n", "\\n")
.Replace("\r", "\\r")
.Replace("/", "\\/");
if (string.IsNullOrEmpty(parameterName)) parameterName = $"p_{_params?.Count}";
var dbtype = (DbType?)_orm.CodeFirst.GetDbInfo(type)?.type;
DbParameter ret = new ClickHouseDbParameter { ParameterName = parameterName };//QuoteParamterName(parameterName)
if (dbtype != null) ret.DbType = dbtype.Value;
ret.Value = value;
if (col != null)
{
var dbtype2 = (DbType)_orm.DbFirst.GetDbType(new DatabaseModel.DbColumnInfo { DbTypeText = col.DbTypeText, DbTypeTextFull = col.Attribute.DbType, MaxLength = col.DbSize });
switch (dbtype2)
{
case DbType.Binary:
default:
dbtype = dbtype2;
//if (col.DbSize != 0) ret.Size = col.DbSize;
if (col.DbPrecision != 0) ret.Precision = col.DbPrecision;
if (col.DbScale != 0) ret.Scale = col.DbScale;
break;
}
//if (value.GetType().IsArray)
//{
// ret.DbType = DbType.Object;
//}
}
_params?.Add(ret);
return ret;
}
public override DbParameter[] GetDbParamtersByObject(string sql, object obj) =>
Utils.GetDbParamtersByObject<DbParameter>(sql, obj, "@", (name, type, value) =>
{
if (value is string str)
value = str?.Replace("\t", "\\t")
.Replace("\r\n", "\\r\\n")
.Replace("\n", "\\n")
.Replace("\r", "\\r")
.Replace("/", "\\/");
DbParameter ret = new ClickHouseDbParameter { ParameterName = $"@{name}", Value = value };
var tp = _orm.CodeFirst.GetDbInfo(type)?.type;
if (tp != null)
ret.DbType = (DbType)tp.Value;
return ret;
});
public override string RewriteColumn(ColumnInfo col, string sql)
{
if (string.IsNullOrWhiteSpace(col?.Attribute?.DbType)) return sql;
col.Attribute.DbType = col.Attribute.DbType.Replace(" NOT NULL", "");
if (string.IsNullOrWhiteSpace(col?.Attribute.RewriteSql) == false)
return string.Format(col.Attribute.RewriteSql, sql);
if (Regex.IsMatch(sql, @"\{\{[\w\d]+_+\d:\{\d\}\}\}"))
return string.Format(sql, col.Attribute.DbType);
return sql;
}
public override string FormatSql(string sql, params object[] args) => sql?.FormatClickHouse(args);
public override string QuoteSqlNameAdapter(params string[] name)
{
if (name.Length == 1)
{
var nametrim = name[0].Trim();
if (nametrim.StartsWith("(") && nametrim.EndsWith(")"))
return nametrim; //原生SQL
if (nametrim.StartsWith("`") && nametrim.EndsWith("`"))
return nametrim;
return $"`{nametrim.Replace(".", "`.`")}`";
}
return $"`{string.Join("`.`", name)}`";
}
public override string TrimQuoteSqlName(string name)
{
var nametrim = name.Trim();
if (nametrim.StartsWith("(") && nametrim.EndsWith(")"))
return nametrim; //原生SQL
return $"{nametrim.Trim('`').Replace("`.`", ".").Replace(".`", ".")}";
}
public override string[] SplitTableName(string name) => GetSplitTableNames(name, '`', '`', 2);
public override string QuoteParamterName(string name) => $"{{{{{name}:{{0}}}}}}";
public override string IsNull(string sql, object value) => $"ifnull({sql}, {value})";
public override string StringConcat(string[] objs, Type[] types) => $"concat({string.Join(", ", objs)})";
public override string Mod(string left, string right, Type leftType, Type rightType) => $"{left} % {right}";
public override string Div(string left, string right, Type leftType, Type rightType) => $"{left} div {right}";
public override string Now => "now()";
public override string NowUtc => "now('UTC')";
public override string QuoteWriteParamterAdapter(Type type, string paramterName)
{
switch (type.FullName)
{
case "MygisPoint":
case "MygisLineString":
case "MygisPolygon":
case "MygisMultiPoint":
case "MygisMultiLineString":
case "MygisMultiPolygon": return $"ST_GeomFromText({paramterName})";
}
return paramterName;
}
protected override string QuoteReadColumnAdapter(Type type, Type mapType, string columnName)
{
switch (mapType.FullName)
{
case "MygisPoint":
case "MygisLineString":
case "MygisPolygon":
case "MygisMultiPoint":
case "MygisMultiLineString":
case "MygisMultiPolygon": return $"ST_AsText({columnName})";
}
return 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 $"0x{CommonUtils.BytesSqlRaw(value as byte[])}";
if (type == typeof(TimeSpan) || type == typeof(TimeSpan?))
{
var ts = (TimeSpan)value;
value = $"{Math.Floor(ts.TotalHours)}:{ts.Minutes}:{ts.Seconds}";
}
else if (value is Array)
{
var valueArr = value as Array;
var eleType = type.GetElementType();
var len = valueArr.GetLength(0);
var sb = new StringBuilder().Append("[");
for (var a = 0; a < len; a++)
{
var item = valueArr.GetValue(a);
if (a > 0) sb.Append(",");
sb.Append(GetNoneParamaterSqlValue(specialParams, specialParamFlag, col, eleType, item));
}
sb.Append("]");
return sb.ToString();
}
return FormatSql("{0}", value, 1);
}
}
}

View File

@ -0,0 +1,96 @@
using FreeSql.Internal;
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.ClickHouse.Curd
{
class ClickHouseDelete<T1> : Internal.CommonProvider.DeleteProvider<T1>
{
public ClickHouseDelete(IFreeSql orm, CommonUtils commonUtils, CommonExpression commonExpression, object dywhere)
: base(orm, commonUtils, commonExpression, dywhere)
{
}
public override List<T1> ExecuteDeleted() => throw new NotImplementedException($"FreeSql.Provider.ClickHouse {CoreStrings.S_Not_Implemented_Feature}");
public override string ToSql()
{
return ReplaceDeleteSql(base.ToSql());
}
string ReplaceDeleteSql(string sql) => sql?.Replace("DELETE FROM ", "ALTER TABLE ").Replace(" WHERE ", " DELETE WHERE ");
public override int ExecuteAffrows()
{
var affrows = 0;
DbParameter[] dbParms = null;
ToSqlFetch(sb =>
{
if (dbParms == null) dbParms = _params.ToArray();
var sql = ReplaceDeleteSql(sb.ToString());
var before = new Aop.CurdBeforeEventArgs(_table.Type, _table, Aop.CurdType.Delete, sql, dbParms);
_orm.Aop.CurdBeforeHandler?.Invoke(this, before);
Exception exception = null;
try
{
affrows += _orm.Ado.ExecuteNonQuery(_connection, _transaction, CommandType.Text, sql, _commandTimeout, dbParms);
}
catch (Exception ex)
{
exception = ex;
throw;
}
finally
{
var after = new Aop.CurdAfterEventArgs(before, exception, affrows);
_orm.Aop.CurdAfterHandler?.Invoke(this, after);
}
});
if (dbParms != null) this.ClearData();
return affrows;
}
#if net40
#else
public override Task<List<T1>> ExecuteDeletedAsync(CancellationToken cancellationToken = default) => throw new NotImplementedException($"FreeSql.Provider.ClickHouse {CoreStrings.S_Not_Implemented_Feature}");
async public override Task<int> ExecuteAffrowsAsync(CancellationToken cancellationToken = default)
{
var affrows = 0;
DbParameter[] dbParms = null;
await ToSqlFetchAsync(async sb =>
{
if (dbParms == null) dbParms = _params.ToArray();
var sql = ReplaceDeleteSql(sb.ToString());
var before = new Aop.CurdBeforeEventArgs(_table.Type, _table, Aop.CurdType.Delete, sql, dbParms);
_orm.Aop.CurdBeforeHandler?.Invoke(this, before);
Exception exception = null;
try
{
affrows += await _orm.Ado.ExecuteNonQueryAsync(_connection, _transaction, CommandType.Text, sql, _commandTimeout, dbParms, cancellationToken);
}
catch (Exception ex)
{
exception = ex;
throw;
}
finally
{
var after = new Aop.CurdAfterEventArgs(before, exception, affrows);
_orm.Aop.CurdAfterHandler?.Invoke(this, after);
}
});
if (dbParms != null) this.ClearData();
return affrows;
}
#endif
}
}

View File

@ -0,0 +1,448 @@
using ClickHouse.Client.ADO;
using ClickHouse.Client.Copy;
using FreeSql.Internal;
using FreeSql.Internal.Model;
using System;
using System.Collections.Generic;
using System.Data;
using System.Data.Common;
using System.Diagnostics;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
namespace FreeSql.ClickHouse.Curd
{
class ClickHouseInsert<T1> : Internal.CommonProvider.InsertProvider<T1> where T1 : class
{
public ClickHouseInsert(IFreeSql orm, CommonUtils commonUtils, CommonExpression commonExpression)
: base(orm, commonUtils, commonExpression)
{
}
internal bool InternalIsIgnoreInto = false;
internal IFreeSql InternalOrm => _orm;
internal TableInfo InternalTable => _table;
internal DbParameter[] InternalParams => _params;
internal DbConnection InternalConnection => _connection;
internal DbTransaction InternalTransaction => _transaction;
internal CommonUtils InternalCommonUtils => _commonUtils;
internal CommonExpression InternalCommonExpression => _commonExpression;
internal List<T1> InternalSource => _source;
internal Dictionary<string, bool> InternalIgnore => _ignore;
internal void InternalClearData() => ClearData();
public override int ExecuteAffrows() => SplitExecuteAffrows(_batchValuesLimit > 0 ? _batchValuesLimit : int.MaxValue, _batchParameterLimit > 0 ? _batchParameterLimit : int.MaxValue);
public override long ExecuteIdentity() => SplitExecuteIdentity(_batchValuesLimit > 0 ? _batchValuesLimit : int.MaxValue, _batchParameterLimit > 0 ? _batchParameterLimit : int.MaxValue);
public override List<T1> ExecuteInserted() => SplitExecuteInserted(_batchValuesLimit > 0 ? _batchValuesLimit : int.MaxValue, _batchParameterLimit > 0 ? _batchParameterLimit : int.MaxValue);
public override string ToSql()
{
if (InternalIsIgnoreInto == false) return base.ToSqlValuesOrSelectUnionAll();
var sql = base.ToSqlValuesOrSelectUnionAll();
return $"INSERT IGNORE INTO {sql.Substring(12)}";
}
protected override int RawExecuteAffrows()
{
var affrows = 0;
Exception exception = null;
Aop.CurdBeforeEventArgs before = null;
if (_source.Count > 1)
{
try
{
before = new Aop.CurdBeforeEventArgs(_table.Type, _table, Aop.CurdType.Insert, null, _params);
_orm.Aop.CurdBeforeHandler?.Invoke(this, before);
InternalBulkCopyAsync().ConfigureAwait(false).GetAwaiter().GetResult();
return affrows;
}
catch (Exception ex)
{
exception = ex;
throw ex;
}
finally
{
var after = new Aop.CurdAfterEventArgs(before, exception, affrows);
_orm.Aop.CurdAfterHandler?.Invoke(this, after);
}
}
return base.RawExecuteAffrows();
}
internal async Task<int> InternalBulkCopyAsync()
{
var data = ToDataTable();
using (var conn = _orm.Ado.MasterPool.Get())
{
using (var bulkCopyInterface = new ClickHouseBulkCopy(conn.Value as ClickHouseConnection)
{
DestinationTableName = data.TableName,
BatchSize = _source.Count
})
{
await bulkCopyInterface.InitAsync();
await bulkCopyInterface.WriteToServerAsync(data, default);
}
}
return 0;
}
private IDictionary<string, object> GetValue<T>(T u, System.Reflection.PropertyInfo[] columns)
{
try
{
Dictionary<string, object> dic = new Dictionary<string, object>();
foreach (var item in columns)
{
object v = null;
if (u != null)
{
v = item.GetValue(u);
}
if (dic.ContainsKey(item.Name) == false)
dic.Add(item.Name, v);
}
return dic;
}
catch
{
throw;
}
}
protected override long RawExecuteIdentity()
{
long ret = 0;
var identCols = _table.Columns.Where(a => a.Value.Attribute.IsIdentity == true);
if (identCols.Any()&&_source.Count==1)
ret = (long)identCols.First().Value.GetValue(_source.First());
return ret;
}
protected override List<T1> RawExecuteInserted()
{
var sql = this.ToSql();
if (string.IsNullOrEmpty(sql)) return new List<T1>();
var sb = new StringBuilder();
sb.Append(sql).Append(" RETURNING ");
var colidx = 0;
foreach (var col in _table.Columns.Values)
{
if (colidx > 0) sb.Append(", ");
sb.Append(_commonUtils.RereadColumn(col, _commonUtils.QuoteSqlName(col.Attribute.Name))).Append(" as ").Append(_commonUtils.QuoteSqlName(col.CsName));
++colidx;
}
sql = sb.ToString();
var before = new Aop.CurdBeforeEventArgs(_table.Type, _table, Aop.CurdType.Insert, sql, _params);
_orm.Aop.CurdBeforeHandler?.Invoke(this, before);
var ret = new List<T1>();
Exception exception = null;
try
{
ret = _orm.Ado.Query<T1>(_table.TypeLazy ?? _table.Type, _connection, null, CommandType.Text, sql, _commandTimeout, _params);
}
catch (Exception ex)
{
exception = ex;
throw;
}
finally
{
var after = new Aop.CurdAfterEventArgs(before, exception, ret);
_orm.Aop.CurdAfterHandler?.Invoke(this, after);
}
return ret;
}
#if net40
#else
public override Task<int> ExecuteAffrowsAsync(CancellationToken cancellationToken = default) => SplitExecuteAffrowsAsync(_batchValuesLimit > 0 ? _batchValuesLimit : int.MaxValue, _batchValuesLimit > 0 ? _batchValuesLimit : int.MaxValue, cancellationToken);
public override Task<long> ExecuteIdentityAsync(CancellationToken cancellationToken = default) => SplitExecuteIdentityAsync(_batchValuesLimit > 0 ? _batchValuesLimit : int.MaxValue, _batchValuesLimit > 0 ? _batchValuesLimit : int.MaxValue, cancellationToken);
public override Task<List<T1>> ExecuteInsertedAsync(CancellationToken cancellationToken = default) => SplitExecuteInsertedAsync(_batchValuesLimit > 0 ? _batchValuesLimit : int.MaxValue, _batchValuesLimit > 0 ? _batchValuesLimit : int.MaxValue, cancellationToken);
async protected override Task<int> RawExecuteAffrowsAsync(CancellationToken cancellationToken = default)
{
var affrows = 0;
Exception exception = null;
Aop.CurdBeforeEventArgs before = null;
if (_source.Count > 1)
{
try
{
before = new Aop.CurdBeforeEventArgs(_table.Type, _table, Aop.CurdType.Insert, null, _params);
_orm.Aop.CurdBeforeHandler?.Invoke(this, before);
var data = ToDataTable();
using (var conn = await _orm.Ado.MasterPool.GetAsync())
{
using (var bulkCopyInterface = new ClickHouseBulkCopy(conn.Value as ClickHouseConnection)
{
DestinationTableName = data.TableName,
BatchSize = _source.Count
})
{
await bulkCopyInterface.WriteToServerAsync(data, default);
}
}
return affrows;
}
catch (Exception ex)
{
exception = ex;
throw ex;
}
finally
{
var after = new Aop.CurdAfterEventArgs(before, exception, affrows);
_orm.Aop.CurdAfterHandler?.Invoke(this, after);
}
}
return await base.RawExecuteAffrowsAsync(cancellationToken);
}
async protected override Task<long> RawExecuteIdentityAsync(CancellationToken cancellationToken = default)
{
//var sql = this.ToSql();
//if (string.IsNullOrEmpty(sql)) return 0;
//sql = string.Concat(sql, "; SELECT LAST_INSERT_ID();");
//var before = new Aop.CurdBeforeEventArgs(_table.Type, _table, Aop.CurdType.Insert, sql, _params);
//_orm.Aop.CurdBeforeHandler?.Invoke(this, before);
long ret = 0;
//Exception exception = null;
//try
//{
// ret = long.TryParse(string.Concat(await _orm.Ado.ExecuteScalarAsync(_connection, null, CommandType.Text, sql, _commandTimeout, _params, cancellationToken)), out var trylng) ? trylng : 0;
//}
//catch (Exception ex)
//{
// exception = ex;
// throw;
//}
//finally
//{
// var after = new Aop.CurdAfterEventArgs(before, exception, ret);
// _orm.Aop.CurdAfterHandler?.Invoke(this, after);
//}
return await Task.FromResult(ret);
}
protected override int SplitExecuteAffrows(int valuesLimit, int parameterLimit)
{
var ss = SplitSource(valuesLimit, parameterLimit);
var ret = 0;
if (ss.Any() == false)
{
ClearData();
return ret;
}
if (ss.Length == 1)
{
_batchProgress?.Invoke(new BatchProgressStatus<T1>(_source, 1, 1));
ret = this.RawExecuteAffrows();
ClearData();
return ret;
}
var before = new Aop.TraceBeforeEventArgs("SplitExecuteAffrows", null);
_orm.Aop.TraceBeforeHandler?.Invoke(this, before);
Exception exception = null;
try
{
for (var a = 0; a < ss.Length; a++)
{
_source = ss[a];
_batchProgress?.Invoke(new BatchProgressStatus<T1>(_source, a + 1, ss.Length));
ret += this.RawExecuteAffrows();
}
}
catch (Exception ex)
{
exception = ex;
throw;
}
finally
{
var after = new Aop.TraceAfterEventArgs(before, null, exception);
_orm.Aop.TraceAfterHandler?.Invoke(this, after);
}
ClearData();
return ret;
}
async protected override Task<int> SplitExecuteAffrowsAsync(int valuesLimit, int parameterLimit, CancellationToken cancellationToken = default)
{
var ss = SplitSource(valuesLimit, parameterLimit);
var ret = 0;
if (ss.Any() == false)
{
ClearData();
return ret;
}
if (ss.Length == 1)
{
_batchProgress?.Invoke(new BatchProgressStatus<T1>(_source, 1, 1));
await this.RawExecuteAffrowsAsync(cancellationToken);
ret = _source.Count;
ClearData();
return ret;
}
var before = new Aop.TraceBeforeEventArgs("SplitExecuteAffrowsAsync", null);
_orm.Aop.TraceBeforeHandler?.Invoke(this, before);
Exception exception = null;
try
{
for (var a = 0; a < ss.Length; a++)
{
_source = ss[a];
_batchProgress?.Invoke(new BatchProgressStatus<T1>(_source, a + 1, ss.Length));
await this.RawExecuteAffrowsAsync(cancellationToken);
ret += _source.Count;
}
}
catch (Exception ex)
{
exception = ex;
throw;
}
finally
{
var after = new Aop.TraceAfterEventArgs(before, null, exception);
_orm.Aop.TraceAfterHandler?.Invoke(this, after);
}
ClearData();
return ret;
}
async protected override Task<long> SplitExecuteIdentityAsync(int valuesLimit, int parameterLimit, CancellationToken cancellationToken = default)
{
var ss = SplitSource(valuesLimit, parameterLimit);
long ret = 0;
if (ss.Any() == false)
{
ClearData();
return ret;
}
if (ss.Length == 1)
{
_batchProgress?.Invoke(new BatchProgressStatus<T1>(_source, 1, 1));
ret = await this.RawExecuteIdentityAsync(cancellationToken);
ClearData();
return ret;
}
var before = new Aop.TraceBeforeEventArgs("SplitExecuteIdentityAsync", null);
_orm.Aop.TraceBeforeHandler?.Invoke(this, before);
Exception exception = null;
try
{
for (var a = 0; a < ss.Length; a++)
{
_source = ss[a];
_batchProgress?.Invoke(new BatchProgressStatus<T1>(_source, a + 1, ss.Length));
if (a < ss.Length - 1) await this.RawExecuteAffrowsAsync(cancellationToken);
else ret = await this.RawExecuteIdentityAsync(cancellationToken);
}
}
catch (Exception ex)
{
exception = ex;
throw;
}
finally
{
var after = new Aop.TraceAfterEventArgs(before, null, exception);
_orm.Aop.TraceAfterHandler?.Invoke(this, after);
}
ClearData();
return ret;
}
async protected override Task<List<T1>> SplitExecuteInsertedAsync(int valuesLimit, int parameterLimit, CancellationToken cancellationToken = default)
{
var ss = SplitSource(valuesLimit, parameterLimit);
var ret = new List<T1>();
if (ss.Any() == false)
{
ClearData();
return ret;
}
if (ss.Length == 1)
{
_batchProgress?.Invoke(new BatchProgressStatus<T1>(_source, 1, 1));
ret = await this.RawExecuteInsertedAsync(cancellationToken);
ClearData();
return ret;
}
var before = new Aop.TraceBeforeEventArgs("SplitExecuteInsertedAsync", null);
_orm.Aop.TraceBeforeHandler?.Invoke(this, before);
Exception exception = null;
try
{
for (var a = 0; a < ss.Length; a++)
{
_source = ss[a];
_batchProgress?.Invoke(new BatchProgressStatus<T1>(_source, a + 1, ss.Length));
ret.AddRange(await this.RawExecuteInsertedAsync(cancellationToken));
}
}
catch (Exception ex)
{
exception = ex;
throw;
}
finally
{
var after = new Aop.TraceAfterEventArgs(before, null, exception);
_orm.Aop.TraceAfterHandler?.Invoke(this, after);
}
ClearData();
return ret;
}
async protected override Task<List<T1>> RawExecuteInsertedAsync(CancellationToken cancellationToken = default)
{
var sql = this.ToSql();
if (string.IsNullOrEmpty(sql)) return new List<T1>();
var sb = new StringBuilder();
sb.Append(sql).Append(" RETURNING ");
var colidx = 0;
foreach (var col in _table.Columns.Values)
{
if (colidx > 0) sb.Append(", ");
sb.Append(_commonUtils.RereadColumn(col, _commonUtils.QuoteSqlName(col.Attribute.Name))).Append(" as ").Append(_commonUtils.QuoteSqlName(col.CsName));
++colidx;
}
sql = sb.ToString();
var before = new Aop.CurdBeforeEventArgs(_table.Type, _table, Aop.CurdType.Insert, sql, _params);
_orm.Aop.CurdBeforeHandler?.Invoke(this, before);
var ret = new List<T1>();
Exception exception = null;
try
{
ret = await _orm.Ado.QueryAsync<T1>(_table.TypeLazy ?? _table.Type, _connection, null, CommandType.Text, sql, _commandTimeout, _params, cancellationToken);
}
catch (Exception ex)
{
exception = ex;
throw;
}
finally
{
var after = new Aop.CurdAfterEventArgs(before, exception, ret);
_orm.Aop.CurdAfterHandler?.Invoke(this, after);
}
return ret;
}
#endif
}
}

View File

@ -0,0 +1,227 @@
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.ClickHouse.Curd
{
class ClickHouseSelect<T1> : FreeSql.Internal.CommonProvider.Select1Provider<T1>
{
public string _limitBy = "";
public string _sample = "";
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,
string _limitBy = "", string _sample = "")
{
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.Where(a => a.Before == false), true);
tb.CascadeBefore = _commonExpression.GetWhereCascadeSql(tb, _whereGlobalFilter.Where(a => a.Before == true), 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 ");
sb.Append(field).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\nGLOBAL LEFT 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) &&
string.IsNullOrEmpty(tbsfrom[b].CascadeBefore)) sb.Append(" ON 1 = 1");
else sb.Append(" ON ").Append(string.Join(" AND ", new[]
{
tbsfrom[b].CascadeBefore,
tbsfrom[b].NavigateCondition ?? tbsfrom[b].On,
tbsfrom[b].Cascade
}.Where(sql => string.IsNullOrEmpty(sql) == false)));
}
break;
}
else
{
if (a > 0 && !string.IsNullOrEmpty(tbsfrom[a].CascadeBefore)) sbnav.Append(" AND ").Append(tbsfrom[a].CascadeBefore);
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(", ");
}
if (string.IsNullOrEmpty(_sample) == false)
sb.Append(" \r\n").Append(_sample);
foreach (var tb in tbsjoin)
{
switch (tb.Type)
{
case SelectTableInfoType.Parent:
case SelectTableInfoType.RawJoin:
continue;
case SelectTableInfoType.LeftJoin:
sb.Append(" \r\nGLOBAL LEFT JOIN ");
break;
case SelectTableInfoType.InnerJoin:
sb.Append(" \r\nGLOBAL INNER JOIN ");
break;
case SelectTableInfoType.RightJoin:
sb.Append(" \r\nGLOBAL RIGHT JOIN ");
break;
}
sb.Append(_commonUtils.QuoteSqlName(tbUnion[tb.Table.Type])).Append(" ").Append(_aliasRule?.Invoke(tb.Table.Type, tb.Alias) ?? tb.Alias)
.Append(" ON ").Append(string.Join(" AND ", new[]
{
tb.CascadeBefore,
tb.On ?? tb.NavigateCondition,
tb.Cascade
}.Where(sql => string.IsNullOrEmpty(sql) == false)));
if (!string.IsNullOrEmpty(tb.On) && !string.IsNullOrEmpty(tb.NavigateCondition)) sbnav.Append(" AND (").Append(tb.NavigateCondition).Append(")");
}
if (_join.Length > 0) sb.Append(_join);
if (!string.IsNullOrEmpty(_tables[0].CascadeBefore)) sbnav.Append(" AND ").Append(_tables[0].CascadeBefore);
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 (string.IsNullOrEmpty(_limitBy) == false)
sb.Append(" \r\n").Append(_limitBy);
if (_skip > 0 || _limit > 0)
sb.Append(" \r\nLIMIT ").Append(Math.Max(0, _skip)).Append(",").Append(_limit > 0 ? _limit : -1);
sbnav.Clear();
if (tbUnionsGt0) sb.Append(") ftb");
}
return sb.Append(_tosqlAppendContent).ToString();
}
public ClickHouseSelect(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 ClickHouseSelect<T1, T2>(_orm, _commonUtils, _commonExpression, null); ClickHouseSelect<T1>.CopyData(this, 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 ClickHouseSelect<T1, T2, T3>(_orm, _commonUtils, _commonExpression, null); ClickHouseSelect<T1>.CopyData(this, 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 ClickHouseSelect<T1, T2, T3, T4>(_orm, _commonUtils, _commonExpression, null); ClickHouseSelect<T1>.CopyData(this, 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 ClickHouseSelect<T1, T2, T3, T4, T5>(_orm, _commonUtils, _commonExpression, null); ClickHouseSelect<T1>.CopyData(this, 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 ClickHouseSelect<T1, T2, T3, T4, T5, T6>(_orm, _commonUtils, _commonExpression, null); ClickHouseSelect<T1>.CopyData(this, 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 ClickHouseSelect<T1, T2, T3, T4, T5, T6, T7>(_orm, _commonUtils, _commonExpression, null); ClickHouseSelect<T1>.CopyData(this, 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 ClickHouseSelect<T1, T2, T3, T4, T5, T6, T7, T8>(_orm, _commonUtils, _commonExpression, null); ClickHouseSelect<T1>.CopyData(this, 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 ClickHouseSelect<T1, T2, T3, T4, T5, T6, T7, T8, T9>(_orm, _commonUtils, _commonExpression, null); ClickHouseSelect<T1>.CopyData(this, 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 ClickHouseSelect<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10>(_orm, _commonUtils, _commonExpression, null); ClickHouseSelect<T1>.CopyData(this, 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 ClickHouseSelect<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11>(_orm, _commonUtils, _commonExpression, null); ClickHouseSelect<T1>.CopyData(this, 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 ClickHouseSelect<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12>(_orm, _commonUtils, _commonExpression, null); ClickHouseSelect<T1>.CopyData(this, 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 ClickHouseSelect<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13>(_orm, _commonUtils, _commonExpression, null); ClickHouseSelect<T1>.CopyData(this, 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 ClickHouseSelect<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14>(_orm, _commonUtils, _commonExpression, null); ClickHouseSelect<T1>.CopyData(this, 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 ClickHouseSelect<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15>(_orm, _commonUtils, _commonExpression, null); ClickHouseSelect<T1>.CopyData(this, 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 ClickHouseSelect<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15, T16>(_orm, _commonUtils, _commonExpression, null); ClickHouseSelect<T1>.CopyData(this, 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, _limitBy);
}
class ClickHouseSelect<T1, T2> : FreeSql.Internal.CommonProvider.Select2Provider<T1, T2> where T2 : class
{
public ClickHouseSelect(IFreeSql orm, CommonUtils commonUtils, CommonExpression commonExpression, object dywhere) : base(orm, commonUtils, commonExpression, dywhere) { }
public override string ToSql(string field = null) => ClickHouseSelect<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 ClickHouseSelect<T1, T2, T3> : FreeSql.Internal.CommonProvider.Select3Provider<T1, T2, T3> where T2 : class where T3 : class
{
public ClickHouseSelect(IFreeSql orm, CommonUtils commonUtils, CommonExpression commonExpression, object dywhere) : base(orm, commonUtils, commonExpression, dywhere) { }
public override string ToSql(string field = null) => ClickHouseSelect<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 ClickHouseSelect<T1, T2, T3, T4> : FreeSql.Internal.CommonProvider.Select4Provider<T1, T2, T3, T4> where T2 : class where T3 : class where T4 : class
{
public ClickHouseSelect(IFreeSql orm, CommonUtils commonUtils, CommonExpression commonExpression, object dywhere) : base(orm, commonUtils, commonExpression, dywhere) { }
public override string ToSql(string field = null) => ClickHouseSelect<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 ClickHouseSelect<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 ClickHouseSelect(IFreeSql orm, CommonUtils commonUtils, CommonExpression commonExpression, object dywhere) : base(orm, commonUtils, commonExpression, dywhere) { }
public override string ToSql(string field = null) => ClickHouseSelect<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 ClickHouseSelect<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 ClickHouseSelect(IFreeSql orm, CommonUtils commonUtils, CommonExpression commonExpression, object dywhere) : base(orm, commonUtils, commonExpression, dywhere) { }
public override string ToSql(string field = null) => ClickHouseSelect<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 ClickHouseSelect<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 ClickHouseSelect(IFreeSql orm, CommonUtils commonUtils, CommonExpression commonExpression, object dywhere) : base(orm, commonUtils, commonExpression, dywhere) { }
public override string ToSql(string field = null) => ClickHouseSelect<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 ClickHouseSelect<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 ClickHouseSelect(IFreeSql orm, CommonUtils commonUtils, CommonExpression commonExpression, object dywhere) : base(orm, commonUtils, commonExpression, dywhere) { }
public override string ToSql(string field = null) => ClickHouseSelect<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 ClickHouseSelect<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 ClickHouseSelect(IFreeSql orm, CommonUtils commonUtils, CommonExpression commonExpression, object dywhere) : base(orm, commonUtils, commonExpression, dywhere) { }
public override string ToSql(string field = null) => ClickHouseSelect<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 ClickHouseSelect<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 ClickHouseSelect(IFreeSql orm, CommonUtils commonUtils, CommonExpression commonExpression, object dywhere) : base(orm, commonUtils, commonExpression, dywhere) { }
public override string ToSql(string field = null) => ClickHouseSelect<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 ClickHouseSelect<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 ClickHouseSelect(IFreeSql orm, CommonUtils commonUtils, CommonExpression commonExpression, object dywhere) : base(orm, commonUtils, commonExpression, dywhere) { }
public override string ToSql(string field = null) => ClickHouseSelect<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 ClickHouseSelect<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 ClickHouseSelect(IFreeSql orm, CommonUtils commonUtils, CommonExpression commonExpression, object dywhere) : base(orm, commonUtils, commonExpression, dywhere) { }
public override string ToSql(string field = null) => ClickHouseSelect<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 ClickHouseSelect<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 ClickHouseSelect(IFreeSql orm, CommonUtils commonUtils, CommonExpression commonExpression, object dywhere) : base(orm, commonUtils, commonExpression, dywhere) { }
public override string ToSql(string field = null) => ClickHouseSelect<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 ClickHouseSelect<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 ClickHouseSelect(IFreeSql orm, CommonUtils commonUtils, CommonExpression commonExpression, object dywhere) : base(orm, commonUtils, commonExpression, dywhere) { }
public override string ToSql(string field = null) => ClickHouseSelect<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 ClickHouseSelect<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 ClickHouseSelect(IFreeSql orm, CommonUtils commonUtils, CommonExpression commonExpression, object dywhere) : base(orm, commonUtils, commonExpression, dywhere) { }
public override string ToSql(string field = null) => ClickHouseSelect<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 ClickHouseSelect<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 ClickHouseSelect(IFreeSql orm, CommonUtils commonUtils, CommonExpression commonExpression, object dywhere) : base(orm, commonUtils, commonExpression, dywhere) { }
public override string ToSql(string field = null) => ClickHouseSelect<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,322 @@
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;
using DateTime = System.DateTime;
namespace FreeSql.ClickHouse.Curd
{
class ClickHouseUpdate<T1> : Internal.CommonProvider.UpdateProvider<T1>
{
public ClickHouseUpdate(IFreeSql orm, CommonUtils commonUtils, CommonExpression commonExpression, object dywhere)
: base(orm, commonUtils, commonExpression, dywhere)
{
}
internal StringBuilder InternalSbSet => _set;
internal StringBuilder InternalSbSetIncr => _setIncr;
internal Dictionary<string, bool> InternalIgnore => _ignore;
internal void InternalResetSource(List<T1> source) => _source = source;
internal string InternalWhereCaseSource(string CsName, Func<string, string> thenValue) => WhereCaseSource(CsName, thenValue);
internal void InternalToSqlCaseWhenEnd(StringBuilder sb, ColumnInfo col) => ToSqlCaseWhenEnd(sb, col);
public override int ExecuteAffrows() => SplitExecuteAffrows(_batchRowsLimit > 0 ? _batchRowsLimit : 500, _batchParameterLimit > 0 ? _batchParameterLimit : 3000);
protected override List<TReturn> ExecuteUpdated<TReturn>(IEnumerable<ColumnInfo> columns) => base.SplitExecuteUpdated<TReturn>(_batchRowsLimit > 0 ? _batchRowsLimit : 500, _batchParameterLimit > 0 ? _batchParameterLimit : 3000, columns);
protected override List<TReturn> RawExecuteUpdated<TReturn>(IEnumerable<ColumnInfo> columns) => throw new NotImplementedException($"FreeSql.Provider.ClickHouse {CoreStrings.S_Not_Implemented_Feature}");
protected override void ToSqlCase(StringBuilder caseWhen, ColumnInfo[] primarys)
{
if (primarys.Length == 1)
{
var pk = primarys.First();
caseWhen.Append(_commonUtils.RereadColumn(pk, _commonUtils.QuoteSqlName(pk.Attribute.Name)));
return;
}
caseWhen.Append("CONCAT(");
var pkidx = 0;
foreach (var pk in primarys)
{
if (pkidx > 0) caseWhen.Append(", '+', ");
caseWhen.Append(_commonUtils.RereadColumn(pk, _commonUtils.QuoteSqlName(pk.Attribute.Name)));
++pkidx;
}
caseWhen.Append(")");
}
protected override void ToSqlWhen(StringBuilder sb, ColumnInfo[] primarys, object d)
{
if (primarys.Length == 1)
{
sb.Append(_commonUtils.FormatSql("{0}", primarys[0].GetDbValue(d)));
return;
}
sb.Append("concat(");
var pkidx = 0;
foreach (var pk in primarys)
{
if (pkidx > 0) sb.Append(", '+', ");
sb.Append(_commonUtils.FormatSql("{0}", pk.GetDbValue(d)));
++pkidx;
}
sb.Append(")");
}
public override void ToSqlExtension110(StringBuilder sb, bool isAsTableSplited)
{
if (_where.Length == 0 && _source.Any() == false) return;
if (_source.Any() == false && _set.Length == 0 && _setIncr.Length == 0) return;
if (_table.AsTableImpl != null && isAsTableSplited == false && _source == _sourceOld && _source.Any())
{
var atarr = _source.Select(a => new
{
item = a,
splitKey = _table.AsTableImpl.GetTableNameByColumnValue(_table.AsTableColumn.GetValue(a))
}).GroupBy(a => a.splitKey, a => a.item).ToArray();
if (atarr.Length > 1)
{
var oldSource = _source;
var arrret = new List<List<T1>>();
foreach (var item in atarr)
{
_source = item.ToList();
ToSqlExtension110(sb, true);
sb.Append("\r\n\r\n;\r\n\r\n");
}
_source = oldSource;
if (sb.Length > 0) sb.Remove(sb.Length - 9, 9);
return;
}
}
sb.Append("ALTER TABLE ").Append(_commonUtils.QuoteSqlName(TableRuleInvoke())).Append(" UPDATE ");
if (_set.Length > 0)
{ //指定 set 更新
sb.Append(_set.ToString().Substring(2));
}
else if (_source.Count == 1)
{ //保存 Source
_paramsSource.Clear();
var colidx = 0;
foreach (var col in _table.Columns.Values)
{
if (col.Attribute.IsPrimary) continue;
if (_tempPrimarys.Any(a => a.CsName == col.CsName)) continue;
if (col.Attribute.IsIdentity == false && col.Attribute.IsVersion == false && _ignore.ContainsKey(col.Attribute.Name) == false)
{
if (colidx > 0) sb.Append(", ");
sb.Append(_commonUtils.QuoteSqlName(col.Attribute.Name)).Append(" = ");
if (col.Attribute.CanUpdate && string.IsNullOrEmpty(col.DbUpdateValue) == false)
sb.Append(col.DbUpdateValue);
else
{
var val = col.GetDbValue(_source.First());
var colsql = _noneParameter ? _commonUtils.GetNoneParamaterSqlValue(_paramsSource, "u", col, col.Attribute.MapType, val) :
_commonUtils.QuoteWriteParamterAdapter(col.Attribute.MapType, _commonUtils.QuoteParamterName($"p_{_paramsSource.Count}"));
sb.Append(_commonUtils.RewriteColumn(col, colsql));
if (_noneParameter == false)
_commonUtils.AppendParamter(_paramsSource, null, col, col.Attribute.MapType, val);
}
++colidx;
}
}
if (colidx == 0) return;
}
else if (_source.Count > 1)
{ //批量保存 Source
if (_tempPrimarys.Any() == false) return;
var caseWhen = new StringBuilder();
ToSqlCase(caseWhen, _tempPrimarys);
var cw = $"{caseWhen.ToString()}=";
_paramsSource.Clear();
var colidx = 0;
foreach (var col in _table.Columns.Values)
{
if (col.Attribute.IsPrimary) continue;
if (_tempPrimarys.Any(a => a.CsName == col.CsName)) continue;
if (col.Attribute.IsIdentity == false && col.Attribute.IsVersion == false && _ignore.ContainsKey(col.Attribute.Name) == false)
{
if (colidx > 0) sb.Append(", ");
var columnName = _commonUtils.QuoteSqlName(col.Attribute.Name);
sb.Append(columnName).Append(" = ");
if (col.Attribute.CanUpdate && string.IsNullOrEmpty(col.DbUpdateValue) == false)
sb.Append(col.DbUpdateValue);
else
{
var nulls = 0;
var cwsb = new StringBuilder().Append(" multiIf( ");
foreach (var d in _source)
{
cwsb.Append(cw);
ToSqlWhen(cwsb, _tempPrimarys, d);
cwsb.Append(",");
var val = col.GetDbValue(d);
var colsql = _noneParameter ? _commonUtils.GetNoneParamaterSqlValue(_paramsSource, "u", col, col.Attribute.MapType, val) :
_commonUtils.QuoteWriteParamterAdapter(col.Attribute.MapType, _commonUtils.QuoteParamterName($"p_{_paramsSource.Count}"));
//判断是否是DateTime类型如果是DateTime类型需要转换成ClickHouse支持的时间格式 #1813
if (col.Attribute.MapType == typeof(DateTime) || col.Attribute.MapType == typeof(DateTime?) )
{
//获取当前实时区
colsql = $"toDateTime({colsql},'Asia/Shanghai')";
}
cwsb.Append(_commonUtils.RewriteColumn(col, colsql));
if (_noneParameter == false)
_commonUtils.AppendParamter(_paramsSource, null, col, col.Attribute.MapType, val);
if (val == null || val == DBNull.Value) nulls++;
cwsb.Append(", ");
}
if (nulls == _source.Count) sb.Append("NULL");
else
{
cwsb.Append(columnName).Append(" )");
ToSqlCaseWhenEnd(cwsb, col);
sb.Append(cwsb);
}
cwsb.Clear();
}
++colidx;
}
}
if (colidx == 0) return;
}
else if (_setIncr.Length == 0)
return;
if (_setIncr.Length > 0)
sb.Append(_set.Length > 0 || _source.Any() ? _setIncr.ToString() : _setIncr.ToString().Substring(2));
if (_source.Any() == false)
{
var sbString = "";
foreach (var col in _table.Columns.Values)
if (col.Attribute.CanUpdate && string.IsNullOrEmpty(col.DbUpdateValue) == false)
{
if (sbString == "") sbString = sb.ToString();
var loc3 = _commonUtils.QuoteSqlName(col.Attribute.Name);
if (sbString.Contains(loc3)) continue;
sb.Append(", ").Append(loc3).Append(" = ").Append(col.DbUpdateValue);
}
}
if (_table.VersionColumn != null)
{
var vcname = _commonUtils.QuoteSqlName(_table.VersionColumn.Attribute.Name);
if (_table.VersionColumn.Attribute.MapType == typeof(byte[]))
{
_updateVersionValue = Utils.GuidToBytes(Guid.NewGuid());
sb.Append(", ").Append(vcname).Append(" = ").Append(_commonUtils.GetNoneParamaterSqlValue(_paramsSource, "uv", _table.VersionColumn, _table.VersionColumn.Attribute.MapType, _updateVersionValue));
}
else if (_versionColumn.Attribute.MapType == typeof(string))
{
_updateVersionValue = Guid.NewGuid().ToString();
sb.Append(", ").Append(vcname).Append(" = ").Append(_noneParameter ? _commonUtils.GetNoneParamaterSqlValue(_paramsSource, "uv", _versionColumn, _versionColumn.Attribute.MapType, _updateVersionValue) :
_commonUtils.QuoteWriteParamterAdapter(_versionColumn.Attribute.MapType, _commonUtils.QuoteParamterName($"p_{_paramsSource.Count}")));
if (_noneParameter == false)
_commonUtils.AppendParamter(_paramsSource, null, _versionColumn, _versionColumn.Attribute.MapType, _updateVersionValue);
}
else
sb.Append(", ").Append(vcname).Append(" = ").Append(_commonUtils.IsNull(vcname, 0)).Append(" + 1");
}
ToSqlWhere(sb);
_interceptSql?.Invoke(sb);
return;
}
protected override void SplitExecute(int valuesLimit, int parameterLimit, string traceName, Action execute)
{
var ss = SplitSource(valuesLimit, parameterLimit);
if (ss.Length <= 1)
{
if (_source?.Any() == true) _batchProgress?.Invoke(new BatchProgressStatus<T1>(_source, 1, 1));
execute();
ClearData();
return;
}
var before = new Aop.TraceBeforeEventArgs(traceName, null);
_orm.Aop.TraceBeforeHandler?.Invoke(this, before);
Exception exception = null;
try
{
for (var a = 0; a < ss.Length; a++)
{
_source = ss[a];
_batchProgress?.Invoke(new BatchProgressStatus<T1>(_source, a + 1, ss.Length));
execute();
}
}
catch (Exception ex)
{
exception = ex;
throw;
}
finally
{
var after = new Aop.TraceAfterEventArgs(before, null, exception);
_orm.Aop.TraceAfterHandler?.Invoke(this, after);
}
ClearData();
}
#if net40
#else
public override Task<int> ExecuteAffrowsAsync(CancellationToken cancellationToken = default) => SplitExecuteAffrowsAsync(_batchRowsLimit > 0 ? _batchRowsLimit : 500, _batchParameterLimit > 0 ? _batchParameterLimit : 3000, cancellationToken);
protected override Task<List<TReturn>> ExecuteUpdatedAsync<TReturn>(IEnumerable<ColumnInfo> columns, CancellationToken cancellationToken = default) => base.SplitExecuteUpdatedAsync<TReturn>(_batchRowsLimit > 0 ? _batchRowsLimit : 500, _batchParameterLimit > 0 ? _batchParameterLimit : 3000, columns, cancellationToken);
protected override Task<List<TReturn>> RawExecuteUpdatedAsync<TReturn>(IEnumerable<ColumnInfo> columns, CancellationToken cancellationToken = default) => throw new NotImplementedException($"FreeSql.Provider.ClickHouse {CoreStrings.S_Not_Implemented_Feature}");
async protected override Task SplitExecuteAsync(int valuesLimit, int parameterLimit, string traceName, Func<Task> executeAsync, CancellationToken cancellationToken = default)
{
var ss = SplitSource(valuesLimit, parameterLimit);
if (ss.Length <= 1)
{
if (_source?.Any() == true) _batchProgress?.Invoke(new BatchProgressStatus<T1>(_source, 1, 1));
await executeAsync();
ClearData();
return;
}
var before = new Aop.TraceBeforeEventArgs(traceName, null);
_orm.Aop.TraceBeforeHandler?.Invoke(this, before);
Exception exception = null;
try
{
for (var a = 0; a < ss.Length; a++)
{
_source = ss[a];
_batchProgress?.Invoke(new BatchProgressStatus<T1>(_source, a + 1, ss.Length));
await executeAsync();
}
}
catch (Exception ex)
{
exception = ex;
throw;
}
finally
{
var after = new Aop.TraceAfterEventArgs(before, null, exception);
_orm.Aop.TraceAfterHandler?.Invoke(this, after);
}
ClearData();
}
#endif
}
}

View File

@ -0,0 +1,40 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<LangVersion>9</LangVersion>
<TargetFrameworks>netstandard2.1</TargetFrameworks>
<GeneratePackageOnBuild>true</GeneratePackageOnBuild>
<Authors>FreeSql;ncc;YeXiangQin;ChenBo</Authors>
<Description>FreeSql 数据库实现,基于 ClickHouse.Client Ado.net</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>False</SignAssembly>
<AssemblyOriginatorKeyFile>key.snk</AssemblyOriginatorKeyFile>
<DelaySign>false</DelaySign>
<Version>3.2.833</Version>
<PackageReadmeFile>readme.md</PackageReadmeFile>
</PropertyGroup>
<ItemGroup>
<None Include="../../readme.md" Pack="true" PackagePath="\" />
<None Include="../../logo.png" Pack="true" PackagePath="\" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\..\FreeSql\FreeSql.csproj" />
</ItemGroup>
<ItemGroup>
<PackageReference Include="ClickHouse.Client" Version="6.8.1" />
</ItemGroup>
</Project>

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 {CoreStrings.S_Not_Implemented_Feature}");
#if net40
#else
public override Task<List<T1>> ExecuteDeletedAsync(CancellationToken cancellationToken = default) => throw new NotImplementedException($"FreeSql.Provider.Custom {CoreStrings.S_Not_Implemented_Feature}");
#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 {CoreStrings.S_Not_Implemented_Feature}");
#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 {CoreStrings.S_Not_Implemented_Feature}");
#endif
}
}

View File

@ -0,0 +1,225 @@
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.Where(a => a.Before == false), true);
tb.CascadeBefore = _commonExpression.GetWhereCascadeSql(tb, _whereGlobalFilter.Where(a => a.Before == true), 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(CoreStrings.S_NotImplementSkipOffset("Custom"));
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) &&
string.IsNullOrEmpty(tbsfrom[b].CascadeBefore)) sb.Append(" ON 1 = 1");
else sb.Append(" ON ").Append(string.Join(" AND ", new[]
{
tbsfrom[b].CascadeBefore,
tbsfrom[b].NavigateCondition ?? tbsfrom[b].On,
tbsfrom[b].Cascade
}.Where(sql => string.IsNullOrEmpty(sql) == false)));
}
break;
}
else
{
if (a > 0 && !string.IsNullOrEmpty(tbsfrom[a].CascadeBefore)) sbnav.Append(" AND ").Append(tbsfrom[a].CascadeBefore);
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)
{
switch (tb.Type)
{
case SelectTableInfoType.Parent:
case SelectTableInfoType.RawJoin:
continue;
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(string.Join(" AND ", new[]
{
tb.CascadeBefore,
tb.On ?? tb.NavigateCondition,
tb.Cascade
}.Where(sql => string.IsNullOrEmpty(sql) == false)));
if (!string.IsNullOrEmpty(tb.On) && !string.IsNullOrEmpty(tb.NavigateCondition)) sbnav.Append(" AND (").Append(tb.NavigateCondition).Append(")");
}
if (_join.Length > 0) sb.Append(_join);
if (!string.IsNullOrEmpty(_tables[0].CascadeBefore)) sbnav.Append(" AND ").Append(_tables[0].CascadeBefore);
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);
protected override List<TReturn> ExecuteUpdated<TReturn>(IEnumerable<ColumnInfo> columns) => base.SplitExecuteUpdated<TReturn>(_batchRowsLimit > 0 ? _batchRowsLimit : _utils.Adapter.UpdateBatchSplitLimit, _batchParameterLimit > 0 ? _batchParameterLimit : 255, columns);
protected override List<TReturn> RawExecuteUpdated<TReturn>(IEnumerable<ColumnInfo> columns) => throw new NotImplementedException($"FreeSql.Provider.Custom {CoreStrings.S_Not_Implemented_Feature}");
protected override void ToSqlCase(StringBuilder caseWhen, ColumnInfo[] primarys)
{
if (primarys.Length == 1)
{
var pk = primarys.First();
caseWhen.Append(_commonUtils.RereadColumn(pk, _commonUtils.QuoteSqlName(pk.Attribute.Name)));
return;
}
caseWhen.Append("(");
var pkidx = 0;
foreach (var pk in 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 (primarys.Length == 1)
{
sb.Append(_commonUtils.FormatSql("{0}", primarys[0].GetDbValue(d)));
return;
}
var pkidx = 0;
foreach (var pk in 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);
protected override Task<List<TReturn>> ExecuteUpdatedAsync<TReturn>(IEnumerable<ColumnInfo> columns, CancellationToken cancellationToken = default) => base.SplitExecuteUpdatedAsync<TReturn>(_batchRowsLimit > 0 ? _batchRowsLimit : _utils.Adapter.UpdateBatchSplitLimit, _batchParameterLimit > 0 ? _batchParameterLimit : 255, columns, cancellationToken);
protected override Task<List<TReturn>> RawExecuteUpdatedAsync<TReturn>(IEnumerable<ColumnInfo> columns, CancellationToken cancellationToken = default) => throw new NotImplementedException($"FreeSql.Provider.Custom {CoreStrings.S_Not_Implemented_Feature}");
#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,85 @@
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);
ConnectionString = pool.TestConnection?.ConnectionString;
MasterPool = pool;
_CreateCommandConnection = pool.TestConnection;
_CreateParameterCommand = CreateCommand();
return;
}
throw new Exception(CoreStrings.S_CustomAdapter_OnlySuppport_UseConnectionFactory);
}
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 AddslashesTypeHandler(param.GetType(), param) ?? ((Enum)param).ToInt64();
else if (decimal.TryParse(string.Concat(param), out var trydec))
return param;
else if (param is DateTime)
return AddslashesTypeHandler(typeof(DateTime), param) ?? Adapter.DateTimeRawSql(param);
else if (param is DateTime?)
return AddslashesTypeHandler(typeof(DateTime?), param) ?? 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(CoreStrings.S_CustomAdapter_Cannot_Use_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 TypeSchemaAndName[] objects) => throw new NotImplementedException($"FreeSql.Provider.Custom {CoreStrings.S_Not_Implemented_Feature}");
}
}

View File

@ -0,0 +1,477 @@
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)
{
if (callExp.Object.Type.NullableTypeOrThis().IsEnum)
{
tsc.SetMapColumnTmp(null);
var oldMapType = tsc.SetMapTypeReturnOld(typeof(string));
var enumStr = ExpressionLambdaToSql(callExp.Object, tsc);
tsc.SetMapColumnTmp(null).SetMapTypeReturnOld(oldMapType);
return enumStr;
}
var value = ExpressionGetValue(callExp.Object, out var success);
if (success) return formatSql(value, typeof(string), null, 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 = objExp?.NodeType == ExpressionType.MemberAccess ? tsc.SetDbParamsReturnOld(null) : null; //#900 UseGenerateCommandParameterWithLambda(true) 子查询 bug、以及 #1173 参数化 bug
tsc.isNotSetMapColumnTmp = true;
var left = objExp == null ? null : getExp(objExp);
tsc.isNotSetMapColumnTmp = false;
tsc.SetMapColumnTmp(null).SetMapTypeReturnOld(oldMapType);
if (oldDbParams != null) 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(",");
if (a % 500 == 499) arrSb.Append(" \r\n \r\n"); //500元素分割, 3空格\r\n4空格
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":
if (exp.Arguments.Count == 1 && exp.Arguments[0].NodeType == ExpressionType.NewArrayInit && exp.Arguments[0] is NewArrayExpression concatNewArrExp)
return _common.StringConcat(concatNewArrExp.Expressions.Select(a => getExp(a)).ToArray(), concatNewArrExp.Expressions.Select(a => a.Type).ToArray());
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,96 @@
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 {CoreStrings.S_Not_Implemented_Feature}");
public override IDbFirst DbFirst => throw new NotImplementedException($"FreeSql.Provider.Custom {CoreStrings.S_Not_Implemented_Feature}");
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);
FreeSqlCustomAdapterGlobalExtensions._dicDbProviderFactory.TryRemove(Ado.Identifier, out var trydbpf);
}
}
}
}
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;
internal static ConcurrentDictionary<Guid, DbProviderFactory> _dicDbProviderFactory = new ConcurrentDictionary<Guid, DbProviderFactory>();
public static void SetDbProviderFactory(this IFreeSql that, DbProviderFactory factory) => _dicDbProviderFactory.AddOrUpdate(that.Ado.Identifier, factory, (fsql, old) => factory);
internal static DbProviderFactory GetDbProviderFactory(this IFreeSql that) => _dicDbProviderFactory.TryGetValue(that.Ado.Identifier, out var trydbpf) ? trydbpf : throw new Exception("需要先设置 fsql.SetDbProviderFactory(..) 方法");
}

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) => (_orm?.Ado as CustomAdo)?.Addslashes(sql, args) ?? _customAdo.Addslashes(sql, args);
public override string QuoteSqlNameAdapter(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,39 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFrameworks>netstandard2.0;net45;net40</TargetFrameworks>
<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>
<Version>3.2.833</Version>
<PackageReadmeFile>readme.md</PackageReadmeFile>
</PropertyGroup>
<ItemGroup>
<None Include="../../readme.md" Pack="true" PackagePath="\"/>
<None Include="../../logo.png" Pack="true" PackagePath="\" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\..\FreeSql\FreeSql.csproj" />
</ItemGroup>
<PropertyGroup Condition="'$(TargetFramework)' == 'net40'">
<DefineConstants>net40</DefineConstants>
</PropertyGroup>
</Project>

View File

@ -0,0 +1,39 @@
public static partial class FreeSqlCustomGlobalExtensions
{
/// <summary>
/// 特殊处理类似 string.Format 的使用方法,防止注入,以及 IS NULL 转换
/// </summary>
/// <param name="that"></param>
/// <param name="args"></param>
/// <returns></returns>
internal static string FormatCustomOracle(this string that, params object[] args) => _customOracleAdo.Addslashes(that, args);
static FreeSql.Custom.Oracle.CustomOracleAdo _customOracleAdo = new FreeSql.Custom.Oracle.CustomOracleAdo();
/// <summary>
/// 特殊处理类似 string.Format 的使用方法,防止注入,以及 IS NULL 转换
/// </summary>
/// <param name="that"></param>
/// <param name="args"></param>
/// <returns></returns>
internal static string FormatCustomSqlServer(this string that, params object[] args) => _customSqlServerAdo.Addslashes(that, args);
static FreeSql.Custom.SqlServer.CustomSqlServerAdo _customSqlServerAdo = new FreeSql.Custom.SqlServer.CustomSqlServerAdo();
/// <summary>
/// 特殊处理类似 string.Format 的使用方法,防止注入,以及 IS NULL 转换
/// </summary>
/// <param name="that"></param>
/// <param name="args"></param>
/// <returns></returns>
internal static string FormatCustomMySql(this string that, params object[] args) => _customMySqlAdo.Addslashes(that, args);
static FreeSql.Custom.MySql.CustomMySqlAdo _customMySqlAdo = new FreeSql.Custom.MySql.CustomMySqlAdo();
/// <summary>
/// 特殊处理类似 string.Format 的使用方法,防止注入,以及 IS NULL 转换
/// </summary>
/// <param name="that"></param>
/// <param name="args"></param>
/// <returns></returns>
internal static string FormatCustomPostgreSQL(this string that, params object[] args) => _customPostgreSQLAdo.Addslashes(that, args);
static FreeSql.Custom.PostgreSQL.CustomPostgreSQLAdo _customPostgreSQLAdo = new FreeSql.Custom.PostgreSQL.CustomPostgreSQLAdo();
}

View File

@ -0,0 +1,121 @@
using FreeSql.Internal;
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.MySql
{
class CustomMySqlDelete<T1> : Internal.CommonProvider.DeleteProvider<T1>
{
public CustomMySqlDelete(IFreeSql orm, CommonUtils commonUtils, CommonExpression commonExpression, object dywhere)
: base(orm, commonUtils, commonExpression, dywhere)
{
}
public override List<T1> ExecuteDeleted()
{
var ret = new List<T1>();
DbParameter[] dbParms = null;
StringBuilder sbret = null;
ToSqlFetch(sb =>
{
if (dbParms == null)
{
dbParms = _params.ToArray();
sbret = new StringBuilder();
sbret.Append(" RETURNING ");
var colidx = 0;
foreach (var col in _table.Columns.Values)
{
if (colidx > 0) sbret.Append(", ");
sbret.Append(_commonUtils.RereadColumn(col, _commonUtils.QuoteSqlName(col.Attribute.Name))).Append(" as ").Append(_commonUtils.QuoteSqlName(col.CsName));
++colidx;
}
}
var sql = sb.Append(sbret).ToString();
var before = new Aop.CurdBeforeEventArgs(_table.Type, _table, Aop.CurdType.Delete, sql, dbParms);
_orm.Aop.CurdBeforeHandler?.Invoke(this, before);
Exception exception = null;
try
{
ret.AddRange(_orm.Ado.Query<T1>(_table.TypeLazy ?? _table.Type, _connection, _transaction, CommandType.Text, sql, _commandTimeout, dbParms));
}
catch (Exception ex)
{
exception = ex;
throw ex;
}
finally
{
var after = new Aop.CurdAfterEventArgs(before, exception, ret);
_orm.Aop.CurdAfterHandler?.Invoke(this, after);
}
});
if (dbParms != null)
{
this.ClearData();
sbret.Clear();
}
return ret;
}
#if net40
#else
async public override Task<List<T1>> ExecuteDeletedAsync(CancellationToken cancellationToken = default)
{
var ret = new List<T1>();
DbParameter[] dbParms = null;
StringBuilder sbret = null;
await ToSqlFetchAsync(async sb =>
{
if (dbParms == null)
{
dbParms = _params.ToArray();
sbret = new StringBuilder();
sbret.Append(" RETURNING ");
var colidx = 0;
foreach (var col in _table.Columns.Values)
{
if (colidx > 0) sbret.Append(", ");
sbret.Append(_commonUtils.RereadColumn(col, _commonUtils.QuoteSqlName(col.Attribute.Name))).Append(" as ").Append(_commonUtils.QuoteSqlName(col.CsName));
++colidx;
}
}
var sql = sb.Append(sbret).ToString();
var before = new Aop.CurdBeforeEventArgs(_table.Type, _table, Aop.CurdType.Delete, sql, dbParms);
_orm.Aop.CurdBeforeHandler?.Invoke(this, before);
Exception exception = null;
try
{
ret.AddRange(await _orm.Ado.QueryAsync<T1>(_table.TypeLazy ?? _table.Type, _connection, _transaction, CommandType.Text, sql, _commandTimeout, dbParms, cancellationToken));
}
catch (Exception ex)
{
exception = ex;
throw ex;
}
finally
{
var after = new Aop.CurdAfterEventArgs(before, exception, ret);
_orm.Aop.CurdAfterHandler?.Invoke(this, after);
}
});
if (dbParms != null)
{
this.ClearData();
sbret.Clear();
}
return ret;
}
#endif
}
}

View File

@ -0,0 +1,201 @@
using FreeSql.Internal;
using FreeSql.Internal.Model;
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.MySql
{
class CustomMySqlInsert<T1> : Internal.CommonProvider.InsertProvider<T1> where T1 : class
{
public CustomMySqlInsert(IFreeSql orm, CommonUtils commonUtils, CommonExpression commonExpression)
: base(orm, commonUtils, commonExpression)
{
}
internal bool InternalIsIgnoreInto = false;
internal IFreeSql InternalOrm => _orm;
internal TableInfo InternalTable => _table;
internal DbParameter[] InternalParams => _params;
internal DbConnection InternalConnection => _connection;
internal DbTransaction InternalTransaction => _transaction;
internal CommonUtils InternalCommonUtils => _commonUtils;
internal CommonExpression InternalCommonExpression => _commonExpression;
internal List<T1> InternalSource => _source;
internal Dictionary<string, bool> InternalIgnore => _ignore;
internal void InternalClearData() => ClearData();
public override int ExecuteAffrows() => base.SplitExecuteAffrows(_batchValuesLimit > 0 ? _batchValuesLimit : 5000, _batchParameterLimit > 0 ? _batchParameterLimit : 3000);
public override long ExecuteIdentity() => base.SplitExecuteIdentity(_batchValuesLimit > 0 ? _batchValuesLimit : 5000, _batchParameterLimit > 0 ? _batchParameterLimit : 3000);
public override List<T1> ExecuteInserted() => base.SplitExecuteInserted(_batchValuesLimit > 0 ? _batchValuesLimit : 5000, _batchParameterLimit > 0 ? _batchParameterLimit : 3000);
public override string ToSql()
{
if (InternalIsIgnoreInto == false) return base.ToSqlValuesOrSelectUnionAll();
var sql = base.ToSqlValuesOrSelectUnionAll();
return $"INSERT IGNORE INTO {sql.Substring(12)}";
}
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, "; SELECT LAST_INSERT_ID();"), _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, " SELECT LAST_INSERT_ID()", _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()
{
var sql = this.ToSql();
if (string.IsNullOrEmpty(sql)) return new List<T1>();
var sb = new StringBuilder();
sb.Append(sql).Append(" RETURNING ");
var colidx = 0;
foreach (var col in _table.Columns.Values)
{
if (colidx > 0) sb.Append(", ");
sb.Append(_commonUtils.RereadColumn(col, _commonUtils.QuoteSqlName(col.Attribute.Name))).Append(" as ").Append(_commonUtils.QuoteSqlName(col.CsName));
++colidx;
}
sql = sb.ToString();
var before = new Aop.CurdBeforeEventArgs(_table.Type, _table, Aop.CurdType.Insert, sql, _params);
_orm.Aop.CurdBeforeHandler?.Invoke(this, before);
var ret = new List<T1>();
Exception exception = null;
try
{
ret = _orm.Ado.Query<T1>(_table.TypeLazy ?? _table.Type, _connection, _transaction, CommandType.Text, sql, _commandTimeout, _params);
}
catch (Exception ex)
{
exception = ex;
throw ex;
}
finally
{
var after = new Aop.CurdAfterEventArgs(before, exception, ret);
_orm.Aop.CurdAfterHandler?.Invoke(this, after);
}
return ret;
}
#if net40
#else
public override Task<int> ExecuteAffrowsAsync(CancellationToken cancellationToken = default) => base.SplitExecuteAffrowsAsync(_batchValuesLimit > 0 ? _batchValuesLimit : 5000, _batchParameterLimit > 0 ? _batchParameterLimit : 3000, cancellationToken);
public override Task<long> ExecuteIdentityAsync(CancellationToken cancellationToken = default) => base.SplitExecuteIdentityAsync(_batchValuesLimit > 0 ? _batchValuesLimit : 5000, _batchParameterLimit > 0 ? _batchParameterLimit : 3000, cancellationToken);
public override Task<List<T1>> ExecuteInsertedAsync(CancellationToken cancellationToken = default) => base.SplitExecuteInsertedAsync(_batchValuesLimit > 0 ? _batchValuesLimit : 5000, _batchParameterLimit > 0 ? _batchParameterLimit : 3000, 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, "; SELECT LAST_INSERT_ID();"), _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, " SELECT LAST_INSERT_ID()", _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;
}
async protected override Task<List<T1>> RawExecuteInsertedAsync(CancellationToken cancellationToken = default)
{
var sql = this.ToSql();
if (string.IsNullOrEmpty(sql)) return new List<T1>();
var sb = new StringBuilder();
sb.Append(sql).Append(" RETURNING ");
var colidx = 0;
foreach (var col in _table.Columns.Values)
{
if (colidx > 0) sb.Append(", ");
sb.Append(_commonUtils.RereadColumn(col, _commonUtils.QuoteSqlName(col.Attribute.Name))).Append(" as ").Append(_commonUtils.QuoteSqlName(col.CsName));
++colidx;
}
sql = sb.ToString();
var before = new Aop.CurdBeforeEventArgs(_table.Type, _table, Aop.CurdType.Insert, sql, _params);
_orm.Aop.CurdBeforeHandler?.Invoke(this, before);
var ret = new List<T1>();
Exception exception = null;
try
{
ret = await _orm.Ado.QueryAsync<T1>(_table.TypeLazy ?? _table.Type, _connection, _transaction, CommandType.Text, sql, _commandTimeout, _params, cancellationToken);
}
catch (Exception ex)
{
exception = ex;
throw ex;
}
finally
{
var after = new Aop.CurdAfterEventArgs(before, exception, ret);
_orm.Aop.CurdAfterHandler?.Invoke(this, after);
}
return ret;
}
#endif
}
}

View File

@ -0,0 +1,114 @@
using FreeSql.Internal;
using System;
using System.Collections.Generic;
using System.Data.Common;
using System.Linq;
using System.Text;
using System.Text.RegularExpressions;
namespace FreeSql.Custom.MySql
{
class CustomMySqlInsertOrUpdate<T1> : Internal.CommonProvider.InsertOrUpdateProvider<T1> where T1 : class
{
public CustomMySqlInsertOrUpdate(IFreeSql orm, CommonUtils commonUtils, CommonExpression commonExpression)
: base(orm, commonUtils, commonExpression)
{
}
public override string ToSql()
{
var dbParams = new List<DbParameter>();
if (_sourceSql != null)
{
var data = new List<T1>();
data.Add((T1)_table.Type.CreateInstanceGetDefaultValue());
var sql = getInsertSql(data, false, false);
var sb = new StringBuilder();
sb.Append(sql.Substring(0, sql.IndexOf(") VALUES")));
sb.Append(") \r\n");
WriteSourceSelectUnionAll(null, sb, null);
if (_doNothing == false)
sb.Append(sql.Substring(sql.IndexOf("\r\nON DUPLICATE KEY UPDATE\r\n") + 2));
else
throw new Exception("Not implemented! fsql.InsertOrUpdate + SetSource(sql) + IfExistsDoNothing + MySql");
return sb.ToString();
}
if (_source?.Any() != true) return null;
var sqls = new string[2];
var ds = SplitSourceByIdentityValueIsNull(_source);
if (ds.Item1.Any()) sqls[0] = string.Join("\r\n\r\n;\r\n\r\n", ds.Item1.Select(a => getInsertSql(a, false, true)));
if (ds.Item2.Any()) sqls[1] = string.Join("\r\n\r\n;\r\n\r\n", ds.Item2.Select(a => getInsertSql(a, true, true)));
_params = dbParams.ToArray();
if (ds.Item2.Any() == false) return sqls[0];
if (ds.Item1.Any() == false) return sqls[1];
return string.Join("\r\n\r\n;\r\n\r\n", sqls);
string getInsertSql(List<T1> data, bool flagInsert, bool noneParameter)
{
var insert = _orm.Insert<T1>()
.AsTable(_tableRule).AsType(_table.Type)
.WithConnection(_connection)
.WithTransaction(_transaction)
.NoneParameter(noneParameter) as Internal.CommonProvider.InsertProvider<T1>;
insert._source = data;
insert._table = _table;
insert._noneParameterFlag = flagInsert ? "cuc" : "cu";
string sql = "";
if (IdentityColumn != null && flagInsert) sql = insert.ToSql();
else
{
insert.InsertIdentity();
if (_doNothing == false)
{
var cols = _table.Columns.Values.Where(a => _updateSetDict.ContainsKey(a.Attribute.Name) ||
_tempPrimarys.Contains(a) == false && a.Attribute.CanUpdate == true && a.Attribute.IsIdentity == false && _updateIgnore.ContainsKey(a.Attribute.Name) == false);
sql = new CustomMySqlOnDuplicateKeyUpdate<T1>(insert)
.UpdateColumns(cols.Select(a => a.Attribute.Name).ToArray())
.ToSql();
if (_updateSetDict.Any())
{
var findregex = new Regex("(t1|t2)." + _commonUtils.QuoteSqlName("test").Replace("test", "(\\w+)"));
foreach (var usd in _updateSetDict)
{
var field = _commonUtils.QuoteSqlName(usd.Key);
var findsql = $"{field} = VALUES({field})";
var usdval = findregex.Replace(usd.Value, m =>
{
if (m.Groups[1].Value == "t1") return _commonUtils.QuoteSqlName(m.Groups[2].Value);
return $"VALUES({_commonUtils.QuoteSqlName(m.Groups[2].Value)})";
});
sql = sql.Replace(findsql, $"{field} = {usdval}");
}
}
}
else
{
if (_tempPrimarys.Any() == false) throw new Exception(CoreStrings.Entity_Must_Primary_Key("fsql.InsertOrUpdate + IfExistsDoNothing + MySql ", _table.CsName));
sql = insert.ToSqlValuesOrSelectUnionAll();
if (sql?.StartsWith("INSERT INTO ") == true)
sql = $"INSERT IGNORE INTO {sql.Substring(12)}";
//sql = insert.ToSqlValuesOrSelectUnionAllExtension101(false, (rowd, idx, sb) =>
//{
// sb.Append(" \r\n FROM dual WHERE NOT EXISTS(");
// if (typeof(T1) == typeof(Dictionary<string, object>) && rowd is T1 dict)
// sb.Append($"SELECT 1 FROM {_commonUtils.QuoteSqlName(_tableRule(null))} WHERE {_commonUtils.WhereItems<T1>(_tempPrimarys, "", new T1[] { dict })})");
// else
// sb.Append(
// _orm.Select<T1>()
// .AsTable((_, __) => _tableRule?.Invoke(__)).AsType(_table.Type)
// .DisableGlobalFilter()
// .WhereDynamic(rowd)
// .Limit(1).ToSql("1").Replace(" \r\n", " \r\n ")).Append(")");
//});
}
}
if (string.IsNullOrEmpty(sql)) return null;
if (insert._params?.Any() == true) dbParams.AddRange(insert._params);
return sql;
}
}
}
}

View File

@ -0,0 +1,175 @@
using FreeSql.Aop;
using System;
using System.Data;
using System.Linq.Expressions;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
namespace FreeSql.Custom.MySql
{
public class CustomMySqlOnDuplicateKeyUpdate<T1> where T1 : class
{
internal CustomMySqlInsert<T1> _mysqlInsert;
internal CustomMySqlUpdate<T1> _mysqlUpdatePriv;
internal CustomMySqlUpdate<T1> _mysqlUpdate => _mysqlUpdatePriv ?? (_mysqlUpdatePriv = new CustomMySqlUpdate<T1>(_mysqlInsert.InternalOrm, _mysqlInsert.InternalCommonUtils, _mysqlInsert.InternalCommonExpression, null).NoneParameter().SetSource(_mysqlInsert.InternalSource) as CustomMySqlUpdate<T1>);
public CustomMySqlOnDuplicateKeyUpdate(IInsert<T1> insert)
{
_mysqlInsert = insert as CustomMySqlInsert<T1>;
if (_mysqlInsert == null) throw new Exception(CoreStrings.S_Features_Unique("OnDuplicateKeyUpdate", "Odbc/MySql"));
if (_mysqlInsert._noneParameterFlag == "c") _mysqlInsert._noneParameterFlag = "cu";
}
protected void ClearData()
{
_mysqlInsert.InternalClearData();
_mysqlUpdatePriv = null;
}
public CustomMySqlOnDuplicateKeyUpdate<T1> IgnoreColumns(Expression<Func<T1, object>> columns)
{
_mysqlUpdate.IgnoreColumns(columns);
return this;
}
public CustomMySqlOnDuplicateKeyUpdate<T1> UpdateColumns(Expression<Func<T1, object>> columns)
{
_mysqlUpdate.UpdateColumns(columns);
return this;
}
public CustomMySqlOnDuplicateKeyUpdate<T1> IgnoreColumns(string[] columns)
{
_mysqlUpdate.IgnoreColumns(columns);
return this;
}
public CustomMySqlOnDuplicateKeyUpdate<T1> UpdateColumns(string[] columns)
{
_mysqlUpdate.UpdateColumns(columns);
return this;
}
public CustomMySqlOnDuplicateKeyUpdate<T1> Set<TMember>(Expression<Func<T1, TMember>> column, TMember value)
{
_mysqlUpdate.Set(column, value);
return this;
}
public CustomMySqlOnDuplicateKeyUpdate<T1> Set<TMember>(Expression<Func<T1, TMember>> exp)
{
_mysqlUpdate.Set(exp);
return this;
}
public CustomMySqlOnDuplicateKeyUpdate<T1> SetRaw(string sql)
{
_mysqlUpdate.SetRaw(sql);
return this;
}
public string ToSql()
{
var sb = new StringBuilder();
sb.Append(_mysqlInsert.ToSql()).Append("\r\nON DUPLICATE KEY UPDATE\r\n");
var sbSetEmpty = _mysqlUpdate.InternalSbSet.Length == 0;
var sbSetIncrEmpty = _mysqlUpdate.InternalSbSetIncr.Length == 0;
if (sbSetEmpty == false || sbSetIncrEmpty == false)
{
if (sbSetEmpty == false) sb.Append(_mysqlUpdate.InternalSbSet.ToString().Substring(2));
if (sbSetIncrEmpty == false) sb.Append(sbSetEmpty ? _mysqlUpdate.InternalSbSetIncr.ToString().Substring(2) : _mysqlUpdate.InternalSbSetIncr.ToString());
}
else
{
var colidx = 0;
foreach (var col in _mysqlInsert.InternalTable.Columns.Values)
{
if (col.Attribute.IsPrimary || _mysqlUpdate.InternalIgnore.ContainsKey(col.Attribute.Name)) continue;
if (colidx > 0) sb.Append(", \r\n");
if (col.Attribute.IsVersion == true && col.Attribute.MapType != typeof(byte[]))
{
var field = _mysqlInsert.InternalCommonUtils.QuoteSqlName(col.Attribute.Name);
sb.Append(field).Append(" = ").Append(field).Append(" + 1");
}
else if (_mysqlInsert.InternalIgnore.ContainsKey(col.Attribute.Name))
{
if (string.IsNullOrEmpty(col.DbUpdateValue) == false)
{
sb.Append(_mysqlInsert.InternalCommonUtils.QuoteSqlName(col.Attribute.Name)).Append(" = ").Append(col.DbUpdateValue);
}
else
{
var caseWhen = _mysqlUpdate.InternalWhereCaseSource(col.CsName, sqlval => sqlval).Trim();
sb.Append(caseWhen);
if (caseWhen.EndsWith(" END")) _mysqlUpdate.InternalToSqlCaseWhenEnd(sb, col);
}
}
else
{
var field = _mysqlInsert.InternalCommonUtils.QuoteSqlName(col.Attribute.Name);
sb.Append(field).Append(" = VALUES(").Append(field).Append(")");
}
++colidx;
}
}
return sb.ToString();
}
public long ExecuteAffrows()
{
var sql = this.ToSql();
if (string.IsNullOrEmpty(sql)) return 0;
var before = new CurdBeforeEventArgs(_mysqlInsert.InternalTable.Type, _mysqlInsert.InternalTable, CurdType.Insert, sql, _mysqlInsert.InternalParams);
_mysqlInsert.InternalOrm.Aop.CurdBeforeHandler?.Invoke(_mysqlInsert, before);
long ret = 0;
Exception exception = null;
try
{
ret = _mysqlInsert.InternalOrm.Ado.ExecuteNonQuery(_mysqlInsert.InternalConnection, _mysqlInsert.InternalTransaction, CommandType.Text, sql, _mysqlInsert._commandTimeout, _mysqlInsert.InternalParams);
}
catch (Exception ex)
{
exception = ex;
throw ex;
}
finally
{
var after = new CurdAfterEventArgs(before, exception, ret);
_mysqlInsert.InternalOrm.Aop.CurdAfterHandler?.Invoke(_mysqlInsert, after);
ClearData();
}
return ret;
}
#if net40
#else
async public Task<long> ExecuteAffrowsAsync(CancellationToken cancellationToken = default)
{
var sql = this.ToSql();
if (string.IsNullOrEmpty(sql)) return 0;
var before = new CurdBeforeEventArgs(_mysqlInsert.InternalTable.Type, _mysqlInsert.InternalTable, CurdType.Insert, sql, _mysqlInsert.InternalParams);
_mysqlInsert.InternalOrm.Aop.CurdBeforeHandler?.Invoke(_mysqlInsert, before);
long ret = 0;
Exception exception = null;
try
{
ret = await _mysqlInsert.InternalOrm.Ado.ExecuteNonQueryAsync(_mysqlInsert.InternalConnection, _mysqlInsert.InternalTransaction, CommandType.Text, sql, _mysqlInsert._commandTimeout, _mysqlInsert.InternalParams, cancellationToken);
}
catch (Exception ex)
{
exception = ex;
throw ex;
}
finally
{
var after = new CurdAfterEventArgs(before, exception, ret);
_mysqlInsert.InternalOrm.Aop.CurdAfterHandler?.Invoke(_mysqlInsert, after);
ClearData();
}
return ret;
}
#endif
}
}

View File

@ -0,0 +1,220 @@
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.MySql
{
class CustomMySqlSelect<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)
{
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.Where(a => a.Before == false), true);
tb.CascadeBefore = _commonExpression.GetWhereCascadeSql(tb, _whereGlobalFilter.Where(a => a.Before == true), 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 ");
sb.Append(field).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) &&
string.IsNullOrEmpty(tbsfrom[b].CascadeBefore)) sb.Append(" ON 1 = 1");
else sb.Append(" ON ").Append(string.Join(" AND ", new[]
{
tbsfrom[b].CascadeBefore,
tbsfrom[b].NavigateCondition ?? tbsfrom[b].On,
tbsfrom[b].Cascade
}.Where(sql => string.IsNullOrEmpty(sql) == false)));
}
break;
}
else
{
if (a > 0 && !string.IsNullOrEmpty(tbsfrom[a].CascadeBefore)) sbnav.Append(" AND ").Append(tbsfrom[a].CascadeBefore);
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)
{
switch (tb.Type)
{
case SelectTableInfoType.Parent:
case SelectTableInfoType.RawJoin:
continue;
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(string.Join(" AND ", new[]
{
tb.CascadeBefore,
tb.On ?? tb.NavigateCondition,
tb.Cascade
}.Where(sql => string.IsNullOrEmpty(sql) == false)));
if (!string.IsNullOrEmpty(tb.On) && !string.IsNullOrEmpty(tb.NavigateCondition)) sbnav.Append(" AND (").Append(tb.NavigateCondition).Append(")");
}
if (_join.Length > 0) sb.Append(_join);
if (!string.IsNullOrEmpty(_tables[0].CascadeBefore)) sbnav.Append(" AND ").Append(_tables[0].CascadeBefore);
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 (_skip > 0 || _limit > 0)
sb.Append(" \r\nlimit ").Append(Math.Max(0, _skip)).Append(",").Append(_limit > 0 ? _limit : -1);
sbnav.Clear();
if (tbUnionsGt0) sb.Append(") ftb");
}
return sb.Append(_tosqlAppendContent).ToString();
}
public CustomMySqlSelect(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 OdbcMySqlSelect<T1, T2>(_orm, _commonUtils, _commonExpression, null); CustomMySqlSelect<T1>.CopyData(this, 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 OdbcMySqlSelect<T1, T2, T3>(_orm, _commonUtils, _commonExpression, null); CustomMySqlSelect<T1>.CopyData(this, 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 OdbcMySqlSelect<T1, T2, T3, T4>(_orm, _commonUtils, _commonExpression, null); CustomMySqlSelect<T1>.CopyData(this, 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 OdbcMySqlSelect<T1, T2, T3, T4, T5>(_orm, _commonUtils, _commonExpression, null); CustomMySqlSelect<T1>.CopyData(this, 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 OdbcMySqlSelect<T1, T2, T3, T4, T5, T6>(_orm, _commonUtils, _commonExpression, null); CustomMySqlSelect<T1>.CopyData(this, 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 OdbcMySqlSelect<T1, T2, T3, T4, T5, T6, T7>(_orm, _commonUtils, _commonExpression, null); CustomMySqlSelect<T1>.CopyData(this, 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 OdbcMySqlSelect<T1, T2, T3, T4, T5, T6, T7, T8>(_orm, _commonUtils, _commonExpression, null); CustomMySqlSelect<T1>.CopyData(this, 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 OdbcMySqlSelect<T1, T2, T3, T4, T5, T6, T7, T8, T9>(_orm, _commonUtils, _commonExpression, null); CustomMySqlSelect<T1>.CopyData(this, 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 OdbcMySqlSelect<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10>(_orm, _commonUtils, _commonExpression, null); CustomMySqlSelect<T1>.CopyData(this, 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 OdbcMySqlSelect<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11>(_orm, _commonUtils, _commonExpression, null); CustomMySqlSelect<T1>.CopyData(this, 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 OdbcMySqlSelect<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12>(_orm, _commonUtils, _commonExpression, null); CustomMySqlSelect<T1>.CopyData(this, 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 OdbcMySqlSelect<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13>(_orm, _commonUtils, _commonExpression, null); CustomMySqlSelect<T1>.CopyData(this, 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 OdbcMySqlSelect<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14>(_orm, _commonUtils, _commonExpression, null); CustomMySqlSelect<T1>.CopyData(this, 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 OdbcMySqlSelect<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15>(_orm, _commonUtils, _commonExpression, null); CustomMySqlSelect<T1>.CopyData(this, 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 OdbcMySqlSelect<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15, T16>(_orm, _commonUtils, _commonExpression, null); CustomMySqlSelect<T1>.CopyData(this, 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 OdbcMySqlSelect<T1, T2> : FreeSql.Internal.CommonProvider.Select2Provider<T1, T2> where T2 : class
{
public OdbcMySqlSelect(IFreeSql orm, CommonUtils commonUtils, CommonExpression commonExpression, object dywhere) : base(orm, commonUtils, commonExpression, dywhere) { }
public override string ToSql(string field = null) => CustomMySqlSelect<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 OdbcMySqlSelect<T1, T2, T3> : FreeSql.Internal.CommonProvider.Select3Provider<T1, T2, T3> where T2 : class where T3 : class
{
public OdbcMySqlSelect(IFreeSql orm, CommonUtils commonUtils, CommonExpression commonExpression, object dywhere) : base(orm, commonUtils, commonExpression, dywhere) { }
public override string ToSql(string field = null) => CustomMySqlSelect<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 OdbcMySqlSelect<T1, T2, T3, T4> : FreeSql.Internal.CommonProvider.Select4Provider<T1, T2, T3, T4> where T2 : class where T3 : class where T4 : class
{
public OdbcMySqlSelect(IFreeSql orm, CommonUtils commonUtils, CommonExpression commonExpression, object dywhere) : base(orm, commonUtils, commonExpression, dywhere) { }
public override string ToSql(string field = null) => CustomMySqlSelect<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 OdbcMySqlSelect<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 OdbcMySqlSelect(IFreeSql orm, CommonUtils commonUtils, CommonExpression commonExpression, object dywhere) : base(orm, commonUtils, commonExpression, dywhere) { }
public override string ToSql(string field = null) => CustomMySqlSelect<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 OdbcMySqlSelect<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 OdbcMySqlSelect(IFreeSql orm, CommonUtils commonUtils, CommonExpression commonExpression, object dywhere) : base(orm, commonUtils, commonExpression, dywhere) { }
public override string ToSql(string field = null) => CustomMySqlSelect<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 OdbcMySqlSelect<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 OdbcMySqlSelect(IFreeSql orm, CommonUtils commonUtils, CommonExpression commonExpression, object dywhere) : base(orm, commonUtils, commonExpression, dywhere) { }
public override string ToSql(string field = null) => CustomMySqlSelect<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 OdbcMySqlSelect<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 OdbcMySqlSelect(IFreeSql orm, CommonUtils commonUtils, CommonExpression commonExpression, object dywhere) : base(orm, commonUtils, commonExpression, dywhere) { }
public override string ToSql(string field = null) => CustomMySqlSelect<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 OdbcMySqlSelect<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 OdbcMySqlSelect(IFreeSql orm, CommonUtils commonUtils, CommonExpression commonExpression, object dywhere) : base(orm, commonUtils, commonExpression, dywhere) { }
public override string ToSql(string field = null) => CustomMySqlSelect<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 OdbcMySqlSelect<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 OdbcMySqlSelect(IFreeSql orm, CommonUtils commonUtils, CommonExpression commonExpression, object dywhere) : base(orm, commonUtils, commonExpression, dywhere) { }
public override string ToSql(string field = null) => CustomMySqlSelect<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 OdbcMySqlSelect<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 OdbcMySqlSelect(IFreeSql orm, CommonUtils commonUtils, CommonExpression commonExpression, object dywhere) : base(orm, commonUtils, commonExpression, dywhere) { }
public override string ToSql(string field = null) => CustomMySqlSelect<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 OdbcMySqlSelect<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 OdbcMySqlSelect(IFreeSql orm, CommonUtils commonUtils, CommonExpression commonExpression, object dywhere) : base(orm, commonUtils, commonExpression, dywhere) { }
public override string ToSql(string field = null) => CustomMySqlSelect<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 OdbcMySqlSelect<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 OdbcMySqlSelect(IFreeSql orm, CommonUtils commonUtils, CommonExpression commonExpression, object dywhere) : base(orm, commonUtils, commonExpression, dywhere) { }
public override string ToSql(string field = null) => CustomMySqlSelect<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 OdbcMySqlSelect<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 OdbcMySqlSelect(IFreeSql orm, CommonUtils commonUtils, CommonExpression commonExpression, object dywhere) : base(orm, commonUtils, commonExpression, dywhere) { }
public override string ToSql(string field = null) => CustomMySqlSelect<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 OdbcMySqlSelect<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 OdbcMySqlSelect(IFreeSql orm, CommonUtils commonUtils, CommonExpression commonExpression, object dywhere) : base(orm, commonUtils, commonExpression, dywhere) { }
public override string ToSql(string field = null) => CustomMySqlSelect<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 OdbcMySqlSelect<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 OdbcMySqlSelect(IFreeSql orm, CommonUtils commonUtils, CommonExpression commonExpression, object dywhere) : base(orm, commonUtils, commonExpression, dywhere) { }
public override string ToSql(string field = null) => CustomMySqlSelect<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,172 @@
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.Threading;
using System.Threading.Tasks;
namespace FreeSql.Custom.MySql
{
class CustomMySqlUpdate<T1> : Internal.CommonProvider.UpdateProvider<T1>
{
public CustomMySqlUpdate(IFreeSql orm, CommonUtils commonUtils, CommonExpression commonExpression, object dywhere)
: base(orm, commonUtils, commonExpression, dywhere)
{
}
internal StringBuilder InternalSbSet => _set;
internal StringBuilder InternalSbSetIncr => _setIncr;
internal Dictionary<string, bool> InternalIgnore => _ignore;
internal void InternalResetSource(List<T1> source) => _source = source;
internal string InternalWhereCaseSource(string CsName, Func<string, string> thenValue) => WhereCaseSource(CsName, thenValue);
internal void InternalToSqlCaseWhenEnd(StringBuilder sb, ColumnInfo col) => ToSqlCaseWhenEnd(sb, col);
public override int ExecuteAffrows() => base.SplitExecuteAffrows(_batchRowsLimit > 0 ? _batchRowsLimit : 500, _batchParameterLimit > 0 ? _batchParameterLimit : 3000);
protected override List<TReturn> ExecuteUpdated<TReturn>(IEnumerable<ColumnInfo> columns) => base.SplitExecuteUpdated<TReturn>(_batchRowsLimit > 0 ? _batchRowsLimit : 500, _batchParameterLimit > 0 ? _batchParameterLimit : 3000, columns);
protected override List<TReturn> RawExecuteUpdated<TReturn>(IEnumerable<ColumnInfo> columns)
{
var ret = new List<TReturn>();
DbParameter[] dbParms = null;
StringBuilder sbret = null;
ToSqlFetch(sb =>
{
if (dbParms == null)
{
dbParms = _params.Concat(_paramsSource).ToArray();
sbret = new StringBuilder();
sbret.Append(" RETURNING ");
var colidx = 0;
foreach (var col in columns)
{
if (colidx > 0) sbret.Append(", ");
sbret.Append(_commonUtils.RereadColumn(col, _commonUtils.QuoteSqlName(col.Attribute.Name))).Append(" as ").Append(_commonUtils.QuoteSqlName(col.CsName));
++colidx;
}
}
var sql = sb.Append(sbret).ToString();
var before = new Aop.CurdBeforeEventArgs(_table.Type, _table, Aop.CurdType.Update, sql, dbParms);
_orm.Aop.CurdBeforeHandler?.Invoke(this, before);
Exception exception = null;
try
{
var queryType = typeof(TReturn) == typeof(T1) ? (_table.TypeLazy ?? _table.Type) : null;
var rettmp = _orm.Ado.Query<TReturn>(queryType, _connection, _transaction, CommandType.Text, sql, _commandTimeout, dbParms);
ValidateVersionAndThrow(rettmp.Count, sql, dbParms);
ret.AddRange(rettmp);
}
catch (Exception ex)
{
exception = ex;
throw;
}
finally
{
var after = new Aop.CurdAfterEventArgs(before, exception, ret);
_orm.Aop.CurdAfterHandler?.Invoke(this, after);
}
});
sbret?.Clear();
return ret;
}
protected override void ToSqlCase(StringBuilder caseWhen, ColumnInfo[] primarys)
{
if (primarys.Length == 1)
{
var pk = primarys.First();
caseWhen.Append(_commonUtils.RereadColumn(pk, _commonUtils.QuoteSqlName(pk.Attribute.Name)));
return;
}
caseWhen.Append("CONCAT(");
var pkidx = 0;
foreach (var pk in primarys)
{
if (pkidx > 0) caseWhen.Append(", '+', ");
caseWhen.Append(_commonUtils.RereadColumn(pk, _commonUtils.QuoteSqlName(pk.Attribute.Name)));
++pkidx;
}
caseWhen.Append(")");
}
protected override void ToSqlWhen(StringBuilder sb, ColumnInfo[] primarys, object d)
{
if (primarys.Length == 1)
{
sb.Append(_commonUtils.FormatSql("{0}", primarys[0].GetDbValue(d)));
return;
}
sb.Append("CONCAT(");
var pkidx = 0;
foreach (var pk in primarys)
{
if (pkidx > 0) sb.Append(", '+', ");
sb.Append(_commonUtils.FormatSql("{0}", pk.GetDbValue(d)));
++pkidx;
}
sb.Append(")");
}
#if net40
#else
public override Task<int> ExecuteAffrowsAsync(CancellationToken cancellationToken = default) => base.SplitExecuteAffrowsAsync(_batchRowsLimit > 0 ? _batchRowsLimit : 500, _batchParameterLimit > 0 ? _batchParameterLimit : 3000, cancellationToken);
protected override Task<List<TReturn>> ExecuteUpdatedAsync<TReturn>(IEnumerable<ColumnInfo> columns, CancellationToken cancellationToken = default) => base.SplitExecuteUpdatedAsync<TReturn>(_batchRowsLimit > 0 ? _batchRowsLimit : 500, _batchParameterLimit > 0 ? _batchParameterLimit : 3000, columns, cancellationToken);
async protected override Task<List<TReturn>> RawExecuteUpdatedAsync<TReturn>(IEnumerable<ColumnInfo> columns, CancellationToken cancellationToken = default)
{
var ret = new List<TReturn>();
DbParameter[] dbParms = null;
StringBuilder sbret = null;
await ToSqlFetchAsync(async sb =>
{
if (dbParms == null)
{
dbParms = _params.Concat(_paramsSource).ToArray();
sbret = new StringBuilder();
sbret.Append(" RETURNING ");
var colidx = 0;
foreach (var col in columns)
{
if (colidx > 0) sbret.Append(", ");
sbret.Append(_commonUtils.RereadColumn(col, _commonUtils.QuoteSqlName(col.Attribute.Name))).Append(" as ").Append(_commonUtils.QuoteSqlName(col.CsName));
++colidx;
}
}
var sql = sb.Append(sbret).ToString();
var before = new Aop.CurdBeforeEventArgs(_table.Type, _table, Aop.CurdType.Update, sql, dbParms);
_orm.Aop.CurdBeforeHandler?.Invoke(this, before);
Exception exception = null;
try
{
var queryType = typeof(TReturn) == typeof(T1) ? (_table.TypeLazy ?? _table.Type) : null;
var rettmp = await _orm.Ado.QueryAsync<TReturn>(queryType, _connection, _transaction, CommandType.Text, sql, _commandTimeout, dbParms, cancellationToken);
ValidateVersionAndThrow(rettmp.Count, sql, dbParms);
ret.AddRange(rettmp);
}
catch (Exception ex)
{
exception = ex;
throw;
}
finally
{
var after = new Aop.CurdAfterEventArgs(before, exception, ret);
_orm.Aop.CurdAfterHandler?.Invoke(this, after);
}
});
sbret?.Clear();
return ret;
}
#endif
}
}

View File

@ -0,0 +1,73 @@
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.MySql
{
public class CustomMySqlAdo : FreeSql.Internal.CommonProvider.AdoProvider
{
DbProviderFactory Factory => FreeSqlCustomAdapterGlobalExtensions.GetDbProviderFactory(_util._orm);
public CustomMySqlAdo() : base(DataType.OdbcMySql, null, null) { }
public CustomMySqlAdo(CommonUtils util, string masterConnectionString, string[] slaveConnectionStrings, Func<DbConnection> connectionFactory) : base(DataType.OdbcMySql, masterConnectionString, slaveConnectionStrings)
{
base._util = util;
if (connectionFactory != null)
{
var pool = new FreeSql.Internal.CommonProvider.DbConnectionPool(DataType.SqlServer, connectionFactory);
ConnectionString = pool.TestConnection?.ConnectionString;
MasterPool = pool;
return;
}
throw new Exception(CoreStrings.S_CustomAdapter_OnlySuppport_UseConnectionFactory);
}
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 string.Concat("'", param.ToString().Replace("'", "''").Replace("\\", "\\\\"), "'"); //只有 mysql 需要处理反斜杠
else if (param is char)
return string.Concat("'", param.ToString().Replace("'", "''").Replace("\\", "\\\\").Replace('\0', ' '), "'");
else if (param is Enum)
return AddslashesTypeHandler(param.GetType(), param) ?? string.Concat("'", param.ToString().Replace("'", "''").Replace("\\", "\\\\").Replace(", ", ","), "'"); //((Enum)val).ToInt64();
else if (decimal.TryParse(string.Concat(param), out var trydec))
return param;
else if (param is DateTime)
return AddslashesTypeHandler(typeof(DateTime), param) ?? string.Concat("'", ((DateTime)param).ToString("yyyy-MM-dd HH:mm:ss.fff"), "'");
else if (param is DateTime?)
return AddslashesTypeHandler(typeof(DateTime?), param) ?? string.Concat("'", ((DateTime)param).ToString("yyyy-MM-dd HH:mm:ss.fff"), "'");
else if (param is TimeSpan || param is TimeSpan?)
return ((TimeSpan)param).Ticks / 10;
else if (param is byte[])
return $"0x{CommonUtils.BytesSqlRaw(param as byte[])}";
else if (param is IEnumerable)
return AddslashesIEnumerable(param, mapType, mapColumn);
return string.Concat("'", param.ToString().Replace("'", "''").Replace("\\", "\\\\"), "'");
}
public override DbCommand CreateCommand()
{
return Factory.CreateCommand();
}
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,423 @@
using FreeSql.Internal;
using FreeSql.Internal.Model;
using FreeSql.Internal.ObjectPool;
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.MySql
{
class CustomMySqlCodeFirst : Internal.CommonProvider.CodeFirstProvider
{
public override bool IsNoneCommandParameter { get => true; set => base.IsNoneCommandParameter = true; }
public CustomMySqlCodeFirst(IFreeSql orm, CommonUtils commonUtils, CommonExpression commonExpression) : base(orm, commonUtils, commonExpression) { }
static object _dicCsToDbLock = new object();
static Dictionary<string, CsToDb<DbType>> _dicCsToDb = new Dictionary<string, CsToDb<DbType>>() {
{ typeof(bool).FullName, CsToDb.New(DbType.Boolean, "bit","bit(1) NOT NULL", null, false, false) },{ typeof(bool?).FullName, CsToDb.New(DbType.Boolean, "bit","bit(1)", null, true, null) },
{ typeof(sbyte).FullName, CsToDb.New(DbType.SByte, "tinyint", "tinyint(3) NOT NULL", false, false, 0) },{ typeof(sbyte?).FullName, CsToDb.New(DbType.SByte, "tinyint", "tinyint(3)", false, true, null) },
{ typeof(short).FullName, CsToDb.New(DbType.Int16, "smallint","smallint(6) NOT NULL", false, false, 0) },{ typeof(short?).FullName, CsToDb.New(DbType.Int16, "smallint", "smallint(6)", false, true, null) },
{ typeof(int).FullName, CsToDb.New(DbType.Int32, "int", "int(11) NOT NULL", false, false, 0) },{ typeof(int?).FullName, CsToDb.New(DbType.Int32, "int", "int(11)", false, true, null) },
{ typeof(long).FullName, CsToDb.New(DbType.Int64, "bigint","bigint(20) NOT NULL", false, false, 0) },{ typeof(long?).FullName, CsToDb.New(DbType.Int64, "bigint","bigint(20)", false, true, null) },
{ typeof(byte).FullName, CsToDb.New(DbType.Byte, "tinyint","tinyint(3) unsigned NOT NULL", true, false, 0) },{ typeof(byte?).FullName, CsToDb.New(DbType.Byte, "tinyint","tinyint(3) unsigned", true, true, null) },
{ typeof(ushort).FullName, CsToDb.New(DbType.UInt16, "smallint","smallint(5) unsigned NOT NULL", true, false, 0) },{ typeof(ushort?).FullName, CsToDb.New(DbType.UInt16, "smallint", "smallint(5) unsigned", true, true, null) },
{ typeof(uint).FullName, CsToDb.New(DbType.UInt32, "int", "int(10) unsigned NOT NULL", true, false, 0) },{ typeof(uint?).FullName, CsToDb.New(DbType.UInt32, "int", "int(10) unsigned", true, true, null) },
{ typeof(ulong).FullName, CsToDb.New(DbType.UInt64, "bigint", "bigint(20) unsigned NOT NULL", true, false, 0) },{ typeof(ulong?).FullName, CsToDb.New(DbType.UInt64, "bigint", "bigint(20) unsigned", true, true, null) },
{ typeof(double).FullName, CsToDb.New(DbType.Double, "double", "double NOT NULL", false, false, 0) },{ typeof(double?).FullName, CsToDb.New(DbType.Double, "double", "double", false, true, null) },
{ typeof(float).FullName, CsToDb.New(DbType.Single, "float","float NOT NULL", false, false, 0) },{ typeof(float?).FullName, CsToDb.New(DbType.Single, "float","float", false, true, null) },
{ typeof(decimal).FullName, CsToDb.New(DbType.Decimal, "decimal", "decimal(10,2) NOT NULL", false, false, 0) },{ typeof(decimal?).FullName, CsToDb.New(DbType.Decimal, "decimal", "decimal(10,2)", false, true, null) },
{ typeof(TimeSpan).FullName, CsToDb.New(DbType.Time, "time","time NOT NULL", false, false, 0) },{ typeof(TimeSpan?).FullName, CsToDb.New(DbType.Time, "time", "time",false, true, null) },
{ typeof(DateTime).FullName, CsToDb.New(DbType.DateTime, "datetime(3)", "datetime(3) NOT NULL", false, false, new DateTime(1970,1,1)) },{ typeof(DateTime?).FullName, CsToDb.New(DbType.DateTime, "datetime(3)", "datetime(3)", false, true, null) },
{ typeof(byte[]).FullName, CsToDb.New(DbType.Binary, "varbinary", "varbinary(255)", false, null, new byte[0]) },
{ typeof(string).FullName, CsToDb.New(DbType.String, "varchar", "varchar(255)", false, null, "") },
{ typeof(char).FullName, CsToDb.New(DbType.AnsiString, "char", "char(1) NULL", false, null, '\0') },
{ typeof(Guid).FullName, CsToDb.New(DbType.Guid, "char", "char(36) NOT NULL", false, false, Guid.Empty) },{ typeof(Guid?).FullName, CsToDb.New(DbType.Guid, "char", "char(36)", false, true, null) },
};
public override DbInfoResult GetDbInfo(Type type)
{
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 names = string.Join(",", Enum.GetNames(enumType).Select(a => _commonUtils.FormatSql("{0}", a)));
var newItem = enumType.GetCustomAttributes(typeof(FlagsAttribute), false).Any() ?
CsToDb.New(DbType.String, "set", $"set({names}){(type.IsEnum ? " NOT NULL" : "")}", false, type.IsEnum ? false : true, enumType.CreateInstanceGetDefaultValue()) :
CsToDb.New(DbType.String, "enum", $"enum({names}){(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 TypeSchemaAndName[] objects)
{
Object<DbConnection> conn = null;
string database = null;
try
{
conn = _orm.Ado.MasterPool.Get(TimeSpan.FromSeconds(5));
database = conn.Value.Database;
var sb = new StringBuilder();
foreach (var obj in objects)
{
if (sb.Length > 0) sb.Append("\r\n");
var tb = obj.tableSchema;
if (tb == null) throw new Exception(CoreStrings.S_Type_IsNot_Migrable(obj.tableSchema.Type.FullName));
if (tb.Columns.Any() == false) throw new Exception(CoreStrings.S_Type_IsNot_Migrable_0Attributes(obj.tableSchema.Type.FullName));
var tbname = _commonUtils.SplitTableName(tb.DbName);
if (tbname?.Length == 1) tbname = new[] { database, tbname[0] };
var tboldname = _commonUtils.SplitTableName(tb.DbOldName); //旧表名
if (tboldname?.Length == 1) tboldname = new[] { database, tboldname[0] };
if (string.IsNullOrEmpty(obj.tableName) == false)
{
var tbtmpname = _commonUtils.SplitTableName(obj.tableName);
if (tbtmpname?.Length == 1) tbtmpname = new[] { database, tbtmpname[0] };
if (tbname[0] != tbtmpname[0] || tbname[1] != tbtmpname[1])
{
tbname = tbtmpname;
tboldname = null;
}
}
if (string.Compare(tbname[0], database, true) != 0 && LocalExecuteScalar(database, _commonUtils.FormatSql(" select 1 from information_schema.schemata where schema_name={0}", tbname[0])) == null) //创建数据库
sb.Append($"CREATE DATABASE IF NOT EXISTS ").Append(_commonUtils.QuoteSqlName(tbname[0])).Append(" default charset utf8 COLLATE utf8_general_ci;\r\n");
var sbalter = new StringBuilder();
var istmpatler = false; //创建临时表,导入数据,删除旧表,修改
if (LocalExecuteScalar(tbname[0], _commonUtils.FormatSql(" SELECT 1 FROM information_schema.TABLES WHERE table_schema={0} and table_name={1}", tbname)) == null)
{ //表不存在
if (tboldname != null)
{
if (string.Compare(tboldname[0], tbname[0], true) != 0 && LocalExecuteScalar(database, _commonUtils.FormatSql(" select 1 from information_schema.schemata where schema_name={0}", tboldname[0])) == null ||
LocalExecuteScalar(tboldname[0], _commonUtils.FormatSql(" SELECT 1 FROM information_schema.TABLES WHERE table_schema={0} and table_name={1}", tboldname)) == null)
//数据库或表不存在
tboldname = null;
}
if (tboldname == null)
{
//创建表
var createTableName = _commonUtils.QuoteSqlName(tbname[0], tbname[1]);
sb.Append("CREATE TABLE IF NOT EXISTS ").Append(createTableName).Append(" ( ");
foreach (var tbcol in tb.ColumnsByPosition)
{
sb.Append(" \r\n ").Append(_commonUtils.QuoteSqlName(tbcol.Attribute.Name)).Append(" ").Append(tbcol.Attribute.DbType);
if (tbcol.Attribute.IsIdentity == true && tbcol.Attribute.DbType.IndexOf("AUTO_INCREMENT", StringComparison.CurrentCultureIgnoreCase) == -1) sb.Append(" AUTO_INCREMENT");
if (string.IsNullOrEmpty(tbcol.Comment) == false) sb.Append(" COMMENT ").Append(_commonUtils.FormatSql("{0}", tbcol.Comment));
sb.Append(",");
}
if (tb.Primarys.Any())
{
sb.Append(" \r\n PRIMARY KEY (");
foreach (var tbcol in tb.Primarys) sb.Append(_commonUtils.QuoteSqlName(tbcol.Attribute.Name)).Append(", ");
sb.Remove(sb.Length - 2, 2).Append("),");
}
//创建表的索引,感谢 @mafeng8这样写可以支持自增不是主键的情况
foreach (var uk in tb.Indexes)
{
sb.Append(" \r\n ");
if (uk.IsUnique) sb.Append("UNIQUE ");
sb.Append("INDEX ").Append(_commonUtils.QuoteSqlName(ReplaceIndexName(uk.Name, tbname[1]))).Append("(");
foreach (var tbcol in uk.Columns)
{
sb.Append(_commonUtils.QuoteSqlName(tbcol.Column.Attribute.Name));
if (tbcol.IsDesc) sb.Append(" DESC");
sb.Append(", ");
}
sb.Remove(sb.Length - 2, 2).Append("),");
}
sb.Remove(sb.Length - 1, 1);
sb.Append("\r\n) Engine=InnoDB");
if (string.IsNullOrEmpty(tb.Comment) == false)
sb.Append(" Comment=").Append(_commonUtils.FormatSql("{0}", tb.Comment));
sb.Append(";\r\n");
continue;
}
//如果新表,旧表在一个数据库下,直接修改表名
if (string.Compare(tbname[0], tboldname[0], true) == 0)
sbalter.Append("ALTER TABLE ").Append(_commonUtils.QuoteSqlName(tboldname[0], tboldname[1])).Append(" RENAME TO ").Append(_commonUtils.QuoteSqlName(tbname[0], tbname[1])).Append(";\r\n");
else
{
//如果新表,旧表不在一起,创建新表,导入数据,删除旧表
istmpatler = true;
}
}
else
tboldname = null; //如果新表已经存在,不走改表名逻辑
//对比字段,只可以修改类型、增加字段、有限的修改字段名;保证安全不删除字段
var sql = _commonUtils.FormatSql(@"
select
a.column_name,
a.column_type,
case when a.is_nullable = 'YES' then 1 else 0 end 'is_nullable',
case when locate('auto_increment', a.extra) > 0 then 1 else 0 end 'is_identity',
a.column_comment 'comment'
from information_schema.columns a
where a.table_schema in ({0}) and a.table_name in ({1})", tboldname ?? tbname);
var ds = _orm.Ado.ExecuteArray(CommandType.Text, sql);
var tbstruct = ds.ToDictionary(a => string.Concat(a[0]), a =>
{
var a1 = string.Concat(a[1]);
if (a1 == "datetime") a1 = string.Concat(a1, "(0)");
return new
{
column = string.Concat(a[0]),
sqlType = a1,
is_nullable = string.Concat(a[2]) == "1",
is_identity = string.Concat(a[3]) == "1",
is_unsigned = string.Concat(a[1]).EndsWith(" unsigned"),
comment = string.Concat(a[4])
};
}, StringComparer.CurrentCultureIgnoreCase);
if (istmpatler == false)
{
var existsPrimary = LocalExecuteScalar(tbname[0], _commonUtils.FormatSql(" select 1 from information_schema.columns where table_schema={0} and table_name={1} and column_key = 'PRI' limit 1", tbname));
foreach (var tbcol in tb.ColumnsByPosition)
{
var isIdentityChanged = tbcol.Attribute.IsIdentity == true && tbcol.Attribute.DbType.IndexOf("AUTO_INCREMENT", StringComparison.CurrentCultureIgnoreCase) == -1;
if (tbstruct.TryGetValue(tbcol.Attribute.Name, out var tbstructcol) ||
string.IsNullOrEmpty(tbcol.Attribute.OldName) == false && tbstruct.TryGetValue(tbcol.Attribute.OldName, out tbstructcol))
{
var isCommentChanged = tbstructcol.comment != (tbcol.Comment ?? "");
var isDbTypeChanged = tbcol.Attribute.DbType.StartsWith(tbstructcol.sqlType, StringComparison.CurrentCultureIgnoreCase) == false;
if (tbstructcol.sqlType == "datetime(0)" && Regex.IsMatch(tbcol.Attribute.DbType, @"datetime\s*\(", RegexOptions.IgnoreCase) == false)
isDbTypeChanged = tbcol.Attribute.DbType.StartsWith("datetime", StringComparison.CurrentCultureIgnoreCase) == false;
else if (tbstructcol.sqlType.StartsWith("datetime", StringComparison.CurrentCultureIgnoreCase)) isDbTypeChanged = tbcol.Attribute.DbType.StartsWith("datetime", StringComparison.CurrentCultureIgnoreCase) == false ||
(int.TryParse(Regex.Match(tbcol.Attribute.DbType, @"datetime\s*\((\d*)", RegexOptions.IgnoreCase).Groups[1].Value, out var trydtrd) ? trydtrd : 3) !=
(int.TryParse(Regex.Match(tbstructcol.sqlType, @"datetime\s*\((\d*)", RegexOptions.IgnoreCase).Groups[1].Value, out var trydtrd2) ? trydtrd2 : 3);
else if (tbstructcol.sqlType.StartsWith("int", StringComparison.CurrentCultureIgnoreCase)) isDbTypeChanged = tbcol.Attribute.DbType.StartsWith("int", StringComparison.CurrentCultureIgnoreCase) == false;
else if (tbstructcol.sqlType.StartsWith("tinyint", StringComparison.CurrentCultureIgnoreCase)) isDbTypeChanged = tbcol.Attribute.DbType.StartsWith("tinyint", StringComparison.CurrentCultureIgnoreCase) == false;
else if (tbstructcol.sqlType.StartsWith("smallint", StringComparison.CurrentCultureIgnoreCase)) isDbTypeChanged = tbcol.Attribute.DbType.StartsWith("smallint", StringComparison.CurrentCultureIgnoreCase) == false;
else if (tbstructcol.sqlType.StartsWith("bigint", StringComparison.CurrentCultureIgnoreCase)) isDbTypeChanged = tbcol.Attribute.DbType.StartsWith("bigint", StringComparison.CurrentCultureIgnoreCase) == false;
if ((tbcol.Attribute.DbType.IndexOf(" unsigned", StringComparison.CurrentCultureIgnoreCase) != -1) != tbstructcol.is_unsigned ||
isDbTypeChanged ||
tbcol.Attribute.IsNullable != tbstructcol.is_nullable ||
tbcol.Attribute.IsIdentity != tbstructcol.is_identity ||
isCommentChanged)
{
if (tbcol.Attribute.IsNullable != tbstructcol.is_nullable && tbcol.Attribute.IsNullable == false && tbcol.DbDefaultValue != "NULL" && tbcol.Attribute.IsIdentity == false)
sbalter.Append("UPDATE ").Append(_commonUtils.QuoteSqlName(tbname[0], tbname[1])).Append(" SET ").Append(_commonUtils.QuoteSqlName(tbstructcol.column)).Append(" = ").Append(tbcol.DbDefaultValue).Append(" WHERE ").Append(_commonUtils.QuoteSqlName(tbstructcol.column)).Append(" IS NULL;\r\n");
sbalter.Append("ALTER TABLE ").Append(_commonUtils.QuoteSqlName(tbname[0], tbname[1])).Append(" MODIFY ").Append(_commonUtils.QuoteSqlName(tbstructcol.column)).Append(" ").Append(tbcol.Attribute.DbType);
if (string.IsNullOrEmpty(tbcol.Comment) == false) sbalter.Append(" COMMENT ").Append(_commonUtils.FormatSql("{0}", tbcol.Comment ?? ""));
if (tbcol.Attribute.IsIdentity == true && tbcol.Attribute.DbType.IndexOf("AUTO_INCREMENT", StringComparison.CurrentCultureIgnoreCase) == -1) sbalter.Append(" AUTO_INCREMENT");
if (tbcol.Attribute.IsIdentity == true) sbalter.Append(existsPrimary == null ? "" : ", DROP PRIMARY KEY").Append(", ADD PRIMARY KEY(").Append(_commonUtils.QuoteSqlName(tbcol.Attribute.Name)).Append(")");
sbalter.Append(";\r\n");
}
if (string.Compare(tbstructcol.column, tbcol.Attribute.OldName, true) == 0)
{
//修改列名
sbalter.Append("ALTER TABLE ").Append(_commonUtils.QuoteSqlName(tbname[0], tbname[1])).Append(" CHANGE COLUMN ").Append(_commonUtils.QuoteSqlName(tbstructcol.column)).Append(" ").Append(_commonUtils.QuoteSqlName(tbcol.Attribute.Name)).Append(" ").Append(tbcol.Attribute.DbType);
if (string.IsNullOrEmpty(tbcol.Comment) == false) sbalter.Append(" COMMENT ").Append(_commonUtils.FormatSql("{0}", tbcol.Comment ?? ""));
if (tbcol.Attribute.IsIdentity == true && tbcol.Attribute.DbType.IndexOf("AUTO_INCREMENT", StringComparison.CurrentCultureIgnoreCase) == -1) sbalter.Append(" AUTO_INCREMENT");
if (tbcol.Attribute.IsIdentity == true) sbalter.Append(existsPrimary == null ? "" : ", DROP PRIMARY KEY").Append(", ADD PRIMARY KEY(").Append(_commonUtils.QuoteSqlName(tbcol.Attribute.Name)).Append(")");
sbalter.Append(";\r\n");
}
continue;
}
//添加列
sbalter.Append("ALTER TABLE ").Append(_commonUtils.QuoteSqlName(tbname[0], tbname[1])).Append(" ADD ").Append(_commonUtils.QuoteSqlName(tbcol.Attribute.Name)).Append(" ").Append(tbcol.Attribute.DbType);
if (tbcol.Attribute.IsNullable == false && tbcol.DbDefaultValue != "NULL" && tbcol.Attribute.IsIdentity == false) sbalter.Append(" DEFAULT ").Append(tbcol.DbDefaultValue);
if (string.IsNullOrEmpty(tbcol.Comment) == false) sbalter.Append(" COMMENT ").Append(_commonUtils.FormatSql("{0}", tbcol.Comment ?? ""));
if (tbcol.Attribute.IsIdentity == true && tbcol.Attribute.DbType.IndexOf("AUTO_INCREMENT", StringComparison.CurrentCultureIgnoreCase) == -1) sbalter.Append(" AUTO_INCREMENT");
if (tbcol.Attribute.IsIdentity == true) sbalter.Append(existsPrimary == null ? "" : ", DROP PRIMARY KEY").Append(", ADD PRIMARY KEY(").Append(_commonUtils.QuoteSqlName(tbcol.Attribute.Name)).Append(")");
sbalter.Append(";\r\n");
}
var dsuksql = _commonUtils.FormatSql(@"
select
a.column_name,
a.index_name 'index_id',
case when a.collation = 'D' then 1 else 0 end 'IsDesc',
case when a.non_unique = 0 then 1 else 0 end 'IsUnique'
from information_schema.statistics a
where a.table_schema IN ({0}) and a.table_name IN ({1}) and a.index_name <> 'PRIMARY'", tboldname ?? tbname);
var dsuk = _orm.Ado.ExecuteArray(CommandType.Text, dsuksql).Select(a => new[] { string.Concat(a[0]), string.Concat(a[1]), string.Concat(a[2]), string.Concat(a[3]) });
foreach (var uk in tb.Indexes)
{
if (string.IsNullOrEmpty(uk.Name) || uk.Columns.Any() == false) continue;
var ukname = ReplaceIndexName(uk.Name, tbname[1]);
var dsukfind1 = dsuk.Where(a => string.Compare(a[1], ukname, true) == 0).ToArray();
if (dsukfind1.Any() == false || dsukfind1.Length != uk.Columns.Length || dsukfind1.Where(a => (a[3] == "1") == uk.IsUnique && uk.Columns.Where(b => string.Compare(b.Column.Attribute.Name, a[0], true) == 0 && (a[2] == "1") == b.IsDesc).Any()).Count() != uk.Columns.Length)
{
if (dsukfind1.Any()) sbalter.Append("DROP INDEX ").Append(_commonUtils.QuoteSqlName(ukname)).Append(" ON ").Append(_commonUtils.QuoteSqlName(tbname[0], tbname[1])).Append(";\r\n");
sbalter.Append("CREATE ");
if (uk.IsUnique) sbalter.Append("UNIQUE ");
sbalter.Append("INDEX ").Append(_commonUtils.QuoteSqlName(ukname)).Append(" ON ").Append(_commonUtils.QuoteSqlName(tbname[0], tbname[1])).Append("(");
foreach (var tbcol in uk.Columns)
{
sbalter.Append(_commonUtils.QuoteSqlName(tbcol.Column.Attribute.Name));
if (tbcol.IsDesc) sbalter.Append(" DESC");
sbalter.Append(", ");
}
sbalter.Remove(sbalter.Length - 2, 2).Append(");\r\n");
}
}
}
if (istmpatler == false)
{
var dbcomment = string.Concat(_orm.Ado.ExecuteScalar(CommandType.Text, _commonUtils.FormatSql(@" select table_comment from information_schema.tables where table_schema = {0} and table_name = {1}", tbname[0], tbname[1])));
if (dbcomment != (tb.Comment ?? ""))
sb.Append("ALTER TABLE ").Append(_commonUtils.QuoteSqlName(tbname[0], tbname[1])).Append(" COMMENT ").Append(" ").Append(_commonUtils.FormatSql("{0}", tb.Comment ?? "")).Append(";\r\n");
sb.Insert(0, sbalter);
continue;
}
//创建临时表,数据导进临时表,然后删除原表,将临时表改名为原表名
var tablename = tboldname == null ? _commonUtils.QuoteSqlName(tbname[0], tbname[1]) : _commonUtils.QuoteSqlName(tboldname[0], tboldname[1]);
var tmptablename = _commonUtils.QuoteSqlName(tbname[0], $"FreeSqlTmp_{tbname[1]}");
//创建临时表
sb.Append("CREATE TABLE IF NOT EXISTS ").Append(tmptablename).Append(" ( ");
foreach (var tbcol in tb.ColumnsByPosition)
{
sb.Append(" \r\n ").Append(_commonUtils.QuoteSqlName(tbcol.Attribute.Name)).Append(" ").Append(tbcol.Attribute.DbType);
if (tbcol.Attribute.IsIdentity == true && tbcol.Attribute.DbType.IndexOf("AUTO_INCREMENT", StringComparison.CurrentCultureIgnoreCase) == -1) sb.Append(" AUTO_INCREMENT");
if (string.IsNullOrEmpty(tbcol.Comment) == false) sb.Append(" COMMENT ").Append(_commonUtils.FormatSql("{0}", tbcol.Comment));
sb.Append(",");
}
if (tb.Primarys.Any())
{
sb.Append(" \r\n PRIMARY KEY (");
foreach (var tbcol in tb.Primarys) sb.Append(_commonUtils.QuoteSqlName(tbcol.Attribute.Name)).Append(", ");
sb.Remove(sb.Length - 2, 2).Append("),");
}
sb.Remove(sb.Length - 1, 1);
sb.Append("\r\n) Engine=InnoDB");
if (string.IsNullOrEmpty(tb.Comment) == false)
sb.Append(" Comment=").Append(_commonUtils.FormatSql("{0}", tb.Comment));
sb.Append(";\r\n");
sb.Append("INSERT INTO ").Append(tmptablename).Append(" (");
foreach (var tbcol in tb.ColumnsByPosition)
sb.Append(_commonUtils.QuoteSqlName(tbcol.Attribute.Name)).Append(", ");
sb.Remove(sb.Length - 2, 2).Append(")\r\nSELECT ");
foreach (var tbcol in tb.ColumnsByPosition)
{
var insertvalue = "NULL";
if (tbstruct.TryGetValue(tbcol.Attribute.Name, out var tbstructcol) ||
string.IsNullOrEmpty(tbcol.Attribute.OldName) == false && tbstruct.TryGetValue(tbcol.Attribute.OldName, out tbstructcol))
{
insertvalue = _commonUtils.QuoteSqlName(tbstructcol.column);
if (tbcol.Attribute.DbType.StartsWith(tbstructcol.sqlType, StringComparison.CurrentCultureIgnoreCase) == false)
{
//insertvalue = $"cast({insertvalue} as {tbcol.Attribute.DbType.Split(' ').First()})";
}
if (tbcol.Attribute.IsNullable != tbstructcol.is_nullable)
insertvalue = $"ifnull({insertvalue},{tbcol.DbDefaultValue})";
}
else if (tbcol.Attribute.IsNullable == false)
if (tbcol.DbDefaultValue != "NULL" && tbcol.Attribute.IsIdentity == false)
insertvalue = tbcol.DbDefaultValue;
sb.Append(insertvalue).Append(", ");
}
sb.Remove(sb.Length - 2, 2).Append(" FROM ").Append(tablename).Append(";\r\n");
sb.Append("DROP TABLE ").Append(tablename).Append(";\r\n");
sb.Append("ALTER TABLE ").Append(tmptablename).Append(" RENAME TO ").Append(_commonUtils.QuoteSqlName(tbname[0], tbname[1])).Append(";\r\n");
//创建表的索引
foreach (var uk in tb.Indexes)
{
sb.Append("CREATE ");
if (uk.IsUnique) sb.Append("UNIQUE ");
sb.Append("INDEX ").Append(_commonUtils.QuoteSqlName(ReplaceIndexName(uk.Name, tbname[1]))).Append(" ON ").Append(tablename).Append("(");
foreach (var tbcol in uk.Columns)
{
sb.Append(_commonUtils.QuoteSqlName(tbcol.Column.Attribute.Name));
if (tbcol.IsDesc) sb.Append(" DESC");
sb.Append(", ");
}
sb.Remove(sb.Length - 2, 2).Append(");\r\n");
}
}
return sb.Length == 0 ? null : sb.ToString();
}
finally
{
try
{
if (string.IsNullOrEmpty(database) == false)
conn.Value.ChangeDatabase(database);
_orm.Ado.MasterPool.Return(conn);
}
catch
{
_orm.Ado.MasterPool.Return(conn, true);
}
}
object LocalExecuteScalar(string db, string sql)
{
if (string.Compare(database, db) != 0) conn.Value.ChangeDatabase(db);
try
{
using (var cmd = conn.Value.CreateCommand())
{
cmd.CommandText = sql;
cmd.CommandType = CommandType.Text;
var before = new Aop.CommandBeforeEventArgs(cmd);
this._orm?.Aop.CommandBeforeHandler?.Invoke(this._orm, before);
Exception afterException = null;
try
{
return cmd.ExecuteScalar();
}
catch (Exception ex)
{
afterException = ex;
throw;
}
finally
{
this._orm?.Aop.CommandAfterHandler?.Invoke(this._orm, new Aop.CommandAfterEventArgs(before, afterException, null));
}
}
}
finally
{
if (string.Compare(database, db) != 0) conn.Value.ChangeDatabase(database);
}
}
}
public override int ExecuteDDLStatements(string ddl)
{
if (string.IsNullOrEmpty(ddl)) return 0;
var scripts = ddl.Split(new string[] { ";\r\n" }, StringSplitOptions.None).Where(a => string.IsNullOrEmpty(a.Trim()) == false).ToArray();
if (scripts.Any() == false) return 0;
var affrows = 0;
foreach (var script in scripts)
affrows += base.ExecuteDDLStatements(script);
return affrows;
}
}
}

View File

@ -0,0 +1,457 @@
using FreeSql.DatabaseModel;
using FreeSql.Internal;
using FreeSql.Internal.Model;
using System;
using System.Collections.Generic;
using System.Data;
using System.Linq;
using System.Text;
using System.Text.RegularExpressions;
namespace FreeSql.Custom.MySql
{
class CustomMySqlDbFirst : IDbFirst
{
IFreeSql _orm;
protected CommonUtils _commonUtils;
protected CommonExpression _commonExpression;
public CustomMySqlDbFirst(IFreeSql orm, CommonUtils commonUtils, CommonExpression commonExpression)
{
_orm = orm;
_commonUtils = commonUtils;
_commonExpression = commonExpression;
}
public int GetDbType(DbColumnInfo column) => (int)GetSqlDbType(column);
DbType GetSqlDbType(DbColumnInfo column)
{
var is_unsigned = column.DbTypeTextFull?.ToLower().EndsWith(" unsigned") == true;
switch (column.DbTypeText?.ToLower())
{
case "bit": return DbType.Boolean;
case "tinyint": return is_unsigned ? DbType.Byte : DbType.SByte;
case "smallint": return is_unsigned ? DbType.Int16 : DbType.Int16;
case "mediumint": return is_unsigned ? DbType.Int32 : DbType.Int32;
case "int": return is_unsigned ? DbType.Int32 : DbType.Int32;
case "bigint": return is_unsigned ? DbType.UInt64 : DbType.Int64;
case "real":
case "double": return DbType.Double;
case "float": return DbType.Single;
case "numeric":
case "decimal": return DbType.Decimal;
case "year": return DbType.Int32;
case "time": return DbType.Time;
case "date": return DbType.Date;
case "timestamp": return DbType.DateTime;
case "datetime": return DbType.DateTime;
case "tinyblob": return DbType.Binary;
case "blob": return DbType.Binary;
case "mediumblob": return DbType.Binary;
case "longblob": return DbType.Binary;
case "binary": return DbType.Binary;
case "varbinary": return DbType.Binary;
case "tinytext": return DbType.String;
case "text": return DbType.String;
case "mediumtext": return DbType.String;
case "longtext": return DbType.String;
case "char": return column.MaxLength == 36 ? DbType.Guid : DbType.AnsiString;
case "varchar": return DbType.String;
case "set": return DbType.String;
case "enum": return DbType.String;
default: return DbType.String;
}
}
static readonly Dictionary<int, DbToCs> _dicDbToCs = new Dictionary<int, DbToCs>() {
{ (int)DbType.Boolean, new DbToCs("(bool?)", "{0} == \"1\"", "{0} == true ? \"1\" : \"0\"", "bool?", typeof(bool), typeof(bool?), "{0}.Value", "GetBoolean") },
{ (int)DbType.SByte, new DbToCs("(sbyte?)", "sbyte.Parse({0})", "{0}.ToString()", "sbyte?", typeof(sbyte), typeof(sbyte?), "{0}.Value", "GetInt16") },
{ (int)DbType.Int16, new DbToCs("(short?)", "short.Parse({0})", "{0}.ToString()", "short?", typeof(short), typeof(short?), "{0}.Value", "GetInt16") },
{ (int)DbType.Int32, new DbToCs("(int?)", "int.Parse({0})", "{0}.ToString()", "int?", typeof(int), typeof(int?), "{0}.Value", "GetInt32") },
{ (int)DbType.Int64, new DbToCs("(long?)", "long.Parse({0})", "{0}.ToString()", "long?", typeof(long), typeof(long?), "{0}.Value", "GetInt64") },
{ (int)DbType.Byte, new DbToCs("(byte?)", "byte.Parse({0})", "{0}.ToString()", "byte?", typeof(byte), typeof(byte?), "{0}.Value", "GetByte") },
{ (int)DbType.UInt16, new DbToCs("(ushort?)", "ushort.Parse({0})", "{0}.ToString()", "ushort?", typeof(ushort), typeof(ushort?), "{0}.Value", "GetInt32") },
{ (int)DbType.UInt32, new DbToCs("(uint?)", "uint.Parse({0})", "{0}.ToString()", "uint?", typeof(uint), typeof(uint?), "{0}.Value", "GetInt64") },
{ (int)DbType.UInt64, new DbToCs("(ulong?)", "ulong.Parse({0})", "{0}.ToString()", "ulong?", typeof(ulong), typeof(ulong?), "{0}.Value", "GetInt64") },
{ (int)DbType.Double, new DbToCs("(double?)", "double.Parse({0})", "{0}.ToString()", "double?", typeof(double), typeof(double?), "{0}.Value", "GetDouble") },
{ (int)DbType.Single, new DbToCs("(float?)", "float.Parse({0})", "{0}.ToString()", "float?", typeof(float), typeof(float?), "{0}.Value", "GetFloat") },
{ (int)DbType.Decimal, new DbToCs("(decimal?)", "decimal.Parse({0})", "{0}.ToString()", "decimal?", typeof(decimal), typeof(decimal?), "{0}.Value", "GetDecimal") },
{ (int)DbType.Time, new DbToCs("(TimeSpan?)", "TimeSpan.Parse(double.Parse({0}))", "{0}.Ticks.ToString()", "TimeSpan?", typeof(TimeSpan), typeof(TimeSpan?), "{0}.Value", "GetValue") },
{ (int)DbType.Date, new DbToCs("(DateTime?)", "new DateTime(long.Parse({0}))", "{0}.Ticks.ToString()", "DateTime?", typeof(DateTime), typeof(DateTime?), "{0}.Value", "GetDateTime") },
{ (int)DbType.DateTime, new DbToCs("(DateTime?)", "new DateTime(long.Parse({0}))", "{0}.Ticks.ToString()", "DateTime?", typeof(DateTime), typeof(DateTime?), "{0}.Value", "GetDateTime") },
{ (int)DbType.Binary, new DbToCs("(byte[])", "Convert.FromBase64String({0})", "Convert.ToBase64String({0})", "byte[]", typeof(byte[]), typeof(byte[]), "{0}", "GetValue") },
{ (int)DbType.String, new DbToCs("", "{0}.Replace(StringifySplit, \"|\")", "{0}.Replace(\"|\", StringifySplit)", "string", typeof(string), typeof(string), "{0}", "GetString") },
{ (int)DbType.AnsiString, new DbToCs("", "{0}.Replace(StringifySplit, \"|\")", "{0}.Replace(\"|\", StringifySplit)", "string", typeof(string), typeof(string), "{0}", "GetString") },
{ (int)DbType.Guid, new DbToCs("(Guid?)", "Guid.Parse({0})", "{0}.ToString()", "Guid?", typeof(Guid), typeof(Guid?), "{0}", "GetString") },
};
public string GetCsConvert(DbColumnInfo column) => _dicDbToCs.TryGetValue(column.DbType, out var trydc) ? (column.IsNullable ? trydc.csConvert : trydc.csConvert.Replace("?", "")) : null;
public string GetCsParse(DbColumnInfo column) => _dicDbToCs.TryGetValue(column.DbType, out var trydc) ? trydc.csParse : null;
public string GetCsStringify(DbColumnInfo column) => _dicDbToCs.TryGetValue(column.DbType, out var trydc) ? trydc.csStringify : null;
public string GetCsType(DbColumnInfo column) => _dicDbToCs.TryGetValue(column.DbType, out var trydc) ? (column.IsNullable ? trydc.csType : trydc.csType.Replace("?", "")) : null;
public Type GetCsTypeInfo(DbColumnInfo column) => _dicDbToCs.TryGetValue(column.DbType, out var trydc) ? trydc.csTypeInfo : null;
public string GetCsTypeValue(DbColumnInfo column) => _dicDbToCs.TryGetValue(column.DbType, out var trydc) ? trydc.csTypeValue : null;
public string GetDataReaderMethod(DbColumnInfo column) => _dicDbToCs.TryGetValue(column.DbType, out var trydc) ? trydc.dataReaderMethod : null;
public List<string> GetDatabases()
{
var sql = @" select schema_name from information_schema.schemata where schema_name not in ('information_schema', 'mysql', 'performance_schema')";
var ds = _orm.Ado.ExecuteArray(CommandType.Text, sql);
return ds.Select(a => a.FirstOrDefault()?.ToString()).ToList();
}
public bool ExistsTable(string name, bool ignoreCase)
{
if (string.IsNullOrEmpty(name)) return false;
var tbname = _commonUtils.SplitTableName(name);
if (tbname?.Length == 1)
{
var database = "";
using (var conn = _orm.Ado.MasterPool.Get(TimeSpan.FromSeconds(5)))
{
database = conn.Value.Database;
}
tbname = new[] { database, tbname[0] };
}
if (ignoreCase) tbname = tbname.Select(a => a.ToLower()).ToArray();
var sql = $" SELECT 1 FROM information_schema.TABLES WHERE {(ignoreCase ? "lower(table_schema)" : "table_schema")} = {_commonUtils.FormatSql("{0}", tbname[0])} and {(ignoreCase ? "lower(table_name)" : "table_name")} = {_commonUtils.FormatSql("{0}", tbname[1])}";
return string.Concat(_orm.Ado.ExecuteScalar(CommandType.Text, sql)) == "1";
}
public DbTableInfo GetTableByName(string name, bool ignoreCase = true) => GetTables(null, name, ignoreCase)?.FirstOrDefault();
public List<DbTableInfo> GetTablesByDatabase(params string[] database) => GetTables(database, null, false);
public List<DbTableInfo> GetTables(string[] database, string tablename, bool ignoreCase)
{
var loc1 = new List<DbTableInfo>();
var loc2 = new Dictionary<string, DbTableInfo>(StringComparer.CurrentCultureIgnoreCase);
var loc3 = new Dictionary<string, Dictionary<string, DbColumnInfo>>(StringComparer.CurrentCultureIgnoreCase);
string[] tbname = null;
if (string.IsNullOrEmpty(tablename) == false)
{
tbname = _commonUtils.SplitTableName(tablename);
if (tbname?.Length == 1)
{
using (var conn = _orm.Ado.MasterPool.Get(TimeSpan.FromSeconds(5)))
{
if (string.IsNullOrEmpty(conn.Value.Database)) return loc1;
tbname = new[] { conn.Value.Database, tbname[0] };
}
}
if (ignoreCase) tbname = tbname.Select(a => a.ToLower()).ToArray();
database = new[] { tbname[0] };
}
else if (database == null || database.Any() == false)
{
using (var conn = _orm.Ado.MasterPool.Get())
{
if (string.IsNullOrEmpty(conn.Value.Database)) return loc1;
database = new[] { conn.Value.Database };
}
}
var databaseIn = string.Join(",", database.Select(a => _commonUtils.FormatSql("{0}", a)));
var sql = $@"
select
concat(a.table_schema, '.', a.table_name) 'id',
a.table_schema 'schema',
a.table_name 'table',
a.table_comment,
a.table_type 'type'
from information_schema.tables a
where {(ignoreCase ? "lower(a.table_schema)" : "a.table_schema")} in ({databaseIn}){(tbname == null ? "" : $" and {(ignoreCase ? "lower(a.table_name)" : "a.table_name")}={_commonUtils.FormatSql("{0}", tbname[1])}")}";
var ds = _orm.Ado.ExecuteArray(CommandType.Text, sql);
if (ds == null) return loc1;
var loc6 = new List<string[]>();
var loc66 = new List<string[]>();
var loc6_1000 = new List<string>();
var loc66_1000 = new List<string>();
foreach (var row in ds)
{
var table_id = string.Concat(row[0]);
var schema = string.Concat(row[1]);
var table = string.Concat(row[2]);
var comment = string.Concat(row[3]);
var type = string.Concat(row[4]) == "VIEW" ? DbTableType.VIEW : DbTableType.TABLE;
if (database.Length == 1)
{
table_id = table_id.Substring(table_id.IndexOf('.') + 1);
schema = "";
}
loc2.Add(table_id, new DbTableInfo { Id = table_id, Schema = schema, Name = table, Comment = comment, Type = type });
loc3.Add(table_id, new Dictionary<string, DbColumnInfo>(StringComparer.CurrentCultureIgnoreCase));
switch (type)
{
case DbTableType.TABLE:
case DbTableType.VIEW:
loc6_1000.Add(table.Replace("'", "''"));
if (loc6_1000.Count >= 500)
{
loc6.Add(loc6_1000.ToArray());
loc6_1000.Clear();
}
break;
case DbTableType.StoreProcedure:
loc66_1000.Add(table.Replace("'", "''"));
if (loc66_1000.Count >= 500)
{
loc66.Add(loc66_1000.ToArray());
loc66_1000.Clear();
}
break;
}
}
if (loc6_1000.Count > 0) loc6.Add(loc6_1000.ToArray());
if (loc66_1000.Count > 0) loc66.Add(loc66_1000.ToArray());
if (loc6.Count == 0) return loc1;
var loc8 = new StringBuilder().Append("(");
for (var loc8idx = 0; loc8idx < loc6.Count; loc8idx++)
{
if (loc8idx > 0) loc8.Append(" OR ");
loc8.Append("a.table_name in (");
for (var loc8idx2 = 0; loc8idx2 < loc6[loc8idx].Length; loc8idx2++)
{
if (loc8idx2 > 0) loc8.Append(",");
loc8.Append($"'{loc6[loc8idx][loc8idx2]}'");
}
loc8.Append(")");
}
loc8.Append(")");
sql = $@"
select
concat(a.table_schema, '.', a.table_name),
a.column_name,
a.data_type,
ifnull(a.character_maximum_length, 0) 'len',
a.column_type,
case when a.is_nullable = 'YES' then 1 else 0 end 'is_nullable',
case when locate('auto_increment', a.extra) > 0 then 1 else 0 end 'is_identity',
a.column_comment 'comment',
a.column_default 'default_value',
a.ordinal_position
from information_schema.columns a
where {(ignoreCase ? "lower(a.table_schema)" : "a.table_schema")} in ({databaseIn}) and {loc8}
";
ds = _orm.Ado.ExecuteArray(CommandType.Text, sql);
if (ds == null) return loc1;
foreach (var row in ds)
{
string table_id = string.Concat(row[0]);
string column = string.Concat(row[1]);
string type = string.Concat(row[2]);
//long max_length = long.Parse(string.Concat(row[3]));
string sqlType = string.Concat(row[4]);
var m_len = Regex.Match(sqlType, @"\w+\((\d+)");
int max_length = m_len.Success ? int.Parse(m_len.Groups[1].Value) : -1;
bool is_nullable = string.Concat(row[5]) == "1";
bool is_identity = string.Concat(row[6]) == "1";
string comment = string.Concat(row[7]);
string defaultValue = string.Concat(row[8]);
var position = int.Parse(string.Concat(row[9]));
if (max_length == 0) max_length = -1;
if (database.Length == 1)
{
table_id = table_id.Substring(table_id.IndexOf('.') + 1);
}
loc3[table_id].Add(column, new DbColumnInfo
{
Name = column,
MaxLength = max_length,
IsIdentity = is_identity,
IsNullable = is_nullable,
IsPrimary = false,
DbTypeText = type,
DbTypeTextFull = sqlType,
Table = loc2[table_id],
Comment = comment,
DefaultValue = defaultValue,
Position = position
});
loc3[table_id][column].DbType = this.GetDbType(loc3[table_id][column]);
loc3[table_id][column].CsType = this.GetCsTypeInfo(loc3[table_id][column]);
}
sql = $@"
select
concat(a.table_schema, '.', a.table_name) 'table_id',
a.column_name,
a.index_name 'index_id',
case when a.non_unique = 0 then 1 else 0 end 'IsUnique',
case when a.index_name = 'PRIMARY' then 1 else 0 end 'IsPrimaryKey',
0 'IsClustered',
case when a.collation = 'D' then 1 else 0 end 'IsDesc'
from information_schema.statistics a
where {(ignoreCase ? "lower(a.table_schema)" : "a.table_schema")} in ({databaseIn}) and {loc8}
";
ds = _orm.Ado.ExecuteArray(CommandType.Text, sql);
if (ds == null) return loc1;
var indexColumns = new Dictionary<string, Dictionary<string, DbIndexInfo>>(StringComparer.CurrentCultureIgnoreCase);
var uniqueColumns = new Dictionary<string, Dictionary<string, DbIndexInfo>>(StringComparer.CurrentCultureIgnoreCase);
foreach (var row in ds)
{
string table_id = string.Concat(row[0]);
string column = string.Concat(row[1]);
string index_id = string.Concat(row[2]);
bool is_unique = string.Concat(row[3]) == "1";
bool is_primary_key = string.Concat(row[4]) == "1";
bool is_clustered = string.Concat(row[5]) == "1";
bool is_desc = string.Concat(row[6]) == "1";
if (database.Length == 1)
table_id = table_id.Substring(table_id.IndexOf('.') + 1);
if (loc3.ContainsKey(table_id) == false || loc3[table_id].ContainsKey(column) == false) continue;
var loc9 = loc3[table_id][column];
if (loc9.IsPrimary == false && is_primary_key) loc9.IsPrimary = is_primary_key;
Dictionary<string, DbIndexInfo> loc10 = null;
DbIndexInfo loc11 = null;
if (!indexColumns.TryGetValue(table_id, out loc10))
indexColumns.Add(table_id, loc10 = new Dictionary<string, DbIndexInfo>(StringComparer.CurrentCultureIgnoreCase));
if (!loc10.TryGetValue(index_id, out loc11))
loc10.Add(index_id, loc11 = new DbIndexInfo());
loc11.Columns.Add(new DbIndexColumnInfo { Column = loc9, IsDesc = is_desc });
if (is_unique && !is_primary_key)
{
if (!uniqueColumns.TryGetValue(table_id, out loc10))
uniqueColumns.Add(table_id, loc10 = new Dictionary<string, DbIndexInfo>(StringComparer.CurrentCultureIgnoreCase));
if (!loc10.TryGetValue(index_id, out loc11))
loc10.Add(index_id, loc11 = new DbIndexInfo());
loc11.Columns.Add(new DbIndexColumnInfo { Column = loc9, IsDesc = is_desc });
}
}
foreach (string table_id in indexColumns.Keys)
{
foreach (var column in indexColumns[table_id])
loc2[table_id].IndexesDict.Add(column.Key, column.Value);
}
foreach (string table_id in uniqueColumns.Keys)
{
foreach (var column in uniqueColumns[table_id])
{
column.Value.Columns.Sort((c1, c2) => c1.Column.Name.CompareTo(c2.Column.Name));
loc2[table_id].UniquesDict.Add(column.Key, column.Value);
}
}
if (tbname == null)
{
sql = $@"
select
concat(a.constraint_schema, '.', a.table_name) 'table_id',
a.column_name,
a.constraint_name 'FKId',
concat(a.referenced_table_schema, '.', a.referenced_table_name) 'ref_table_id',
1 'IsForeignKey',
a.referenced_column_name 'ref_column'
from information_schema.key_column_usage a
where {(ignoreCase ? "lower(a.constraint_schema)" : "a.constraint_schema")} in ({databaseIn}) and {loc8} and not isnull(position_in_unique_constraint)
";
ds = _orm.Ado.ExecuteArray(CommandType.Text, sql);
if (ds == null) return loc1;
var fkColumns = new Dictionary<string, Dictionary<string, DbForeignInfo>>(StringComparer.CurrentCultureIgnoreCase);
foreach (var row in ds)
{
string table_id = string.Concat(row[0]);
string column = string.Concat(row[1]);
string fk_id = string.Concat(row[2]);
string ref_table_id = string.Concat(row[3]);
bool is_foreign_key = string.Concat(row[4]) == "1";
string referenced_column = string.Concat(row[5]);
if (database.Length == 1)
{
table_id = table_id.Substring(table_id.IndexOf('.') + 1);
ref_table_id = ref_table_id.Substring(ref_table_id.IndexOf('.') + 1);
}
if (loc3.ContainsKey(table_id) == false || loc3[table_id].ContainsKey(column) == false) continue;
var loc9 = loc3[table_id][column];
if (loc2.ContainsKey(ref_table_id) == false) continue;
var loc10 = loc2[ref_table_id];
var loc11 = loc3[ref_table_id][referenced_column];
Dictionary<string, DbForeignInfo> loc12 = null;
DbForeignInfo loc13 = null;
if (!fkColumns.TryGetValue(table_id, out loc12))
fkColumns.Add(table_id, loc12 = new Dictionary<string, DbForeignInfo>(StringComparer.CurrentCultureIgnoreCase));
if (!loc12.TryGetValue(fk_id, out loc13))
loc12.Add(fk_id, loc13 = new DbForeignInfo { Table = loc2[table_id], ReferencedTable = loc10 });
loc13.Columns.Add(loc9);
loc13.ReferencedColumns.Add(loc11);
}
foreach (var table_id in fkColumns.Keys)
foreach (var fk in fkColumns[table_id])
loc2[table_id].ForeignsDict.Add(fk.Key, fk.Value);
}
foreach (var table_id in loc3.Keys)
{
foreach (var loc5 in loc3[table_id].Values)
{
loc2[table_id].Columns.Add(loc5);
if (loc5.IsIdentity) loc2[table_id].Identitys.Add(loc5);
if (loc5.IsPrimary) loc2[table_id].Primarys.Add(loc5);
}
}
foreach (var loc4 in loc2.Values)
{
//if (loc4.Primarys.Count == 0 && loc4.UniquesDict.Count > 0)
//{
// foreach (var loc5 in loc4.UniquesDict.First().Value.Columns)
// {
// loc5.Column.IsPrimary = true;
// loc4.Primarys.Add(loc5.Column);
// }
//}
loc4.Primarys.Sort((c1, c2) => c1.Name.CompareTo(c2.Name));
loc4.Columns.Sort((c1, c2) =>
{
int compare = c2.IsPrimary.CompareTo(c1.IsPrimary);
if (compare == 0)
{
bool b1 = loc4.ForeignsDict.Values.Where(fk => fk.Columns.Where(c3 => c3.Name == c1.Name).Any()).Any();
bool b2 = loc4.ForeignsDict.Values.Where(fk => fk.Columns.Where(c3 => c3.Name == c2.Name).Any()).Any();
compare = b2.CompareTo(b1);
}
if (compare == 0) compare = c1.Name.CompareTo(c2.Name);
return compare;
});
loc1.Add(loc4);
}
loc1.Sort((t1, t2) =>
{
var ret = t1.Schema.CompareTo(t2.Schema);
if (ret == 0) ret = t1.Name.CompareTo(t2.Name);
return ret;
});
loc2.Clear();
loc3.Clear();
return loc1;
}
public List<DbEnumInfo> GetEnumsByDatabase(params string[] database)
{
return new List<DbEnumInfo>();
}
}
}

View File

@ -0,0 +1,578 @@
using FreeSql.Internal;
using System;
using System.Collections;
using System.Linq;
using System.Linq.Expressions;
using System.Text;
using System.Text.RegularExpressions;
namespace FreeSql.Custom.MySql
{
class CustomMySqlExpression : CommonExpression
{
public CustomMySqlExpression(CommonUtils common) : base(common) { }
public override string ExpressionLambdaToSqlOther(Expression exp, ExpTSC tsc)
{
Func<Expression, string> getExp = exparg => ExpressionLambdaToSql(exparg, tsc);
switch (exp.NodeType)
{
case ExpressionType.ArrayLength:
var arrOper = (exp as UnaryExpression)?.Operand;
if (arrOper.Type == typeof(byte[])) return $"octet_length({getExp(arrOper)})";
break;
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 $"({getExp(operandExp)} not in ('0','false'))";
case "System.Byte": return $"cast({getExp(operandExp)} as unsigned)";
case "System.Char": return $"substr(cast({getExp(operandExp)} as char), 1, 1)";
case "System.DateTime": return ExpressionConstDateTime(operandExp) ?? $"cast({getExp(operandExp)} as datetime)";
case "System.Decimal": return $"cast({getExp(operandExp)} as decimal(36,18))";
case "System.Double": return $"cast({getExp(operandExp)} as decimal(32,16))";
case "System.Int16":
case "System.Int32":
case "System.Int64":
case "System.SByte": return $"cast({getExp(operandExp)} as signed)";
case "System.Single": return $"cast({getExp(operandExp)} as decimal(14,7))";
case "System.String": return $"cast({getExp(operandExp)} as char)";
case "System.UInt16":
case "System.UInt32":
case "System.UInt64": return $"cast({getExp(operandExp)} as unsigned)";
case "System.Guid": return $"substr(cast({getExp(operandExp)} as char), 1, 36)";
}
}
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 $"({getExp(callExp.Arguments[0])} not in ('0','false'))";
case "System.Byte": return $"cast({getExp(callExp.Arguments[0])} as unsigned)";
case "System.Char": return $"substr(cast({getExp(callExp.Arguments[0])} as char), 1, 1)";
case "System.DateTime": return ExpressionConstDateTime(callExp.Arguments[0]) ?? $"cast({getExp(callExp.Arguments[0])} as datetime)";
case "System.Decimal": return $"cast({getExp(callExp.Arguments[0])} as decimal(36,18))";
case "System.Double": return $"cast({getExp(callExp.Arguments[0])} as decimal(32,16))";
case "System.Int16":
case "System.Int32":
case "System.Int64":
case "System.SByte": return $"cast({getExp(callExp.Arguments[0])} as signed)";
case "System.Single": return $"cast({getExp(callExp.Arguments[0])} as decimal(14,7))";
case "System.UInt16":
case "System.UInt32":
case "System.UInt64": return $"cast({getExp(callExp.Arguments[0])} as unsigned)";
case "System.Guid": return $"substr(cast({getExp(callExp.Arguments[0])} as char), 1, 36)";
}
return null;
case "NewGuid":
return null;
case "Next":
if (callExp.Object?.Type == typeof(Random)) return "cast(rand()*1000000000 as signed)";
return null;
case "NextDouble":
if (callExp.Object?.Type == typeof(Random)) return "rand()";
return null;
case "Random":
if (callExp.Method.DeclaringType.IsNumberType()) return "rand()";
return null;
case "ToString":
if (callExp.Object != null)
{
if (callExp.Object.Type.NullableTypeOrThis().IsEnum)
{
tsc.SetMapColumnTmp(null);
var oldMapType = tsc.SetMapTypeReturnOld(typeof(string));
var enumStr = ExpressionLambdaToSql(callExp.Object, tsc);
tsc.SetMapColumnTmp(null).SetMapTypeReturnOld(oldMapType);
return enumStr;
}
var value = ExpressionGetValue(callExp.Object, out var success);
if (success) return formatSql(value, typeof(string), null, null);
return callExp.Arguments.Count == 0 ? $"cast({getExp(callExp.Object)} as char)" : 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 $"substr({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 = objExp?.NodeType == ExpressionType.MemberAccess ? tsc.SetDbParamsReturnOld(null) : null; //#900 UseGenerateCommandParameterWithLambda(true) 子查询 bug、以及 #1173 参数化 bug
tsc.isNotSetMapColumnTmp = true;
var left = objExp == null ? null : getExp(objExp);
tsc.isNotSetMapColumnTmp = false;
tsc.SetMapColumnTmp(null).SetMapTypeReturnOld(oldMapType);
if (oldDbParams != null) 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(",");
if (a % 500 == 499) arrSb.Append(" \r\n \r\n"); //500元素分割, 3空格\r\n4空格
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 $"char_length({left})";
}
return null;
}
public override string ExpressionLambdaToSqlMemberAccessDateTime(MemberExpression exp, ExpTSC tsc)
{
if (exp.Expression == null)
{
switch (exp.Member.Name)
{
case "Now": return _common.Now;
case "UtcNow": return _common.NowUtc;
case "Today": return "curdate()";
case "MinValue": return "cast('0001/1/1 0:00:00' as datetime)";
case "MaxValue": return "cast('9999/12/31 23:59:59' as datetime)";
}
return null;
}
var left = ExpressionLambdaToSql(exp.Expression, tsc);
switch (exp.Member.Name)
{
case "Date": return $"cast(date_format({left},'%Y-%m-%d') as datetime)";
case "TimeOfDay": return $"timestampdiff(microsecond, date_format({left},'%Y-%m-%d'), {left})";
case "DayOfWeek": return $"(dayofweek({left})-1)";
case "Day": return $"dayofmonth({left})";
case "DayOfYear": return $"dayofyear({left})";
case "Month": return $"month({left})";
case "Year": return $"year({left})";
case "Hour": return $"hour({left})";
case "Minute": return $"minute({left})";
case "Second": return $"second({left})";
case "Millisecond": return $"floor(microsecond({left})/1000)";
case "Ticks": return $"(timestampdiff(microsecond, '0001-1-1', {left})*10)";
}
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 $"(({left}) div {(long)1000000 * 60 * 60 * 24})";
case "Hours": return $"(({left}) div {(long)1000000 * 60 * 60} mod 24)";
case "Milliseconds": return $"(({left}) div 1000 mod 1000)";
case "Minutes": return $"(({left}) div {(long)1000000 * 60} mod 60)";
case "Seconds": return $"(({left}) div 1000000 mod 60)";
case "Ticks": return $"(({left}) * 10)";
case "TotalDays": return $"(({left}) / {(long)1000000 * 60 * 60 * 24})";
case "TotalHours": return $"(({left}) / {(long)1000000 * 60 * 60})";
case "TotalMilliseconds": return $"(({left}) / 1000)";
case "TotalMinutes": return $"(({left}) / {(long)1000000 * 60})";
case "TotalSeconds": return $"(({left}) / 1000000)";
}
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":
var arg1 = getExp(exp.Arguments[0]);
return $"({arg1} is null or {arg1} = '')";
case "IsNullOrWhiteSpace":
var arg2 = getExp(exp.Arguments[0]);
return $"({arg2} is null or {arg2} = '' or ltrim({arg2}) = '')";
case "Concat":
if (exp.Arguments.Count == 1 && exp.Arguments[0].NodeType == ExpressionType.NewArrayInit && exp.Arguments[0] is NewArrayExpression concatNewArrExp)
return _common.StringConcat(concatNewArrExp.Expressions.Select(a => getExp(a)).ToArray(), null);
return _common.StringConcat(exp.Arguments.Select(a => getExp(a)).ToArray(), null);
case "Format":
if (exp.Arguments[0].NodeType != ExpressionType.Constant) throw new Exception(CoreStrings.Not_Implemented_Expression_ParameterUseConstant(exp,exp.Arguments[0]));
if (exp.Arguments.Count == 1) return ExpressionLambdaToSql(exp.Arguments[0], tsc);
var expArgsHack = exp.Arguments.Count == 2 && exp.Arguments[1].NodeType == ExpressionType.NewArrayInit ?
(exp.Arguments[1] as NewArrayExpression).Expressions : exp.Arguments.Where((a, z) => z > 0);
//3个 {} 时Arguments 解析出来是分开的
//4个 {} 时Arguments[1] 只能解析这个出来,然后里面是 NewArray []
var expArgs = expArgsHack.Select(a => $"',{_common.IsNull(ExpressionLambdaToSql(a, tsc), "''")},'").ToArray();
return $"concat({string.Format(ExpressionLambdaToSql(exp.Arguments[0], tsc), expArgs)})";
case "Join":
if (exp.IsStringJoin(out var tolistObjectExp, out var toListMethod, out var toListArgs1))
{
var newToListArgs0 = Expression.Call(tolistObjectExp, toListMethod,
Expression.Lambda(
Expression.Call(
typeof(SqlExtExtensions).GetMethod("StringJoinMySqlGroupConcat"),
Expression.Convert(toListArgs1.Body, typeof(object)),
Expression.Convert(exp.Arguments[0], typeof(object))),
toListArgs1.Parameters));
var newToListSql = getExp(newToListArgs0);
return newToListSql;
}
break;
}
}
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 (args0Value.Contains("%"))
{
if (exp.Method.Name == "StartsWith") return $"locate({args0Value}, {left}) = 1";
if (exp.Method.Name == "EndsWith") return $"locate({args0Value}, {left}) = char_length({left})-char_length({args0Value})+1";
return $"locate({args0Value}, {left}) > 0";
}
if (exp.Method.Name == "StartsWith") return $"({left}) LIKE {(args0Value.EndsWith("'") ? args0Value.Insert(args0Value.Length - 1, "%") : $"concat({args0Value}, '%')")}";
if (exp.Method.Name == "EndsWith") return $"({left}) LIKE {(args0Value.StartsWith("'") ? args0Value.Insert(1, "%") : $"concat('%', {args0Value})")}";
if (args0Value.StartsWith("'") && args0Value.EndsWith("'")) return $"({left}) LIKE {args0Value.Insert(1, "%").Insert(args0Value.Length, "%")}";
return $"({left}) LIKE concat('%', {args0Value}, '%')";
case "ToLower": return $"lower({left})";
case "ToUpper": return $"upper({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 $"substr({left}, {substrArgs1})";
return $"substr({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 $"(locate({indexOfFindStr}, {left}, {locateArgs1})-1)";
}
return $"(locate({indexOfFindStr}, {left})-1)";
case "PadLeft":
if (exp.Arguments.Count == 1) return $"lpad({left}, {getExp(exp.Arguments[0])})";
return $"lpad({left}, {getExp(exp.Arguments[0])}, {getExp(exp.Arguments[1])})";
case "PadRight":
if (exp.Arguments.Count == 1) return $"rpad({left}, {getExp(exp.Arguments[0])})";
return $"rpad({left}, {getExp(exp.Arguments[0])}, {getExp(exp.Arguments[1])})";
case "Trim":
case "TrimStart":
case "TrimEnd":
if (exp.Arguments.Count == 0)
{
if (exp.Method.Name == "Trim") return $"trim({left})";
if (exp.Method.Name == "TrimStart") return $"ltrim({left})";
if (exp.Method.Name == "TrimEnd") return $"rtrim({left})";
}
foreach (var argsTrim02 in exp.Arguments)
{
var argsTrim01s = new[] { argsTrim02 };
if (argsTrim02.NodeType == ExpressionType.NewArrayInit)
{
var arritem = argsTrim02 as NewArrayExpression;
argsTrim01s = arritem.Expressions.ToArray();
}
foreach (var argsTrim01 in argsTrim01s)
{
if (exp.Method.Name == "Trim") left = $"trim({getExp(argsTrim01)} from {left})";
if (exp.Method.Name == "TrimStart") left = $"trim(leading {getExp(argsTrim01)} from {left})";
if (exp.Method.Name == "TrimEnd") left = $"trim(trailing {getExp(argsTrim01)} from {left})";
}
}
return left;
case "Replace": return $"replace({left}, {getExp(exp.Arguments[0])}, {getExp(exp.Arguments[1])})";
case "CompareTo": return $"strcmp({left}, {getExp(exp.Arguments[0])})";
case "Equals": return $"({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 $"abs({getExp(exp.Arguments[0])})";
case "Sign": return $"sign({getExp(exp.Arguments[0])})";
case "Floor": return $"floor({getExp(exp.Arguments[0])})";
case "Ceiling": return $"ceiling({getExp(exp.Arguments[0])})";
case "Round":
if (exp.Arguments.Count > 1 && exp.Arguments[1].Type.FullName == "System.Int32") return $"round({getExp(exp.Arguments[0])}, {getExp(exp.Arguments[1])})";
return $"round({getExp(exp.Arguments[0])})";
case "Exp": return $"exp({getExp(exp.Arguments[0])})";
case "Log": return $"log({getExp(exp.Arguments[0])})";
case "Log10": return $"log10({getExp(exp.Arguments[0])})";
case "Pow": return $"pow({getExp(exp.Arguments[0])}, {getExp(exp.Arguments[1])})";
case "Sqrt": return $"sqrt({getExp(exp.Arguments[0])})";
case "Cos": return $"cos({getExp(exp.Arguments[0])})";
case "Sin": return $"sin({getExp(exp.Arguments[0])})";
case "Tan": return $"tan({getExp(exp.Arguments[0])})";
case "Acos": return $"acos({getExp(exp.Arguments[0])})";
case "Asin": return $"asin({getExp(exp.Arguments[0])})";
case "Atan": return $"atan({getExp(exp.Arguments[0])})";
case "Atan2": return $"atan2({getExp(exp.Arguments[0])}, {getExp(exp.Arguments[1])})";
case "Truncate": return $"truncate({getExp(exp.Arguments[0])}, 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 $"({getExp(exp.Arguments[0])} - ({getExp(exp.Arguments[1])}))";
case "DaysInMonth": return $"dayofmonth(last_day(concat({getExp(exp.Arguments[0])}, '-', {getExp(exp.Arguments[1])}, '-01')))";
case "Equals": return $"({getExp(exp.Arguments[0])} = {getExp(exp.Arguments[1])})";
case "IsLeapYear":
var isLeapYearArgs1 = getExp(exp.Arguments[0]);
return $"(({isLeapYearArgs1})%4=0 AND ({isLeapYearArgs1})%100<>0 OR ({isLeapYearArgs1})%400=0)";
case "Parse": return ExpressionConstDateTime(exp.Arguments[0]) ?? $"cast({getExp(exp.Arguments[0])} as datetime)";
case "ParseExact":
case "TryParse":
case "TryParseExact": return ExpressionConstDateTime(exp.Arguments[0]) ?? $"cast({getExp(exp.Arguments[0])} as datetime)";
}
}
else
{
var left = getExp(exp.Object);
var args1 = exp.Arguments.Count == 0 ? null : getExp(exp.Arguments[0]);
switch (exp.Method.Name)
{
case "Add": return $"date_add({left}, interval ({args1}) microsecond)";
case "AddDays": return $"date_add({left}, interval ({args1}) day)";
case "AddHours": return $"date_add({left}, interval ({args1}) hour)";
case "AddMilliseconds": return $"date_add({left}, interval ({args1})*1000 microsecond)";
case "AddMinutes": return $"date_add({left}, interval ({args1}) minute)";
case "AddMonths": return $"date_add({left}, interval ({args1}) month)";
case "AddSeconds": return $"date_add({left}, interval ({args1}) second)";
case "AddTicks": return $"date_add({left}, interval ({args1})/10 microsecond)";
case "AddYears": return $"date_add({left}, interval ({args1}) year)";
case "Subtract":
switch ((exp.Arguments[0].Type.IsNullableType() ? exp.Arguments[0].Type.GetGenericArguments().FirstOrDefault() : exp.Arguments[0].Type).FullName)
{
case "System.DateTime": return $"timestampdiff(microsecond, {args1}, {left})";
case "System.TimeSpan": return $"date_sub({left}, interval ({args1}) microsecond)";
}
break;
case "Equals": return $"({left} = {args1})";
case "CompareTo": return $"timestampdiff(microsecond,{args1},{left})";
case "ToString":
if (exp.Arguments.Count == 0) return $"date_format({left},'%Y-%m-%d %H:%i:%s.%f')";
switch (args1)
{
case "'yyyy-MM-dd HH:mm:ss'": return $"date_format({left},'%Y-%m-%d %H:%i:%s')";
case "'yyyy-MM-dd HH:mm'": return $"date_format({left},'%Y-%m-%d %H:%i')";
case "'yyyy-MM-dd HH'": return $"date_format({left},'%Y-%m-%d %H')";
case "'yyyy-MM-dd'": return $"date_format({left},'%Y-%m-%d')";
case "'yyyy-MM'": return $"date_format({left},'%Y-%m')";
case "'yyyyMMddHHmmss'": return $"date_format({left},'%Y%m%d%H%i%s')";
case "'yyyyMMddHHmm'": return $"date_format({left},'%Y%m%d%H%i')";
case "'yyyyMMddHH'": return $"date_format({left},'%Y%m%d%H')";
case "'yyyyMMdd'": return $"date_format({left},'%Y%m%d')";
case "'yyyyMM'": return $"date_format({left},'%Y%m')";
case "'yyyy'": return $"date_format({left},'%Y')";
case "'HH:mm:ss'": return $"date_format({left},'%H:%i:%s')";
}
args1 = Regex.Replace(args1, "(yyyy|yy|MM|M|dd|d|HH|H|hh|h|mm|ss|tt)", m =>
{
switch (m.Groups[1].Value)
{
case "yyyy": return $"%Y";
case "yy": return $"%y";
case "MM": return $"%_a1";
case "M": return $"%c";
case "dd": return $"%d";
case "d": return $"%e";
case "HH": return $"%H";
case "H": return $"%k";
case "hh": return $"%h";
case "h": return $"%l";
case "mm": return $"%i";
case "ss": return $"%_a2";
case "tt": return $"%p";
}
return m.Groups[0].Value;
});
var argsFinds = new[] { "%Y", "%y", "%_a1", "%c", "%d", "%e", "%H", "%k", "%h", "%l", "%i", "%_a2", "%p" };
var argsSpts = Regex.Split(args1, "(m|s|t)");
for (var a = 0; a < argsSpts.Length; a++)
{
switch (argsSpts[a])
{
case "m": argsSpts[a] = $"case when substr(date_format({left},'%i'),1,1) = '0' then substr(date_format({left},'%i'),2,1) else date_format({left},'%i') end"; break;
case "s": argsSpts[a] = $"case when substr(date_format({left},'%s'),1,1) = '0' then substr(date_format({left},'%s'),2,1) else date_format({left},'%s') end"; break;
case "t": argsSpts[a] = $"trim(trailing 'M' from date_format({left},'%p'))"; break;
default:
var argsSptsA = argsSpts[a];
if (argsSptsA.StartsWith("'")) argsSptsA = argsSptsA.Substring(1);
if (argsSptsA.EndsWith("'")) argsSptsA = argsSptsA.Remove(argsSptsA.Length - 1);
argsSpts[a] = argsFinds.Any(m => argsSptsA.Contains(m)) ? $"date_format({left},'{argsSptsA}')" : $"'{argsSptsA}'";
break;
}
}
if (argsSpts.Length > 0) args1 = $"concat({string.Join(", ", argsSpts.Where(a => a != "''"))})";
return args1.Replace("%_a1", "%m").Replace("%_a2", "%s");
}
}
return null;
}
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])})*{(long)1000000 * 60 * 60 * 24})";
case "FromHours": return $"(({getExp(exp.Arguments[0])})*{(long)1000000 * 60 * 60})";
case "FromMilliseconds": return $"(({getExp(exp.Arguments[0])})*1000)";
case "FromMinutes": return $"(({getExp(exp.Arguments[0])})*{(long)1000000 * 60})";
case "FromSeconds": return $"(({getExp(exp.Arguments[0])})*1000000)";
case "FromTicks": return $"(({getExp(exp.Arguments[0])})/10)";
case "Parse": return $"cast({getExp(exp.Arguments[0])} as signed)";
case "ParseExact":
case "TryParse":
case "TryParseExact": return $"cast({getExp(exp.Arguments[0])} as signed)";
}
}
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 $"cast({left} as char)";
}
}
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 $"({getExp(exp.Arguments[0])} not in ('0','false'))";
case "ToByte": return $"cast({getExp(exp.Arguments[0])} as unsigned)";
case "ToChar": return $"substr(cast({getExp(exp.Arguments[0])} as char), 1, 1)";
case "ToDateTime": return ExpressionConstDateTime(exp.Arguments[0]) ?? $"cast({getExp(exp.Arguments[0])} as datetime)";
case "ToDecimal": return $"cast({getExp(exp.Arguments[0])} as decimal(36,18))";
case "ToDouble": return $"cast({getExp(exp.Arguments[0])} as decimal(32,16))";
case "ToInt16":
case "ToInt32":
case "ToInt64":
case "ToSByte": return $"cast({getExp(exp.Arguments[0])} as signed)";
case "ToSingle": return $"cast({getExp(exp.Arguments[0])} as decimal(14,7))";
case "ToString": return $"cast({getExp(exp.Arguments[0])} as char)";
case "ToUInt16":
case "ToUInt32":
case "ToUInt64": return $"cast({getExp(exp.Arguments[0])} as unsigned)";
}
}
return null;
}
}
}

View File

@ -0,0 +1,46 @@
using FreeSql.Internal.CommonProvider;
using System;
using System.Collections.Concurrent;
using System.Data.Common;
using System.Threading;
namespace FreeSql.Custom.MySql
{
public class CustomMySqlProvider<TMark> : BaseDbProvider, IFreeSql<TMark>
{
public override ISelect<T1> CreateSelectProvider<T1>(object dywhere) => new CustomMySqlSelect<T1>(this, this.InternalCommonUtils, this.InternalCommonExpression, dywhere);
public override IInsert<T1> CreateInsertProvider<T1>() => new CustomMySqlInsert<T1>(this, this.InternalCommonUtils, this.InternalCommonExpression);
public override IUpdate<T1> CreateUpdateProvider<T1>(object dywhere) => new CustomMySqlUpdate<T1>(this, this.InternalCommonUtils, this.InternalCommonExpression, dywhere);
public override IDelete<T1> CreateDeleteProvider<T1>(object dywhere) => new CustomMySqlDelete<T1>(this, this.InternalCommonUtils, this.InternalCommonExpression, dywhere);
public override IInsertOrUpdate<T1> CreateInsertOrUpdateProvider<T1>() => new CustomMySqlInsertOrUpdate<T1>(this, this.InternalCommonUtils, this.InternalCommonExpression);
public CustomMySqlProvider(string masterConnectionString, string[] slaveConnectionString, Func<DbConnection> connectionFactory = null)
{
this.InternalCommonUtils = new CustomMySqlUtils(this);
this.InternalCommonExpression = new CustomMySqlExpression(this.InternalCommonUtils);
this.Ado = new CustomMySqlAdo(this.InternalCommonUtils, masterConnectionString, slaveConnectionString, connectionFactory);
this.Aop = new AopProvider();
this.DbFirst = new CustomMySqlDbFirst(this, this.InternalCommonUtils, this.InternalCommonExpression);
this.CodeFirst = new CustomMySqlCodeFirst(this, this.InternalCommonUtils, this.InternalCommonExpression);
}
~CustomMySqlProvider() => 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);
FreeSqlCustomAdapterGlobalExtensions._dicDbProviderFactory.TryRemove(Ado.Identifier, out var trydbpf);
}
}
}
}

View File

@ -0,0 +1,113 @@
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.MySql
{
class CustomMySqlUtils : CommonUtils
{
DbProviderFactory Factory => FreeSqlCustomAdapterGlobalExtensions.GetDbProviderFactory(_orm);
public CustomMySqlUtils(IFreeSql orm) : base(orm)
{
}
public override DbParameter AppendParamter(List<DbParameter> _params, string parameterName, ColumnInfo col, Type type, object value)
{
if (string.IsNullOrEmpty(parameterName)) parameterName = $"p_{_params?.Count}";
var ret = Factory.CreateParameter();
ret.ParameterName = QuoteParamterName(parameterName);
var tp = _orm.CodeFirst.GetDbInfo(type)?.type;
if (tp != null) ret.DbType = (DbType)tp.Value;
ret.Value = value;
_params?.Add(ret);
return ret;
}
public override DbParameter[] GetDbParamtersByObject(string sql, object obj) =>
Utils.GetDbParamtersByObject<DbParameter>(sql, obj, null, (name, type, value) =>
{
var ret = Factory.CreateParameter();
ret.ParameterName = $"@{name}";
var tp = _orm.CodeFirst.GetDbInfo(type)?.type;
if (tp != null) ret.DbType = (DbType)tp.Value;
ret.Value = value;
return ret;
});
public override string FormatSql(string sql, params object[] args) => sql?.FormatCustomMySql(args);
public override string QuoteSqlNameAdapter(params string[] name)
{
if (name.Length == 1)
{
var nametrim = name[0].Trim();
if (nametrim.StartsWith("(") && nametrim.EndsWith(")"))
return nametrim; //原生SQL
if (nametrim.StartsWith("`") && nametrim.EndsWith("`"))
return nametrim;
return $"`{nametrim.Replace(".", "`.`")}`";
}
return $"`{string.Join("`.`", name)}`";
}
public override string TrimQuoteSqlName(string name)
{
var nametrim = name.Trim();
if (nametrim.StartsWith("(") && nametrim.EndsWith(")"))
return nametrim; //原生SQL
return $"{nametrim.Trim('`').Replace("`.`", ".").Replace(".`", ".")}";
}
public override string[] SplitTableName(string name) => GetSplitTableNames(name, '`', '`', 2);
public override string QuoteParamterName(string name) => $"@{name}";
public override string IsNull(string sql, object value) => $"ifnull({sql}, {value})";
public override string StringConcat(string[] objs, Type[] types) => $"concat({string.Join(", ", objs)})";
public override string Mod(string left, string right, Type leftType, Type rightType) => $"{left} % {right}";
public override string Div(string left, string right, Type leftType, Type rightType) => $"{left} div {right}";
public override string Now => "now()";
public override string NowUtc => "utc_timestamp()";
public override string QuoteWriteParamterAdapter(Type type, string paramterName)
{
switch (type.FullName)
{
case "MygisPoint":
case "MygisLineString":
case "MygisPolygon":
case "MygisMultiPoint":
case "MygisMultiLineString":
case "MygisMultiPolygon": return $"ST_GeomFromText({paramterName})";
}
return paramterName;
}
protected override string QuoteReadColumnAdapter(Type type, Type mapType, string columnName)
{
switch (mapType.FullName)
{
case "MygisPoint":
case "MygisLineString":
case "MygisPolygon":
case "MygisMultiPoint":
case "MygisMultiLineString":
case "MygisMultiPolygon": return $"ST_AsText({columnName})";
}
return 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 $"0x{CommonUtils.BytesSqlRaw(value as byte[])}";
if (type == typeof(TimeSpan) || type == typeof(TimeSpan?))
{
var ts = (TimeSpan)value;
value = $"{Math.Floor(ts.TotalHours)}:{ts.Minutes}:{ts.Seconds}";
}
return FormatSql("{0}", value, 1);
}
}
}

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.Oracle
{
class CustomOracleDelete<T1> : Internal.CommonProvider.DeleteProvider<T1>
{
public CustomOracleDelete(IFreeSql orm, CommonUtils commonUtils, CommonExpression commonExpression, object dywhere)
: base(orm, commonUtils, commonExpression, dywhere)
{
}
public override List<T1> ExecuteDeleted() => throw new NotImplementedException($"FreeSql.Odbc.Oracle {CoreStrings.S_Not_Implemented_Feature}");
#if net40
#else
public override Task<List<T1>> ExecuteDeletedAsync(CancellationToken cancellationToken = default) => throw new NotImplementedException($"FreeSql.Odbc.Oracle {CoreStrings.S_Not_Implemented_Feature}");
#endif
}
}

View File

@ -0,0 +1,224 @@
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.Threading;
using System.Threading.Tasks;
namespace FreeSql.Custom.Oracle
{
class CustomOracleInsert<T1> : Internal.CommonProvider.InsertProvider<T1> where T1 : class
{
public CustomOracleInsert(IFreeSql orm, CommonUtils commonUtils, CommonExpression commonExpression)
: base(orm, commonUtils, commonExpression)
{
}
public override int ExecuteAffrows() => base.SplitExecuteAffrows(_batchValuesLimit > 0 ? _batchValuesLimit : 500, _batchParameterLimit > 0 ? _batchParameterLimit : 999);
public override long ExecuteIdentity() => base.SplitExecuteIdentity(_batchValuesLimit > 0 ? _batchValuesLimit : 500, _batchParameterLimit > 0 ? _batchParameterLimit : 999);
public override List<T1> ExecuteInserted() => base.SplitExecuteInserted(_batchValuesLimit > 0 ? _batchValuesLimit : 500, _batchParameterLimit > 0 ? _batchParameterLimit : 999);
public override string ToSql()
{
if (_source == null || _source.Any() == false) return null;
var sb = new StringBuilder();
sb.Append("INSERT ");
if (_source.Count > 1) sb.Append("ALL");
_identCol = null;
var sbtb = new StringBuilder();
sbtb.Append("INTO ");
sbtb.Append(_commonUtils.QuoteSqlName(TableRuleInvoke())).Append("(");
var colidx = 0;
foreach (var col in _table.Columns.Values)
{
if (col.Attribute.IsIdentity) _identCol = col;
if (col.Attribute.IsIdentity && _insertIdentity == false && string.IsNullOrEmpty(col.DbInsertValue)) continue;
if (col.Attribute.IsIdentity == false && _ignore.ContainsKey(col.Attribute.Name)) continue;
if (colidx > 0) sbtb.Append(", ");
sbtb.Append(_commonUtils.QuoteSqlName(col.Attribute.Name));
++colidx;
}
sbtb.Append(") ");
_params = _noneParameter ? new DbParameter[0] : new DbParameter[colidx * _source.Count];
var specialParams = new List<DbParameter>();
var didx = 0;
foreach (var d in _source)
{
if (_source.Count > 1) sb.Append("\r\n");
sb.Append(sbtb);
sb.Append("VALUES");
sb.Append("(");
var colidx2 = 0;
foreach (var col in _table.Columns.Values)
{
if (col.Attribute.IsIdentity && _insertIdentity == false && string.IsNullOrEmpty(col.DbInsertValue)) continue;
if (col.Attribute.IsIdentity == false && _ignore.ContainsKey(col.Attribute.Name)) continue;
if (colidx2 > 0) sb.Append(", ");
if (string.IsNullOrEmpty(col.DbInsertValue) == false && _ignoreInsertValueSql.ContainsKey(col.Attribute.Name) == false)
sb.Append(col.DbInsertValue);
else
{
object val = col.GetDbValue(d);
if (val == null && col.Attribute.IsNullable == false) val = col.CsType == typeof(string) ? "" : Utils.GetDataReaderValue(col.CsType.NullableTypeOrThis(), null);//#384
var colsql = _noneParameter ? _commonUtils.GetNoneParamaterSqlValue(specialParams, _noneParameterFlag, col, col.Attribute.MapType, val) :
_commonUtils.QuoteWriteParamterAdapter(col.Attribute.MapType, _commonUtils.QuoteParamterName($"{col.CsName}_{didx}"));
sb.Append(_commonUtils.RewriteColumn(col, colsql));
if (_noneParameter == false)
_params[didx * colidx + colidx2] = _commonUtils.AppendParamter(null, $"{col.CsName}_{didx}", col, col.Attribute.MapType, val);
}
++colidx2;
}
sb.Append(")");
++didx;
}
if (_noneParameter && specialParams.Any()) _params = specialParams.ToArray();
if (_source.Count > 1) sb.Append("\r\n SELECT 1 FROM DUAL");
return sb.ToString();
}
ColumnInfo _identCol;
protected override long RawExecuteIdentity()
{
var sql = this.ToSql();
if (string.IsNullOrEmpty(sql)) return 0;
long ret = 0;
Exception exception = null;
Aop.CurdBeforeEventArgs before = null;
if (_identCol == null || _source.Count > 1)
{
before = new Aop.CurdBeforeEventArgs(_table.Type, _table, Aop.CurdType.Insert, sql, _params);
_orm.Aop.CurdBeforeHandler?.Invoke(this, before);
try
{
ret = _orm.Ado.ExecuteNonQuery(_connection, _transaction, CommandType.Text, sql, _commandTimeout, _params);
}
catch (Exception ex)
{
exception = ex;
throw ex;
}
finally
{
var after = new Aop.CurdAfterEventArgs(before, exception, ret);
_orm.Aop.CurdAfterHandler?.Invoke(this, after);
}
return 0;
}
var identColName = _commonUtils.QuoteSqlName(_identCol.Attribute.Name);
var identParam = _commonUtils.AppendParamter(null, $"{_identCol.CsName}99", _identCol, _identCol.Attribute.MapType, 0);
identParam.Direction = ParameterDirection.Output;
sql = $"{sql} RETURNING {identColName} INTO {identParam.ParameterName}";
var dbParms = _params.Concat(new[] { identParam }).ToArray();
before = new Aop.CurdBeforeEventArgs(_table.Type, _table, Aop.CurdType.Insert, sql, dbParms);
_orm.Aop.CurdBeforeHandler?.Invoke(this, before);
try
{
_orm.Ado.ExecuteNonQuery(_connection, _transaction, CommandType.Text, sql, _commandTimeout, dbParms);
long.TryParse(string.Concat(identParam.Value), out ret);
}
catch (Exception ex)
{
exception = ex;
throw ex;
}
finally
{
var after = new Aop.CurdAfterEventArgs(before, exception, ret);
_orm.Aop.CurdAfterHandler?.Invoke(this, after);
}
return ret;
}
protected override List<T1> RawExecuteInserted()
{
var sql = this.ToSql();
if (string.IsNullOrEmpty(sql)) return new List<T1>();
var ret = _source.ToList();
this.RawExecuteAffrows();
return ret;
}
#if net40
#else
public override Task<int> ExecuteAffrowsAsync(CancellationToken cancellationToken = default) => base.SplitExecuteAffrowsAsync(_batchValuesLimit > 0 ? _batchValuesLimit : 500, _batchParameterLimit > 0 ? _batchParameterLimit : 999, cancellationToken);
public override Task<long> ExecuteIdentityAsync(CancellationToken cancellationToken = default) => base.SplitExecuteIdentityAsync(_batchValuesLimit > 0 ? _batchValuesLimit : 500, _batchParameterLimit > 0 ? _batchParameterLimit : 999, cancellationToken);
public override Task<List<T1>> ExecuteInsertedAsync(CancellationToken cancellationToken = default) => base.SplitExecuteInsertedAsync(_batchValuesLimit > 0 ? _batchValuesLimit : 500, _batchParameterLimit > 0 ? _batchParameterLimit : 999, cancellationToken);
async protected override Task<long> RawExecuteIdentityAsync(CancellationToken cancellationToken = default)
{
var sql = this.ToSql();
if (string.IsNullOrEmpty(sql)) return 0;
long ret = 0;
Exception exception = null;
Aop.CurdBeforeEventArgs before = null;
if (_identCol == null || _source.Count > 1)
{
before = new Aop.CurdBeforeEventArgs(_table.Type, _table, Aop.CurdType.Insert, sql, _params);
_orm.Aop.CurdBeforeHandler?.Invoke(this, before);
try
{
ret = await _orm.Ado.ExecuteNonQueryAsync(_connection, _transaction, CommandType.Text, sql, _commandTimeout, _params, cancellationToken);
}
catch (Exception ex)
{
exception = ex;
throw ex;
}
finally
{
var after = new Aop.CurdAfterEventArgs(before, exception, ret);
_orm.Aop.CurdAfterHandler?.Invoke(this, after);
}
return 0;
}
var identColName = _commonUtils.QuoteSqlName(_identCol.Attribute.Name);
var identParam = _commonUtils.AppendParamter(null, $"{_identCol.CsName}99", _identCol, _identCol.Attribute.MapType, 0);
identParam.Direction = ParameterDirection.Output;
sql = $"{sql} RETURNING {identColName} INTO {identParam.ParameterName}";
var dbParms = _params.Concat(new[] { identParam }).ToArray();
before = new Aop.CurdBeforeEventArgs(_table.Type, _table, Aop.CurdType.Insert, sql, dbParms);
_orm.Aop.CurdBeforeHandler?.Invoke(this, before);
try
{
await _orm.Ado.ExecuteNonQueryAsync(_connection, _transaction, CommandType.Text, sql, _commandTimeout, dbParms, cancellationToken);
long.TryParse(string.Concat(identParam.Value), out ret);
}
catch (Exception ex)
{
exception = ex;
throw ex;
}
finally
{
var after = new Aop.CurdAfterEventArgs(before, exception, ret);
_orm.Aop.CurdAfterHandler?.Invoke(this, after);
}
return ret;
}
async protected override Task<List<T1>> RawExecuteInsertedAsync(CancellationToken cancellationToken = default)
{
var sql = this.ToSql();
if (string.IsNullOrEmpty(sql)) return new List<T1>();
var ret = _source.ToList();
await this.RawExecuteAffrowsAsync(cancellationToken);
return ret;
}
#endif
}
}

View File

@ -0,0 +1,85 @@
using FreeSql.Internal;
using System;
using System.Collections.Generic;
using System.Data.Common;
using System.Linq;
using System.Text;
namespace FreeSql.Custom.Oracle
{
class CustomOracleInsertOrUpdate<T1> : Internal.CommonProvider.InsertOrUpdateProvider<T1> where T1 : class
{
public CustomOracleInsertOrUpdate(IFreeSql orm, CommonUtils commonUtils, CommonExpression commonExpression)
: base(orm, commonUtils, commonExpression)
{
}
public override string ToSql()
{
var dbParams = new List<DbParameter>();
if (_sourceSql != null) return getMergeSql(null);
if (_source?.Any() != true) return null;
var sqls = new string[2];
var ds = SplitSourceByIdentityValueIsNull(_source);
if (ds.Item1.Any()) sqls[0] = string.Join("\r\n\r\n;\r\n\r\n", ds.Item1.Select(a => getMergeSql(a)));
if (ds.Item2.Any()) sqls[1] = string.Join("\r\n\r\n;\r\n\r\n", ds.Item2.Select(a => getInsertSql(a)));
_params = dbParams.ToArray();
if (ds.Item2.Any() == false) return sqls[0];
if (ds.Item1.Any() == false) return sqls[1];
return string.Join("\r\n\r\n;\r\n\r\n", sqls);
string getMergeSql(List<T1> data)
{
if (_tempPrimarys.Any() == false) throw new Exception(CoreStrings.InsertOrUpdate_Must_Primary_Key(_table.CsName));
var tempPrimaryIsIdentity = _tempPrimarys.Any(b => b.Attribute.IsIdentity);
var sb = new StringBuilder().Append("MERGE INTO ").Append(_commonUtils.QuoteSqlName(TableRuleInvoke())).Append(" t1 \r\nUSING (");
WriteSourceSelectUnionAll(data, sb, dbParams);
sb.Append(" ) t2 ON (").Append(string.Join(" AND ", _tempPrimarys.Select(a => $"t1.{_commonUtils.QuoteSqlName(a.Attribute.Name)} = t2.{_commonUtils.QuoteSqlName(a.Attribute.Name)}"))).Append(") \r\n");
var cols = _table.Columns.Values.Where(a => _updateSetDict.ContainsKey(a.Attribute.Name) ||
_tempPrimarys.Contains(a) == false && a.Attribute.CanUpdate == true && a.Attribute.IsIdentity == false && _updateIgnore.ContainsKey(a.Attribute.Name) == false);
if (_doNothing == false && cols.Any())
sb.Append("WHEN MATCHED THEN \r\n")
.Append(" update set ").Append(string.Join(", ", cols.Select(a =>
{
if (_updateSetDict.TryGetValue(a.Attribute.Name, out var valsql))
return $"{_commonUtils.QuoteSqlName(a.Attribute.Name)} = {valsql}";
return a.Attribute.IsVersion && a.Attribute.MapType != typeof(byte[]) ?
$"{_commonUtils.QuoteSqlName(a.Attribute.Name)} = t1.{_commonUtils.QuoteSqlName(a.Attribute.Name)} + 1" :
$"{_commonUtils.QuoteSqlName(a.Attribute.Name)} = t2.{_commonUtils.QuoteSqlName(a.Attribute.Name)}";
}))).Append(" \r\n");
cols = _table.Columns.Values.Where(a => a.Attribute.CanInsert == true);
if (tempPrimaryIsIdentity == false) cols = cols.Where(a => a.Attribute.IsIdentity == false || string.IsNullOrEmpty(a.DbInsertValue) == false);
if (cols.Any())
sb.Append("WHEN NOT MATCHED THEN \r\n")
.Append(" insert (").Append(string.Join(", ", cols.Select(a => _commonUtils.QuoteSqlName(a.Attribute.Name)))).Append(") \r\n")
.Append(" values (").Append(string.Join(", ", cols.Select(a =>
{
//InsertValueSql = "seq.nextval"
if (tempPrimaryIsIdentity == false && a.Attribute.IsIdentity && string.IsNullOrEmpty(a.DbInsertValue) == false) return a.DbInsertValue;
return $"t2.{_commonUtils.QuoteSqlName(a.Attribute.Name)}";
}))).Append(")");
return sb.ToString();
}
string getInsertSql(List<T1> data)
{
var insert = _orm.Insert<T1>()
.AsTable(_tableRule).AsType(_table.Type)
.WithConnection(_connection)
.WithTransaction(_transaction)
.NoneParameter(true) as Internal.CommonProvider.InsertProvider<T1>;
insert._source = data;
insert._table = _table;
var sql = insert.ToSql();
if (string.IsNullOrEmpty(sql)) return null;
if (insert._params?.Any() == true) dbParams.AddRange(insert._params);
return sql;
}
}
}
}

View File

@ -0,0 +1,244 @@
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.Oracle
{
class CustomOracleSelect<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)
{
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.Where(a => a.Before == false), true);
tb.CascadeBefore = _commonExpression.GetWhereCascadeSql(tb, _whereGlobalFilter.Where(a => a.Before == true), true);
}
var sb = new StringBuilder();
var sbunion = new StringBuilder();
var sbnav = 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");
var tbUnion = tbUnions[tbUnionsIdx];
sbunion.Append(_select);
if (_distinct) sbunion.Append("DISTINCT ");
var tbsjoin = _tables.Where(a => a.Type != SelectTableInfoType.From).ToArray();
var tbsfrom = _tables.Where(a => a.Type == SelectTableInfoType.From).ToArray();
var isRownum = string.IsNullOrEmpty(_orderby) && _skip > 0;
if (isRownum && field == "*") sbunion.Append(tbsfrom[0].Alias).Append("."); //#1519 bug
sbunion.Append(field);
if (isRownum) sbunion.Append(", ROWNUM AS \"__rownum__\"");
sbunion.Append(" \r\nFROM ");
for (var a = 0; a < tbsfrom.Length; a++)
{
sbunion.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++)
{
sbunion.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) &&
string.IsNullOrEmpty(tbsfrom[b].CascadeBefore)) sbunion.Append(" ON 1 = 1");
else sbunion.Append(" ON ").Append(string.Join(" AND ", new[]
{
tbsfrom[b].CascadeBefore,
tbsfrom[b].NavigateCondition ?? tbsfrom[b].On,
tbsfrom[b].Cascade
}.Where(onSql => string.IsNullOrEmpty(onSql) == false)));
}
break;
}
else
{
if (a > 0 && !string.IsNullOrEmpty(tbsfrom[a].CascadeBefore)) sbnav.Append(" AND ").Append(tbsfrom[a].CascadeBefore);
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) sbunion.Append(", ");
}
foreach (var tb in tbsjoin)
{
switch (tb.Type)
{
case SelectTableInfoType.Parent:
case SelectTableInfoType.RawJoin:
continue;
case SelectTableInfoType.LeftJoin:
sbunion.Append(" \r\nLEFT JOIN ");
break;
case SelectTableInfoType.InnerJoin:
sbunion.Append(" \r\nINNER JOIN ");
break;
case SelectTableInfoType.RightJoin:
sbunion.Append(" \r\nRIGHT JOIN ");
break;
}
sbunion.Append(_commonUtils.QuoteSqlName(tbUnion[tb.Table.Type])).Append(" ").Append(_aliasRule?.Invoke(tb.Table.Type, tb.Alias) ?? tb.Alias)
.Append(" ON ").Append(string.Join(" AND ", new[]
{
tb.CascadeBefore,
tb.On ?? tb.NavigateCondition,
tb.Cascade
}.Where(onSql => string.IsNullOrEmpty(onSql) == false)));
if (!string.IsNullOrEmpty(tb.On) && !string.IsNullOrEmpty(tb.NavigateCondition)) sbnav.Append(" AND (").Append(tb.NavigateCondition).Append(")");
}
if (_join.Length > 0) sbunion.Append(_join);
if (!string.IsNullOrEmpty(_tables[0].CascadeBefore)) sbnav.Append(" AND ").Append(_tables[0].CascadeBefore);
sbnav.Append(_where);
if (!string.IsNullOrEmpty(_tables[0].Cascade)) sbnav.Append(" AND ").Append(_tables[0].Cascade);
if (string.IsNullOrEmpty(_orderby) && (_skip > 0 || _limit > 0))
sbnav.Append(" AND ROWNUM < ").Append(_skip + _limit + 1);
if (sbnav.Length > 0)
sbunion.Append(" \r\nWHERE ").Append(sbnav.Remove(0, 5));
if (string.IsNullOrEmpty(_groupby) == false)
{
sbunion.Append(_groupby);
if (string.IsNullOrEmpty(_having) == false)
sbunion.Append(" \r\nHAVING ").Append(_having.Substring(5));
}
sbunion.Append(_orderby);
if (string.IsNullOrEmpty(_orderby))
{
if (_skip > 0)
sbunion.Insert(0, $"{_select}t.* FROM (").Append(") t WHERE t.\"__rownum__\" > ").Append(_skip);
}
else
{
if (_skip > 0 && _limit > 0) sbunion.Insert(0, $"{_select}t.* FROM (SELECT rt.*, ROWNUM AS \"__rownum__\" FROM (").Append(") rt WHERE ROWNUM < ").Append(_skip + _limit + 1).Append(") t WHERE t.\"__rownum__\" > ").Append(_skip);
else if (_skip > 0) sbunion.Insert(0, $"{_select}t.* FROM (").Append(") t WHERE ROWNUM > ").Append(_skip);
else if (_limit > 0) sbunion.Insert(0, $"{_select}t.* FROM (").Append(") t WHERE ROWNUM < ").Append(_limit + 1);
}
if (tbUnionsGt0) sbunion.Insert(0, $"{_select}* from (").Append(") ftb");
sb.Append(sbunion);
sbnav.Clear();
sbunion.Clear();
}
var sql = sb.Append(_tosqlAppendContent).ToString();
var aliasGreater30 = 0;
foreach (var tb in _tables)
if (tb.Alias.Length > 30) sql = sql.Replace(tb.Alias, $"than30_{aliasGreater30++}");
return sql;
}
public CustomOracleSelect(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 OdbcOracleSelect<T1, T2>(_orm, _commonUtils, _commonExpression, null); CustomOracleSelect<T1>.CopyData(this, 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 OdbcOracleSelect<T1, T2, T3>(_orm, _commonUtils, _commonExpression, null); CustomOracleSelect<T1>.CopyData(this, 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 OdbcOracleSelect<T1, T2, T3, T4>(_orm, _commonUtils, _commonExpression, null); CustomOracleSelect<T1>.CopyData(this, 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 OdbcOracleSelect<T1, T2, T3, T4, T5>(_orm, _commonUtils, _commonExpression, null); CustomOracleSelect<T1>.CopyData(this, 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 OdbcOracleSelect<T1, T2, T3, T4, T5, T6>(_orm, _commonUtils, _commonExpression, null); CustomOracleSelect<T1>.CopyData(this, 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 OdbcOracleSelect<T1, T2, T3, T4, T5, T6, T7>(_orm, _commonUtils, _commonExpression, null); CustomOracleSelect<T1>.CopyData(this, 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 OdbcOracleSelect<T1, T2, T3, T4, T5, T6, T7, T8>(_orm, _commonUtils, _commonExpression, null); CustomOracleSelect<T1>.CopyData(this, 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 OdbcOracleSelect<T1, T2, T3, T4, T5, T6, T7, T8, T9>(_orm, _commonUtils, _commonExpression, null); CustomOracleSelect<T1>.CopyData(this, 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 OdbcOracleSelect<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10>(_orm, _commonUtils, _commonExpression, null); CustomOracleSelect<T1>.CopyData(this, 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 OdbcOracleSelect<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11>(_orm, _commonUtils, _commonExpression, null); CustomOracleSelect<T1>.CopyData(this, 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 OdbcOracleSelect<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12>(_orm, _commonUtils, _commonExpression, null); CustomOracleSelect<T1>.CopyData(this, 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 OdbcOracleSelect<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13>(_orm, _commonUtils, _commonExpression, null); CustomOracleSelect<T1>.CopyData(this, 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 OdbcOracleSelect<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14>(_orm, _commonUtils, _commonExpression, null); CustomOracleSelect<T1>.CopyData(this, 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 OdbcOracleSelect<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15>(_orm, _commonUtils, _commonExpression, null); CustomOracleSelect<T1>.CopyData(this, 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 OdbcOracleSelect<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15, T16>(_orm, _commonUtils, _commonExpression, null); CustomOracleSelect<T1>.CopyData(this, 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 OdbcOracleSelect<T1, T2> : FreeSql.Internal.CommonProvider.Select2Provider<T1, T2> where T2 : class
{
public OdbcOracleSelect(IFreeSql orm, CommonUtils commonUtils, CommonExpression commonExpression, object dywhere) : base(orm, commonUtils, commonExpression, dywhere) { }
public override string ToSql(string field = null) => CustomOracleSelect<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 OdbcOracleSelect<T1, T2, T3> : FreeSql.Internal.CommonProvider.Select3Provider<T1, T2, T3> where T2 : class where T3 : class
{
public OdbcOracleSelect(IFreeSql orm, CommonUtils commonUtils, CommonExpression commonExpression, object dywhere) : base(orm, commonUtils, commonExpression, dywhere) { }
public override string ToSql(string field = null) => CustomOracleSelect<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 OdbcOracleSelect<T1, T2, T3, T4> : FreeSql.Internal.CommonProvider.Select4Provider<T1, T2, T3, T4> where T2 : class where T3 : class where T4 : class
{
public OdbcOracleSelect(IFreeSql orm, CommonUtils commonUtils, CommonExpression commonExpression, object dywhere) : base(orm, commonUtils, commonExpression, dywhere) { }
public override string ToSql(string field = null) => CustomOracleSelect<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 OdbcOracleSelect<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 OdbcOracleSelect(IFreeSql orm, CommonUtils commonUtils, CommonExpression commonExpression, object dywhere) : base(orm, commonUtils, commonExpression, dywhere) { }
public override string ToSql(string field = null) => CustomOracleSelect<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 OdbcOracleSelect<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 OdbcOracleSelect(IFreeSql orm, CommonUtils commonUtils, CommonExpression commonExpression, object dywhere) : base(orm, commonUtils, commonExpression, dywhere) { }
public override string ToSql(string field = null) => CustomOracleSelect<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 OdbcOracleSelect<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 OdbcOracleSelect(IFreeSql orm, CommonUtils commonUtils, CommonExpression commonExpression, object dywhere) : base(orm, commonUtils, commonExpression, dywhere) { }
public override string ToSql(string field = null) => CustomOracleSelect<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 OdbcOracleSelect<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 OdbcOracleSelect(IFreeSql orm, CommonUtils commonUtils, CommonExpression commonExpression, object dywhere) : base(orm, commonUtils, commonExpression, dywhere) { }
public override string ToSql(string field = null) => CustomOracleSelect<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 OdbcOracleSelect<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 OdbcOracleSelect(IFreeSql orm, CommonUtils commonUtils, CommonExpression commonExpression, object dywhere) : base(orm, commonUtils, commonExpression, dywhere) { }
public override string ToSql(string field = null) => CustomOracleSelect<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 OdbcOracleSelect<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 OdbcOracleSelect(IFreeSql orm, CommonUtils commonUtils, CommonExpression commonExpression, object dywhere) : base(orm, commonUtils, commonExpression, dywhere) { }
public override string ToSql(string field = null) => CustomOracleSelect<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 OdbcOracleSelect<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 OdbcOracleSelect(IFreeSql orm, CommonUtils commonUtils, CommonExpression commonExpression, object dywhere) : base(orm, commonUtils, commonExpression, dywhere) { }
public override string ToSql(string field = null) => CustomOracleSelect<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 OdbcOracleSelect<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 OdbcOracleSelect(IFreeSql orm, CommonUtils commonUtils, CommonExpression commonExpression, object dywhere) : base(orm, commonUtils, commonExpression, dywhere) { }
public override string ToSql(string field = null) => CustomOracleSelect<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 OdbcOracleSelect<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 OdbcOracleSelect(IFreeSql orm, CommonUtils commonUtils, CommonExpression commonExpression, object dywhere) : base(orm, commonUtils, commonExpression, dywhere) { }
public override string ToSql(string field = null) => CustomOracleSelect<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 OdbcOracleSelect<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 OdbcOracleSelect(IFreeSql orm, CommonUtils commonUtils, CommonExpression commonExpression, object dywhere) : base(orm, commonUtils, commonExpression, dywhere) { }
public override string ToSql(string field = null) => CustomOracleSelect<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 OdbcOracleSelect<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 OdbcOracleSelect(IFreeSql orm, CommonUtils commonUtils, CommonExpression commonExpression, object dywhere) : base(orm, commonUtils, commonExpression, dywhere) { }
public override string ToSql(string field = null) => CustomOracleSelect<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 OdbcOracleSelect<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 OdbcOracleSelect(IFreeSql orm, CommonUtils commonUtils, CommonExpression commonExpression, object dywhere) : base(orm, commonUtils, commonExpression, dywhere) { }
public override string ToSql(string field = null) => CustomOracleSelect<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,74 @@
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.Oracle
{
class CustomOracleUpdate<T1> : Internal.CommonProvider.UpdateProvider<T1>
{
public CustomOracleUpdate(IFreeSql orm, CommonUtils commonUtils, CommonExpression commonExpression, object dywhere)
: base(orm, commonUtils, commonExpression, dywhere)
{
}
public override int ExecuteAffrows() => base.SplitExecuteAffrows(_batchRowsLimit > 0 ? _batchRowsLimit : 200, _batchParameterLimit > 0 ? _batchParameterLimit : 999);
protected override List<TReturn> ExecuteUpdated<TReturn>(IEnumerable<ColumnInfo> columns) => base.SplitExecuteUpdated<TReturn>(_batchRowsLimit > 0 ? _batchRowsLimit : 200, _batchParameterLimit > 0 ? _batchParameterLimit : 999, columns);
protected override List<TReturn> RawExecuteUpdated<TReturn>(IEnumerable<ColumnInfo> columns) => throw new NotImplementedException($"FreeSql.Custom.Oracle {CoreStrings.S_Not_Implemented_Feature}");
protected override void ToSqlCase(StringBuilder caseWhen, ColumnInfo[] primarys)
{
if (primarys.Length == 1)
{
var pk = primarys.First();
caseWhen.Append(_commonUtils.RereadColumn(pk, _commonUtils.QuoteSqlName(pk.Attribute.Name)));
return;
}
caseWhen.Append("(");
var pkidx = 0;
foreach (var pk in primarys)
{
if (pkidx > 0) caseWhen.Append(" || '+' || ");
caseWhen.Append(_commonUtils.RereadColumn(pk, _commonUtils.QuoteSqlName(pk.Attribute.Name)));
++pkidx;
}
caseWhen.Append(")");
}
protected override void ToSqlWhen(StringBuilder sb, ColumnInfo[] primarys, object d)
{
if (primarys.Length == 1)
{
if (primarys[0].Attribute.DbType.Contains("NVARCHAR2"))
sb.Append("N");
sb.Append(_commonUtils.FormatSql("{0}", primarys[0].GetDbValue(d)));
return;
}
sb.Append("(");
var pkidx = 0;
foreach (var pk in primarys)
{
if (pkidx > 0) sb.Append(" || '+' || ");
sb.Append(_commonUtils.FormatSql("{0}", pk.GetDbValue(d)));
++pkidx;
}
sb.Append(")");
}
#if net40
#else
public override Task<int> ExecuteAffrowsAsync(CancellationToken cancellationToken = default) => base.SplitExecuteAffrowsAsync(_batchRowsLimit > 0 ? _batchRowsLimit : 200, _batchParameterLimit > 0 ? _batchParameterLimit : 999, cancellationToken);
protected override Task<List<TReturn>> ExecuteUpdatedAsync<TReturn>(IEnumerable<ColumnInfo> columns, CancellationToken cancellationToken = default) => base.SplitExecuteUpdatedAsync<TReturn>(_batchRowsLimit > 0 ? _batchRowsLimit : 200, _batchParameterLimit > 0 ? _batchParameterLimit : 999, columns, cancellationToken);
protected override Task<List<TReturn>> RawExecuteUpdatedAsync<TReturn>(IEnumerable<ColumnInfo> columns, CancellationToken cancellationToken = default) => throw new NotImplementedException($"FreeSql.Custom.Oracle {CoreStrings.S_Not_Implemented_Feature}");
#endif
}
}

View File

@ -0,0 +1,86 @@
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.Text.RegularExpressions;
using System.Threading;
namespace FreeSql.Custom.Oracle
{
class CustomOracleAdo : FreeSql.Internal.CommonProvider.AdoProvider
{
DbProviderFactory Factory => FreeSqlCustomAdapterGlobalExtensions.GetDbProviderFactory(_util._orm);
public CustomOracleAdo() : base(DataType.OdbcOracle, null, null) { }
public CustomOracleAdo(CommonUtils util, string masterConnectionString, string[] slaveConnectionStrings, Func<DbConnection> connectionFactory) : base(DataType.OdbcOracle, masterConnectionString, slaveConnectionStrings)
{
base._util = util;
if (connectionFactory != null)
{
var pool = new FreeSql.Internal.CommonProvider.DbConnectionPool(DataType.SqlServer, connectionFactory);
ConnectionString = pool.TestConnection?.ConnectionString;
MasterPool = pool;
using (var conn = pool.Get())
UserId = CustomOracleAdo.GetUserId(conn.Value.ConnectionString);
return;
}
throw new Exception(CoreStrings.S_CustomAdapter_OnlySuppport_UseConnectionFactory);
}
internal string UserId { get; set; }
public static string GetUserId(string connectionString)
{
var userIdMatch = Regex.Match(connectionString, @"(User\s+Id|Uid)\s*=\s*([^;]+)", RegexOptions.IgnoreCase);
if (userIdMatch.Success == false) throw new Exception(@"从 ConnectionString 中无法匹配 (User\s+Id|Uid)\s*=\s*([^;]+)");
return userIdMatch.Groups[2].Value.Trim().ToUpper();
}
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 byte[])
return $"hextoraw('{CommonUtils.BytesSqlRaw(param as byte[])}')";
else if (param is bool || param is bool?)
return (bool)param ? 1 : 0;
else if (param is string)
return string.Concat("'", param.ToString().Replace("'", "''"), "'");
else if (param is char)
return string.Concat("'", param.ToString().Replace("'", "''").Replace('\0', ' '), "'");
else if (param is Enum)
return AddslashesTypeHandler(param.GetType(), param) ?? ((Enum)param).ToInt64();
else if (decimal.TryParse(string.Concat(param), out var trydec))
return param;
else if (param is DateTime)
return AddslashesTypeHandler(typeof(DateTime), param) ?? string.Concat("to_timestamp('", ((DateTime)param).ToString("yyyy-MM-dd HH:mm:ss.ffffff"), "','YYYY-MM-DD HH24:MI:SS.FF6')");
else if (param is DateTime?)
return AddslashesTypeHandler(typeof(DateTime?), param) ?? string.Concat("to_timestamp('", ((DateTime)param).ToString("yyyy-MM-dd HH:mm:ss.ffffff"), "','YYYY-MM-DD HH24:MI:SS.FF6')");
else if (param is TimeSpan || param is TimeSpan?)
return $"numtodsinterval({((TimeSpan)param).Ticks * 1.0 / 10000000},'second')";
else if (param is IEnumerable)
return AddslashesIEnumerable(param, mapType, mapColumn);
return string.Concat("'", param.ToString().Replace("'", "''"), "'");
//if (param is string) return string.Concat('N', nparms[a]);
}
public override DbCommand CreateCommand()
{
return Factory.CreateCommand();
}
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,509 @@
using FreeSql.DataAnnotations;
using FreeSql.Internal;
using FreeSql.Internal.Model;
using System;
using System.Collections.Generic;
using System.Data;
using System.Linq;
using System.Reflection;
using System.Text;
using System.Text.RegularExpressions;
namespace FreeSql.Custom.Oracle
{
class CustomOracleCodeFirst : Internal.CommonProvider.CodeFirstProvider
{
public override bool IsNoneCommandParameter { get => true; set => base.IsNoneCommandParameter = true; }
public CustomOracleCodeFirst(IFreeSql orm, CommonUtils commonUtils, CommonExpression commonExpression) : base(orm, commonUtils, commonExpression) { }
static object _dicCsToDbLock = new object();
static Dictionary<string, CsToDb<DbType>> _dicCsToDb = new Dictionary<string, CsToDb<DbType>>() {
{ typeof(bool).FullName, CsToDb.New(DbType.Boolean, "number","number(1) NOT NULL", null, false, false) },{ typeof(bool?).FullName, CsToDb.New(DbType.Boolean, "number","number(1) NULL", null, true, null) },
{ typeof(sbyte).FullName, CsToDb.New(DbType.SByte, "number", "number(4) NOT NULL", false, false, 0) },{ typeof(sbyte?).FullName, CsToDb.New(DbType.SByte, "number", "number(4) NULL", false, true, null) },
{ typeof(short).FullName, CsToDb.New(DbType.Int16, "number","number(6) NOT NULL", false, false, 0) },{ typeof(short?).FullName, CsToDb.New(DbType.Int16, "number", "number(6) NULL", false, true, null) },
{ typeof(int).FullName, CsToDb.New(DbType.Int32, "number", "number(11) NOT NULL", false, false, 0) },{ typeof(int?).FullName, CsToDb.New(DbType.Int32, "number", "number(11) NULL", false, true, null) },
{ typeof(long).FullName, CsToDb.New(DbType.Int64, "number","number(21) NOT NULL", false, false, 0) },{ typeof(long?).FullName, CsToDb.New(DbType.Int64, "number","number(21) NULL", false, true, null) },
{ typeof(byte).FullName, CsToDb.New(DbType.Byte, "number","number(3) NOT NULL", true, false, 0) },{ typeof(byte?).FullName, CsToDb.New(DbType.Byte, "number","number(3) NULL", true, true, null) },
{ typeof(ushort).FullName, CsToDb.New(DbType.UInt16, "number","number(5) NOT NULL", true, false, 0) },{ typeof(ushort?).FullName, CsToDb.New(DbType.UInt16, "number", "number(5) NULL", true, true, null) },
{ typeof(uint).FullName, CsToDb.New(DbType.UInt32, "number", "number(10) NOT NULL", true, false, 0) },{ typeof(uint?).FullName, CsToDb.New(DbType.UInt32, "number", "number(10) NULL", true, true, null) },
{ typeof(ulong).FullName, CsToDb.New(DbType.UInt64, "number", "number(20) NOT NULL", true, false, 0) },{ typeof(ulong?).FullName, CsToDb.New(DbType.UInt64, "number", "number(20) NULL", true, true, null) },
{ typeof(double).FullName, CsToDb.New(DbType.Double, "float", "float(126) NOT NULL", false, false, 0) },{ typeof(double?).FullName, CsToDb.New(DbType.Double, "float", "float(126) NULL", false, true, null) },
{ typeof(float).FullName, CsToDb.New(DbType.Single, "float","float(63) NOT NULL", false, false, 0) },{ typeof(float?).FullName, CsToDb.New(DbType.Single, "float","float(63) NULL", false, true, null) },
{ typeof(decimal).FullName, CsToDb.New(DbType.Decimal, "number", "number(10,2) NOT NULL", false, false, 0) },{ typeof(decimal?).FullName, CsToDb.New(DbType.Decimal, "number", "number(10,2) NULL", false, true, null) },
{ typeof(TimeSpan).FullName, CsToDb.New(DbType.Time, "interval day to second","interval day(2) to second(6) NOT NULL", false, false, 0) },{ typeof(TimeSpan?).FullName, CsToDb.New(DbType.Time, "interval day to second", "interval day(2) to second(6) NULL",false, true, null) },
{ typeof(DateTime).FullName, CsToDb.New(DbType.DateTime, "timestamp", "timestamp(6) NOT NULL", false, false, new DateTime(1970,1,1)) },{ typeof(DateTime?).FullName, CsToDb.New(DbType.DateTime, "timestamp", "timestamp(6) NULL", false, true, null) },
{ typeof(DateTimeOffset).FullName, CsToDb.New(DbType.DateTimeOffset, "timestamp with local time zone", "timestamp(6) with local time zone NOT NULL", false, false, new DateTime(1970,1,1)) },{ typeof(DateTimeOffset?).FullName, CsToDb.New(DbType.DateTimeOffset, "timestamp with local time zone", "timestamp(6) with local time zone NULL", false, true, null) },
{ typeof(byte[]).FullName, CsToDb.New(DbType.Binary, "blob", "blob NULL", false, null, new byte[0]) },
{ typeof(string).FullName, CsToDb.New(DbType.String, "nvarchar2", "nvarchar2(255) NULL", false, null, "") },
{ typeof(char).FullName, CsToDb.New(DbType.AnsiString, "char", "char(1 CHAR) NULL", false, null, '\0') },
{ typeof(Guid).FullName, CsToDb.New(DbType.Guid, "char", "char(36 CHAR) NOT NULL", false, false, Guid.Empty) },{ typeof(Guid?).FullName, CsToDb.New(DbType.Guid, "char", "char(36 CHAR) NULL", false, true, null) },
};
public override DbInfoResult GetDbInfo(Type type)
{
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.Int32, "number", $"number(32){(type.IsEnum ? " NOT NULL" : "")}", false, type.IsEnum ? false : true, enumType.CreateInstanceGetDefaultValue()) :
CsToDb.New(DbType.Int64, "number", $"number(16){(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 TypeSchemaAndName[] objects)
{
var userId = (_orm.Ado as CustomOracleAdo)?.UserId;
if (string.IsNullOrEmpty(userId))
using (var conn = _orm.Ado.MasterPool.Get())
{
userId = CustomOracleAdo.GetUserId(conn.Value.ConnectionString);
}
var seqcols = new List<NativeTuple<ColumnInfo, string[], bool>>(); //序列:列,表,自增
var seqnameDel = new List<string>(); //要删除的序列+触发器
var sb = new StringBuilder();
var sbDeclare = new StringBuilder();
foreach (var obj in objects)
{
if (sb.Length > 0) sb.Append("\r\n");
var tb = obj.tableSchema;
if (tb == null) throw new Exception(CoreStrings.S_Type_IsNot_Migrable(obj.tableSchema.Type.FullName));
if (tb.Columns.Any() == false) throw new Exception(CoreStrings.S_Type_IsNot_Migrable_0Attributes(obj.tableSchema.Type.FullName));
var tbname = _commonUtils.SplitTableName(tb.DbName);
if (tbname?.Length == 1) tbname = new[] { userId, tbname[0] };
var tboldname = _commonUtils.SplitTableName(tb.DbOldName); //旧表名
if (tboldname?.Length == 1) tboldname = new[] { userId, tboldname[0] };
var primaryKeyName = (obj.tableSchema.Type.GetCustomAttributes(typeof(OraclePrimaryKeyNameAttribute), false)?.FirstOrDefault() as OraclePrimaryKeyNameAttribute)?.Name;
if (string.IsNullOrEmpty(obj.tableName) == false)
{
var tbtmpname = _commonUtils.SplitTableName(obj.tableName);
if (tbtmpname?.Length == 1) tbtmpname = new[] { userId, tbtmpname[0] };
if (tbname[0] != tbtmpname[0] || tbname[1] != tbtmpname[1])
{
tbname = tbtmpname;
tboldname = null;
primaryKeyName = null;
}
}
//codefirst 不支持表名中带 .
if (string.Compare(tbname[0], userId) != 0 && _orm.Ado.ExecuteScalar(CommandType.Text, _commonUtils.FormatSql(" select 1 from sys.dba_users where username={0}", tbname[0])) == null) //创建数据库
throw new NotImplementedException(CoreStrings.S_Oracle_NotSupport_TablespaceSchemas(tbname[0]));
var sbalter = new StringBuilder();
var istmpatler = false; //创建临时表,导入数据,删除旧表,修改
if (_orm.Ado.ExecuteScalar(CommandType.Text, _commonUtils.FormatSql(" select 1 from all_tab_comments where owner={0} and table_name={1}", tbname)) == null)
{ //表不存在
if (tboldname != null)
{
if (_orm.Ado.ExecuteScalar(CommandType.Text, _commonUtils.FormatSql(" select 1 from all_tab_comments where owner={0} and table_name={1}", tboldname)) == null)
//模式或表不存在
tboldname = null;
}
if (tboldname == null)
{
//创建表
var createTableName = _commonUtils.QuoteSqlName($"{tbname[0]}.{tbname[1]}");
sb.Append("execute immediate 'CREATE TABLE ").Append(createTableName).Append(" ( ");
foreach (var tbcol in tb.ColumnsByPosition)
{
sb.Append(" \r\n ").Append(_commonUtils.QuoteSqlName(tbcol.Attribute.Name)).Append(" ").Append(tbcol.Attribute.DbType).Append(",");
if (tbcol.Attribute.IsIdentity == true) seqcols.Add(NativeTuple.Create(tbcol, tbname, true));
}
if (tb.Primarys.Any())
{
var pkname = primaryKeyName ?? $"{tbname[0]}_{tbname[1]}_pk1";
sb.Append(" \r\n CONSTRAINT ").Append(_commonUtils.QuoteSqlName(pkname)).Append(" PRIMARY KEY (");
foreach (var tbcol in tb.Primarys) sb.Append(_commonUtils.QuoteSqlName(tbcol.Attribute.Name)).Append(", ");
sb.Remove(sb.Length - 2, 2).Append("),");
}
sb.Remove(sb.Length - 1, 1);
sb.Append("\r\n) \r\nLOGGING \r\nNOCOMPRESS \r\nNOCACHE\r\n';\r\n");
//创建表的索引
foreach (var uk in tb.Indexes)
{
sb.Append("execute immediate 'CREATE ");
if (uk.IsUnique) sb.Append("UNIQUE ");
sb.Append("INDEX ").Append(_commonUtils.QuoteSqlName(ReplaceIndexName(uk.Name, tbname[1]))).Append(" ON ").Append(createTableName).Append("(");
foreach (var tbcol in uk.Columns)
{
sb.Append(_commonUtils.QuoteSqlName(tbcol.Column.Attribute.Name));
if (tbcol.IsDesc) sb.Append(" DESC");
sb.Append(", ");
}
sb.Remove(sb.Length - 2, 2).Append(")';\r\n");
}
//备注
foreach (var tbcol in tb.ColumnsByPosition)
{
if (string.IsNullOrEmpty(tbcol.Comment) == false)
sb.Append("execute immediate 'COMMENT ON COLUMN ").Append(_commonUtils.QuoteSqlName($"{tbname[0]}.{tbname[1]}.{tbcol.Attribute.Name}")).Append(" IS ").Append(_commonUtils.FormatSql("{0}", tbcol.Comment).Replace("'", "''")).Append("';\r\n");
}
if (string.IsNullOrEmpty(tb.Comment) == false)
sb.Append("execute immediate 'COMMENT ON TABLE ").Append(_commonUtils.QuoteSqlName($"{tbname[0]}.{tbname[1]}")).Append(" IS ").Append(_commonUtils.FormatSql("{0}", tb.Comment).Replace("'", "''")).Append("';\r\n");
continue;
}
//如果新表,旧表在一个模式下,直接修改表名
if (string.Compare(tbname[0], tboldname[0], true) == 0)
sbalter.Append("execute immediate 'ALTER TABLE ").Append(_commonUtils.QuoteSqlName($"{tboldname[0]}.{tboldname[1]}")).Append(" RENAME TO ").Append(_commonUtils.QuoteSqlName($"{tbname[1]}")).Append("';\r\n");
else
{
//如果新表,旧表不在一起,创建新表,导入数据,删除旧表
istmpatler = true;
}
}
else
tboldname = null; //如果新表已经存在,不走改表名逻辑
//对比字段,只可以修改类型、增加字段、有限的修改字段名;保证安全不删除字段
var sql = _commonUtils.FormatSql($@"
select
a.column_name,
a.data_type,
a.data_length,
a.data_precision,
a.data_scale,
a.char_used,
case when a.nullable = 'N' then 0 else 1 end,
nvl((select 1 from user_sequences where upper(sequence_name)=upper('{Utils.GetCsName((tboldname ?? tbname).Last())}_seq_'||a.column_name) and rownum < 2), 0),
nvl((select 1 from user_triggers where upper(trigger_name)=upper('{Utils.GetCsName((tboldname ?? tbname).Last())}_seq_'||a.column_name||'TI') and rownum < 2), 0),
b.comments
from all_tab_columns a
left join all_col_comments b on b.owner = a.owner and b.table_name = a.table_name and b.column_name = a.column_name
where a.owner={{0}} and a.table_name={{1}} and a.column_id is not null", tboldname ?? tbname);
var ds = _orm.Ado.ExecuteArray(CommandType.Text, sql);
var tbstruct = ds.ToDictionary(a => string.Concat(a[0]), a =>
{
var sqlType = GetOracleSqlTypeFullName(a);
return new
{
column = string.Concat(a[0]),
sqlType,
is_nullable = string.Concat(a[6]) == "1",
is_identity = string.Concat(a[7]) == "1" && string.Concat(a[8]) == "1",
comment = string.Concat(a[9])
};
}, StringComparer.CurrentCultureIgnoreCase);
if (istmpatler == false)
{
foreach (var tbcol in tb.ColumnsByPosition)
{
var dbtypeNoneNotNull = Regex.Replace(tbcol.Attribute.DbType, @"NOT\s+NULL", "NULL");
if (tbstruct.TryGetValue(tbcol.Attribute.Name, out var tbstructcol) ||
string.IsNullOrEmpty(tbcol.Attribute.OldName) == false && tbstruct.TryGetValue(tbcol.Attribute.OldName, out tbstructcol))
{
var isCommentChanged = tbstructcol.comment != (tbcol.Comment ?? "");
if (tbcol.Attribute.DbType.StartsWith(tbstructcol.sqlType, StringComparison.CurrentCultureIgnoreCase) == false)
{
istmpatler = true;
if (tbcol.Attribute.DbType.StartsWith("varchar", StringComparison.CurrentCultureIgnoreCase) && tbstructcol.sqlType.StartsWith("varchar2", StringComparison.CurrentCultureIgnoreCase)
&& Regex.Match(tbcol.Attribute.DbType, @"\(\d+").Groups[0].Value == Regex.Match(tbstructcol.sqlType, @"\(\d+").Groups[0].Value)
istmpatler = false;
if (istmpatler) break;
}
//sbalter.Append("execute immediate 'ALTER TABLE ").Append(_commonUtils.QuoteSqlName($"{tbname[0]}.{tbname[1]}")).Append(" MODIFY (").Append(_commonUtils.QuoteSqlName(tbstructcol.column)).Append(" ").Append(dbtypeNoneNotNull).Append(")';\r\n");
if (tbcol.Attribute.IsNullable != tbstructcol.is_nullable)
{
if (tbcol.Attribute.IsNullable == false)
sbalter.Append("execute immediate 'UPDATE ").Append(_commonUtils.QuoteSqlName($"{tbname[0]}.{tbname[1]}")).Append(" SET ").Append(_commonUtils.QuoteSqlName(tbstructcol.column)).Append(" = ").Append(tbcol.DbDefaultValue.Replace("'", "''")).Append(" WHERE ").Append(_commonUtils.QuoteSqlName(tbstructcol.column)).Append(" IS NULL';\r\n");
sbalter.Append("execute immediate 'ALTER TABLE ").Append(_commonUtils.QuoteSqlName($"{tbname[0]}.{tbname[1]}")).Append(" MODIFY ").Append(_commonUtils.QuoteSqlName(tbstructcol.column)).Append(" ").Append(tbcol.Attribute.IsNullable == true ? "" : "NOT").Append(" NULL';\r\n");
}
if (string.Compare(tbstructcol.column, tbcol.Attribute.OldName, true) == 0)
{
if (tbstructcol.is_identity)
seqnameDel.Add(Utils.GetCsName($"{tbname[1]}_seq_{tbstructcol.column}"));
//修改列名
sbalter.Append("execute immediate 'ALTER TABLE ").Append(_commonUtils.QuoteSqlName($"{tbname[0]}.{tbname[1]}")).Append(" RENAME COLUMN ").Append(_commonUtils.QuoteSqlName(tbstructcol.column)).Append(" TO ").Append(_commonUtils.QuoteSqlName(tbcol.Attribute.Name)).Append("';\r\n");
if (tbcol.Attribute.IsIdentity)
seqcols.Add(NativeTuple.Create(tbcol, tbname, tbcol.Attribute.IsIdentity == true));
}
else if (tbcol.Attribute.IsIdentity != tbstructcol.is_identity)
seqcols.Add(NativeTuple.Create(tbcol, tbname, tbcol.Attribute.IsIdentity == true));
if (isCommentChanged)
sbalter.Append("execute immediate 'COMMENT ON COLUMN ").Append(_commonUtils.QuoteSqlName($"{tbname[0]}.{tbname[1]}.{tbcol.Attribute.Name}")).Append(" IS ").Append(_commonUtils.FormatSql("{0}", tbcol.Comment ?? "").Replace("'", "''")).Append("';\r\n");
continue;
}
//添加列
sbalter.Append("execute immediate 'ALTER TABLE ").Append(_commonUtils.QuoteSqlName($"{tbname[0]}.{tbname[1]}")).Append(" ADD (").Append(_commonUtils.QuoteSqlName(tbcol.Attribute.Name)).Append(" ").Append(dbtypeNoneNotNull).Append(")';\r\n");
if (tbcol.Attribute.IsNullable == false)
{
sbalter.Append("execute immediate 'UPDATE ").Append(_commonUtils.QuoteSqlName($"{tbname[0]}.{tbname[1]}")).Append(" SET ").Append(_commonUtils.QuoteSqlName(tbcol.Attribute.Name)).Append(" = ").Append(tbcol.DbDefaultValue.Replace("'", "''")).Append("';\r\n");
sbalter.Append("execute immediate 'ALTER TABLE ").Append(_commonUtils.QuoteSqlName($"{tbname[0]}.{tbname[1]}")).Append(" MODIFY ").Append(_commonUtils.QuoteSqlName(tbcol.Attribute.Name)).Append(" NOT NULL';\r\n");
}
if (tbcol.Attribute.IsIdentity == true) seqcols.Add(NativeTuple.Create(tbcol, tbname, tbcol.Attribute.IsIdentity == true));
if (string.IsNullOrEmpty(tbcol.Comment) == false) sbalter.Append("execute immediate 'COMMENT ON COLUMN ").Append(_commonUtils.QuoteSqlName($"{tbname[0]}.{tbname[1]}.{tbcol.Attribute.Name}")).Append(" IS ").Append(_commonUtils.FormatSql("{0}", tbcol.Comment ?? "").Replace("'", "''")).Append("';\r\n");
}
}
if (istmpatler == false)
{
CreateOracleFunction(_orm);
var dsuksql = _commonUtils.FormatSql(@"
select
nvl(freesql_long_2_varchar(a.index_name, c.table_name, c.column_position), c.column_name),
a.index_name,
case when c.descend = 'DESC' then 1 else 0 end,
case when a.uniqueness = 'UNIQUE' then 1 else 0 end
from all_indexes a,
all_ind_columns c
where a.index_name = c.index_name
and a.table_owner = c.table_owner
and a.table_name = c.table_name
and a.owner in ({0}) and a.table_name in ({1})
and not exists(select 1 from all_constraints where constraint_name = a.index_name and constraint_type = 'P')", tboldname ?? tbname);
var dsuk = _orm.Ado.ExecuteArray(CommandType.Text, dsuksql).Select(a => new[] { string.Concat(a[0]).Trim('"'), string.Concat(a[1]), string.Concat(a[2]), string.Concat(a[3]) }).ToArray();
foreach (var uk in tb.Indexes)
{
if (string.IsNullOrEmpty(uk.Name) || uk.Columns.Any() == false) continue;
var ukname = ReplaceIndexName(uk.Name, tbname[1]);
var dsukfind1 = dsuk.Where(a => string.Compare(a[1], ukname, true) == 0).ToArray();
if (dsukfind1.Any() == false || dsukfind1.Length != uk.Columns.Length || dsukfind1.Where(a => uk.Columns.Where(b => (a[3] == "1") == uk.IsUnique && string.Compare(b.Column.Attribute.Name, a[0], true) == 0 && (a[2] == "1") == b.IsDesc).Any()).Count() != uk.Columns.Length)
{
if (dsukfind1.Any()) sbalter.Append("execute immediate 'DROP INDEX ").Append(_commonUtils.QuoteSqlName(ukname)).Append("';\r\n");
sbalter.Append("execute immediate 'CREATE ");
if (uk.IsUnique) sbalter.Append("UNIQUE ");
sbalter.Append("INDEX ").Append(_commonUtils.QuoteSqlName(ukname)).Append(" ON ").Append(_commonUtils.QuoteSqlName($"{tbname[0]}.{tbname[1]}")).Append("(");
foreach (var tbcol in uk.Columns)
{
sbalter.Append(_commonUtils.QuoteSqlName(tbcol.Column.Attribute.Name));
if (tbcol.IsDesc) sbalter.Append(" DESC");
sbalter.Append(", ");
}
sbalter.Remove(sbalter.Length - 2, 2).Append(")';\r\n");
}
}
}
if (istmpatler == false)
{
var dbcomment = string.Concat(_orm.Ado.ExecuteScalar(CommandType.Text, _commonUtils.FormatSql(@" select comments from all_tab_comments where owner = {0} and table_name = {1} and table_type = 'TABLE'", tbname[0], tbname[1])));
if (dbcomment != (tb.Comment ?? ""))
sb.Append("execute immediate 'COMMENT ON TABLE ").Append(_commonUtils.QuoteSqlName($"{tbname[0]}.{tbname[1]}")).Append(" IS ").Append(_commonUtils.FormatSql("{0}", tb.Comment).Replace("'", "''")).Append("';\r\n");
sb.Append(sbalter);
continue;
}
var oldpk = _orm.Ado.ExecuteScalar(CommandType.Text, _commonUtils.FormatSql(@" select constraint_name from user_constraints where owner={0} and table_name={1} and constraint_type='P'", tbname))?.ToString();
if (string.IsNullOrEmpty(oldpk) == false)
sb.Append("execute immediate 'ALTER TABLE ").Append(_commonUtils.QuoteSqlName($"{tbname[0]}.{tbname[1]}")).Append(" DROP CONSTRAINT ").Append(_commonUtils.QuoteSqlName(oldpk)).Append("';\r\n");
//创建临时表,数据导进临时表,然后删除原表,将临时表改名为原表名
var tablename = tboldname == null ? _commonUtils.QuoteSqlName($"{tbname[0]}.{tbname[1]}") : _commonUtils.QuoteSqlName($"{tboldname[0]}.{tboldname[1]}");
var tmptablename = _commonUtils.QuoteSqlName($"{tbname[0]}.FTmp_{tbname[1]}");
//创建临时表
sb.Append("execute immediate 'CREATE TABLE ").Append(tmptablename).Append(" ( ");
foreach (var tbcol in tb.ColumnsByPosition)
{
sb.Append(" \r\n ").Append(_commonUtils.QuoteSqlName(tbcol.Attribute.Name)).Append(" ").Append(tbcol.Attribute.DbType).Append(",");
if (tbcol.Attribute.IsIdentity == true) seqcols.Add(NativeTuple.Create(tbcol, tbname, true));
}
if (tb.Primarys.Any())
{
var pkname = primaryKeyName ?? $"{tbname[0]}_{tbname[1]}_pk2";
sb.Append(" \r\n CONSTRAINT ").Append(_commonUtils.QuoteSqlName(pkname)).Append(" PRIMARY KEY (");
foreach (var tbcol in tb.Primarys) sb.Append(_commonUtils.QuoteSqlName(tbcol.Attribute.Name)).Append(", ");
sb.Remove(sb.Length - 2, 2).Append("),");
}
sb.Remove(sb.Length - 1, 1);
sb.Append("\r\n) LOGGING \r\nNOCOMPRESS \r\nNOCACHE\r\n';\r\n");
//备注
foreach (var tbcol in tb.ColumnsByPosition)
{
if (string.IsNullOrEmpty(tbcol.Comment) == false)
sb.Append("execute immediate 'COMMENT ON COLUMN ").Append(_commonUtils.QuoteSqlName($"{tbname[0]}.FTmp_{tbname[1]}.{tbcol.Attribute.Name}")).Append(" IS ").Append(_commonUtils.FormatSql("{0}", tbcol.Comment).Replace("'", "''")).Append("';\r\n");
}
if (string.IsNullOrEmpty(tb.Comment) == false)
sb.Append("execute immediate 'COMMENT ON TABLE ").Append(_commonUtils.QuoteSqlName($"{tbname[0]}.FTmp_{tbname[1]}")).Append(" IS ").Append(_commonUtils.FormatSql("{0}", tb.Comment).Replace("'", "''")).Append("';\r\n");
sb.Append("execute immediate 'INSERT INTO ").Append(tmptablename).Append(" (");
foreach (var tbcol in tb.ColumnsByPosition)
sb.Append(_commonUtils.QuoteSqlName(tbcol.Attribute.Name)).Append(", ");
sb.Remove(sb.Length - 2, 2).Append(")\r\nSELECT ");
foreach (var tbcol in tb.ColumnsByPosition)
{
var insertvalue = "NULL";
if (tbstruct.TryGetValue(tbcol.Attribute.Name, out var tbstructcol) ||
string.IsNullOrEmpty(tbcol.Attribute.OldName) == false && tbstruct.TryGetValue(tbcol.Attribute.OldName, out tbstructcol))
{
insertvalue = _commonUtils.QuoteSqlName(tbstructcol.column);
if (tbcol.Attribute.DbType.StartsWith(tbstructcol.sqlType, StringComparison.CurrentCultureIgnoreCase) == false)
{
var dbtypeNoneNotNull = Regex.Replace(tbcol.Attribute.DbType, @"(NOT\s+)?NULL", "");
insertvalue = $"cast({insertvalue} as {dbtypeNoneNotNull})";
}
if (tbcol.Attribute.IsNullable != tbstructcol.is_nullable)
insertvalue = $"nvl({insertvalue},{tbcol.DbDefaultValue})";
}
else if (tbcol.Attribute.IsNullable == false)
insertvalue = tbcol.DbDefaultValue;
sb.Append(insertvalue.Replace("'", "''")).Append(", ");
}
sb.Remove(sb.Length - 2, 2).Append(" FROM ").Append(tablename).Append("';\r\n");
sb.Append("execute immediate 'DROP TABLE ").Append(tablename).Append("';\r\n");
sb.Append("execute immediate 'ALTER TABLE ").Append(tmptablename).Append(" RENAME TO ").Append(_commonUtils.QuoteSqlName($"{tbname[1]}")).Append("';\r\n");
//创建表的索引
foreach (var uk in tb.Indexes)
{
sb.Append("execute immediate 'CREATE ");
if (uk.IsUnique) sb.Append("UNIQUE ");
sb.Append("INDEX ").Append(_commonUtils.QuoteSqlName(ReplaceIndexName(uk.Name, tbname[1]))).Append(" ON ").Append(tablename).Append("(");
foreach (var tbcol in uk.Columns)
{
sb.Append(_commonUtils.QuoteSqlName(tbcol.Column.Attribute.Name));
if (tbcol.IsDesc) sb.Append(" DESC");
sb.Append(", ");
}
sb.Remove(sb.Length - 2, 2).Append(")';\r\n");
}
}
Dictionary<string, bool> dicDeclare = new Dictionary<string, bool>();
Action<string> dropSequence = seqname =>
{
if (dicDeclare.ContainsKey(seqname) == false)
{
sbDeclare.Append("\r\nIS").Append(seqname).Append(" NUMBER; \r\n");
dicDeclare.Add(seqname, true);
}
sb.Append("IS").Append(seqname).Append(" := 0; \r\n")
.Append(" select count(1) into IS").Append(seqname).Append(_commonUtils.FormatSql(" from user_sequences where sequence_name={0}; \r\n", seqname))
.Append("if IS").Append(seqname).Append(" > 0 then \r\n")
.Append(" execute immediate 'DROP SEQUENCE ").Append(_commonUtils.QuoteSqlName(seqname)).Append("';\r\n")
.Append("end if; \r\n");
};
Action<string> dropTrigger = tiggerName =>
{
if (dicDeclare.ContainsKey(tiggerName) == false)
{
sbDeclare.Append("\r\nIS").Append(tiggerName).Append(" NUMBER; \r\n");
dicDeclare.Add(tiggerName, true);
}
sb.Append("IS").Append(tiggerName).Append(" := 0; \r\n")
.Append(" select count(1) into IS").Append(tiggerName).Append(_commonUtils.FormatSql(" from user_triggers where trigger_name={0}; \r\n", tiggerName))
.Append("if IS").Append(tiggerName).Append(" > 0 then \r\n")
.Append(" execute immediate 'DROP TRIGGER ").Append(_commonUtils.QuoteSqlName(tiggerName)).Append("';\r\n")
.Append("end if; \r\n");
};
foreach (var seqname in seqnameDel)
{
dropSequence(seqname);
dropTrigger(seqname + "TI");
}
foreach (var seqcol in seqcols)
{
var tbname = seqcol.Item2;
var seqname = Utils.GetCsName($"{tbname[1]}_seq_{seqcol.Item1.Attribute.Name}").ToUpper();
var tiggerName = seqname + "TI";
var tbname2 = _commonUtils.QuoteSqlName($"{tbname[0]}.{tbname[1]}");
var colname2 = _commonUtils.QuoteSqlName(seqcol.Item1.Attribute.Name);
dropSequence(seqname);
if (seqcol.Item3)
{
var startWith = _orm.Ado.ExecuteScalar(CommandType.Text, _commonUtils.FormatSql(" select 1 from all_tab_columns where owner={0} and table_name={1} and column_name={2}", tbname[0], tbname[1], seqcol.Item1.Attribute.Name)) == null ? 1 :
_orm.Ado.ExecuteScalar(CommandType.Text, $" select nvl(max({colname2})+1,1) from {tbname2}");
sb.Append("execute immediate 'CREATE SEQUENCE ").Append(_commonUtils.QuoteSqlName(seqname)).Append(" start with ").Append(startWith).Append("';\r\n");
sb.Append("execute immediate 'CREATE OR REPLACE TRIGGER ").Append(_commonUtils.QuoteSqlName(tiggerName))
.Append(" \r\nbefore insert on ").Append(tbname2)
.Append(" \r\nfor each row \r\nbegin\r\nselect ").Append(_commonUtils.QuoteSqlName(seqname))
.Append(".nextval into :new.").Append(colname2).Append(" from dual;\r\nend;';\r\n");
}
else
dropTrigger(tiggerName);
}
if (sbDeclare.Length > 0) sbDeclare.Insert(0, "declare ");
return sb.Length == 0 ? null : sb.Insert(0, "BEGIN \r\n").Insert(0, sbDeclare.ToString()).Append("END;").ToString();
}
internal static string GetOracleSqlTypeFullName(object[] row)
{
var a = row;
var sqlType = string.Concat(a[1]).ToUpper();
var data_length = long.Parse(string.Concat(a[2]));
long.TryParse(string.Concat(a[3]), out var data_precision);
long.TryParse(string.Concat(a[4]), out var data_scale);
var char_used = string.Concat(a[5]);
if (Regex.IsMatch(sqlType, @"INTERVAL DAY\(\d+\) TO SECOND\(\d+\)", RegexOptions.IgnoreCase))
{
}
else if (Regex.IsMatch(sqlType, @"INTERVAL YEAR\(\d+\) TO MONTH", RegexOptions.IgnoreCase))
{
}
else if (sqlType.StartsWith("TIMESTAMP", StringComparison.CurrentCultureIgnoreCase))
{
}
else if (sqlType.StartsWith("BLOB"))
{
}
else if (sqlType.StartsWith("CLOB"))
{
}
else if (sqlType.StartsWith("NCLOB"))
{
}
else if (sqlType.StartsWith("RAW"))
{
}
else if (sqlType.StartsWith("LONG RAW"))
{
}
else if (char_used.ToLower() == "c")
sqlType += sqlType.StartsWith("N") ? $"({data_length / 2})" : $"({data_length / 4} CHAR)";
else if (char_used.ToLower() == "b")
sqlType += $"({data_length} BYTE)";
else if (sqlType.ToLower() == "float")
sqlType += $"({data_precision})";
else if (data_precision > 0 && data_scale > 0)
sqlType += $"({data_precision},{data_scale})";
else if (data_precision > 0)
sqlType += $"({data_precision})";
else
sqlType += $"({data_length})";
return sqlType;
}
internal static void CreateOracleFunction(IFreeSql fsql)
{
fsql.Ado.ExecuteNonQuery(CommandType.Text, @"
CREATE OR REPLACE FUNCTION freesql_long_2_varchar (
p_index_name IN user_ind_expressions.index_name%TYPE,
p_table_name IN user_ind_expressions.table_name%TYPE,
p_COLUMN_POSITION IN user_ind_expressions.table_name%TYPE)
RETURN VARCHAR2
AS
l_COLUMN_EXPRESSION LONG;
BEGIN
SELECT COLUMN_EXPRESSION
INTO l_COLUMN_EXPRESSION
FROM user_ind_expressions
WHERE index_name = p_index_name
AND table_name = p_table_name
AND COLUMN_POSITION = p_COLUMN_POSITION;
RETURN SUBSTR (l_COLUMN_EXPRESSION, 1, 4000);
END;");
}
}
}

View File

@ -0,0 +1,584 @@
using FreeSql.DatabaseModel;
using FreeSql.Internal;
using FreeSql.Internal.Model;
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Data;
using System.Linq;
using System.Text;
using System.Text.RegularExpressions;
namespace FreeSql.Custom.Oracle
{
class CustomOracleDbFirst : IDbFirst
{
IFreeSql _orm;
protected CommonUtils _commonUtils;
protected CommonExpression _commonExpression;
public CustomOracleDbFirst(IFreeSql orm, CommonUtils commonUtils, CommonExpression commonExpression)
{
_orm = orm;
_commonUtils = commonUtils;
_commonExpression = commonExpression;
}
public int GetDbType(DbColumnInfo column) => (int)GetSqlDbType(column);
DbType GetSqlDbType(DbColumnInfo column)
{
var dbfull = column.DbTypeTextFull?.ToLower();
switch (dbfull)
{
case "number(1)": return DbType.Boolean;
case "number(4)": return DbType.SByte;
case "number(6)": return DbType.Int16;
case "number(11)": return DbType.Int32;
case "number(21)": return DbType.Int64;
case "number(3)": return DbType.Byte;
case "number(5)": return DbType.UInt16;
case "number(10)": return DbType.UInt32;
case "number(20)": return DbType.UInt64;
case "float(126)": return DbType.Double;
case "float(63)": return DbType.Single;
case "number(10,2)": return DbType.Decimal;
case "interval day(2) to second(6)": return DbType.Time;
case "timestamp(6)": return DbType.DateTime;
case "timestamp(6) with local time zone": return DbType.DateTime;
case "blob": return DbType.Binary;
case "nvarchar2(255)": return DbType.String;
case "char(36 char)": return DbType.Guid;
}
switch (column.DbTypeText?.ToLower())
{
case "number":
_dicDbToCs.TryAdd(dbfull, _dicDbToCs["number(10,2)"]);
return DbType.Decimal;
case "float":
_dicDbToCs.TryAdd(dbfull, _dicDbToCs["float(126)"]);
return DbType.Double;
case "interval day to second":
_dicDbToCs.TryAdd(dbfull, _dicDbToCs["interval day(2) to second(6)"]);
return DbType.Time;
case "date":
_dicDbToCs.TryAdd(dbfull, _dicDbToCs["date"]);
return DbType.DateTime;
case "timestamp":
_dicDbToCs.TryAdd(dbfull, _dicDbToCs["timestamp(6)"]);
return DbType.DateTime;
case "timestamp with local time zone":
_dicDbToCs.TryAdd(dbfull, _dicDbToCs["timestamp(6) with local time zone"]);
return DbType.DateTime;
case "blob":
_dicDbToCs.TryAdd(dbfull, _dicDbToCs["blob"]);
return DbType.Binary;
case "nvarchar2":
_dicDbToCs.TryAdd(dbfull, _dicDbToCs["nvarchar2(255)"]);
return DbType.String;
case "varchar2":
_dicDbToCs.TryAdd(dbfull, _dicDbToCs["nvarchar2(255)"]);
return DbType.String;
case "char":
_dicDbToCs.TryAdd(dbfull, _dicDbToCs["nvarchar2(255)"]);
return DbType.String;
case "nchar":
_dicDbToCs.TryAdd(dbfull, _dicDbToCs["nvarchar2(255)"]);
return DbType.String;
case "clob":
_dicDbToCs.TryAdd(dbfull, _dicDbToCs["nvarchar2(255)"]);
return DbType.String;
case "nclob":
_dicDbToCs.TryAdd(dbfull, _dicDbToCs["nvarchar2(255)"]);
return DbType.String;
case "raw":
_dicDbToCs.TryAdd(dbfull, _dicDbToCs["blob"]);
return DbType.Binary;
case "long raw":
_dicDbToCs.TryAdd(dbfull, _dicDbToCs["blob"]);
return DbType.Binary;
case "binary_float":
_dicDbToCs.TryAdd(dbfull, _dicDbToCs["float(63)"]);
return DbType.Single;
case "binary_double":
_dicDbToCs.TryAdd(dbfull, _dicDbToCs["float(126)"]);
return DbType.Double;
case "rowid":
default:
if (dbfull != null) _dicDbToCs.TryAdd(dbfull, _dicDbToCs["nvarchar2(255)"]);
return DbType.String;
}
throw new NotImplementedException(CoreStrings.S_TypeMappingNotImplemented(column.DbTypeTextFull));
}
static ConcurrentDictionary<string, DbToCs> _dicDbToCs = new ConcurrentDictionary<string, DbToCs>(StringComparer.CurrentCultureIgnoreCase);
static CustomOracleDbFirst()
{
var defaultDbToCs = new Dictionary<string, DbToCs>() {
{ "number(1)", new DbToCs("(bool?)", "{0} == \"1\"", "{0} == true ? \"1\" : \"0\"", "bool?", typeof(bool), typeof(bool?), "{0}.Value", "GetBoolean") },
{ "number(4)", new DbToCs("(sbyte?)", "sbyte.Parse({0})", "{0}.ToString()", "sbyte?", typeof(sbyte), typeof(sbyte?), "{0}.Value", "GetInt16") },
{ "number(6)", new DbToCs("(short?)", "short.Parse({0})", "{0}.ToString()", "short?", typeof(short), typeof(short?), "{0}.Value", "GetInt16") },
{ "number(11)", new DbToCs("(int?)", "int.Parse({0})", "{0}.ToString()", "int?", typeof(int), typeof(int?), "{0}.Value", "GetInt32") },
{ "number(21)", new DbToCs("(long?)", "long.Parse({0})", "{0}.ToString()", "long?", typeof(long), typeof(long?), "{0}.Value", "GetInt64") },
{ "number(3)", new DbToCs("(byte?)", "byte.Parse({0})", "{0}.ToString()", "byte?", typeof(byte), typeof(byte?), "{0}.Value", "GetByte") },
{ "number(5)", new DbToCs("(ushort?)", "ushort.Parse({0})", "{0}.ToString()", "ushort?", typeof(ushort), typeof(ushort?), "{0}.Value", "GetInt32") },
{ "number(10)", new DbToCs("(uint?)", "uint.Parse({0})", "{0}.ToString()", "uint?", typeof(uint), typeof(uint?), "{0}.Value", "GetInt64") },
{ "number(20)", new DbToCs("(ulong?)", "ulong.Parse({0})", "{0}.ToString()", "ulong?", typeof(ulong), typeof(ulong?), "{0}.Value", "GetDecimal") },
{ "float(126)", new DbToCs("(double?)", "double.Parse({0})", "{0}.ToString()", "double?", typeof(double), typeof(double?), "{0}.Value", "GetDouble") },
{ "float(63)", new DbToCs("(float?)", "float.Parse({0})", "{0}.ToString()", "float?", typeof(float), typeof(float?), "{0}.Value", "GetFloat") },
{ "number(10,2)", new DbToCs("(decimal?)", "decimal.Parse({0})", "{0}.ToString()", "decimal?", typeof(decimal), typeof(decimal?), "{0}.Value", "GetDecimal") },
{ "interval day(2) to second(6)", new DbToCs("(TimeSpan?)", "TimeSpan.Parse(double.Parse({0}))", "{0}.Ticks.ToString()", "TimeSpan?", typeof(TimeSpan), typeof(TimeSpan?), "{0}.Value", "GetValue") },
{ "date", new DbToCs("(DateTime?)", "new DateTime(long.Parse({0}))", "{0}.Ticks.ToString()", "DateTime?", typeof(DateTime), typeof(DateTime?), "{0}.Value", "GetValue") },
{ "timestamp(6)", new DbToCs("(DateTime?)", "new DateTime(long.Parse({0}))", "{0}.Ticks.ToString()", "DateTime?", typeof(DateTime), typeof(DateTime?), "{0}.Value", "GetValue") },
{ "timestamp(6) with local time zone", new DbToCs("(DateTime?)", "new DateTime(long.Parse({0}))", "{0}.Ticks.ToString()", "DateTime?", typeof(DateTime), typeof(DateTime?), "{0}.Value", "GetValue") },
{ "blob", new DbToCs("(byte[])", "Convert.FromBase64String({0})", "Convert.ToBase64String({0})", "byte[]", typeof(byte[]), typeof(byte[]), "{0}", "GetValue") },
{ "nvarchar2(255)", new DbToCs("", "{0}.Replace(StringifySplit, \"|\")", "{0}.Replace(\"|\", StringifySplit)", "string", typeof(string), typeof(string), "{0}", "GetString") },
{ "char(36 char)", new DbToCs("(Guid?)", "Guid.Parse({0})", "{0}.ToString()", "Guid?", typeof(Guid), typeof(Guid?), "{0}.Value", "GetGuid") },
};
foreach (var kv in defaultDbToCs)
_dicDbToCs.TryAdd(kv.Key, kv.Value);
}
public string GetCsConvert(DbColumnInfo column) => _dicDbToCs.TryGetValue(column.DbTypeTextFull, out var trydc) ? (column.IsNullable ? trydc.csConvert : trydc.csConvert.Replace("?", "")) : null;
public string GetCsParse(DbColumnInfo column) => _dicDbToCs.TryGetValue(column.DbTypeTextFull, out var trydc) ? trydc.csParse : null;
public string GetCsStringify(DbColumnInfo column) => _dicDbToCs.TryGetValue(column.DbTypeTextFull, out var trydc) ? trydc.csStringify : null;
public string GetCsType(DbColumnInfo column) => _dicDbToCs.TryGetValue(column.DbTypeTextFull, out var trydc) ? (column.IsNullable ? trydc.csType : trydc.csType.Replace("?", "")) : null;
public Type GetCsTypeInfo(DbColumnInfo column) => _dicDbToCs.TryGetValue(column.DbTypeTextFull, out var trydc) ? trydc.csTypeInfo : null;
public string GetCsTypeValue(DbColumnInfo column) => _dicDbToCs.TryGetValue(column.DbTypeTextFull, out var trydc) ? trydc.csTypeValue : null;
public string GetDataReaderMethod(DbColumnInfo column) => _dicDbToCs.TryGetValue(column.DbTypeTextFull, out var trydc) ? trydc.dataReaderMethod : null;
public List<string> GetDatabases()
{
var sql = @" select username from all_users";
var ds = _orm.Ado.ExecuteArray(CommandType.Text, sql);
return ds.Select(a => a.FirstOrDefault()?.ToString()).ToList();
}
public bool ExistsTable(string name, bool ignoreCase)
{
if (string.IsNullOrEmpty(name)) return false;
var tbname = _commonUtils.SplitTableName(name);
if (tbname?.Length == 1)
{
var userId = (_orm.Ado as CustomOracleAdo)?.UserId;
if (string.IsNullOrEmpty(userId))
using (var conn = _orm.Ado.MasterPool.Get())
{
userId = CustomOracleAdo.GetUserId(conn.Value.ConnectionString);
}
tbname = new[] { userId, tbname[0] };
}
if (ignoreCase) tbname = tbname.Select(a => a.ToLower()).ToArray();
var sql = $" select 1 from all_tab_comments where {(ignoreCase ? "lower(owner)" : "owner")}={_commonUtils.FormatSql("{0}", tbname[0])} and {(ignoreCase ? "lower(table_name)" : "table_name")}={_commonUtils.FormatSql("{0}", tbname[1])}";
return string.Concat(_orm.Ado.ExecuteScalar(CommandType.Text, sql)) == "1";
}
public DbTableInfo GetTableByName(string name, bool ignoreCase = true) => GetTables(null, name, ignoreCase)?.FirstOrDefault();
public List<DbTableInfo> GetTablesByDatabase(params string[] database) => GetTables(database, null, false);
public List<DbTableInfo> GetTables(string[] database, string tablename, bool ignoreCase)
{
var loc1 = new List<DbTableInfo>();
var loc2 = new Dictionary<string, DbTableInfo>();
var loc3 = new Dictionary<string, Dictionary<string, DbColumnInfo>>();
string[] tbname = null;
if (string.IsNullOrEmpty(tablename) == false)
{
tbname = _commonUtils.SplitTableName(tablename);
if (tbname?.Length == 1)
{
var userUsers = _orm.Ado.ExecuteScalar(" select username from user_users")?.ToString();
if (string.IsNullOrEmpty(userUsers)) return loc1;
tbname = new[] { userUsers, tbname[0] };
}
if (ignoreCase) tbname = tbname.Select(a => a.ToLower()).ToArray();
database = new[] { tbname[0] };
}
else if (database == null || database.Any() == false)
{
var userUsers = _orm.Ado.ExecuteScalar(" select username from user_users")?.ToString();
if (string.IsNullOrEmpty(userUsers)) return loc1;
database = new[] { userUsers };
}
var databaseIn = string.Join(",", database.Select(a => _commonUtils.FormatSql("{0}", a)));
var sql = $@"
select
a.owner || '.' || a.table_name AS tbname,
a.owner,
a.table_name,
b.comments,
'TABLE' AS tp
from all_tables a
left join all_tab_comments b on b.owner = a.owner and b.table_name = a.table_name and b.table_type = 'TABLE'
where {(ignoreCase ? "lower(a.owner)" : "a.owner")} in ({databaseIn}){(tbname == null ? "" : $" and {(ignoreCase ? "lower(a.table_name)" : "a.table_name")}={_commonUtils.FormatSql("{0}", tbname[1])}")}
UNION ALL
select
a.owner || '.' || a.view_name,
a.owner,
a.view_name,
b.comments,
'VIEW' AS tp
from all_views a
left join all_tab_comments b on b.owner = a.owner and b.table_name = a.view_name and b.table_type = 'VIEW'
where {(ignoreCase ? "lower(a.owner)" : "a.owner")} in ({databaseIn}){(tbname == null ? "" : $" and {(ignoreCase ? "lower(a.view_name)" : "a.view_name")}={_commonUtils.FormatSql("{0}", tbname[1])}")}
";
var ds = _orm.Ado.ExecuteArray(CommandType.Text, sql);
if (ds == null) return loc1;
var loc6 = new List<string[]>();
var loc66 = new List<string[]>();
var loc6_1000 = new List<string>();
var loc66_1000 = new List<string>();
foreach (var row in ds)
{
var table_id = string.Concat(row[0]);
var schema = string.Concat(row[1]);
var table = string.Concat(row[2]);
var comment = string.Concat(row[3]);
var type = string.Concat(row[4]) == "VIEW" ? DbTableType.VIEW : DbTableType.TABLE;
if (database.Length == 1)
{
table_id = table_id.Substring(table_id.IndexOf('.') + 1);
schema = "";
}
loc2.Add(table_id, new DbTableInfo { Id = table_id, Schema = schema, Name = table, Comment = comment, Type = type });
loc3.Add(table_id, new Dictionary<string, DbColumnInfo>());
switch (type)
{
case DbTableType.TABLE:
case DbTableType.VIEW:
loc6_1000.Add(table.Replace("'", "''"));
if (loc6_1000.Count >= 999)
{
loc6.Add(loc6_1000.ToArray());
loc6_1000.Clear();
}
break;
case DbTableType.StoreProcedure:
loc66_1000.Add(table.Replace("'", "''"));
if (loc66_1000.Count >= 999)
{
loc66.Add(loc66_1000.ToArray());
loc66_1000.Clear();
}
break;
}
}
if (loc6_1000.Count > 0) loc6.Add(loc6_1000.ToArray());
if (loc66_1000.Count > 0) loc66.Add(loc66_1000.ToArray());
if (loc6.Count == 0) return loc1;
var loc8 = new StringBuilder().Append("(");
for (var loc8idx = 0; loc8idx < loc6.Count; loc8idx++)
{
if (loc8idx > 0) loc8.Append(" OR ");
loc8.Append("a.table_name in (");
for (var loc8idx2 = 0; loc8idx2 < loc6[loc8idx].Length; loc8idx2++)
{
if (loc8idx2 > 0) loc8.Append(",");
loc8.Append($"'{loc6[loc8idx][loc8idx2]}'");
}
loc8.Append(")");
}
loc8.Append(")");
_orm.Ado.ExecuteNonQuery(CommandType.Text, @"
CREATE OR REPLACE FUNCTION FREESQL_LONG_TO_CHAR_DEFAULT
(
TABLE_NAME VARCHAR,
COLUMN VARCHAR2
)
RETURN VARCHAR AS
TEXT_C1 VARCHAR2(32767);
SQL_CUR VARCHAR2(2000);
BEGIN
DBMS_OUTPUT.ENABLE(BUFFER_SIZE => NULL);
SQL_CUR := 'SELECT T.DATA_DEFAULT FROM USER_TAB_COLUMNS T WHERE T.TABLE_NAME = '''||TABLE_NAME||''' AND T.COLUMN_NAME='''||COLUMN||'''';
DBMS_OUTPUT.PUT_LINE(SQL_CUR);
EXECUTE IMMEDIATE SQL_CUR
INTO TEXT_C1;
TEXT_C1 := SUBSTR(TEXT_C1, 1, 4000);
RETURN TEXT_C1;
END;");
sql = $@"
select
a.owner || '.' || a.table_name,
a.column_name,
a.data_type,
a.data_length,
a.data_precision,
a.data_scale,
a.char_used,
case when a.nullable = 'N' then 0 else 1 end,
nvl((select 1 from user_sequences where upper(sequence_name)=upper(a.table_name||'_seq_'||a.column_name) and rownum < 2), 0),
to_char(b.comments),
nvl(FREESQL_LONG_TO_CHAR_DEFAULT(a.table_name, a.column_name),'')
from all_tab_cols a
left join all_col_comments b on b.owner = a.owner and b.table_name = a.table_name and b.column_name = a.column_name
where {(ignoreCase ? "lower(a.owner)" : "a.owner")} in ({databaseIn}) and {loc8} and a.column_id is not null
";
ds = _orm.Ado.ExecuteArray(CommandType.Text, sql);
if (ds == null) return loc1;
var ds2 = new List<object[]>();
foreach (var row in ds)
{
var ds2item = new object[9];
ds2item[0] = row[0];
ds2item[1] = row[1];
ds2item[2] = Regex.Replace(string.Concat(row[2]), @"\(\d+\)", "");
ds2item[4] = CustomOracleCodeFirst.GetOracleSqlTypeFullName(new object[] { row[1], row[2], row[3], row[4], row[5], row[6] });
ds2item[5] = string.Concat(row[7]);
ds2item[6] = string.Concat(row[8]);
ds2item[7] = string.Concat(row[9]);
ds2item[8] = string.Concat(row[10]);
ds2.Add(ds2item);
}
var position = 0;
foreach (var row in ds2)
{
string table_id = string.Concat(row[0]);
string column = string.Concat(row[1]);
string type = string.Concat(row[2]);
//long max_length = long.Parse(string.Concat(row[3]));
string sqlType = string.Concat(row[4]);
var m_len = Regex.Match(sqlType, @"\w+\((\d+)");
int max_length = m_len.Success ? int.Parse(m_len.Groups[1].Value) : -1;
bool is_nullable = string.Concat(row[5]) == "1";
bool is_identity = string.Concat(row[6]) == "1";
string comment = string.Concat(row[7]);
string defaultValue = string.Concat(row[8]);
if (max_length == 0) max_length = -1;
if (database.Length == 1)
{
table_id = table_id.Substring(table_id.IndexOf('.') + 1);
}
loc3[table_id].Add(column, new DbColumnInfo
{
Name = column,
MaxLength = max_length,
IsIdentity = is_identity,
IsNullable = is_nullable,
IsPrimary = false,
DbTypeText = type,
DbTypeTextFull = sqlType,
Table = loc2[table_id],
Comment = comment,
DefaultValue = defaultValue,
Position = ++position
});
loc3[table_id][column].DbType = this.GetDbType(loc3[table_id][column]);
loc3[table_id][column].CsType = this.GetCsTypeInfo(loc3[table_id][column]);
}
CustomOracleCodeFirst.CreateOracleFunction(_orm);
sql = $@"
select
a.table_owner || '.' || a.table_name,
nvl(freesql_long_2_varchar(a.index_name, c.table_name, c.column_position), c.column_name),
c.index_name,
case when a.uniqueness = 'UNIQUE' then 1 else 0 end,
case when exists(select 1 from all_constraints where constraint_name = a.index_name and constraint_type = 'P') then 1 else 0 end,
0,
case when c.descend = 'DESC' then 1 else 0 end,
c.column_position
from all_indexes a,
all_ind_columns c
where a.index_name = c.index_name
and a.table_owner = c.table_owner
and a.table_name = c.table_name
and {(ignoreCase ? "lower(a.table_owner)" : "a.table_owner")} in ({databaseIn}) and {loc8}
";
ds = _orm.Ado.ExecuteArray(CommandType.Text, sql);
if (ds == null) return loc1;
var indexColumns = new Dictionary<string, Dictionary<string, DbIndexInfo>>();
var uniqueColumns = new Dictionary<string, Dictionary<string, DbIndexInfo>>();
foreach (var row in ds)
{
string table_id = string.Concat(row[0]);
string column = string.Concat(row[1]).Trim('"');
string index_id = string.Concat(row[2]);
bool is_unique = string.Concat(row[3]) == "1";
bool is_primary_key = string.Concat(row[4]) == "1";
bool is_clustered = string.Concat(row[5]) == "1";
bool is_desc = string.Concat(row[6]) == "1";
if (database.Length == 1)
table_id = table_id.Substring(table_id.IndexOf('.') + 1);
if (loc3.ContainsKey(table_id) == false || loc3[table_id].ContainsKey(column) == false) continue;
var loc9 = loc3[table_id][column];
if (loc9.IsPrimary == false && is_primary_key) loc9.IsPrimary = is_primary_key;
if (is_primary_key) continue;
Dictionary<string, DbIndexInfo> loc10 = null;
DbIndexInfo loc11 = null;
if (!indexColumns.TryGetValue(table_id, out loc10))
indexColumns.Add(table_id, loc10 = new Dictionary<string, DbIndexInfo>());
if (!loc10.TryGetValue(index_id, out loc11))
loc10.Add(index_id, loc11 = new DbIndexInfo());
loc11.Columns.Add(new DbIndexColumnInfo { Column = loc9, IsDesc = is_desc });
if (is_unique && !is_primary_key)
{
if (!uniqueColumns.TryGetValue(table_id, out loc10))
uniqueColumns.Add(table_id, loc10 = new Dictionary<string, DbIndexInfo>());
if (!loc10.TryGetValue(index_id, out loc11))
loc10.Add(index_id, loc11 = new DbIndexInfo());
loc11.Columns.Add(new DbIndexColumnInfo { Column = loc9, IsDesc = is_desc });
}
}
foreach (string table_id in indexColumns.Keys)
{
foreach (var column in indexColumns[table_id])
loc2[table_id].IndexesDict.Add(column.Key, column.Value);
}
foreach (string table_id in uniqueColumns.Keys)
{
foreach (var column in uniqueColumns[table_id])
{
column.Value.Columns.Sort((c1, c2) => c1.Column.Name.CompareTo(c2.Column.Name));
loc2[table_id].UniquesDict.Add(column.Key, column.Value);
}
}
if (tbname == null)
{
sql = $@"
select
a.owner || '.' || a.table_name,
c.column_name,
c.constraint_name,
b.owner || '.' || b.table_name,
1,
d.column_name
-- a.owner 外键拥有者,
-- a.table_name 外键表,
-- c.column_name 外键列,
-- b.owner 主键拥有者,
-- b.table_name 主键表,
-- d.column_name 主键列,
-- c.constraint_name 外键名,
-- d.constraint_name 主键名
from
all_constraints a,
all_constraints b,
all_cons_columns c, --外键表
all_cons_columns d --主键表
where
a.r_constraint_name = b.constraint_name   
and a.constraint_type = 'R'   
and b.constraint_type = 'P'   
and a.r_owner = b.owner   
and a.constraint_name = c.constraint_name   
and b.constraint_name = d.constraint_name   
and a.owner = c.owner   
and a.table_name = c.table_name   
and b.owner = d.owner   
and b.table_name = d.table_name
and {(ignoreCase ? "lower(a.owner)" : "a.owner")} in ({databaseIn}) and {loc8}
";
ds = _orm.Ado.ExecuteArray(CommandType.Text, sql);
if (ds == null) return loc1;
var fkColumns = new Dictionary<string, Dictionary<string, DbForeignInfo>>();
foreach (var row in ds)
{
string table_id = string.Concat(row[0]);
string column = string.Concat(row[1]);
string fk_id = string.Concat(row[2]);
string ref_table_id = string.Concat(row[3]);
bool is_foreign_key = string.Concat(row[4]) == "1";
string referenced_column = string.Concat(row[5]);
if (database.Length == 1)
{
table_id = table_id.Substring(table_id.IndexOf('.') + 1);
ref_table_id = ref_table_id.Substring(ref_table_id.IndexOf('.') + 1);
}
if (loc3.ContainsKey(table_id) == false || loc3[table_id].ContainsKey(column) == false) continue;
var loc9 = loc3[table_id][column];
if (loc2.ContainsKey(ref_table_id) == false) continue;
var loc10 = loc2[ref_table_id];
var loc11 = loc3[ref_table_id][referenced_column];
Dictionary<string, DbForeignInfo> loc12 = null;
DbForeignInfo loc13 = null;
if (!fkColumns.TryGetValue(table_id, out loc12))
fkColumns.Add(table_id, loc12 = new Dictionary<string, DbForeignInfo>());
if (!loc12.TryGetValue(fk_id, out loc13))
loc12.Add(fk_id, loc13 = new DbForeignInfo { Table = loc2[table_id], ReferencedTable = loc10 });
loc13.Columns.Add(loc9);
loc13.ReferencedColumns.Add(loc11);
}
foreach (var table_id in fkColumns.Keys)
foreach (var fk in fkColumns[table_id])
loc2[table_id].ForeignsDict.Add(fk.Key, fk.Value);
}
foreach (var table_id in loc3.Keys)
{
foreach (var loc5 in loc3[table_id].Values)
{
loc2[table_id].Columns.Add(loc5);
if (loc5.IsIdentity) loc2[table_id].Identitys.Add(loc5);
if (loc5.IsPrimary) loc2[table_id].Primarys.Add(loc5);
}
}
foreach (var loc4 in loc2.Values)
{
//if (loc4.Primarys.Count == 0 && loc4.UniquesDict.Count > 0)
//{
// foreach (var loc5 in loc4.UniquesDict.First().Value.Columns)
// {
// loc5.Column.IsPrimary = true;
// loc4.Primarys.Add(loc5.Column);
// }
//}
loc4.Primarys.Sort((c1, c2) => c1.Name.CompareTo(c2.Name));
loc4.Columns.Sort((c1, c2) =>
{
int compare = c2.IsPrimary.CompareTo(c1.IsPrimary);
if (compare == 0)
{
bool b1 = loc4.ForeignsDict.Values.Where(fk => fk.Columns.Where(c3 => c3.Name == c1.Name).Any()).Any();
bool b2 = loc4.ForeignsDict.Values.Where(fk => fk.Columns.Where(c3 => c3.Name == c2.Name).Any()).Any();
compare = b2.CompareTo(b1);
}
if (compare == 0) compare = c1.Name.CompareTo(c2.Name);
return compare;
});
loc1.Add(loc4);
}
loc1.Sort((t1, t2) =>
{
var ret = t1.Schema.CompareTo(t2.Schema);
if (ret == 0) ret = t1.Name.CompareTo(t2.Name);
return ret;
});
loc2.Clear();
loc3.Clear();
return loc1;
}
public List<DbEnumInfo> GetEnumsByDatabase(params string[] database)
{
return new List<DbEnumInfo>();
}
}
}

View File

@ -0,0 +1,584 @@
using FreeSql.Internal;
using System;
using System.Collections;
using System.Linq;
using System.Linq.Expressions;
using System.Text;
using System.Text.RegularExpressions;
namespace FreeSql.Custom.Oracle
{
class CustomOracleExpression : CommonExpression
{
public CustomOracleExpression(CommonUtils common) : base(common) { }
public override string ExpressionLambdaToSqlOther(Expression exp, ExpTSC tsc)
{
Func<Expression, string> getExp = exparg => ExpressionLambdaToSql(exparg, tsc);
switch (exp.NodeType)
{
case ExpressionType.ArrayLength:
var arrOper = (exp as UnaryExpression)?.Operand;
if (arrOper.Type == typeof(byte[])) return $"dbms_lob.getlength({getExp(arrOper)})";
break;
case ExpressionType.Convert:
var operandExp = (exp as UnaryExpression)?.Operand;
var gentype = exp.Type.NullableTypeOrThis();
if (gentype != operandExp.Type.NullableTypeOrThis())
{
switch (exp.Type.NullableTypeOrThis().ToString())
{
//case "System.Boolean": return $"({getExp(operandExp)} not in ('0','false'))";
case "System.Byte": return $"cast({getExp(operandExp)} as number)";
case "System.Char": return $"substr(to_char({getExp(operandExp)}), 1, 1)";
case "System.DateTime": return $"to_timestamp({getExp(operandExp)},'YYYY-MM-DD HH24:MI:SS.FF6')";
case "System.Decimal": return $"cast({getExp(operandExp)} as number)";
case "System.Double": return $"cast({getExp(operandExp)} as number)";
case "System.Int16":
case "System.Int32":
case "System.Int64":
case "System.SByte": return $"cast({getExp(operandExp)} as number)";
case "System.Single": return $"cast({getExp(operandExp)} as number)";
case "System.String": return $"to_char({getExp(operandExp)})";
case "System.UInt16":
case "System.UInt32":
case "System.UInt64": return $"cast({getExp(operandExp)} as number)";
case "System.Guid":
if (tsc.mapType == typeof(byte[])) return $"hextoraw({getExp(operandExp)})";
return $"to_char({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 $"({getExp(callExp.Arguments[0])} not in ('0','false'))";
case "System.Byte": return $"cast({getExp(callExp.Arguments[0])} as number)";
case "System.Char": return $"substr(to_char({getExp(callExp.Arguments[0])}), 1, 1)";
case "System.DateTime": return $"to_timestamp({getExp(callExp.Arguments[0])},'YYYY-MM-DD HH24:MI:SS.FF6')";
case "System.Decimal": return $"cast({getExp(callExp.Arguments[0])} as number)";
case "System.Double": return $"cast({getExp(callExp.Arguments[0])} as number)";
case "System.Int16":
case "System.Int32":
case "System.Int64":
case "System.SByte": return $"cast({getExp(callExp.Arguments[0])} as number)";
case "System.Single": return $"cast({getExp(callExp.Arguments[0])} as number)";
case "System.UInt16":
case "System.UInt32":
case "System.UInt64": return $"cast({getExp(callExp.Arguments[0])} as number)";
case "System.Guid":
if (tsc.mapType == typeof(byte[])) return $"hextoraw({getExp(callExp.Arguments[0])})";
return $"to_char({getExp(callExp.Arguments[0])})";
}
return null;
case "NewGuid":
return null;
case "Next":
if (callExp.Object?.Type == typeof(Random)) return "cast(dbms_random.value*1000000000 as smallint)";
return null;
case "NextDouble":
if (callExp.Object?.Type == typeof(Random)) return "dbms_random.value";
return null;
case "Random":
if (callExp.Method.DeclaringType.IsNumberType()) return "dbms_random.value";
return null;
case "ToString":
if (callExp.Object != null)
{
if (callExp.Object.Type.NullableTypeOrThis().IsEnum)
{
tsc.SetMapColumnTmp(null);
var oldMapType = tsc.SetMapTypeReturnOld(typeof(string));
var enumStr = ExpressionLambdaToSql(callExp.Object, tsc);
tsc.SetMapColumnTmp(null).SetMapTypeReturnOld(oldMapType);
return enumStr;
}
var value = ExpressionGetValue(callExp.Object, out var success);
if (success) return formatSql(value, typeof(string), null, null);
return callExp.Arguments.Count == 0 ? $"to_char({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 $"substr({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 = objExp?.NodeType == ExpressionType.MemberAccess ? tsc.SetDbParamsReturnOld(null) : null; //#900 UseGenerateCommandParameterWithLambda(true) 子查询 bug、以及 #1173 参数化 bug
tsc.isNotSetMapColumnTmp = true;
var left = objExp == null ? null : getExp(objExp);
tsc.isNotSetMapColumnTmp = false;
tsc.SetMapColumnTmp(null).SetMapTypeReturnOld(oldMapType);
if (oldDbParams != null) 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(",");
if (a % 500 == 499) arrSb.Append(" \r\n \r\n"); //500元素分割, 3空格\r\n4空格
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 $"length({left})";
}
return null;
}
public override string ExpressionLambdaToSqlMemberAccessDateTime(MemberExpression exp, ExpTSC tsc)
{
if (exp.Expression == null)
{
switch (exp.Member.Name)
{
case "Now": return _common.Now;
case "UtcNow": return _common.NowUtc;
case "Today": return "trunc(systimestamp)";
case "MinValue": return "to_timestamp('0001-01-01 00:00:00','YYYY-MM-DD HH24:MI:SS.FF6')";
case "MaxValue": return "to_timestamp('9999-12-31 23:59:59','YYYY-MM-DD HH24:MI:SS.FF6')";
}
return null;
}
var left = ExpressionLambdaToSql(exp.Expression, tsc);
switch (exp.Member.Name)
{
case "Date": return $"trunc({left})";
case "TimeOfDay": return $"({left}-trunc({left}))";
case "DayOfWeek": return $"case when to_char({left},'D')='7' then 0 else cast(to_char({left},'D') as number) end";
case "Day": return $"cast(to_char({left},'DD') as number)";
case "DayOfYear": return $"cast(to_char({left},'DDD') as number)";
case "Month": return $"cast(to_char({left},'MM') as number)";
case "Year": return $"cast(to_char({left},'YYYY') as number)";
case "Hour": return $"cast(to_char({left},'HH24') as number)";
case "Minute": return $"cast(to_char({left},'MI') as number)";
case "Second": return $"cast(to_char({left},'SS') as number)";
case "Millisecond": return $"cast(to_char({left},'FF3') as number)";
case "Ticks": return $"cast(to_char({left},'FF7') as number)";
}
return null;
}
public override string ExpressionLambdaToSqlMemberAccessTimeSpan(MemberExpression exp, ExpTSC tsc)
{
if (exp.Expression == null)
{
switch (exp.Member.Name)
{
case "Zero": return "numtodsinterval(0,'second')";
case "MinValue": return "numtodsinterval(-233720368.5477580,'second')";
case "MaxValue": return "numtodsinterval(233720368.5477580,'second')";
}
return null;
}
var left = ExpressionLambdaToSql(exp.Expression, tsc);
switch (exp.Member.Name)
{
case "Days": return $"extract(day from {left})";
case "Hours": return $"extract(hour from {left})";
case "Milliseconds": return $"cast(substr(extract(second from {left})-floor(extract(second from {left})),3,3) as number)";
case "Minutes": return $"extract(minute from {left})";
case "Seconds": return $"floor(extract(second from {left}))";
case "Ticks": return $"(extract(day from {left})*86400+extract(hour from {left})*3600+extract(minute from {left})*60+extract(second from {left}))*10000000";
case "TotalDays": return $"extract(day from {left})";
case "TotalHours": return $"(extract(day from {left})*24+extract(hour from {left}))";
case "TotalMilliseconds": return $"(extract(day from {left})*86400+extract(hour from {left})*3600+extract(minute from {left})*60+extract(second from {left}))*1000";
case "TotalMinutes": return $"(extract(day from {left})*1440+extract(hour from {left})*60+extract(minute from {left}))";
case "TotalSeconds": return $"(extract(day from {left})*86400+extract(hour from {left})*3600+extract(minute from {left})*60+extract(second from {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":
var arg1 = getExp(exp.Arguments[0]);
return $"({arg1} is null or {arg1} = '')";
case "IsNullOrWhiteSpace":
var arg2 = getExp(exp.Arguments[0]);
return $"({arg2} is null or {arg2} = '' or ltrim({arg2}) = '')";
case "Concat":
if (exp.Arguments.Count == 1 && exp.Arguments[0].NodeType == ExpressionType.NewArrayInit && exp.Arguments[0] is NewArrayExpression concatNewArrExp)
return _common.StringConcat(concatNewArrExp.Expressions.Select(a => getExp(a)).ToArray(), null);
return _common.StringConcat(exp.Arguments.Select(a => getExp(a)).ToArray(), null);
case "Format":
if (exp.Arguments[0].NodeType != ExpressionType.Constant) throw new Exception(CoreStrings.Not_Implemented_Expression_ParameterUseConstant(exp,exp.Arguments[0]));
var expArgsHack = exp.Arguments.Count == 2 && exp.Arguments[1].NodeType == ExpressionType.NewArrayInit ?
(exp.Arguments[1] as NewArrayExpression).Expressions : exp.Arguments.Where((a, z) => z > 0);
//3个 {} 时Arguments 解析出来是分开的
//4个 {} 时Arguments[1] 只能解析这个出来,然后里面是 NewArray []
var expArgs = expArgsHack.Select(a => $"'||{_common.IsNull(ExpressionLambdaToSql(a, tsc), "''")}||'").ToArray();
return string.Format(ExpressionLambdaToSql(exp.Arguments[0], tsc), expArgs);
case "Join":
if (exp.IsStringJoin(out var tolistObjectExp, out var toListMethod, out var toListArgs1))
{
var newToListArgs0 = Expression.Call(tolistObjectExp, toListMethod,
Expression.Lambda(
Expression.Call(
typeof(SqlExtExtensions).GetMethod("StringJoinOracleGroupConcat"),
Expression.Convert(toListArgs1.Body, typeof(object)),
Expression.Convert(exp.Arguments[0], typeof(object))),
toListArgs1.Parameters));
var newToListSql = getExp(newToListArgs0);
return newToListSql;
}
break;
}
}
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 (args0Value.Contains("%"))
{
if (exp.Method.Name == "StartsWith") return $"instr({left}, {args0Value}, 1, 1) = 1";
if (exp.Method.Name == "EndsWith") return $"instr({left}, {args0Value}, 1, 1) = length({left})-length({args0Value})+1";
return $"instr({left}, {args0Value}, 1, 1) > 0";
}
if (exp.Method.Name == "StartsWith") return $"({left}) LIKE {(args0Value.EndsWith("'") ? args0Value.Insert(args0Value.Length - 1, "%") : $"(to_char({args0Value})||'%')")}";
if (exp.Method.Name == "EndsWith") return $"({left}) LIKE {(args0Value.StartsWith("'") ? args0Value.Insert(1, "%") : $"('%'||to_char({args0Value}))")}";
if (args0Value.StartsWith("'") && args0Value.EndsWith("'")) return $"({left}) LIKE {args0Value.Insert(1, "%").Insert(args0Value.Length, "%")}";
return $"({left}) LIKE ('%'||to_char({args0Value})||'%')";
case "ToLower": return $"lower({left})";
case "ToUpper": return $"upper({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 $"substr({left}, {substrArgs1})";
return $"substr({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 $"(instr({left}, {indexOfFindStr}, {locateArgs1}, 1)-1)";
}
return $"(instr({left}, {indexOfFindStr}, 1, 1))-1";
case "PadLeft":
if (exp.Arguments.Count == 1) return $"lpad({left}, {getExp(exp.Arguments[0])}, ' ')";
return $"lpad({left}, {getExp(exp.Arguments[0])}, {getExp(exp.Arguments[1])})";
case "PadRight":
if (exp.Arguments.Count == 1) return $"rpad({left}, {getExp(exp.Arguments[0])}, ' ')";
return $"rpad({left}, {getExp(exp.Arguments[0])}, {getExp(exp.Arguments[1])})";
case "Trim":
case "TrimStart":
case "TrimEnd":
if (exp.Arguments.Count == 0)
{
if (exp.Method.Name == "Trim") return $"trim({left})";
if (exp.Method.Name == "TrimStart") return $"ltrim({left})";
if (exp.Method.Name == "TrimEnd") return $"rtrim({left})";
}
foreach (var argsTrim02 in exp.Arguments)
{
var argsTrim01s = new[] { argsTrim02 };
if (argsTrim02.NodeType == ExpressionType.NewArrayInit)
{
var arritem = argsTrim02 as NewArrayExpression;
argsTrim01s = arritem.Expressions.ToArray();
}
foreach (var argsTrim01 in argsTrim01s)
{
if (exp.Method.Name == "Trim") left = $"trim(both {getExp(argsTrim01)} from {left})";
if (exp.Method.Name == "TrimStart") left = $"ltrim({left},{getExp(argsTrim01)})";
if (exp.Method.Name == "TrimEnd") left = $"rtrim({left},{getExp(argsTrim01)})";
}
}
return left;
case "Replace": return $"replace({left}, {getExp(exp.Arguments[0])}, {getExp(exp.Arguments[1])})";
case "CompareTo": return $"case when {left} = {getExp(exp.Arguments[0])} then 0 when {left} > {getExp(exp.Arguments[0])} then 1 else -1 end";
case "Equals": return $"({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 $"abs({getExp(exp.Arguments[0])})";
case "Sign": return $"sign({getExp(exp.Arguments[0])})";
case "Floor": return $"floor({getExp(exp.Arguments[0])})";
case "Ceiling": return $"ceil({getExp(exp.Arguments[0])})";
case "Round":
if (exp.Arguments.Count > 1 && exp.Arguments[1].Type.FullName == "System.Int32") return $"round({getExp(exp.Arguments[0])}, {getExp(exp.Arguments[1])})";
return $"round({getExp(exp.Arguments[0])})";
case "Exp": return $"exp({getExp(exp.Arguments[0])})";
case "Log":
if (exp.Arguments.Count > 1) return $"log({getExp(exp.Arguments[1])},{getExp(exp.Arguments[0])})";
return $"log(2.7182818284590451,{getExp(exp.Arguments[0])})";
case "Log10": return $"log(10,{getExp(exp.Arguments[0])})";
case "Pow": return $"power({getExp(exp.Arguments[0])}, {getExp(exp.Arguments[1])})";
case "Sqrt": return $"sqrt({getExp(exp.Arguments[0])})";
case "Cos": return $"cos({getExp(exp.Arguments[0])})";
case "Sin": return $"sin({getExp(exp.Arguments[0])})";
case "Tan": return $"tan({getExp(exp.Arguments[0])})";
case "Acos": return $"acos({getExp(exp.Arguments[0])})";
case "Asin": return $"asin({getExp(exp.Arguments[0])})";
case "Atan": return $"atan({getExp(exp.Arguments[0])})";
//case "Atan2": return $"atan2({getExp(exp.Arguments[0])}, {getExp(exp.Arguments[1])})";
case "Truncate": return $"trunc({getExp(exp.Arguments[0])}, 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 $"extract(day from ({getExp(exp.Arguments[0])}-({getExp(exp.Arguments[1])})))";
case "DaysInMonth": return $"cast(to_char(last_day(to_date(({getExp(exp.Arguments[0])})||'-'||({getExp(exp.Arguments[1])})||'-01','yyyy-mm-dd')),'DD') as number)";
case "Equals": return $"({getExp(exp.Arguments[0])} = {getExp(exp.Arguments[1])})";
case "IsLeapYear":
var isLeapYearArgs1 = getExp(exp.Arguments[0]);
return $"(mod({isLeapYearArgs1},4)=0 AND mod({isLeapYearArgs1},100)<>0 OR mod({isLeapYearArgs1},400)=0)";
case "Parse": return $"to_timestamp({getExp(exp.Arguments[0])},'YYYY-MM-DD HH24:MI:SS.FF6')";
case "ParseExact":
case "TryParse":
case "TryParseExact": return $"to_timestamp({getExp(exp.Arguments[0])},'YYYY-MM-DD HH24:MI:SS.FF6')";
}
}
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 "AddDays": return $"({left}+{args1})";
case "AddHours": return $"({left}+({args1})/24)";
case "AddMilliseconds": return $"({left}+({args1})/86400000)";
case "AddMinutes": return $"({left}+({args1})/1440)";
case "AddMonths": return $"add_months({left},{args1})";
case "AddSeconds": return $"({left}+({args1})/86400)";
case "AddTicks": return $"({left}+({args1})/864000000000)";
case "AddYears": return $"add_months({left},({args1})*12)";
case "Subtract":
switch ((exp.Arguments[0].Type.IsNullableType() ? exp.Arguments[0].Type.GetGenericArguments().FirstOrDefault() : exp.Arguments[0].Type).FullName)
{
case "System.DateTime": return $"numtodsinterval(({left}+0)-({args1}+0),'day')";
case "System.TimeSpan": return $"({left}-{args1})";
}
break;
case "Equals": return $"({left} = {args1})";
case "CompareTo": return $"extract(day from ({left}-({args1})))";
case "ToString":
if (left.StartsWith("'") || left.EndsWith("'")) left = $"to_timestamp({left},'YYYY-MM-DD HH24:MI:SS.FF6')";
if (exp.Arguments.Count == 0) return $"to_char({left},'YYYY-MM-DD HH24:MI:SS.FF6')";
switch (args1)
{
case "'yyyy-MM-dd HH:mm:ss'": return $"to_char({left},'YYYY-MM-DD HH24:MI:SS')";
case "'yyyy-MM-dd HH:mm'": return $"to_char({left},'YYYY-MM-DD HH24:MI')";
case "'yyyy-MM-dd HH'": return $"to_char({left},'YYYY-MM-DD HH24')";
case "'yyyy-MM-dd'": return $"to_char({left},'YYYY-MM-DD')";
case "'yyyy-MM'": return $"to_char({left},'YYYY-MM')";
case "'yyyyMMddHHmmss'": return $"to_char({left},'YYYYMMDDHH24MISS')";
case "'yyyyMMddHHmm'": return $"to_char({left},'YYYYMMDDHH24MI')";
case "'yyyyMMddHH'": return $"to_char({left},'YYYYMMDDHH24')";
case "'yyyyMMdd'": return $"to_char({left},'YYYYMMDD')";
case "'yyyyMM'": return $"to_char({left},'YYYYMM')";
case "'yyyy'": return $"to_char({left},'YYYY')";
case "'HH:mm:ss'": return $"to_char({left},'HH24:MI:SS')";
}
args1 = Regex.Replace(args1, "(yyyy|yy|MM|dd|HH|hh|mm|ss|tt)", m =>
{
switch (m.Groups[1].Value)
{
case "yyyy": return $"YYYY";
case "yy": return $"YY";
case "MM": return $"%_a1";
case "dd": return $"%_a2";
case "HH": return $"%_a3";
case "hh": return $"%_a4";
case "mm": return $"%_a5";
case "ss": return $"SS";
case "tt": return $"%_a6";
}
return m.Groups[0].Value;
});
var argsFinds = new[] { "YYYY", "YY", "%_a1", "%_a2", "%_a3", "%_a4", "%_a5", "SS", "%_a6" };
var argsSpts = Regex.Split(args1, "(M|d|H|h|m|s|t)");
for (var a = 0; a < argsSpts.Length; a++)
{
switch (argsSpts[a])
{
case "M": argsSpts[a] = $"ltrim(to_char({left},'MM'),'0')"; break;
case "d": argsSpts[a] = $"case when substr(to_char({left},'DD'),1,1) = '0' then substr(to_char({left},'DD'),2,1) else to_char({left},'DD') end"; break;
case "H": argsSpts[a] = $"case when substr(to_char({left},'HH24'),1,1) = '0' then substr(to_char({left},'HH24'),2,1) else to_char({left},'HH24') end"; break;
case "h": argsSpts[a] = $"case when substr(to_char({left},'HH12'),1,1) = '0' then substr(to_char({left},'HH12'),2,1) else to_char({left},'HH12') end"; break;
case "m": argsSpts[a] = $"case when substr(to_char({left},'MI'),1,1) = '0' then substr(to_char({left},'MI'),2,1) else to_char({left},'MI') end"; break;
case "s": argsSpts[a] = $"case when substr(to_char({left},'SS'),1,1) = '0' then substr(to_char({left},'SS'),2,1) else to_char({left},'SS') end"; break;
case "t": argsSpts[a] = $"rtrim(to_char({left},'AM'),'M')"; break;
default:
var argsSptsA = argsSpts[a];
if (argsSptsA.StartsWith("'")) argsSptsA = argsSptsA.Substring(1);
if (argsSptsA.EndsWith("'")) argsSptsA = argsSptsA.Remove(argsSptsA.Length - 1);
argsSpts[a] = argsFinds.Any(m => argsSptsA.Contains(m)) ? $"to_char({left},'{argsSptsA}')" : $"'{argsSptsA}'";
break;
}
}
if (argsSpts.Length > 0) args1 = $"({string.Join(" || ", argsSpts.Where(a => a != "''"))})";
return args1.Replace("%_a1", "MM").Replace("%_a2", "DD").Replace("%_a3", "HH24").Replace("%_a4", "HH12").Replace("%_a5", "MI").Replace("%_a6", "AM");
}
}
return null;
}
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 $"extract(day from ({getExp(exp.Arguments[0])}-({getExp(exp.Arguments[1])})))";
case "Equals": return $"({getExp(exp.Arguments[0])} = {getExp(exp.Arguments[1])})";
case "FromDays": return $"numtodsinterval(({getExp(exp.Arguments[0])})*{(long)60 * 60 * 24},'second')";
case "FromHours": return $"numtodsinterval(({getExp(exp.Arguments[0])})*{(long)60 * 60},'second')";
case "FromMilliseconds": return $"numtodsinterval(({getExp(exp.Arguments[0])})/1000,'second')";
case "FromMinutes": return $"numtodsinterval(({getExp(exp.Arguments[0])})*60,'second')";
case "FromSeconds": return $"numtodsinterval(({getExp(exp.Arguments[0])}),'second')";
case "FromTicks": return $"numtodsinterval(({getExp(exp.Arguments[0])})/10000000,'second')";
case "Parse": return $"cast({getExp(exp.Arguments[0])} as interval day(9) to second(7))";
case "ParseExact":
case "TryParse":
case "TryParseExact": return $"cast({getExp(exp.Arguments[0])} as interval day(9) to second(7))";
}
}
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 $"extract(day from ({left}-({args1})))";
case "ToString": return $"to_char({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 $"({getExp(exp.Arguments[0])} not in ('0','false'))";
case "ToByte": return $"cast({getExp(exp.Arguments[0])} as number)";
case "ToChar": return $"substr(to_char({getExp(exp.Arguments[0])}), 1, 1)";
case "ToDateTime": return $"to_timestamp({getExp(exp.Arguments[0])},'YYYY-MM-DD HH24:MI:SS.FF6')";
case "ToDecimal": return $"cast({getExp(exp.Arguments[0])} as number)";
case "ToDouble": return $"cast({getExp(exp.Arguments[0])} as number)";
case "ToInt16":
case "ToInt32":
case "ToInt64":
case "ToSByte": return $"cast({getExp(exp.Arguments[0])} as number)";
case "ToSingle": return $"cast({getExp(exp.Arguments[0])} as number)";
case "ToString": return $"to_char({getExp(exp.Arguments[0])})";
case "ToUInt16":
case "ToUInt32":
case "ToUInt64": return $"cast({getExp(exp.Arguments[0])} as number)";
}
}
return null;
}
}
}

View File

@ -0,0 +1,51 @@
using FreeSql.Internal.CommonProvider;
using System;
using System.Data.Common;
using System.Threading;
namespace FreeSql.Custom.Oracle
{
public class CustomOracleProvider<TMark> : BaseDbProvider, IFreeSql<TMark>
{
public override ISelect<T1> CreateSelectProvider<T1>(object dywhere) => new CustomOracleSelect<T1>(this, this.InternalCommonUtils, this.InternalCommonExpression, dywhere);
public override IInsert<T1> CreateInsertProvider<T1>() => new CustomOracleInsert<T1>(this, this.InternalCommonUtils, this.InternalCommonExpression);
public override IUpdate<T1> CreateUpdateProvider<T1>(object dywhere) => new CustomOracleUpdate<T1>(this, this.InternalCommonUtils, this.InternalCommonExpression, dywhere);
public override IDelete<T1> CreateDeleteProvider<T1>(object dywhere) => new CustomOracleDelete<T1>(this, this.InternalCommonUtils, this.InternalCommonExpression, dywhere);
public override IInsertOrUpdate<T1> CreateInsertOrUpdateProvider<T1>() => new CustomOracleInsertOrUpdate<T1>(this, this.InternalCommonUtils, this.InternalCommonExpression);
public CustomOracleProvider(string masterConnectionString, string[] slaveConnectionString, Func<DbConnection> connectionFactory = null)
{
this.InternalCommonUtils = new CustomOracleUtils(this);
this.InternalCommonExpression = new CustomOracleExpression(this.InternalCommonUtils);
this.Ado = new CustomOracleAdo(this.InternalCommonUtils, masterConnectionString, slaveConnectionString, connectionFactory);
this.Aop = new AopProvider();
this.DbFirst = new CustomOracleDbFirst(this, this.InternalCommonUtils, this.InternalCommonExpression);
this.CodeFirst = new CustomOracleCodeFirst(this, this.InternalCommonUtils, this.InternalCommonExpression);
//this.Aop.AuditValue += new EventHandler<Aop.AuditValueEventArgs>((_, e) =>
//{
// if (e.Value == null && e.Column.Attribute.IsPrimary == false && e.Column.Attribute.IsIdentity == false)
// e.Value = Utils.GetDataReaderValue(e.Property.PropertyType.NullableTypeOrThis(), e.Column.Attribute.DbDefautValue);
//});
}
~CustomOracleProvider() => 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);
FreeSqlCustomAdapterGlobalExtensions._dicDbProviderFactory.TryRemove(Ado.Identifier, out var trydbpf);
}
}
}
}

View File

@ -0,0 +1,133 @@
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.Oracle
{
class CustomOracleUtils : CommonUtils
{
DbProviderFactory Factory => FreeSqlCustomAdapterGlobalExtensions.GetDbProviderFactory(_orm);
public CustomOracleUtils(IFreeSql orm) : base(orm)
{
}
public override DbParameter AppendParamter(List<DbParameter> _params, string parameterName, ColumnInfo col, Type type, object value)
{
if (string.IsNullOrEmpty(parameterName)) parameterName = $"p_{_params?.Count}";
var dbtype = (DbType?)_orm.CodeFirst.GetDbInfo(type)?.type;
switch (dbtype)
{
case DbType.Boolean:
if (value == null) value = null;
else value = (bool)value == true ? 1 : 0;
dbtype = DbType.Int32;
break;
case DbType.String:
case DbType.AnsiString:
case DbType.StringFixedLength:
case DbType.AnsiStringFixedLength:
value = string.Concat(value);
break;
}
var ret = Factory.CreateParameter();
ret.ParameterName = QuoteParamterName(parameterName);
if (dbtype != null) ret.DbType = dbtype.Value;
ret.Value = value;
_params?.Add(ret);
return ret;
}
public override DbParameter[] GetDbParamtersByObject(string sql, object obj) =>
Utils.GetDbParamtersByObject<DbParameter>(sql, obj, null, (name, type, value) =>
{
var dbtype = (DbType?)_orm.CodeFirst.GetDbInfo(type)?.type;
switch (dbtype)
{
case DbType.Boolean:
if (value == null) value = null;
else value = (bool)value == true ? 1 : 0;
dbtype = DbType.Int32;
break;
case DbType.String:
case DbType.AnsiString:
case DbType.StringFixedLength:
case DbType.AnsiStringFixedLength:
value = string.Concat(value);
break;
}
var ret = Factory.CreateParameter();
ret.ParameterName = $":{name}";
if (dbtype != null) ret.DbType = dbtype.Value;
ret.Value = value;
return ret;
});
public override string FormatSql(string sql, params object[] args) => sql?.FormatCustomOracle(args);
public override string QuoteSqlNameAdapter(params string[] name)
{
if (name.Length == 1)
{
var nametrim = name[0].Trim();
if (nametrim.StartsWith("(") && nametrim.EndsWith(")"))
return nametrim; //原生SQL
if (nametrim.StartsWith("\"") && nametrim.EndsWith("\""))
return nametrim;
return $"\"{nametrim.Replace(".", "\".\"")}\"";
}
return $"\"{string.Join("\".\"", name)}\"";
}
public override string TrimQuoteSqlName(string name)
{
var nametrim = name.Trim();
if (nametrim.StartsWith("(") && nametrim.EndsWith(")"))
return nametrim; //原生SQL
return $"{nametrim.Trim('"').Replace("\".\"", ".").Replace(".\"", ".")}";
}
public override string[] SplitTableName(string name) => GetSplitTableNames(name, '"', '"', 2);
public override string QuoteParamterName(string name) => $":{name}";
public override string IsNull(string sql, object value) => $"nvl({sql}, {value})";
public override string StringConcat(string[] objs, Type[] types) => $"{string.Join(" || ", objs)}";
public override string Mod(string left, string right, Type leftType, Type rightType) => $"mod({left}, {right})";
public override string Div(string left, string right, Type leftType, Type rightType) => $"trunc({left} / {right})";
public override string Now => "systimestamp";
public override string NowUtc => "sys_extract_utc(systimestamp)";
public override string QuoteWriteParamterAdapter(Type type, string paramterName) => paramterName;
protected override string QuoteReadColumnAdapter(Type type, Type mapType, string columnName) => 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(string))
{
var valueString = value as string;
if (valueString != null)
{
if (valueString.Length < 4000) return string.Concat("'", valueString.Replace("'", "''"), "'");
var pam = AppendParamter(specialParams, $"p_{specialParams?.Count}{specialParamFlag}", col, type, value);
return pam.ParameterName;
}
}
if (type == typeof(byte[]))
{
var valueBytes = value as byte[];
if (valueBytes != null)
{
if (valueBytes.Length < 2000) return $"hextoraw('{CommonUtils.BytesSqlRaw(valueBytes)}')";
var pam = AppendParamter(specialParams, $"p_{specialParams?.Count}{specialParamFlag}", col, type, value);
return pam.ParameterName;
}
}
return FormatSql("{0}", value, 1);
}
}
}

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 OracleAdapter
{
/// <summary>
/// Select TOP 1或 Limit 1 风格
/// </summary>
public virtual SelecTopStyle SelectTopStyle => SelecTopStyle.RowNum;
public enum SelecTopStyle { Top, Limit, RowNum }
/// <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,121 @@
using FreeSql.Internal;
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.PostgreSQL
{
class CustomPostgreSQLDelete<T1> : Internal.CommonProvider.DeleteProvider<T1>
{
public CustomPostgreSQLDelete(IFreeSql orm, CommonUtils commonUtils, CommonExpression commonExpression, object dywhere)
: base(orm, commonUtils, commonExpression, dywhere)
{
}
public override List<T1> ExecuteDeleted()
{
var ret = new List<T1>();
DbParameter[] dbParms = null;
StringBuilder sbret = null;
ToSqlFetch(sb =>
{
if (dbParms == null)
{
dbParms = _params.ToArray();
sbret = new StringBuilder();
sbret.Append(" RETURNING ");
var colidx = 0;
foreach (var col in _table.Columns.Values)
{
if (colidx > 0) sbret.Append(", ");
sbret.Append(_commonUtils.RereadColumn(col, _commonUtils.QuoteSqlName(col.Attribute.Name))).Append(" as ").Append(_commonUtils.QuoteSqlName(col.CsName));
++colidx;
}
}
var sql = sb.Append(sbret).ToString();
var before = new Aop.CurdBeforeEventArgs(_table.Type, _table, Aop.CurdType.Delete, sql, dbParms);
_orm.Aop.CurdBeforeHandler?.Invoke(this, before);
Exception exception = null;
try
{
ret.AddRange(_orm.Ado.Query<T1>(_table.TypeLazy ?? _table.Type, _connection, _transaction, CommandType.Text, sql, _commandTimeout, dbParms));
}
catch (Exception ex)
{
exception = ex;
throw ex;
}
finally
{
var after = new Aop.CurdAfterEventArgs(before, exception, ret);
_orm.Aop.CurdAfterHandler?.Invoke(this, after);
}
});
if (dbParms != null)
{
this.ClearData();
sbret.Clear();
}
return ret;
}
#if net40
#else
async public override Task<List<T1>> ExecuteDeletedAsync(CancellationToken cancellationToken = default)
{
var ret = new List<T1>();
DbParameter[] dbParms = null;
StringBuilder sbret = null;
await ToSqlFetchAsync(async sb =>
{
if (dbParms == null)
{
dbParms = _params.ToArray();
sbret = new StringBuilder();
sbret.Append(" RETURNING ");
var colidx = 0;
foreach (var col in _table.Columns.Values)
{
if (colidx > 0) sbret.Append(", ");
sbret.Append(_commonUtils.RereadColumn(col, _commonUtils.QuoteSqlName(col.Attribute.Name))).Append(" as ").Append(_commonUtils.QuoteSqlName(col.CsName));
++colidx;
}
}
var sql = sb.Append(sbret).ToString();
var before = new Aop.CurdBeforeEventArgs(_table.Type, _table, Aop.CurdType.Delete, sql, dbParms);
_orm.Aop.CurdBeforeHandler?.Invoke(this, before);
Exception exception = null;
try
{
ret.AddRange(await _orm.Ado.QueryAsync<T1>(_table.TypeLazy ?? _table.Type, _connection, _transaction, CommandType.Text, sql, _commandTimeout, dbParms, cancellationToken));
}
catch (Exception ex)
{
exception = ex;
throw ex;
}
finally
{
var after = new Aop.CurdAfterEventArgs(before, exception, ret);
_orm.Aop.CurdAfterHandler?.Invoke(this, after);
}
});
if (dbParms != null)
{
this.ClearData();
sbret.Clear();
}
return ret;
}
#endif
}
}

View File

@ -0,0 +1,217 @@
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.Threading;
using System.Threading.Tasks;
namespace FreeSql.Custom.PostgreSQL
{
class CustomPostgreSQLInsert<T1> : Internal.CommonProvider.InsertProvider<T1> where T1 : class
{
public CustomPostgreSQLInsert(IFreeSql orm, CommonUtils commonUtils, CommonExpression commonExpression)
: base(orm, commonUtils, commonExpression)
{
}
internal IFreeSql InternalOrm => _orm;
internal TableInfo InternalTable => _table;
internal DbParameter[] InternalParams => _params;
internal DbConnection InternalConnection => _connection;
internal DbTransaction InternalTransaction => _transaction;
internal CommonUtils InternalCommonUtils => _commonUtils;
internal CommonExpression InternalCommonExpression => _commonExpression;
internal List<T1> InternalSource => _source;
internal Dictionary<string, bool> InternalIgnore => _ignore;
internal void InternalClearData() => ClearData();
public override int ExecuteAffrows() => base.SplitExecuteAffrows(_batchValuesLimit > 0 ? _batchValuesLimit : 5000, _batchParameterLimit > 0 ? _batchParameterLimit : 3000);
public override long ExecuteIdentity() => base.SplitExecuteIdentity(_batchValuesLimit > 0 ? _batchValuesLimit : 5000, _batchParameterLimit > 0 ? _batchParameterLimit : 3000);
public override List<T1> ExecuteInserted() => base.SplitExecuteInserted(_batchValuesLimit > 0 ? _batchValuesLimit : 5000, _batchParameterLimit > 0 ? _batchParameterLimit : 3000);
protected override long RawExecuteIdentity()
{
var sql = this.ToSql();
if (string.IsNullOrEmpty(sql)) return 0;
long ret = 0;
Exception exception = null;
Aop.CurdBeforeEventArgs before = null;
var identCols = _table.Columns.Where(a => a.Value.Attribute.IsIdentity == true);
if (identCols.Any() == false)
{
before = new Aop.CurdBeforeEventArgs(_table.Type, _table, Aop.CurdType.Insert, sql, _params);
_orm.Aop.CurdBeforeHandler?.Invoke(this, before);
try
{
ret = _orm.Ado.ExecuteNonQuery(_connection, _transaction, CommandType.Text, sql, _commandTimeout, _params);
}
catch (Exception ex)
{
exception = ex;
throw ex;
}
finally
{
var after = new Aop.CurdAfterEventArgs(before, exception, ret);
_orm.Aop.CurdAfterHandler?.Invoke(this, after);
}
return 0;
}
sql = string.Concat(sql, " RETURNING ", _commonUtils.QuoteSqlName(identCols.First().Value.Attribute.Name));
before = new Aop.CurdBeforeEventArgs(_table.Type, _table, Aop.CurdType.Insert, sql, _params);
_orm.Aop.CurdBeforeHandler?.Invoke(this, before);
try
{
long.TryParse(string.Concat(_orm.Ado.ExecuteScalar(_connection, _transaction, CommandType.Text, sql, _commandTimeout, _params)), out ret);
}
catch (Exception ex)
{
exception = ex;
throw ex;
}
finally
{
var after = new Aop.CurdAfterEventArgs(before, exception, ret);
_orm.Aop.CurdAfterHandler?.Invoke(this, after);
}
return ret;
}
protected override List<T1> RawExecuteInserted()
{
var sql = this.ToSql();
if (string.IsNullOrEmpty(sql)) return new List<T1>();
var sb = new StringBuilder();
sb.Append(sql).Append(" RETURNING ");
var colidx = 0;
foreach (var col in _table.Columns.Values)
{
if (colidx > 0) sb.Append(", ");
sb.Append(_commonUtils.RereadColumn(col, _commonUtils.QuoteSqlName(col.Attribute.Name))).Append(" as ").Append(_commonUtils.QuoteSqlName(col.CsName));
++colidx;
}
sql = sb.ToString();
var before = new Aop.CurdBeforeEventArgs(_table.Type, _table, Aop.CurdType.Insert, sql, _params);
_orm.Aop.CurdBeforeHandler?.Invoke(this, before);
var ret = new List<T1>();
Exception exception = null;
try
{
ret = _orm.Ado.Query<T1>(_table.TypeLazy ?? _table.Type, _connection, _transaction, CommandType.Text, sql, _commandTimeout, _params);
}
catch (Exception ex)
{
exception = ex;
throw ex;
}
finally
{
var after = new Aop.CurdAfterEventArgs(before, exception, ret);
_orm.Aop.CurdAfterHandler?.Invoke(this, after);
}
return ret;
}
#if net40
#else
public override Task<int> ExecuteAffrowsAsync(CancellationToken cancellationToken = default) => base.SplitExecuteAffrowsAsync(_batchValuesLimit > 0 ? _batchValuesLimit : 5000, _batchParameterLimit > 0 ? _batchParameterLimit : 3000, cancellationToken);
public override Task<long> ExecuteIdentityAsync(CancellationToken cancellationToken = default) => base.SplitExecuteIdentityAsync(_batchValuesLimit > 0 ? _batchValuesLimit : 5000, _batchParameterLimit > 0 ? _batchParameterLimit : 3000, cancellationToken);
public override Task<List<T1>> ExecuteInsertedAsync(CancellationToken cancellationToken = default) => base.SplitExecuteInsertedAsync(_batchValuesLimit > 0 ? _batchValuesLimit : 5000, _batchParameterLimit > 0 ? _batchParameterLimit : 3000, cancellationToken);
async protected override Task<long> RawExecuteIdentityAsync(CancellationToken cancellationToken = default)
{
var sql = this.ToSql();
if (string.IsNullOrEmpty(sql)) return 0;
long ret = 0;
Exception exception = null;
Aop.CurdBeforeEventArgs before = null;
var identCols = _table.Columns.Where(a => a.Value.Attribute.IsIdentity == true);
if (identCols.Any() == false)
{
before = new Aop.CurdBeforeEventArgs(_table.Type, _table, Aop.CurdType.Insert, sql, _params);
_orm.Aop.CurdBeforeHandler?.Invoke(this, before);
try
{
ret = await _orm.Ado.ExecuteNonQueryAsync(_connection, _transaction, CommandType.Text, sql, _commandTimeout, _params, cancellationToken);
}
catch (Exception ex)
{
exception = ex;
throw ex;
}
finally
{
var after = new Aop.CurdAfterEventArgs(before, exception, ret);
_orm.Aop.CurdAfterHandler?.Invoke(this, after);
}
return 0;
}
sql = string.Concat(sql, " RETURNING ", _commonUtils.QuoteSqlName(identCols.First().Value.Attribute.Name));
before = new Aop.CurdBeforeEventArgs(_table.Type, _table, Aop.CurdType.Insert, sql, _params);
_orm.Aop.CurdBeforeHandler?.Invoke(this, before);
try
{
long.TryParse(string.Concat(await _orm.Ado.ExecuteScalarAsync(_connection, _transaction, CommandType.Text, sql, _commandTimeout, _params, cancellationToken)), out ret);
}
catch (Exception ex)
{
exception = ex;
throw ex;
}
finally
{
var after = new Aop.CurdAfterEventArgs(before, exception, ret);
_orm.Aop.CurdAfterHandler?.Invoke(this, after);
}
return ret;
}
async protected override Task<List<T1>> RawExecuteInsertedAsync(CancellationToken cancellationToken = default)
{
var sql = this.ToSql();
if (string.IsNullOrEmpty(sql)) return new List<T1>();
var sb = new StringBuilder();
sb.Append(sql).Append(" RETURNING ");
var colidx = 0;
foreach (var col in _table.Columns.Values)
{
if (colidx > 0) sb.Append(", ");
sb.Append(_commonUtils.RereadColumn(col, _commonUtils.QuoteSqlName(col.Attribute.Name))).Append(" as ").Append(_commonUtils.QuoteSqlName(col.CsName));
++colidx;
}
sql = sb.ToString();
var before = new Aop.CurdBeforeEventArgs(_table.Type, _table, Aop.CurdType.Insert, sql, _params);
_orm.Aop.CurdBeforeHandler?.Invoke(this, before);
var ret = new List<T1>();
Exception exception = null;
try
{
ret = await _orm.Ado.QueryAsync<T1>(_table.TypeLazy ?? _table.Type, _connection, _transaction, CommandType.Text, sql, _commandTimeout, _params, cancellationToken);
}
catch (Exception ex)
{
exception = ex;
throw ex;
}
finally
{
var after = new Aop.CurdAfterEventArgs(before, exception, ret);
_orm.Aop.CurdAfterHandler?.Invoke(this, after);
}
return ret;
}
#endif
}
}

View File

@ -0,0 +1,91 @@
using FreeSql.Internal;
using System.Collections.Generic;
using System.Data.Common;
using System.Linq;
using System.Text;
using System.Text.RegularExpressions;
namespace FreeSql.Custom.PostgreSQL
{
class CustomPostgreSQLInsertOrUpdate<T1> : Internal.CommonProvider.InsertOrUpdateProvider<T1> where T1 : class
{
public CustomPostgreSQLInsertOrUpdate(IFreeSql orm, CommonUtils commonUtils, CommonExpression commonExpression)
: base(orm, commonUtils, commonExpression)
{
}
public override string ToSql()
{
var dbParams = new List<DbParameter>();
if (_sourceSql != null)
{
var data = new List<T1>();
data.Add((T1)_table.Type.CreateInstanceGetDefaultValue());
var sql = getInsertSql(data, false, false);
var sb = new StringBuilder();
sb.Append(sql.Substring(0, sql.IndexOf(") VALUES")));
sb.Append(") \r\n");
WriteSourceSelectUnionAll(null, sb, null);
sb.Append(sql.Substring(sql.IndexOf("\r\nON CONFLICT(") + 2));
return sb.ToString();
}
if (_source?.Any() != true) return null;
var sqls = new string[2];
var ds = SplitSourceByIdentityValueIsNull(_source);
if (ds.Item1.Any()) sqls[0] = string.Join("\r\n\r\n;\r\n\r\n", ds.Item1.Select(a => getInsertSql(a, false, true)));
if (ds.Item2.Any()) sqls[1] = string.Join("\r\n\r\n;\r\n\r\n", ds.Item2.Select(a => getInsertSql(a, true, true)));
_params = dbParams.ToArray();
if (ds.Item2.Any() == false) return sqls[0];
if (ds.Item1.Any() == false) return sqls[1];
return string.Join("\r\n\r\n;\r\n\r\n", sqls);
string getInsertSql(List<T1> data, bool flagInsert, bool noneParameter)
{
var insert = _orm.Insert<T1>()
.AsTable(_tableRule).AsType(_table.Type)
.WithConnection(_connection)
.WithTransaction(_transaction)
.NoneParameter(noneParameter) as Internal.CommonProvider.InsertProvider<T1>;
insert._source = data;
insert._table = _table;
insert._noneParameterFlag = flagInsert ? "cuc" : "cu";
string sql = "";
if (IdentityColumn != null && flagInsert) sql = insert.ToSql();
else
{
var ocdu = new CustomPostgreSQLOnConflictDoUpdate<T1>(insert.InsertIdentity());
ocdu._tempPrimarys = _tempPrimarys;
var cols = _table.Columns.Values.Where(a => _updateSetDict.ContainsKey(a.Attribute.Name) ||
_tempPrimarys.Contains(a) == false && a.Attribute.CanUpdate == true && a.Attribute.IsIdentity == false && _updateIgnore.ContainsKey(a.Attribute.Name) == false);
ocdu.UpdateColumns(cols.Select(a => a.Attribute.Name).ToArray());
if (_doNothing == true || cols.Any() == false)
ocdu.DoNothing();
sql = ocdu.ToSql();
if (_updateSetDict.Any())
{
var findregex = new Regex("(t1|t2)." + _commonUtils.QuoteSqlName("test").Replace("test", "(\\w+)"));
var tableName = _commonUtils.QuoteSqlName(TableRuleInvoke());
foreach (var usd in _updateSetDict)
{
var field = _commonUtils.QuoteSqlName(usd.Key);
var findsql = $"{field} = EXCLUDED.{field}";
var usdval = findregex.Replace(usd.Value, m =>
{
if (m.Groups[1].Value == "t1") return $"{tableName}.{_commonUtils.QuoteSqlName(m.Groups[2].Value)}";
return $"EXCLUDED.{_commonUtils.QuoteSqlName(m.Groups[2].Value)}";
});
sql = sql.Replace(findsql, $"{field} = {usdval}");
}
}
}
if (string.IsNullOrEmpty(sql)) return null;
if (insert._params?.Any() == true) dbParams.AddRange(insert._params);
return sql;
}
}
}
}

View File

@ -0,0 +1,217 @@
using FreeSql.Aop;
using FreeSql.Internal.Model;
using System;
using System.Collections.Generic;
using System.Data;
using System.Linq;
using System.Linq.Expressions;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
namespace FreeSql.Custom.PostgreSQL
{
public class CustomPostgreSQLOnConflictDoUpdate<T1> where T1 : class
{
internal CustomPostgreSQLInsert<T1> _pgsqlInsert;
internal CustomPostgreSQLUpdate<T1> _pgsqlUpdatePriv;
internal CustomPostgreSQLUpdate<T1> _pgsqlUpdate => _pgsqlUpdatePriv ??
(_pgsqlUpdatePriv = new CustomPostgreSQLUpdate<T1>(_pgsqlInsert.InternalOrm, _pgsqlInsert.InternalCommonUtils, _pgsqlInsert.InternalCommonExpression, null) { InternalTableAlias = "EXCLUDED" }
.NoneParameter().SetSource(_pgsqlInsert.InternalSource) as CustomPostgreSQLUpdate<T1>);
internal ColumnInfo[] _tempPrimarys;
bool _doNothing;
public CustomPostgreSQLOnConflictDoUpdate(IInsert<T1> insert, Expression<Func<T1, object>> columns = null)
{
_pgsqlInsert = insert as CustomPostgreSQLInsert<T1>;
if (_pgsqlInsert == null) throw new Exception(CoreStrings.S_Features_Unique("OnConflictDoUpdate", "Custom/PostgreSQL"));
if (_pgsqlInsert._noneParameterFlag == "c") _pgsqlInsert._noneParameterFlag = "cu";
if (columns != null)
{
var colsList = new List<ColumnInfo>();
var cols = _pgsqlInsert.InternalCommonExpression.ExpressionSelectColumns_MemberAccess_New_NewArrayInit(null, null, columns?.Body, false, null).ToDictionary(a => a, a => true);
foreach (var col in _pgsqlInsert.InternalTable.Columns.Values)
if (cols.ContainsKey(col.Attribute.Name))
colsList.Add(col);
_tempPrimarys = colsList.ToArray();
}
if (_tempPrimarys == null || _tempPrimarys.Any() == false)
_tempPrimarys = _pgsqlInsert.InternalTable.Primarys;
if (_tempPrimarys.Any() == false) throw new Exception(CoreStrings.S_OnConflictDoUpdate_MustIsPrimary);
}
protected void ClearData()
{
_pgsqlInsert.InternalClearData();
_pgsqlUpdatePriv = null;
}
public CustomPostgreSQLOnConflictDoUpdate<T1> IgnoreColumns(Expression<Func<T1, object>> columns)
{
_pgsqlUpdate.IgnoreColumns(columns);
return this;
}
public CustomPostgreSQLOnConflictDoUpdate<T1> UpdateColumns(Expression<Func<T1, object>> columns)
{
_pgsqlUpdate.UpdateColumns(columns);
return this;
}
public CustomPostgreSQLOnConflictDoUpdate<T1> IgnoreColumns(string[] columns)
{
_pgsqlUpdate.IgnoreColumns(columns);
return this;
}
public CustomPostgreSQLOnConflictDoUpdate<T1> UpdateColumns(string[] columns)
{
_pgsqlUpdate.UpdateColumns(columns);
return this;
}
public CustomPostgreSQLOnConflictDoUpdate<T1> Set<TMember>(Expression<Func<T1, TMember>> column, TMember value)
{
_pgsqlUpdate.Set(column, value);
return this;
}
//由于表达式解析问题ON CONFLICT("id") DO UPDATE SET 需要指定表别名,如 Set(a => a.Clicks + 1) 解析会失败
//暂时不开放这个功能,如有需要使用 SetRaw("click = t.click + 1") 替代该操作
//public OnConflictDoUpdate<T1> Set<TMember>(Expression<Func<T1, TMember>> exp)
//{
// _pgsqlUpdate.Set(exp);
// return this;
//}
public CustomPostgreSQLOnConflictDoUpdate<T1> SetRaw(string sql)
{
_pgsqlUpdate.SetRaw(sql);
return this;
}
public CustomPostgreSQLOnConflictDoUpdate<T1> DoNothing()
{
_doNothing = true;
return this;
}
public string ToSql()
{
var sb = new StringBuilder();
sb.Append(_pgsqlInsert.ToSql()).Append("\r\nON CONFLICT(");
for (var a = 0; a < _tempPrimarys.Length; a++)
{
if (a > 0) sb.Append(", ");
sb.Append(_pgsqlInsert.InternalCommonUtils.QuoteSqlName(_tempPrimarys[a].Attribute.Name));
}
if (_doNothing)
{
sb.Append(") DO NOTHING");
}
else
{
sb.Append(") DO UPDATE SET\r\n");
if (_pgsqlUpdate._tempPrimarys.Any() == false) _pgsqlUpdate._tempPrimarys = _tempPrimarys;
var sbSetEmpty = _pgsqlUpdate.InternalSbSet.Length == 0;
var sbSetIncrEmpty = _pgsqlUpdate.InternalSbSetIncr.Length == 0;
if (sbSetEmpty == false || sbSetIncrEmpty == false)
{
if (sbSetEmpty == false) sb.Append(_pgsqlUpdate.InternalSbSet.ToString().Substring(2));
if (sbSetIncrEmpty == false) sb.Append(sbSetEmpty ? _pgsqlUpdate.InternalSbSetIncr.ToString().Substring(2) : _pgsqlUpdate.InternalSbSetIncr.ToString());
}
else
{
var colidx = 0;
foreach (var col in _pgsqlInsert.InternalTable.Columns.Values)
{
if (col.Attribute.IsPrimary || _pgsqlUpdate.InternalIgnore.ContainsKey(col.Attribute.Name)) continue;
if (colidx > 0) sb.Append(", \r\n");
if (col.Attribute.IsVersion == true && col.Attribute.MapType != typeof(byte[]))
{
var field = _pgsqlInsert.InternalCommonUtils.QuoteSqlName(col.Attribute.Name);
sb.Append(field).Append(" = ").Append(_pgsqlInsert.InternalCommonUtils.QuoteSqlName(_pgsqlInsert.InternalTable.DbName)).Append(".").Append(field).Append(" + 1");
}
else if (_pgsqlInsert.InternalIgnore.ContainsKey(col.Attribute.Name))
{
if (string.IsNullOrEmpty(col.DbUpdateValue) == false)
{
sb.Append(_pgsqlInsert.InternalCommonUtils.QuoteSqlName(col.Attribute.Name)).Append(" = ").Append(col.DbUpdateValue);
}
else
{
var caseWhen = _pgsqlUpdate.InternalWhereCaseSource(col.CsName, sqlval => sqlval).Trim();
sb.Append(caseWhen);
if (caseWhen.EndsWith(" END")) _pgsqlUpdate.InternalToSqlCaseWhenEnd(sb, col);
}
}
else
{
var field = _pgsqlInsert.InternalCommonUtils.QuoteSqlName(col.Attribute.Name);
sb.Append(field).Append(" = EXCLUDED.").Append(field);
}
++colidx;
}
}
}
return sb.ToString();
}
public long ExecuteAffrows()
{
var sql = this.ToSql();
if (string.IsNullOrEmpty(sql)) return 0;
var before = new CurdBeforeEventArgs(_pgsqlInsert.InternalTable.Type, _pgsqlInsert.InternalTable, CurdType.Insert, sql, _pgsqlInsert.InternalParams);
_pgsqlInsert.InternalOrm.Aop.CurdBeforeHandler?.Invoke(_pgsqlInsert, before);
long ret = 0;
Exception exception = null;
try
{
ret = _pgsqlInsert.InternalOrm.Ado.ExecuteNonQuery(_pgsqlInsert.InternalConnection, _pgsqlInsert.InternalTransaction, CommandType.Text, sql, _pgsqlInsert._commandTimeout, _pgsqlInsert.InternalParams);
}
catch (Exception ex)
{
exception = ex;
throw ex;
}
finally
{
var after = new CurdAfterEventArgs(before, exception, ret);
_pgsqlInsert.InternalOrm.Aop.CurdAfterHandler?.Invoke(_pgsqlInsert, after);
ClearData();
}
return ret;
}
#if net40
#else
async public Task<long> ExecuteAffrowsAsync(CancellationToken cancellationToken = default)
{
var sql = this.ToSql();
if (string.IsNullOrEmpty(sql)) return 0;
var before = new CurdBeforeEventArgs(_pgsqlInsert.InternalTable.Type, _pgsqlInsert.InternalTable, CurdType.Insert, sql, _pgsqlInsert.InternalParams);
_pgsqlInsert.InternalOrm.Aop.CurdBeforeHandler?.Invoke(_pgsqlInsert, before);
long ret = 0;
Exception exception = null;
try
{
ret = await _pgsqlInsert.InternalOrm.Ado.ExecuteNonQueryAsync(_pgsqlInsert.InternalConnection, _pgsqlInsert.InternalTransaction, CommandType.Text, sql, _pgsqlInsert._commandTimeout, _pgsqlInsert.InternalParams, cancellationToken);
}
catch (Exception ex)
{
exception = ex;
throw ex;
}
finally
{
var after = new CurdAfterEventArgs(before, exception, ret);
_pgsqlInsert.InternalOrm.Aop.CurdAfterHandler?.Invoke(_pgsqlInsert, after);
ClearData();
}
return ret;
}
#endif
}
}

View File

@ -0,0 +1,222 @@
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.PostgreSQL
{
class CustomPostgreSQLSelect<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)
{
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.Where(a => a.Before == false), true);
tb.CascadeBefore = _commonExpression.GetWhereCascadeSql(tb, _whereGlobalFilter.Where(a => a.Before == true), 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 ");
sb.Append(field).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) &&
string.IsNullOrEmpty(tbsfrom[b].CascadeBefore)) sb.Append(" ON 1 = 1");
else sb.Append(" ON ").Append(string.Join(" AND ", new[]
{
tbsfrom[b].CascadeBefore,
tbsfrom[b].NavigateCondition ?? tbsfrom[b].On,
tbsfrom[b].Cascade
}.Where(sql => string.IsNullOrEmpty(sql) == false)));
}
break;
}
else
{
if (a > 0 && !string.IsNullOrEmpty(tbsfrom[a].CascadeBefore)) sbnav.Append(" AND ").Append(tbsfrom[a].CascadeBefore);
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)
{
switch (tb.Type)
{
case SelectTableInfoType.Parent:
case SelectTableInfoType.RawJoin:
continue;
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(string.Join(" AND ", new[]
{
tb.CascadeBefore,
tb.On ?? tb.NavigateCondition,
tb.Cascade
}.Where(sql => string.IsNullOrEmpty(sql) == false)));
if (!string.IsNullOrEmpty(tb.On) && !string.IsNullOrEmpty(tb.NavigateCondition)) sbnav.Append(" AND (").Append(tb.NavigateCondition).Append(")");
}
if (_join.Length > 0) sb.Append(_join);
if (!string.IsNullOrEmpty(_tables[0].CascadeBefore)) sbnav.Append(" AND ").Append(_tables[0].CascadeBefore);
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)
sb.Append(" \r\nlimit ").Append(_limit);
if (_skip > 0)
sb.Append(" \r\noffset ").Append(_skip);
sbnav.Clear();
if (tbUnionsGt0) sb.Append(") ftb");
}
return sb.Append(_tosqlAppendContent).ToString();
}
public CustomPostgreSQLSelect(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 OdbcPostgreSQLSelect<T1, T2>(_orm, _commonUtils, _commonExpression, null); CustomPostgreSQLSelect<T1>.CopyData(this, 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 OdbcPostgreSQLSelect<T1, T2, T3>(_orm, _commonUtils, _commonExpression, null); CustomPostgreSQLSelect<T1>.CopyData(this, 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 OdbcPostgreSQLSelect<T1, T2, T3, T4>(_orm, _commonUtils, _commonExpression, null); CustomPostgreSQLSelect<T1>.CopyData(this, 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 OdbcPostgreSQLSelect<T1, T2, T3, T4, T5>(_orm, _commonUtils, _commonExpression, null); CustomPostgreSQLSelect<T1>.CopyData(this, 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 OdbcPostgreSQLSelect<T1, T2, T3, T4, T5, T6>(_orm, _commonUtils, _commonExpression, null); CustomPostgreSQLSelect<T1>.CopyData(this, 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 OdbcPostgreSQLSelect<T1, T2, T3, T4, T5, T6, T7>(_orm, _commonUtils, _commonExpression, null); CustomPostgreSQLSelect<T1>.CopyData(this, 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 OdbcPostgreSQLSelect<T1, T2, T3, T4, T5, T6, T7, T8>(_orm, _commonUtils, _commonExpression, null); CustomPostgreSQLSelect<T1>.CopyData(this, 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 OdbcPostgreSQLSelect<T1, T2, T3, T4, T5, T6, T7, T8, T9>(_orm, _commonUtils, _commonExpression, null); CustomPostgreSQLSelect<T1>.CopyData(this, 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 OdbcPostgreSQLSelect<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10>(_orm, _commonUtils, _commonExpression, null); CustomPostgreSQLSelect<T1>.CopyData(this, 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 OdbcPostgreSQLSelect<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11>(_orm, _commonUtils, _commonExpression, null); CustomPostgreSQLSelect<T1>.CopyData(this, 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 OdbcPostgreSQLSelect<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12>(_orm, _commonUtils, _commonExpression, null); CustomPostgreSQLSelect<T1>.CopyData(this, 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 OdbcPostgreSQLSelect<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13>(_orm, _commonUtils, _commonExpression, null); CustomPostgreSQLSelect<T1>.CopyData(this, 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 OdbcPostgreSQLSelect<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14>(_orm, _commonUtils, _commonExpression, null); CustomPostgreSQLSelect<T1>.CopyData(this, 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 OdbcPostgreSQLSelect<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15>(_orm, _commonUtils, _commonExpression, null); CustomPostgreSQLSelect<T1>.CopyData(this, 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 OdbcPostgreSQLSelect<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15, T16>(_orm, _commonUtils, _commonExpression, null); CustomPostgreSQLSelect<T1>.CopyData(this, 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 OdbcPostgreSQLSelect<T1, T2> : FreeSql.Internal.CommonProvider.Select2Provider<T1, T2> where T2 : class
{
public OdbcPostgreSQLSelect(IFreeSql orm, CommonUtils commonUtils, CommonExpression commonExpression, object dywhere) : base(orm, commonUtils, commonExpression, dywhere) { }
public override string ToSql(string field = null) => CustomPostgreSQLSelect<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 OdbcPostgreSQLSelect<T1, T2, T3> : FreeSql.Internal.CommonProvider.Select3Provider<T1, T2, T3> where T2 : class where T3 : class
{
public OdbcPostgreSQLSelect(IFreeSql orm, CommonUtils commonUtils, CommonExpression commonExpression, object dywhere) : base(orm, commonUtils, commonExpression, dywhere) { }
public override string ToSql(string field = null) => CustomPostgreSQLSelect<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 OdbcPostgreSQLSelect<T1, T2, T3, T4> : FreeSql.Internal.CommonProvider.Select4Provider<T1, T2, T3, T4> where T2 : class where T3 : class where T4 : class
{
public OdbcPostgreSQLSelect(IFreeSql orm, CommonUtils commonUtils, CommonExpression commonExpression, object dywhere) : base(orm, commonUtils, commonExpression, dywhere) { }
public override string ToSql(string field = null) => CustomPostgreSQLSelect<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 OdbcPostgreSQLSelect<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 OdbcPostgreSQLSelect(IFreeSql orm, CommonUtils commonUtils, CommonExpression commonExpression, object dywhere) : base(orm, commonUtils, commonExpression, dywhere) { }
public override string ToSql(string field = null) => CustomPostgreSQLSelect<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 OdbcPostgreSQLSelect<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 OdbcPostgreSQLSelect(IFreeSql orm, CommonUtils commonUtils, CommonExpression commonExpression, object dywhere) : base(orm, commonUtils, commonExpression, dywhere) { }
public override string ToSql(string field = null) => CustomPostgreSQLSelect<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 OdbcPostgreSQLSelect<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 OdbcPostgreSQLSelect(IFreeSql orm, CommonUtils commonUtils, CommonExpression commonExpression, object dywhere) : base(orm, commonUtils, commonExpression, dywhere) { }
public override string ToSql(string field = null) => CustomPostgreSQLSelect<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 OdbcPostgreSQLSelect<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 OdbcPostgreSQLSelect(IFreeSql orm, CommonUtils commonUtils, CommonExpression commonExpression, object dywhere) : base(orm, commonUtils, commonExpression, dywhere) { }
public override string ToSql(string field = null) => CustomPostgreSQLSelect<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 OdbcPostgreSQLSelect<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 OdbcPostgreSQLSelect(IFreeSql orm, CommonUtils commonUtils, CommonExpression commonExpression, object dywhere) : base(orm, commonUtils, commonExpression, dywhere) { }
public override string ToSql(string field = null) => CustomPostgreSQLSelect<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 OdbcPostgreSQLSelect<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 OdbcPostgreSQLSelect(IFreeSql orm, CommonUtils commonUtils, CommonExpression commonExpression, object dywhere) : base(orm, commonUtils, commonExpression, dywhere) { }
public override string ToSql(string field = null) => CustomPostgreSQLSelect<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 OdbcPostgreSQLSelect<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 OdbcPostgreSQLSelect(IFreeSql orm, CommonUtils commonUtils, CommonExpression commonExpression, object dywhere) : base(orm, commonUtils, commonExpression, dywhere) { }
public override string ToSql(string field = null) => CustomPostgreSQLSelect<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 OdbcPostgreSQLSelect<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 OdbcPostgreSQLSelect(IFreeSql orm, CommonUtils commonUtils, CommonExpression commonExpression, object dywhere) : base(orm, commonUtils, commonExpression, dywhere) { }
public override string ToSql(string field = null) => CustomPostgreSQLSelect<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 OdbcPostgreSQLSelect<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 OdbcPostgreSQLSelect(IFreeSql orm, CommonUtils commonUtils, CommonExpression commonExpression, object dywhere) : base(orm, commonUtils, commonExpression, dywhere) { }
public override string ToSql(string field = null) => CustomPostgreSQLSelect<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 OdbcPostgreSQLSelect<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 OdbcPostgreSQLSelect(IFreeSql orm, CommonUtils commonUtils, CommonExpression commonExpression, object dywhere) : base(orm, commonUtils, commonExpression, dywhere) { }
public override string ToSql(string field = null) => CustomPostgreSQLSelect<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 OdbcPostgreSQLSelect<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 OdbcPostgreSQLSelect(IFreeSql orm, CommonUtils commonUtils, CommonExpression commonExpression, object dywhere) : base(orm, commonUtils, commonExpression, dywhere) { }
public override string ToSql(string field = null) => CustomPostgreSQLSelect<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 OdbcPostgreSQLSelect<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 OdbcPostgreSQLSelect(IFreeSql orm, CommonUtils commonUtils, CommonExpression commonExpression, object dywhere) : base(orm, commonUtils, commonExpression, dywhere) { }
public override string ToSql(string field = null) => CustomPostgreSQLSelect<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,189 @@
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.Threading;
using System.Threading.Tasks;
namespace FreeSql.Custom.PostgreSQL
{
class CustomPostgreSQLUpdate<T1> : Internal.CommonProvider.UpdateProvider<T1>
{
public CustomPostgreSQLUpdate(IFreeSql orm, CommonUtils commonUtils, CommonExpression commonExpression, object dywhere)
: base(orm, commonUtils, commonExpression, dywhere)
{
}
internal string InternalTableAlias { get; set; }
internal StringBuilder InternalSbSet => _set;
internal StringBuilder InternalSbSetIncr => _setIncr;
internal Dictionary<string, bool> InternalIgnore => _ignore;
internal void InternalResetSource(List<T1> source) => _source = source;
internal string InternalWhereCaseSource(string CsName, Func<string, string> thenValue) => WhereCaseSource(CsName, thenValue);
internal void InternalToSqlCaseWhenEnd(StringBuilder sb, ColumnInfo col) => ToSqlCaseWhenEnd(sb, col);
public override int ExecuteAffrows() => base.SplitExecuteAffrows(_batchRowsLimit > 0 ? _batchRowsLimit : 500, _batchParameterLimit > 0 ? _batchParameterLimit : 3000);
protected override List<TReturn> ExecuteUpdated<TReturn>(IEnumerable<ColumnInfo> columns) => base.SplitExecuteUpdated<TReturn>(_batchRowsLimit > 0 ? _batchRowsLimit : 500, _batchParameterLimit > 0 ? _batchParameterLimit : 3000, columns);
protected override List<TReturn> RawExecuteUpdated<TReturn>(IEnumerable<ColumnInfo> columns)
{
var ret = new List<TReturn>();
DbParameter[] dbParms = null;
StringBuilder sbret = null;
ToSqlFetch(sb =>
{
if (dbParms == null)
{
dbParms = _params.Concat(_paramsSource).ToArray();
sbret = new StringBuilder();
sbret.Append(" RETURNING ");
var colidx = 0;
foreach (var col in columns)
{
if (colidx > 0) sbret.Append(", ");
sbret.Append(_commonUtils.RereadColumn(col, _commonUtils.QuoteSqlName(col.Attribute.Name))).Append(" as ").Append(_commonUtils.QuoteSqlName(col.CsName));
++colidx;
}
}
var sql = sb.Append(sbret).ToString();
var before = new Aop.CurdBeforeEventArgs(_table.Type, _table, Aop.CurdType.Update, sql, dbParms);
_orm.Aop.CurdBeforeHandler?.Invoke(this, before);
Exception exception = null;
try
{
var queryType = typeof(TReturn) == typeof(T1) ? (_table.TypeLazy ?? _table.Type) : null;
var rettmp = _orm.Ado.Query<TReturn>(queryType, _connection, _transaction, CommandType.Text, sql, _commandTimeout, dbParms);
ValidateVersionAndThrow(rettmp.Count, sql, dbParms);
ret.AddRange(rettmp);
}
catch (Exception ex)
{
exception = ex;
throw;
}
finally
{
var after = new Aop.CurdAfterEventArgs(before, exception, ret);
_orm.Aop.CurdAfterHandler?.Invoke(this, after);
}
});
sbret?.Clear();
return ret;
}
protected override void ToSqlCase(StringBuilder caseWhen, ColumnInfo[] primarys)
{
if (primarys.Length == 1)
{
var pk = primarys.First();
if (string.IsNullOrEmpty(InternalTableAlias) == false) caseWhen.Append(InternalTableAlias).Append(".");
caseWhen.Append(_commonUtils.RereadColumn(pk, _commonUtils.QuoteSqlName(pk.Attribute.Name)));
return;
}
caseWhen.Append("(");
var pkidx = 0;
foreach (var pk in primarys)
{
if (pkidx > 0) caseWhen.Append(" || '+' || ");
if (string.IsNullOrEmpty(InternalTableAlias) == false) caseWhen.Append(InternalTableAlias).Append(".");
caseWhen.Append(_commonUtils.RereadColumn(pk, _commonUtils.QuoteSqlName(pk.Attribute.Name))).Append("::text");
++pkidx;
}
caseWhen.Append(")");
}
protected override void ToSqlWhen(StringBuilder sb, ColumnInfo[] primarys, object d)
{
if (primarys.Length == 1)
{
sb.Append(_commonUtils.FormatSql("{0}", primarys[0].GetDbValue(d)));
return;
}
sb.Append("(");
var pkidx = 0;
foreach (var pk in primarys)
{
if (pkidx > 0) sb.Append(" || '+' || ");
sb.Append(_commonUtils.FormatSql("{0}", pk.GetDbValue(d))).Append("::text");
++pkidx;
}
sb.Append(")");
}
protected override void ToSqlCaseWhenEnd(StringBuilder sb, ColumnInfo col)
{
if (_noneParameter == false) return;
if (col.Attribute.MapType == typeof(string))
{
sb.Append("::text");
return;
}
var dbtype = _commonUtils.CodeFirst.GetDbInfo(col.Attribute.MapType)?.dbtype;
if (dbtype == null) return;
sb.Append("::").Append(dbtype);
}
#if net40
#else
public override Task<int> ExecuteAffrowsAsync(CancellationToken cancellationToken = default) => base.SplitExecuteAffrowsAsync(_batchRowsLimit > 0 ? _batchRowsLimit : 500, _batchParameterLimit > 0 ? _batchParameterLimit : 3000, cancellationToken);
protected override Task<List<TReturn>> ExecuteUpdatedAsync<TReturn>(IEnumerable<ColumnInfo> columns, CancellationToken cancellationToken = default) => base.SplitExecuteUpdatedAsync<TReturn>(_batchRowsLimit > 0 ? _batchRowsLimit : 500, _batchParameterLimit > 0 ? _batchParameterLimit : 3000, columns, cancellationToken);
async protected override Task<List<TReturn>> RawExecuteUpdatedAsync<TReturn>(IEnumerable<ColumnInfo> columns, CancellationToken cancellationToken = default)
{
var ret = new List<TReturn>();
DbParameter[] dbParms = null;
StringBuilder sbret = null;
await ToSqlFetchAsync(async sb =>
{
if (dbParms == null)
{
dbParms = _params.Concat(_paramsSource).ToArray();
sbret = new StringBuilder();
sbret.Append(" RETURNING ");
var colidx = 0;
foreach (var col in columns)
{
if (colidx > 0) sbret.Append(", ");
sbret.Append(_commonUtils.RereadColumn(col, _commonUtils.QuoteSqlName(col.Attribute.Name))).Append(" as ").Append(_commonUtils.QuoteSqlName(col.CsName));
++colidx;
}
}
var sql = sb.Append(sbret).ToString();
var before = new Aop.CurdBeforeEventArgs(_table.Type, _table, Aop.CurdType.Update, sql, dbParms);
_orm.Aop.CurdBeforeHandler?.Invoke(this, before);
Exception exception = null;
try
{
var queryType = typeof(TReturn) == typeof(T1) ? (_table.TypeLazy ?? _table.Type) : null;
var rettmp = await _orm.Ado.QueryAsync<TReturn>(queryType, _connection, _transaction, CommandType.Text, sql, _commandTimeout, dbParms, cancellationToken);
ValidateVersionAndThrow(rettmp.Count, sql, dbParms);
ret.AddRange(rettmp);
}
catch (Exception ex)
{
exception = ex;
throw;
}
finally
{
var after = new Aop.CurdAfterEventArgs(before, exception, ret);
_orm.Aop.CurdAfterHandler?.Invoke(this, after);
}
});
sbret?.Clear();
return ret;
}
#endif
}
}

View File

@ -0,0 +1,75 @@
using FreeSql.Internal;
using FreeSql.Internal.Model;
using FreeSql.Internal.ObjectPool;
using System;
using System.Collections;
using System.Collections.Generic;
using System.Data.Common;
using System.Text;
using System.Threading;
namespace FreeSql.Custom.PostgreSQL
{
class CustomPostgreSQLAdo : FreeSql.Internal.CommonProvider.AdoProvider
{
DbProviderFactory Factory => FreeSqlCustomAdapterGlobalExtensions.GetDbProviderFactory(_util._orm);
public CustomPostgreSQLAdo() : base(DataType.OdbcPostgreSQL, null, null) { }
public CustomPostgreSQLAdo(CommonUtils util, string masterConnectionString, string[] slaveConnectionStrings, Func<DbConnection> connectionFactory) : base(DataType.OdbcPostgreSQL, masterConnectionString, slaveConnectionStrings)
{
base._util = util;
if (connectionFactory != null)
{
var pool = new FreeSql.Internal.CommonProvider.DbConnectionPool(DataType.SqlServer, connectionFactory);
ConnectionString = pool.TestConnection?.ConnectionString;
MasterPool = pool;
return;
}
throw new Exception(CoreStrings.S_CustomAdapter_OnlySuppport_UseConnectionFactory);
}
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 ? "'t'" : "'f'";
else if (param is string)
return string.Concat("'", param.ToString().Replace("'", "''"), "'");
else if (param is char)
return string.Concat("'", param.ToString().Replace("'", "''").Replace('\0', ' '), "'");
else if (param is Enum)
return AddslashesTypeHandler(param.GetType(), param) ?? ((Enum)param).ToInt64();
else if (decimal.TryParse(string.Concat(param), out var trydec))
return param;
else if (param is DateTime)
return AddslashesTypeHandler(typeof(DateTime), param) ?? string.Concat("'", ((DateTime)param).ToString("yyyy-MM-dd HH:mm:ss.ffffff"), "'");
else if (param is DateTime?)
return AddslashesTypeHandler(typeof(DateTime?), param) ?? string.Concat("'", ((DateTime)param).ToString("yyyy-MM-dd HH:mm:ss.ffffff"), "'");
else if (param is TimeSpan || param is TimeSpan?)
return ((TimeSpan)param).Ticks / 10;
else if (param is byte[])
return $"'\\x{CommonUtils.BytesSqlRaw(param as byte[])}'";
else if (param is IEnumerable)
return AddslashesIEnumerable(param, mapType, mapColumn);
return string.Concat("'", param.ToString().Replace("'", "''"), "'");
}
public override DbCommand CreateCommand()
{
return Factory.CreateCommand();
}
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,500 @@
using FreeSql.Internal;
using FreeSql.Internal.Model;
using System;
using System.Collections.Generic;
using System.Data;
using System.Linq;
using System.Text;
namespace FreeSql.Custom.PostgreSQL
{
class CustomPostgreSQLCodeFirst : Internal.CommonProvider.CodeFirstProvider
{
public override bool IsNoneCommandParameter { get => true; set => base.IsNoneCommandParameter = true; }
public CustomPostgreSQLCodeFirst(IFreeSql orm, CommonUtils commonUtils, CommonExpression commonExpression) : base(orm, commonUtils, commonExpression) { }
static object _dicCsToDbLock = new object();
static Dictionary<string, CsToDb<DbType>> _dicCsToDb = new Dictionary<string, CsToDb<DbType>>() {
{ typeof(sbyte).FullName, CsToDb.New(DbType.SByte, "int2","int2 NOT NULL", false, false, 0) },{ typeof(sbyte?).FullName, CsToDb.New(DbType.SByte, "int2", "int2", false, true, null) },
{ typeof(short).FullName, CsToDb.New(DbType.Int16, "int2","int2 NOT NULL", false, false, 0) },{ typeof(short?).FullName, CsToDb.New(DbType.Int16, "int2", "int2", false, true, null) },
{ typeof(int).FullName, CsToDb.New(DbType.Int32, "int4","int4 NOT NULL", false, false, 0) },{ typeof(int?).FullName, CsToDb.New(DbType.Int32, "int4", "int4", false, true, null) },
{ typeof(long).FullName, CsToDb.New(DbType.Int64, "int8","int8 NOT NULL", false, false, 0) },{ typeof(long?).FullName, CsToDb.New(DbType.Int64, "int8", "int8", false, true, null) },
{ typeof(byte).FullName, CsToDb.New(DbType.Byte, "int2","int2 NOT NULL", false, false, 0) },{ typeof(byte?).FullName, CsToDb.New(DbType.Byte, "int2", "int2", false, true, null) },
{ typeof(ushort).FullName, CsToDb.New(DbType.UInt16, "int4","int4 NOT NULL", false, false, 0) },{ typeof(ushort?).FullName, CsToDb.New(DbType.UInt16, "int4", "int4", false, true, null) },
{ typeof(uint).FullName, CsToDb.New(DbType.UInt32, "int8","int8 NOT NULL", false, false, 0) },{ typeof(uint?).FullName, CsToDb.New(DbType.UInt32, "int8", "int8", false, true, null) },
{ typeof(ulong).FullName, CsToDb.New(DbType.UInt64, "numeric","numeric(20,0) NOT NULL", false, false, 0) },{ typeof(ulong?).FullName, CsToDb.New(DbType.UInt64, "numeric", "numeric(20,0)", false, true, null) },
{ typeof(float).FullName, CsToDb.New(DbType.Single, "float4","float4 NOT NULL", false, false, 0) },{ typeof(float?).FullName, CsToDb.New(DbType.Single, "float4", "float4", false, true, null) },
{ typeof(double).FullName, CsToDb.New(DbType.Double, "float8","float8 NOT NULL", false, false, 0) },{ typeof(double?).FullName, CsToDb.New(DbType.Double, "float8", "float8", false, true, null) },
{ typeof(decimal).FullName, CsToDb.New(DbType.Decimal, "numeric", "numeric(10,2) NOT NULL", false, false, 0) },{ typeof(decimal?).FullName, CsToDb.New(DbType.Decimal, "numeric", "numeric(10,2)", false, true, null) },
{ typeof(string).FullName, CsToDb.New(DbType.String, "varchar", "varchar(255)", false, null, "") },
{ typeof(char).FullName, CsToDb.New(DbType.AnsiString, "char", "char(1) NULL", false, null, '\0') },
{ typeof(TimeSpan).FullName, CsToDb.New(DbType.Time, "time","time NOT NULL", false, false, 0) },{ typeof(TimeSpan?).FullName, CsToDb.New(DbType.Time, "time", "time",false, true, null) },
{ typeof(DateTime).FullName, CsToDb.New(DbType.DateTime, "timestamp", "timestamp NOT NULL", false, false, new DateTime(1970,1,1)) },{ typeof(DateTime?).FullName, CsToDb.New(DbType.DateTime, "timestamp", "timestamp", false, true, null) },
{ typeof(bool).FullName, CsToDb.New(DbType.Boolean, "bool","bool NOT NULL", null, false, false) },{ typeof(bool?).FullName, CsToDb.New(DbType.Boolean, "bool","bool", null, true, null) },
{ typeof(Byte[]).FullName, CsToDb.New(DbType.Binary, "bytea", "bytea", false, null, new byte[0]) },
{ typeof(Guid).FullName, CsToDb.New(DbType.Guid, "uuid", "uuid NOT NULL", false, false, Guid.Empty) },{ typeof(Guid?).FullName, CsToDb.New(DbType.Guid, "uuid", "uuid", false, true, null) },
};
public override DbInfoResult GetDbInfo(Type type)
{
var isarray = type.FullName != "System.Byte[]" && type.IsArray;
var elementType = isarray ? type.GetElementType() : type;
var info = GetDbInfoNoneArray(elementType);
if (info == null) return null;
return new DbInfoResult((int)info.type, info.dbtype, info.dbtypeFull, info.isnullable, info.defaultValue);
}
CsToDb<DbType> GetDbInfoNoneArray(Type type)
{
if (_dicCsToDb.TryGetValue(type.FullName, out var trydc)) return trydc;
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.Int32, "int8", $"int8{(type.IsEnum ? " NOT NULL" : "")}", false, type.IsEnum ? false : true, enumType.CreateInstanceGetDefaultValue()) :
CsToDb.New(DbType.Int64, "int4", $"int4{(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 newItem;
}
return null;
}
protected override string GetComparisonDDLStatements(params TypeSchemaAndName[] objects)
{
var sb = new StringBuilder();
var seqcols = new List<NativeTuple<ColumnInfo, string[], bool>>(); //序列
var isPg95 = true;
var isPg96 = true;
var isPg10 = (_orm.DbFirst as CustomPostgreSQLDbFirst).IsPg10;
using (var conn = _orm.Ado.MasterPool.Get(TimeSpan.FromSeconds(5)))
{
isPg95 = CustomPostgreSQLDbFirst.ParsePgVersion(conn.Value.ServerVersion, 9, 5).Item1;
isPg96 = CustomPostgreSQLDbFirst.ParsePgVersion(conn.Value.ServerVersion, 9, 6).Item1;
}
foreach (var obj in objects)
{
if (sb.Length > 0) sb.Append("\r\n");
var tb = obj.tableSchema;
if (tb == null) throw new Exception(CoreStrings.S_Type_IsNot_Migrable(obj.tableSchema.Type.FullName));
if (tb.Columns.Any() == false) throw new Exception(CoreStrings.S_Type_IsNot_Migrable_0Attributes(obj.tableSchema.Type.FullName));
var tbname = _commonUtils.SplitTableName(tb.DbName);
if (tbname?.Length == 1) tbname = new[] { "public", tbname[0] };
var tboldname = _commonUtils.SplitTableName(tb.DbOldName); //旧表名
if (tboldname?.Length == 1) tboldname = new[] { "public", tboldname[0] };
if (string.IsNullOrEmpty(obj.tableName) == false)
{
var tbtmpname = _commonUtils.SplitTableName(obj.tableName);
if (tbtmpname?.Length == 1) tbtmpname = new[] { "public", tbtmpname[0] };
if (tbname[0] != tbtmpname[0] || tbname[1] != tbtmpname[1])
{
tbname = tbtmpname;
tboldname = null;
}
}
//codefirst 不支持表名、模式名、数据库名中带 .
if (string.Compare(tbname[0], "public", true) != 0 && _orm.Ado.ExecuteScalar(CommandType.Text, _commonUtils.FormatSql(" select 1 from pg_namespace where nspname={0}", tbname[0])) == null) //创建模式
sb.Append("CREATE SCHEMA IF NOT EXISTS ").Append(tbname[0]).Append(";\r\n");
var sbalter = new StringBuilder();
var istmpatler = false; //创建临时表,导入数据,删除旧表,修改
if (_orm.Ado.ExecuteScalar(CommandType.Text, string.Format(" select 1 from pg_tables a inner join pg_namespace b on b.nspname = a.schemaname where b.nspname || '.' || a.tablename = '{0}.{1}'", tbname)) == null)
{ //表不存在
if (tboldname != null)
{
if (_orm.Ado.ExecuteScalar(CommandType.Text, string.Format(" select 1 from pg_tables a inner join pg_namespace b on b.nspname = a.schemaname where b.nspname || '.' || a.tablename = '{0}.{1}'", tboldname)) == null)
//旧表不存在
tboldname = null;
}
if (tboldname == null)
{
//创建表
var createTableName = _commonUtils.QuoteSqlName($"{tbname[0]}.{tbname[1]}");
sb.Append("CREATE TABLE IF NOT EXISTS ").Append(createTableName).Append(" ( ");
foreach (var tbcol in tb.ColumnsByPosition)
{
sb.Append(" \r\n ").Append(_commonUtils.QuoteSqlName(tbcol.Attribute.Name)).Append(" ").Append(tbcol.Attribute.DbType);
if (tbcol.Attribute.IsIdentity == true)
{
if (isPg10) sb.Append(" GENERATED BY DEFAULT AS IDENTITY");
else seqcols.Add(NativeTuple.Create(tbcol, tbname, true));
}
sb.Append(",");
}
if (tb.Primarys.Any())
{
var pkname = $"{tbname[0]}_{tbname[1]}_pkey";
sb.Append(" \r\n CONSTRAINT ").Append(_commonUtils.QuoteSqlName(pkname)).Append(" PRIMARY KEY (");
foreach (var tbcol in tb.Primarys) sb.Append(_commonUtils.QuoteSqlName(tbcol.Attribute.Name)).Append(", ");
sb.Remove(sb.Length - 2, 2).Append("),");
}
sb.Remove(sb.Length - 1, 1);
sb.Append("\r\n) WITH (OIDS=FALSE);\r\n");
//创建表的索引
foreach (var uk in tb.Indexes)
{
sb.Append("CREATE ");
if (uk.IsUnique) sb.Append("UNIQUE ");
sb.Append("INDEX ");
if (isPg95) sb.Append("IF NOT EXISTS ");
sb.Append(_commonUtils.QuoteSqlName(ReplaceIndexName(uk.Name, tbname[1]))).Append(" ON ").Append(createTableName).Append("(");
foreach (var tbcol in uk.Columns)
{
sb.Append(_commonUtils.QuoteSqlName(tbcol.Column.Attribute.Name));
if (tbcol.IsDesc) sb.Append(" DESC");
sb.Append(", ");
}
sb.Remove(sb.Length - 2, 2).Append(");\r\n");
}
//备注
foreach (var tbcol in tb.ColumnsByPosition)
{
if (string.IsNullOrEmpty(tbcol.Comment) == false)
sb.Append("COMMENT ON COLUMN ").Append(_commonUtils.QuoteSqlName($"{tbname[0]}.{tbname[1]}.{tbcol.Attribute.Name}")).Append(" IS ").Append(_commonUtils.FormatSql("{0}", tbcol.Comment)).Append(";\r\n");
}
if (string.IsNullOrEmpty(tb.Comment) == false)
sb.Append("COMMENT ON TABLE ").Append(_commonUtils.QuoteSqlName($"{tbname[0]}.{tbname[1]}")).Append(" IS ").Append(_commonUtils.FormatSql("{0}", tb.Comment)).Append(";\r\n");
continue;
}
//如果新表,旧表在一个数据库和模式下,直接修改表名
if (string.Compare(tbname[0], tboldname[0], true) == 0)
sbalter.Append("ALTER TABLE ").Append(_commonUtils.QuoteSqlName($"{tboldname[0]}.{tboldname[1]}")).Append(" RENAME TO ").Append(_commonUtils.QuoteSqlName($"{tbname[1]}")).Append(";\r\n");
else
{
//如果新表,旧表不在一起,创建新表,导入数据,删除旧表
istmpatler = true;
}
}
else
tboldname = null; //如果新表已经存在,不走改表名逻辑
//对比字段,只可以修改类型、增加字段、有限的修改字段名;保证安全不删除字段
var sql = _commonUtils.FormatSql($@"
select
a.attname,
t.typname,
case when a.atttypmod > 0 and a.atttypmod < 32767 then a.atttypmod - 4 else a.attlen end len,
case when t.typelem > 0 and t.typinput::varchar = 'array_in' then t2.typname else t.typname end,
case when a.attnotnull then '0' else '1' end as is_nullable,
--e.adsrc,
(select pg_get_expr(adbin, adrelid) from pg_attrdef where adrelid = e.adrelid limit 1) is_identity,
a.attndims,
d.description as comment{(isPg10 ? ", a.attidentity" : "")}
from pg_class c
inner join pg_attribute a on a.attnum > 0 and a.attrelid = c.oid
inner join pg_type t on t.oid = a.atttypid
left join pg_type t2 on t2.oid = t.typelem
left join pg_description d on d.objoid = a.attrelid and d.objsubid = a.attnum
left join pg_attrdef e on e.adrelid = a.attrelid and e.adnum = a.attnum
inner join pg_namespace ns on ns.oid = c.relnamespace
inner join pg_namespace ns2 on ns2.oid = t.typnamespace
where ns.nspname = {{0}} and c.relname = {{1}}", tboldname ?? tbname);
var ds = _orm.Ado.ExecuteArray(CommandType.Text, sql);
var tbstruct = ds.ToDictionary(a => string.Concat(a[0]), a =>
{
var attndims = int.Parse(string.Concat(a[6]));
var type = string.Concat(a[1]);
var sqlType = string.Concat(a[3]);
var max_length = long.Parse(string.Concat(a[2]));
type = type.Replace("smallint", "int2")
.Replace("integer", "int4")
.Replace("bigint", "int8")
.Replace("real", "float4")
.Replace("double precision", "float8")
.Replace("character varying", "varchar"); //pg15+
sqlType = type.Replace("smallint", "int2")
.Replace("integer", "int4")
.Replace("bigint", "int8")
.Replace("real", "float4")
.Replace("double precision", "float8")
.Replace("character varying", "varchar"); //pg15+
switch (sqlType.ToLower())
{
case "bool": case "name": case "bit": case "varbit": case "bpchar": case "varchar": case "bytea": case "text": case "uuid": break;
default: max_length *= 8; break;
}
if (type.StartsWith("_"))
{
type = type.Substring(1);
if (attndims == 0) attndims++;
}
if (sqlType.StartsWith("_")) sqlType = sqlType.Substring(1);
var is_identity_pg9 = string.Concat(a[5]).StartsWith(@"nextval('") && (string.Concat(a[5]).EndsWith(@"'::regclass)") || string.Concat(a[5]).EndsWith(@"')"));
return new
{
column = string.Concat(a[0]),
sqlType = string.Concat(sqlType),
max_length = long.Parse(string.Concat(a[2])),
is_nullable = string.Concat(a[4]) == "1",
is_identity_pg9 = is_identity_pg9,
is_identity = is_identity_pg9
|| isPg10 && new[] { "a", "d" }.Contains(string.Concat(a[8])), //pg10 GENERATED { BY DEFAULT | AWAYS } AS IDENTITY
attndims,
comment = string.Concat(a[7])
};
}, StringComparer.CurrentCultureIgnoreCase);
if (istmpatler == false)
{
foreach (var tbcol in tb.ColumnsByPosition)
{
if (tbstruct.TryGetValue(tbcol.Attribute.Name, out var tbstructcol) ||
string.IsNullOrEmpty(tbcol.Attribute.OldName) == false && tbstruct.TryGetValue(tbcol.Attribute.OldName, out tbstructcol))
{
var isCommentChanged = tbstructcol.comment != (tbcol.Comment ?? "");
var sqlTypeSize = tbstructcol.sqlType;
if (sqlTypeSize.Contains("(") == false)
{
switch (sqlTypeSize.ToLower())
{
case "bit":
case "varbit":
case "bpchar":
case "varchar":
sqlTypeSize = $"{sqlTypeSize}({tbstructcol.max_length})"; break;
}
}
if (tbcol.Attribute.DbType.StartsWith(sqlTypeSize, StringComparison.CurrentCultureIgnoreCase) == false ||
tbcol.Attribute.DbType.Contains("[]") != (tbstructcol.attndims > 0))
sbalter.Append("ALTER TABLE ").Append(_commonUtils.QuoteSqlName($"{tbname[0]}.{tbname[1]}")).Append(" ALTER COLUMN ").Append(_commonUtils.QuoteSqlName(tbstructcol.column)).Append(" TYPE ").Append(tbcol.Attribute.DbType.Split(' ').First()).Append(";\r\n");
if (tbcol.Attribute.IsNullable != tbstructcol.is_nullable)
{
if (tbcol.Attribute.IsNullable != true || tbcol.Attribute.IsNullable == true && tbcol.Attribute.IsPrimary == false)
{
if (tbcol.Attribute.IsNullable == false)
sbalter.Append("UPDATE ").Append(_commonUtils.QuoteSqlName($"{tbname[0]}.{tbname[1]}")).Append(" SET ").Append(_commonUtils.QuoteSqlName(tbstructcol.column)).Append(" = ").Append(tbcol.DbDefaultValue).Append(" WHERE ").Append(_commonUtils.QuoteSqlName(tbstructcol.column)).Append(" IS NULL;\r\n");
sbalter.Append("ALTER TABLE ").Append(_commonUtils.QuoteSqlName($"{tbname[0]}.{tbname[1]}")).Append(" ALTER COLUMN ").Append(_commonUtils.QuoteSqlName(tbstructcol.column)).Append(" ").Append(tbcol.Attribute.IsNullable == true ? "DROP" : "SET").Append(" NOT NULL;\r\n");
}
}
if (tbcol.Attribute.IsIdentity != tbstructcol.is_identity)
{
if (isPg10)
{
if (tbstructcol.is_identity)
{
if (tbstructcol.is_identity_pg9)
seqcols.Add(NativeTuple.Create(tbcol, tbname, false));
sbalter.Append("ALTER TABLE ").Append(_commonUtils.QuoteSqlName($"{tbname[0]}.{tbname[1]}")).Append(" ALTER COLUMN ").Append(_commonUtils.QuoteSqlName(tbcol.Attribute.Name)).Append(" DROP IDENTITY IF EXISTS;\r\n");
}
else
{
sbalter.Append("ALTER TABLE ").Append(_commonUtils.QuoteSqlName($"{tbname[0]}.{tbname[1]}")).Append(" ALTER COLUMN ").Append(_commonUtils.QuoteSqlName(tbcol.Attribute.Name)).Append(" ADD GENERATED BY DEFAULT AS IDENTITY");
var maxval = _orm.Ado.QuerySingle<int>($"select max({_commonUtils.QuoteSqlName(tbcol.Attribute.Name)}) from {_commonUtils.QuoteSqlName($"{tbname[0]}.{tbname[1]}")}");
if (maxval > 0)
sbalter.Append(" (START ").Append(maxval + 1).Append(")");
sbalter.Append(";\r\n");
}
}
else
seqcols.Add(NativeTuple.Create(tbcol, tbname, tbcol.Attribute.IsIdentity == true));
}
if (string.Compare(tbstructcol.column, tbcol.Attribute.OldName, true) == 0)
//修改列名
sbalter.Append("ALTER TABLE ").Append(_commonUtils.QuoteSqlName($"{tbname[0]}.{tbname[1]}")).Append(" RENAME COLUMN ").Append(_commonUtils.QuoteSqlName(tbstructcol.column)).Append(" TO ").Append(_commonUtils.QuoteSqlName(tbcol.Attribute.Name)).Append(";\r\n");
if (isCommentChanged)
sbalter.Append("COMMENT ON COLUMN ").Append(_commonUtils.QuoteSqlName($"{tbname[0]}.{tbname[1]}.{tbcol.Attribute.Name}")).Append(" IS ").Append(_commonUtils.FormatSql("{0}", tbcol.Comment)).Append(";\r\n");
continue;
}
//添加列
sbalter.Append("ALTER TABLE ").Append(_commonUtils.QuoteSqlName($"{tbname[0]}.{tbname[1]}")).Append(" ADD COLUMN ").Append(_commonUtils.QuoteSqlName(tbcol.Attribute.Name)).Append(" ").Append(tbcol.Attribute.DbType.Split(' ').First()).Append(";\r\n");
sbalter.Append("UPDATE ").Append(_commonUtils.QuoteSqlName($"{tbname[0]}.{tbname[1]}")).Append(" SET ").Append(_commonUtils.QuoteSqlName(tbcol.Attribute.Name)).Append(" = ").Append(tbcol.DbDefaultValue).Append(";\r\n");
if (tbcol.Attribute.IsNullable == false) sbalter.Append("ALTER TABLE ").Append(_commonUtils.QuoteSqlName($"{tbname[0]}.{tbname[1]}")).Append(" ALTER COLUMN ").Append(_commonUtils.QuoteSqlName(tbcol.Attribute.Name)).Append(" SET NOT NULL;\r\n");
if (tbcol.Attribute.IsIdentity == true)
{
if (isPg10)
sbalter.Append("ALTER TABLE ").Append(_commonUtils.QuoteSqlName($"{tbname[0]}.{tbname[1]}")).Append(" ALTER COLUMN ").Append(_commonUtils.QuoteSqlName(tbcol.Attribute.Name)).Append(" ADD GENERATED BY DEFAULT AS IDENTITY;\r\n");
else
seqcols.Add(NativeTuple.Create(tbcol, tbname, tbcol.Attribute.IsIdentity == true));
}
if (string.IsNullOrEmpty(tbcol.Comment) == false) sbalter.Append("COMMENT ON COLUMN ").Append(_commonUtils.QuoteSqlName($"{tbname[0]}.{tbname[1]}.{tbcol.Attribute.Name}")).Append(" IS ").Append(_commonUtils.FormatSql("{0}", tbcol.Comment)).Append(";\r\n");
}
var dsuksql = _commonUtils.FormatSql($@"
select
c.attname,
b.relname,
{(isPg96 ? "case when pg_index_column_has_property(b.oid, c.attnum, 'desc') = 't' then 1 else 0 end" : "0")} IsDesc,
case when indisunique = 't' then 1 else 0 end IsUnique
from pg_index a
inner join pg_class b on b.oid = a.indexrelid
inner join pg_attribute c on c.attnum > 0 and c.attrelid = b.oid
inner join pg_namespace ns on ns.oid = b.relnamespace
inner join pg_class d on d.oid = a.indrelid
where ns.nspname in ({{0}}) and d.relname in ({{1}}) and a.indisprimary = 'f'", tboldname ?? tbname);
var dsuk = _orm.Ado.ExecuteArray(CommandType.Text, dsuksql).Select(a => new[] { string.Concat(a[0]), string.Concat(a[1]), string.Concat(a[2]), string.Concat(a[3]) });
foreach (var uk in tb.Indexes)
{
if (string.IsNullOrEmpty(uk.Name) || uk.Columns.Any() == false) continue;
var ukname = ReplaceIndexName(uk.Name, tbname[1]);
var dsukfind1 = dsuk.Where(a => string.Compare(a[1], ukname, true) == 0).ToArray();
if (dsukfind1.Any() == false || dsukfind1.Length != uk.Columns.Length || dsukfind1.Where(a => uk.Columns.Where(b => (a[3] == "1") == uk.IsUnique && string.Compare(b.Column.Attribute.Name, a[0], true) == 0 && ((a[2] == "1") == b.IsDesc || isPg96 == false)).Any()).Count() != uk.Columns.Length)
{
if (dsukfind1.Any()) sbalter.Append("DROP INDEX ").Append(_commonUtils.QuoteSqlName(ukname)).Append(";\r\n");
sbalter.Append("CREATE ");
if (uk.IsUnique) sbalter.Append("UNIQUE ");
sbalter.Append("INDEX ");
if (isPg95) sbalter.Append("IF NOT EXISTS ");
sbalter.Append(_commonUtils.QuoteSqlName(ukname)).Append(" ON ").Append(_commonUtils.QuoteSqlName($"{tbname[0]}.{tbname[1]}")).Append("(");
foreach (var tbcol in uk.Columns)
{
sbalter.Append(_commonUtils.QuoteSqlName(tbcol.Column.Attribute.Name));
if (tbcol.IsDesc) sbalter.Append(" DESC");
sbalter.Append(", ");
}
sbalter.Remove(sbalter.Length - 2, 2).Append(");\r\n");
}
}
}
if (istmpatler == false)
{
var dbcomment = string.Concat(_orm.Ado.ExecuteScalar(CommandType.Text, _commonUtils.FormatSql(@" select
d.description
from pg_class a
inner join pg_namespace b on b.oid = a.relnamespace
left join pg_description d on d.objoid = a.oid and objsubid = 0
where b.nspname not in ('pg_catalog', 'information_schema') and a.relkind in ('r') and b.nspname = {0} and a.relname = {1}
and b.nspname || '.' || a.relname not in ('public.geography_columns','public.geometry_columns','public.raster_columns','public.raster_overviews')", tbname[0], tbname[1])));
if (dbcomment != (tb.Comment ?? ""))
sbalter.Append("COMMENT ON TABLE ").Append(_commonUtils.QuoteSqlName($"{tbname[0]}.{tbname[1]}")).Append(" IS ").Append(_commonUtils.FormatSql("{0}", tb.Comment)).Append(";\r\n");
sb.Append(sbalter);
continue;
}
var oldpk = _orm.Ado.ExecuteScalar(CommandType.Text, _commonUtils.FormatSql(@" select pg_constraint.conname as pk_name from pg_constraint
inner join pg_class on pg_constraint.conrelid = pg_class.oid
inner join pg_namespace on pg_namespace.oid = pg_class.relnamespace
where pg_namespace.nspname={0} and pg_class.relname={1} and pg_constraint.contype='p'
", tbname))?.ToString();
if (string.IsNullOrEmpty(oldpk) == false)
sb.Append("ALTER TABLE ").Append(_commonUtils.QuoteSqlName($"{tbname[0]}.{tbname[1]}")).Append(" DROP CONSTRAINT ").Append(oldpk).Append(";\r\n");
//创建临时表,数据导进临时表,然后删除原表,将临时表改名为原表名
var tablename = tboldname == null ? _commonUtils.QuoteSqlName($"{tbname[0]}.{tbname[1]}") : _commonUtils.QuoteSqlName($"{tboldname[0]}.{tboldname[1]}");
var tmptablename = _commonUtils.QuoteSqlName($"{tbname[0]}.FreeSqlTmp_{tbname[1]}");
//创建临时表
sb.Append("CREATE TABLE IF NOT EXISTS ").Append(tmptablename).Append(" ( ");
foreach (var tbcol in tb.ColumnsByPosition)
{
sb.Append(" \r\n ").Append(_commonUtils.QuoteSqlName(tbcol.Attribute.Name)).Append(" ").Append(tbcol.Attribute.DbType);
if (tbcol.Attribute.IsIdentity == true)
{
if (isPg10) sb.Append(" GENERATED BY DEFAULT AS IDENTITY");
else seqcols.Add(NativeTuple.Create(tbcol, tbname, true));
}
sb.Append(",");
}
if (tb.Primarys.Any())
{
var pkname = $"{tbname[0]}_{tbname[1]}_pkey";
sb.Append(" \r\n CONSTRAINT ").Append(_commonUtils.QuoteSqlName(pkname)).Append(" PRIMARY KEY (");
foreach (var tbcol in tb.Primarys) sb.Append(_commonUtils.QuoteSqlName(tbcol.Attribute.Name)).Append(", ");
sb.Remove(sb.Length - 2, 2).Append("),");
}
sb.Remove(sb.Length - 1, 1);
sb.Append("\r\n) WITH (OIDS=FALSE);\r\n");
//备注
foreach (var tbcol in tb.ColumnsByPosition)
{
if (string.IsNullOrEmpty(tbcol.Comment) == false)
sb.Append("COMMENT ON COLUMN ").Append(_commonUtils.QuoteSqlName($"{tbname[0]}.FreeSqlTmp_{tbname[1]}.{tbcol.Attribute.Name}")).Append(" IS ").Append(_commonUtils.FormatSql("{0}", tbcol.Comment)).Append(";\r\n");
}
if (string.IsNullOrEmpty(tb.Comment) == false)
sb.Append("COMMENT ON TABLE ").Append(_commonUtils.QuoteSqlName($"{tbname[0]}.FreeSqlTmp_{tbname[1]}")).Append(" IS ").Append(_commonUtils.FormatSql("{0}", tb.Comment)).Append(";\r\n");
sb.Append("INSERT INTO ").Append(tmptablename).Append(" (");
foreach (var tbcol in tb.ColumnsByPosition)
sb.Append(_commonUtils.QuoteSqlName(tbcol.Attribute.Name)).Append(", ");
sb.Remove(sb.Length - 2, 2).Append(")\r\nSELECT ");
foreach (var tbcol in tb.ColumnsByPosition)
{
var insertvalue = "NULL";
if (tbstruct.TryGetValue(tbcol.Attribute.Name, out var tbstructcol) ||
string.IsNullOrEmpty(tbcol.Attribute.OldName) == false && tbstruct.TryGetValue(tbcol.Attribute.OldName, out tbstructcol))
{
insertvalue = _commonUtils.QuoteSqlName(tbstructcol.column);
if (tbcol.Attribute.DbType.StartsWith(tbstructcol.sqlType, StringComparison.CurrentCultureIgnoreCase) == false)
insertvalue = $"cast({insertvalue} as {tbcol.Attribute.DbType.Split(' ').First()})";
if (tbcol.Attribute.IsNullable != tbstructcol.is_nullable)
insertvalue = $"coalesce({insertvalue},{tbcol.DbDefaultValue})";
}
else if (tbcol.Attribute.IsNullable == false)
insertvalue = tbcol.DbDefaultValue;
sb.Append(insertvalue).Append(", ");
}
sb.Remove(sb.Length - 2, 2).Append(" FROM ").Append(tablename).Append(";\r\n");
sb.Append("DROP TABLE ").Append(tablename).Append(";\r\n");
sb.Append("ALTER TABLE ").Append(tmptablename).Append(" RENAME TO ").Append(_commonUtils.QuoteSqlName(tbname[1])).Append(";\r\n");
//创建表的索引
foreach (var uk in tb.Indexes)
{
sb.Append("CREATE ");
if (uk.IsUnique) sb.Append("UNIQUE ");
sb.Append("INDEX ");
if (isPg95) sb.Append("IF NOT EXISTS ");
sb.Append(_commonUtils.QuoteSqlName(ReplaceIndexName(uk.Name, tbname[1]))).Append(" ON ").Append(tablename).Append("(");
foreach (var tbcol in uk.Columns)
{
sb.Append(_commonUtils.QuoteSqlName(tbcol.Column.Attribute.Name));
if (tbcol.IsDesc) sb.Append(" DESC");
sb.Append(", ");
}
sb.Remove(sb.Length - 2, 2).Append(");\r\n");
}
if (isPg10)
{
foreach (var tbcol in tb.ColumnsByPosition)
{
if (tbcol.Attribute.IsIdentity)
{
var maxval = _orm.Ado.QuerySingle<int>($"select max({_commonUtils.QuoteSqlName(tbcol.Attribute.Name)}) from {tablename}");
if (maxval > 0)
{
sb.Append("ALTER TABLE ").Append(_commonUtils.QuoteSqlName($"{tbname[0]}.{tbname[1]}")).Append(" ALTER COLUMN ").Append(_commonUtils.QuoteSqlName(tbcol.Attribute.Name)).Append(" SET GENERATED BY DEFAULT");
sb.Append(" RESTART ").Append(maxval + 1).Append("");
sb.Append(";\r\n");
}
}
}
}
}
foreach (var seqcol in seqcols)
{
var tbname = seqcol.Item2;
var seqname = Utils.GetCsName($"{tbname[0]}.{tbname[1]}_{seqcol.Item1.Attribute.Name}_sequence_name").ToLower();
var tbname2 = _commonUtils.QuoteSqlName($"{tbname[0]}.{tbname[1]}");
var colname2 = _commonUtils.QuoteSqlName(seqcol.Item1.Attribute.Name);
sb.Append("ALTER TABLE ").Append(tbname2).Append(" ALTER COLUMN ").Append(colname2).Append(" SET DEFAULT null;\r\n");
sb.Append("DROP SEQUENCE IF EXISTS ").Append(seqname).Append(";\r\n");
if (seqcol.Item3)
{
sb.Append("CREATE SEQUENCE ").Append(seqname).Append(";\r\n");
sb.Append("ALTER TABLE ").Append(tbname2).Append(" ALTER COLUMN ").Append(colname2).Append(" SET DEFAULT nextval('").Append(seqname).Append("'::regclass);\r\n");
sb.Append(" SELECT case when max(").Append(colname2).Append(") is null then 0 else setval('").Append(seqname).Append("', max(").Append(colname2).Append(")) end FROM ").Append(tbname2).Append(";\r\n");
}
}
return sb.Length == 0 ? null : sb.ToString();
}
}
}

View File

@ -0,0 +1,570 @@
using FreeSql.DatabaseModel;
using FreeSql.Internal;
using FreeSql.Internal.Model;
using System;
using System.Collections.Generic;
using System.Data;
using System.Linq;
using System.Text;
using System.Text.RegularExpressions;
namespace FreeSql.Custom.PostgreSQL
{
class CustomPostgreSQLDbFirst : IDbFirst
{
IFreeSql _orm;
protected CommonUtils _commonUtils;
protected CommonExpression _commonExpression;
public CustomPostgreSQLDbFirst(IFreeSql orm, CommonUtils commonUtils, CommonExpression commonExpression)
{
_orm = orm;
_commonUtils = commonUtils;
_commonExpression = commonExpression;
}
public bool IsPg10 => ServerVersion >= 10;
public int ServerVersion
{
get
{
if (_ServerVersionValue == 0 && _orm.Ado.MasterPool != null)
using (var conn = _orm.Ado.MasterPool.Get())
{
try
{
_ServerVersionValue = ParsePgVersion(conn.Value.ServerVersion, 10, 0).Item2;
}
catch
{
_ServerVersionValue = 9;
}
}
return _ServerVersionValue;
}
}
int _ServerVersionValue = 0;
public int GetDbType(DbColumnInfo column) => (int)GetSqlDbType(column);
DbType GetSqlDbType(DbColumnInfo column)
{
var dbtype = column.DbTypeText;
var isarray = dbtype?.EndsWith("[]") == true;
if (isarray) dbtype = dbtype.Remove(dbtype.Length - 2);
DbType ret = DbType.String;
switch (dbtype?.ToLower().TrimStart('_'))
{
case "smallint":
case "int2": ret = DbType.Int16; break;
case "integer":
case "int4": ret = DbType.Int32; break;
case "bigint":
case "int8": ret = DbType.Int64; break;
case "numeric": ret = DbType.Decimal; break;
case "real":
case "float4": ret = DbType.Single; break;
case "double precision":
case "float8": ret = DbType.Double; break;
case "money": ret = DbType.Decimal; break;
case "bpchar": ret = DbType.AnsiString; break;
case "character varying":
case "varchar": ret = DbType.String; break;
case "text": ret = DbType.String; break;
case "timestamp": ret = DbType.DateTime; break;
case "timestamptz": ret = DbType.DateTime; break;
case "date": ret = DbType.Date; break;
case "time": ret = DbType.Time; break;
case "timetz": ret = DbType.Time; break;
case "interval": ret = DbType.Time; break;
case "bool": ret = DbType.Boolean; break;
case "bytea": ret = DbType.Binary; break;
case "bit": ret = DbType.Boolean; break;
case "varbit": ret = DbType.Binary; break;
case "json": ret = DbType.String; break;
case "jsonb": ret = DbType.String; break;
case "uuid": ret = DbType.Guid; break;
}
return ret;
}
static readonly Dictionary<int, DbToCs> _dicDbToCs = new Dictionary<int, DbToCs>() {
{ (int)DbType.Boolean, new DbToCs("(bool?)", "{0} == \"1\"", "{0} == true ? \"1\" : \"0\"", "bool?", typeof(bool), typeof(bool?), "{0}.Value", "GetBoolean") },
{ (int)DbType.SByte, new DbToCs("(sbyte?)", "sbyte.Parse({0})", "{0}.ToString()", "sbyte?", typeof(sbyte), typeof(sbyte?), "{0}.Value", "GetInt16") },
{ (int)DbType.Int16, new DbToCs("(short?)", "short.Parse({0})", "{0}.ToString()", "short?", typeof(short), typeof(short?), "{0}.Value", "GetInt16") },
{ (int)DbType.Int32, new DbToCs("(int?)", "int.Parse({0})", "{0}.ToString()", "int?", typeof(int), typeof(int?), "{0}.Value", "GetInt32") },
{ (int)DbType.Int64, new DbToCs("(long?)", "long.Parse({0})", "{0}.ToString()", "long?", typeof(long), typeof(long?), "{0}.Value", "GetInt64") },
{ (int)DbType.Byte, new DbToCs("(byte?)", "byte.Parse({0})", "{0}.ToString()", "byte?", typeof(byte), typeof(byte?), "{0}.Value", "GetByte") },
{ (int)DbType.UInt16, new DbToCs("(ushort?)", "ushort.Parse({0})", "{0}.ToString()", "ushort?", typeof(ushort), typeof(ushort?), "{0}.Value", "GetInt32") },
{ (int)DbType.UInt32, new DbToCs("(uint?)", "uint.Parse({0})", "{0}.ToString()", "uint?", typeof(uint), typeof(uint?), "{0}.Value", "GetInt64") },
{ (int)DbType.UInt64, new DbToCs("(ulong?)", "ulong.Parse({0})", "{0}.ToString()", "ulong?", typeof(ulong), typeof(ulong?), "{0}.Value", "GetInt64") },
{ (int)DbType.Decimal, new DbToCs("(decimal?)", "decimal.Parse({0})", "{0}.ToString()", "decimal?", typeof(decimal), typeof(decimal?), "{0}.Value", "GetDecimal") },
{ (int)DbType.Single, new DbToCs("(float?)", "float.Parse({0})", "{0}.ToString()", "float?", typeof(float), typeof(float?), "{0}.Value", "GetFloat") },
{ (int)DbType.Double, new DbToCs("(double?)", "double.Parse({0})", "{0}.ToString()", "double?", typeof(double), typeof(double?), "{0}.Value", "GetDouble") },
{ (int)DbType.AnsiString, new DbToCs("", "{0}.Replace(StringifySplit, \"|\")", "{0}.Replace(\"|\", StringifySplit)", "string", typeof(string), typeof(string), "{0}", "GetString") },
{ (int)DbType.String, new DbToCs("", "{0}.Replace(StringifySplit, \"|\")", "{0}.Replace(\"|\", StringifySplit)", "string", typeof(string), typeof(string), "{0}", "GetString") },
{ (int)DbType.DateTime, new DbToCs("(DateTime?)", "new DateTime(long.Parse({0}))", "{0}.Ticks.ToString()", "DateTime?", typeof(DateTime), typeof(DateTime?), "{0}.Value", "GetDateTime") },
{ (int)DbType.Date, new DbToCs("(DateTime?)", "new DateTime(long.Parse({0}))", "{0}.Ticks.ToString()", "DateTime?", typeof(DateTime), typeof(DateTime?), "{0}.Value", "GetDateTime") },
{ (int)DbType.Time, new DbToCs("(TimeSpan?)", "TimeSpan.Parse(double.Parse({0}))", "{0}.Ticks.ToString()", "TimeSpan?", typeof(TimeSpan), typeof(TimeSpan?), "{0}.Value", "GetValue") },
{ (int)DbType.Binary, new DbToCs("(byte[])", "Convert.FromBase64String({0})", "Convert.ToBase64String({0})", "byte[]", typeof(byte[]), typeof(byte[]), "{0}", "GetValue") },
{ (int)DbType.Guid, new DbToCs("(Guid?)", "Guid.Parse({0})", "{0}.ToString()", "Guid", typeof(Guid), typeof(Guid?), "{0}", "GetString") },
};
public string GetCsConvert(DbColumnInfo column) => _dicDbToCs.TryGetValue(column.DbType, out var trydc) ? (column.IsNullable ? trydc.csConvert : trydc.csConvert.Replace("?", "")) : null;
public string GetCsParse(DbColumnInfo column) => _dicDbToCs.TryGetValue(column.DbType, out var trydc) ? trydc.csParse : null;
public string GetCsStringify(DbColumnInfo column) => _dicDbToCs.TryGetValue(column.DbType, out var trydc) ? trydc.csStringify : null;
public string GetCsType(DbColumnInfo column) => _dicDbToCs.TryGetValue(column.DbType, out var trydc) ? (column.IsNullable ? trydc.csType : trydc.csType.Replace("?", "")) : null;
public Type GetCsTypeInfo(DbColumnInfo column) => _dicDbToCs.TryGetValue(column.DbType, out var trydc) ? trydc.csTypeInfo : null;
public string GetCsTypeValue(DbColumnInfo column) => _dicDbToCs.TryGetValue(column.DbType, out var trydc) ? trydc.csTypeValue : null;
public string GetDataReaderMethod(DbColumnInfo column) => _dicDbToCs.TryGetValue(column.DbType, out var trydc) ? trydc.dataReaderMethod : null;
public List<string> GetDatabases()
{
var sql = @" select datname from pg_database where datname not in ('template1', 'template0')";
var ds = _orm.Ado.ExecuteArray(CommandType.Text, sql);
return ds.Select(a => a.FirstOrDefault()?.ToString()).ToList();
}
public bool ExistsTable(string name, bool ignoreCase)
{
if (string.IsNullOrEmpty(name)) return false;
var tbname = _commonUtils.SplitTableName(name);
if (tbname?.Length == 1) tbname = new[] { "public", tbname[0] };
if (ignoreCase) tbname = tbname.Select(a => a.ToLower()).ToArray();
var sql = $" select 1 from pg_tables a inner join pg_namespace b on b.nspname = a.schemaname where {(ignoreCase ? "lower(b.nspname)" : "b.nspname")}={_commonUtils.FormatSql("{0}", tbname[0])} and {(ignoreCase ? "lower(a.tablename)" : "a.tablename")}={_commonUtils.FormatSql("{0}", tbname[1])}";
return string.Concat(_orm.Ado.ExecuteScalar(CommandType.Text, sql)) == "1";
}
public DbTableInfo GetTableByName(string name, bool ignoreCase = true) => GetTables(null, name, ignoreCase)?.FirstOrDefault();
public List<DbTableInfo> GetTablesByDatabase(params string[] database) => GetTables(database, null, false);
public List<DbTableInfo> GetTables(string[] database, string tablename, bool ignoreCase)
{
var olddatabase = "";
var is96 = true;
using (var conn = _orm.Ado.MasterPool.Get(TimeSpan.FromSeconds(5)))
{
olddatabase = conn.Value.Database;
is96 = ParsePgVersion(conn.Value.ServerVersion, 9, 6).Item1;
}
string[] tbname = null;
string[] dbs = database == null || database.Any() == false ? new[] { olddatabase } : database;
if (string.IsNullOrEmpty(tablename) == false)
{
tbname = _commonUtils.SplitTableName(tablename);
if (tbname?.Length == 1) tbname = new[] { "public", tbname[0] };
if (ignoreCase) tbname = tbname.Select(a => a.ToLower()).ToArray();
dbs = new[] { olddatabase };
}
var tables = new List<DbTableInfo>();
foreach (var db in dbs)
{
if (string.IsNullOrEmpty(db) || string.Compare(db, olddatabase, true) != 0) continue;
var loc1 = new List<DbTableInfo>();
var loc2 = new Dictionary<string, DbTableInfo>();
var loc3 = new Dictionary<string, Dictionary<string, DbColumnInfo>>();
var sql = $@"
{(tbname == null ? "" : $"select * from (")}select
b.nspname || '.' || a.tablename,
a.schemaname,
a.tablename ,
d.description,
'TABLE'
from pg_tables a
inner join pg_namespace b on b.nspname = a.schemaname
inner join pg_class c on c.relnamespace = b.oid and c.relname = a.tablename
left join pg_description d on d.objoid = c.oid and objsubid = 0
where a.schemaname not in ('pg_catalog', 'information_schema', 'topology')
and b.nspname || '.' || a.tablename not in ('public.spatial_ref_sys')
union all
select
b.nspname || '.' || a.relname,
b.nspname,
a.relname,
d.description,
'VIEW'
from pg_class a
inner join pg_namespace b on b.oid = a.relnamespace
left join pg_description d on d.objoid = a.oid and objsubid = 0
where b.nspname not in ('pg_catalog', 'information_schema') and a.relkind in ('m','v')
and b.nspname || '.' || a.relname not in ('public.geography_columns','public.geometry_columns','public.raster_columns','public.raster_overviews')
{(tbname == null ? "" : $") ft_dbf where {(ignoreCase ? "lower(schemaname)" : "schemaname")}={_commonUtils.FormatSql("{0}", tbname[0])} and {(ignoreCase ? "lower(tablename)" : "tablename")}={_commonUtils.FormatSql("{0}", tbname[1])}")}";
var ds = _orm.Ado.ExecuteArray(CommandType.Text, sql);
if (ds == null) return loc1;
var loc6 = new List<string[]>();
var loc66 = new List<string[]>();
var loc6_1000 = new List<string>();
var loc66_1000 = new List<string>();
foreach (object[] row in ds)
{
var object_id = string.Concat(row[0]);
var owner = string.Concat(row[1]);
var table = string.Concat(row[2]);
var comment = string.Concat(row[3]);
Enum.TryParse<DbTableType>(string.Concat(row[4]), out var type);
loc2.Add(object_id, new DbTableInfo { Id = object_id.ToString(), Schema = owner, Name = table, Comment = comment, Type = type });
loc3.Add(object_id, new Dictionary<string, DbColumnInfo>());
switch (type)
{
case DbTableType.VIEW:
case DbTableType.TABLE:
loc6_1000.Add(object_id);
if (loc6_1000.Count >= 500)
{
loc6.Add(loc6_1000.ToArray());
loc6_1000.Clear();
}
break;
case DbTableType.StoreProcedure:
loc66_1000.Add(object_id);
if (loc66_1000.Count >= 500)
{
loc66.Add(loc66_1000.ToArray());
loc66_1000.Clear();
}
break;
}
}
if (loc6_1000.Count > 0) loc6.Add(loc6_1000.ToArray());
if (loc66_1000.Count > 0) loc66.Add(loc66_1000.ToArray());
if (loc6.Count == 0) return loc1;
var loc8 = new StringBuilder().Append("(");
for (var loc8idx = 0; loc8idx < loc6.Count; loc8idx++)
{
if (loc8idx > 0) loc8.Append(" OR ");
loc8.Append("a.table_name in (");
for (var loc8idx2 = 0; loc8idx2 < loc6[loc8idx].Length; loc8idx2++)
{
if (loc8idx2 > 0) loc8.Append(",");
loc8.Append($"'{loc6[loc8idx][loc8idx2]}'");
}
loc8.Append(")");
}
loc8.Append(")");
sql = $@"
select
ns.nspname || '.' || c.relname as id,
a.attname,
t.typname,
case when a.atttypmod > 0 and a.atttypmod < 32767 then a.atttypmod - 4 else a.attlen end len,
case when t.typelem = 0 then t.typname else t2.typname end,
case when a.attnotnull then 0 else 1 end as is_nullable,
--e.adsrc as is_identity, pg12以下
(select pg_get_expr(adbin, adrelid) from pg_attrdef where adrelid = e.adrelid and adnum = e.adnum limit 1) is_identity,
d.description as comment,
a.attndims,
case when t.typelem = 0 then t.typtype else t2.typtype end,
ns2.nspname,
a.attnum{(IsPg10 ? ", a.attidentity" : "")}
from pg_class c
inner join pg_attribute a on a.attnum > 0 and a.attrelid = c.oid
inner join pg_type t on t.oid = a.atttypid
left join pg_type t2 on t2.oid = t.typelem
left join pg_description d on d.objoid = a.attrelid and d.objsubid = a.attnum
left join pg_attrdef e on e.adrelid = a.attrelid and e.adnum = a.attnum
inner join pg_namespace ns on ns.oid = c.relnamespace
inner join pg_namespace ns2 on ns2.oid = t.typnamespace
where {loc8.ToString().Replace("a.table_name", "ns.nspname || '.' || c.relname")}";
ds = _orm.Ado.ExecuteArray(CommandType.Text, sql);
if (ds == null) return loc1;
foreach (object[] row in ds)
{
var object_id = string.Concat(row[0]);
var column = string.Concat(row[1]);
var type = string.Concat(row[2]);
var max_length = int.Parse(string.Concat(row[3]));
var sqlType = string.Concat(row[4]);
var is_nullable = string.Concat(row[5]) == "1";
var is_identity = string.Concat(row[6]).StartsWith(@"nextval('") && (string.Concat(row[6]).EndsWith(@"'::regclass)") || string.Concat(row[6]).EndsWith(@"')"))
|| IsPg10 && new[] { "a", "d" }.Contains(string.Concat(row[12])); //pg10 GENERATED { BY DEFAULT | AWAYS } AS IDENTITY
var comment = string.Concat(row[7]);
var defaultValue = string.Concat(row[6]);
int attndims = int.Parse(string.Concat(row[8]));
string typtype = string.Concat(row[9]);
string owner = string.Concat(row[10]);
int attnum = int.Parse(string.Concat(row[11]));
switch (sqlType.ToLower())
{
case "bool": case "name": case "bit": case "varbit": case "bpchar": case "varchar": case "bytea": case "text": case "uuid": break;
default: max_length *= 8; break;
}
if (max_length <= 0) max_length = -1;
if (type.StartsWith("_"))
{
type = type.Substring(1);
if (attndims == 0) attndims++;
}
if (sqlType.StartsWith("_")) sqlType = sqlType.Substring(1);
if (max_length > 0)
{
switch (sqlType.ToLower())
{
//case "numeric": sqlType += $"({max_length})"; break;
case "bpchar": case "varchar": case "bytea": case "bit": case "varbit": sqlType += $"({max_length})"; break;
}
}
if (attndims > 0) type += "[]";
loc3[object_id].Add(column, new DbColumnInfo
{
Name = column,
MaxLength = max_length,
IsIdentity = is_identity,
IsNullable = is_nullable,
IsPrimary = false,
DbTypeText = type,
DbTypeTextFull = sqlType,
Table = loc2[object_id],
Comment = comment,
DefaultValue = defaultValue,
Position = attnum
});
loc3[object_id][column].DbType = this.GetDbType(loc3[object_id][column]);
loc3[object_id][column].CsType = this.GetCsTypeInfo(loc3[object_id][column]);
}
sql = $@"
select
ns.nspname || '.' || d.relname as table_id,
c.attname,
b.relname as index_id,
case when a.indisunique then 1 else 0 end IsUnique,
case when a.indisprimary then 1 else 0 end IsPrimary,
case when a.indisclustered then 0 else 1 end IsClustered,
{(is96 ? "case when pg_index_column_has_property(b.oid, c.attnum, 'desc') = 't' then 1 else 0 end" : "0")} IsDesc,
a.indkey::text,
c.attnum
from pg_index a
inner join pg_class b on b.oid = a.indexrelid
inner join pg_attribute c on c.attnum > 0 and c.attrelid = b.oid
inner join pg_namespace ns on ns.oid = b.relnamespace
inner join pg_class d on d.oid = a.indrelid
where {loc8.ToString().Replace("a.table_name", "ns.nspname || '.' || d.relname")}
";
ds = _orm.Ado.ExecuteArray(CommandType.Text, sql);
if (ds == null) return loc1;
var indexColumns = new Dictionary<string, Dictionary<string, DbIndexInfo>>();
var uniqueColumns = new Dictionary<string, Dictionary<string, DbIndexInfo>>();
foreach (object[] row in ds)
{
var object_id = string.Concat(row[0]);
var column = string.Concat(row[1]);
var index_id = string.Concat(row[2]);
var is_unique = string.Concat(row[3]) == "1";
var is_primary_key = string.Concat(row[4]) == "1";
var is_clustered = string.Concat(row[5]) == "1";
var is_desc = string.Concat(row[6]) == "1";
var inkey = string.Concat(row[7]).Split(' ');
var attnum = int.Parse(string.Concat(row[8]));
attnum = int.Parse(inkey[attnum - 1]);
//foreach (string tc in loc3[object_id].Keys)
//{
// if (loc3[object_id][tc].DbTypeText.EndsWith("[]"))
// {
// column = tc;
// break;
// }
//}
if (loc3.ContainsKey(object_id) == false || loc3[object_id].ContainsKey(column) == false) continue;
var loc9 = loc3[object_id][column];
if (loc9.IsPrimary == false && is_primary_key) loc9.IsPrimary = is_primary_key;
Dictionary<string, DbIndexInfo> loc10 = null;
DbIndexInfo loc11 = null;
if (!indexColumns.TryGetValue(object_id, out loc10))
indexColumns.Add(object_id, loc10 = new Dictionary<string, DbIndexInfo>());
if (!loc10.TryGetValue(index_id, out loc11))
loc10.Add(index_id, loc11 = new DbIndexInfo());
loc11.Columns.Add(new DbIndexColumnInfo { Column = loc9, IsDesc = is_desc });
if (is_unique && !is_primary_key)
{
if (!uniqueColumns.TryGetValue(object_id, out loc10))
uniqueColumns.Add(object_id, loc10 = new Dictionary<string, DbIndexInfo>());
if (!loc10.TryGetValue(index_id, out loc11))
loc10.Add(index_id, loc11 = new DbIndexInfo());
loc11.Columns.Add(new DbIndexColumnInfo { Column = loc9, IsDesc = is_desc });
}
}
foreach (var object_id in indexColumns.Keys)
{
foreach (var column in indexColumns[object_id])
loc2[object_id].IndexesDict.Add(column.Key, column.Value);
}
foreach (var object_id in uniqueColumns.Keys)
{
foreach (var column in uniqueColumns[object_id])
{
column.Value.Columns.Sort((c1, c2) => c1.Column.Name.CompareTo(c2.Column.Name));
loc2[object_id].UniquesDict.Add(column.Key, column.Value);
}
}
if (tbname == null)
{
sql = $@"
select
ns.nspname || '.' || b.relname as table_id,
array(select attname from pg_attribute where attrelid = a.conrelid and attnum = any(a.conkey)) as column_name,
a.conname as FKId,
ns2.nspname || '.' || c.relname as ref_table_id,
1 as IsForeignKey,
array(select attname from pg_attribute where attrelid = a.confrelid and attnum = any(a.confkey)) as ref_column,
null ref_sln,
null ref_table
from pg_constraint a
inner join pg_class b on b.oid = a.conrelid
inner join pg_class c on c.oid = a.confrelid
inner join pg_namespace ns on ns.oid = b.relnamespace
inner join pg_namespace ns2 on ns2.oid = c.relnamespace
where {loc8.ToString().Replace("a.table_name", "ns.nspname || '.' || b.relname")}
";
ds = _orm.Ado.ExecuteArray(CommandType.Text, sql);
if (ds == null) return loc1;
var fkColumns = new Dictionary<string, Dictionary<string, DbForeignInfo>>();
foreach (object[] row in ds)
{
var table_id = string.Concat(row[0]);
var column = row[1] as string[];
var fk_id = string.Concat(row[2]);
var ref_table_id = string.Concat(row[3]);
var is_foreign_key = string.Concat(row[4]) == "1";
var referenced_column = row[5] as string[];
var referenced_db = string.Concat(row[6]);
var referenced_table = string.Concat(row[7]);
if (loc2.ContainsKey(ref_table_id) == false) continue;
Dictionary<string, DbForeignInfo> loc12 = null;
DbForeignInfo loc13 = null;
if (!fkColumns.TryGetValue(table_id, out loc12))
fkColumns.Add(table_id, loc12 = new Dictionary<string, DbForeignInfo>());
if (!loc12.TryGetValue(fk_id, out loc13))
loc12.Add(fk_id, loc13 = new DbForeignInfo { Table = loc2[table_id], ReferencedTable = loc2[ref_table_id] });
for (int a = 0; a < column.Length; a++)
{
loc13.Columns.Add(loc3[table_id][column[a]]);
loc13.ReferencedColumns.Add(loc3[ref_table_id][referenced_column[a]]);
}
}
foreach (var table_id in fkColumns.Keys)
foreach (var fk in fkColumns[table_id])
loc2[table_id].ForeignsDict.Add(fk.Key, fk.Value);
}
foreach (var table_id in loc3.Keys)
{
foreach (var loc5 in loc3[table_id].Values)
{
loc2[table_id].Columns.Add(loc5);
if (loc5.IsIdentity) loc2[table_id].Identitys.Add(loc5);
if (loc5.IsPrimary) loc2[table_id].Primarys.Add(loc5);
}
}
foreach (var loc4 in loc2.Values)
{
//if (loc4.Primarys.Count == 0 && loc4.UniquesDict.Count > 0)
//{
// foreach (var loc5 in loc4.UniquesDict.First().Value.Columns)
// {
// loc5.Column.IsPrimary = true;
// loc4.Primarys.Add(loc5.Column);
// }
//}
loc4.Primarys.Sort((c1, c2) => c1.Name.CompareTo(c2.Name));
loc4.Columns.Sort((c1, c2) =>
{
int compare = c2.IsPrimary.CompareTo(c1.IsPrimary);
if (compare == 0)
{
bool b1 = loc4.ForeignsDict.Values.Where(fk => fk.Columns.Where(c3 => c3.Name == c1.Name).Any()).Any();
bool b2 = loc4.ForeignsDict.Values.Where(fk => fk.Columns.Where(c3 => c3.Name == c2.Name).Any()).Any();
compare = b2.CompareTo(b1);
}
if (compare == 0) compare = c1.Name.CompareTo(c2.Name);
return compare;
});
loc1.Add(loc4);
}
loc1.Sort((t1, t2) =>
{
var ret = t1.Schema.CompareTo(t2.Schema);
if (ret == 0) ret = t1.Name.CompareTo(t2.Name);
return ret;
});
loc2.Clear();
loc3.Clear();
tables.AddRange(loc1);
}
return tables;
}
public class GetEnumsByDatabaseQueryInfo
{
public string name { get; set; }
public string label { get; set; }
}
public List<DbEnumInfo> GetEnumsByDatabase(params string[] database)
{
if (database == null || database.Length == 0) return new List<DbEnumInfo>();
var drs = _orm.Ado.Query<GetEnumsByDatabaseQueryInfo>(CommandType.Text, _commonUtils.FormatSql(@"
select
ns.nspname || '.' || a.typname AS name,
b.enumlabel AS label
from pg_type a
inner join pg_enum b on b.enumtypid = a.oid
inner join pg_namespace ns on ns.oid = a.typnamespace
where a.typtype = 'e' and ns.nspname in (SELECT ""schema_name"" FROM information_schema.schemata where catalog_name in {0})", database));
var ret = new Dictionary<string, Dictionary<string, string>>();
foreach (var dr in drs)
{
if (ret.TryGetValue(dr.name, out var labels) == false) ret.Add(dr.name, labels = new Dictionary<string, string>());
var key = dr.label;
if (Regex.IsMatch(key, @"^[\u0391-\uFFE5a-zA-Z_\$][\u0391-\uFFE5a-zA-Z_\$\d]*$") == false)
key = $"Unkown{ret[dr.name].Count + 1}";
if (labels.ContainsKey(key) == false) labels.Add(key, dr.label);
}
return ret.Select(a => new DbEnumInfo { Name = a.Key, Labels = a.Value }).ToList();
}
public static NativeTuple<bool, int, int> ParsePgVersion(string versionString, int v1, int v2)
{
int[] version = new int[] { 0, 0 };
var vmatch = Regex.Match(versionString, @"(\d+)\.(\d+)");
if (vmatch.Success)
{
version[0] = int.Parse(vmatch.Groups[1].Value);
version[1] = int.Parse(vmatch.Groups[2].Value);
}
else
{
vmatch = Regex.Match(versionString, @"(\d+)");
version[0] = int.Parse(vmatch.Groups[1].Value);
}
if (version[0] > v1) return NativeTuple.Create(true, version[0], version[1]);
if (version[0] == v1 && version[1] >= v2) return NativeTuple.Create(true, version[0], version[1]);
return NativeTuple.Create(false, version[0], version[1]);
}
}
}

View File

@ -0,0 +1,673 @@
using FreeSql.Internal;
using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Linq.Expressions;
using System.Text;
using System.Text.RegularExpressions;
namespace FreeSql.Custom.PostgreSQL
{
class CustomPostgreSQLExpression : CommonExpression
{
public CustomPostgreSQLExpression(CommonUtils common) : base(common) { }
public override string ExpressionLambdaToSqlOther(Expression exp, ExpTSC tsc)
{
Func<Expression, string> getExp = exparg => ExpressionLambdaToSql(exparg, tsc);
switch (exp.NodeType)
{
case ExpressionType.ArrayLength:
var arrOper = (exp as UnaryExpression)?.Operand;
var arrOperExp = getExp(arrOper);
if (arrOperExp.StartsWith("(") || arrOperExp.EndsWith(")")) return $"array_length(array[{arrOperExp.TrimStart('(').TrimEnd(')')}],1)";
if (arrOper.Type == typeof(byte[])) return $"octet_length({getExp(arrOper)})";
return $"case when {arrOperExp} is null then 0 else array_length({arrOperExp},1) end";
case ExpressionType.Convert:
var operandExp = (exp as UnaryExpression)?.Operand;
var gentype = exp.Type.NullableTypeOrThis();
if (gentype != operandExp.Type.NullableTypeOrThis())
{
switch (exp.Type.NullableTypeOrThis().ToString())
{
case "System.Boolean": return $"(({getExp(operandExp)})::varchar not in ('0','false','f','no'))";
case "System.Byte": return $"({getExp(operandExp)})::int2";
case "System.Char": return $"substr(({getExp(operandExp)})::char, 1, 1)";
case "System.DateTime": return ExpressionConstDateTime(operandExp) ?? $"({getExp(operandExp)})::timestamp";
case "System.Decimal": return $"({getExp(operandExp)})::numeric";
case "System.Double": return $"({getExp(operandExp)})::float8";
case "System.Int16": return $"({getExp(operandExp)})::int2";
case "System.Int32": return $"({getExp(operandExp)})::int4";
case "System.Int64": return $"({getExp(operandExp)})::int8";
case "System.SByte": return $"({getExp(operandExp)})::int2";
case "System.Single": return $"({getExp(operandExp)})::float4";
case "System.String": return $"({getExp(operandExp)})::text";
case "System.UInt16": return $"({getExp(operandExp)})::int2";
case "System.UInt32": return $"({getExp(operandExp)})::int4";
case "System.UInt64": return $"({getExp(operandExp)})::int8";
case "System.Guid": return $"({getExp(operandExp)})::uuid";
}
}
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 $"(({getExp(callExp.Arguments[0])})::varchar not in ('0','false','f','no'))";
case "System.Byte": return $"({getExp(callExp.Arguments[0])})::int2";
case "System.Char": return $"substr(({getExp(callExp.Arguments[0])})::char, 1, 1)";
case "System.DateTime": return ExpressionConstDateTime(callExp.Arguments[0]) ?? $"({getExp(callExp.Arguments[0])})::timestamp";
case "System.Decimal": return $"({getExp(callExp.Arguments[0])})::numeric";
case "System.Double": return $"({getExp(callExp.Arguments[0])})::float8";
case "System.Int16": return $"({getExp(callExp.Arguments[0])})::int2";
case "System.Int32": return $"({getExp(callExp.Arguments[0])})::int4";
case "System.Int64": return $"({getExp(callExp.Arguments[0])})::int8";
case "System.SByte": return $"({getExp(callExp.Arguments[0])})::int2";
case "System.Single": return $"({getExp(callExp.Arguments[0])})::float4";
case "System.UInt16": return $"({getExp(callExp.Arguments[0])})::int2";
case "System.UInt32": return $"({getExp(callExp.Arguments[0])})::int4";
case "System.UInt64": return $"({getExp(callExp.Arguments[0])})::int8";
case "System.Guid": return $"({getExp(callExp.Arguments[0])})::uuid";
}
break;
case "NewGuid":
return null;
case "Next":
if (callExp.Object?.Type == typeof(Random)) return "(random()*1000000000)::int4";
return null;
case "NextDouble":
if (callExp.Object?.Type == typeof(Random)) return "random()";
return null;
case "Random":
if (callExp.Method.DeclaringType.IsNumberType()) return "random()";
return null;
case "ToString":
if (callExp.Object != null)
{
if (callExp.Object.Type.NullableTypeOrThis().IsEnum)
{
tsc.SetMapColumnTmp(null);
var oldMapType = tsc.SetMapTypeReturnOld(typeof(string));
var enumStr = ExpressionLambdaToSql(callExp.Object, tsc);
tsc.SetMapColumnTmp(null).SetMapTypeReturnOld(oldMapType);
return enumStr;
}
var value = ExpressionGetValue(callExp.Object, out var success);
if (success) return formatSql(value, typeof(string), null, null);
return callExp.Arguments.Count == 0 ? $"({getExp(callExp.Object)})::text" : 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 $"substr({getExp(callExp.Arguments[0])}, 1, 1)";
}
}
}
if (objType == null) objType = callExp.Method.DeclaringType;
if (objType != null || objType.IsArrayOrList())
{
string left = null;
if (objType == typeof(Dictionary<string, string>))
{
left = objExp == null ? null : getExp(objExp);
switch (callExp.Method.Name)
{
case "get_Item": return $"{left}->{getExp(callExp.Arguments[argIndex])}";
case "Contains":
var right = getExp(callExp.Arguments[argIndex]);
return $"({left} @> ({right}))";
case "ContainsKey": return $"({left} ? {getExp(callExp.Arguments[argIndex])})";
case "Concat": return $"({left} || {getExp(callExp.Arguments[argIndex])})";
case "GetLength":
case "GetLongLength":
case "Count": return $"case when {left} is null then 0 else array_length(akeys({left}),1) end";
case "Keys": return $"akeys({left})";
case "Values": return $"avals({left})";
}
}
switch (callExp.Method.Name)
{
case "Any":
left = objExp == null ? null : getExp(objExp);
if (left.StartsWith("(") || left.EndsWith(")")) left = $"array[{left.TrimStart('(').TrimEnd(')')}]";
return $"(case when {left} is null then 0 else array_length({left},1) end > 0)";
case "Contains":
tsc.SetMapColumnTmp(null);
var args1 = getExp(callExp.Arguments[argIndex]);
var oldMapType = tsc.SetMapTypeReturnOld(tsc.mapTypeTmp);
var oldDbParams = objExp?.NodeType == ExpressionType.MemberAccess ? tsc.SetDbParamsReturnOld(null) : null; //#900 UseGenerateCommandParameterWithLambda(true) 子查询 bug、以及 #1173 参数化 bug
tsc.isNotSetMapColumnTmp = true;
left = objExp == null ? null : getExp(objExp);
tsc.isNotSetMapColumnTmp = false;
tsc.SetMapColumnTmp(null).SetMapTypeReturnOld(oldMapType);
if (oldDbParams != null) tsc.SetDbParamsReturnOld(oldDbParams);
//判断 in 或 array @> array
if (left.StartsWith("array[") && left.EndsWith("]"))
return $"({args1}) in ({left.Substring(6, left.Length - 7)})";
if (left.StartsWith("(") && left.EndsWith(")")) //在各大 Provider AdoProvider 中已约定500元素分割, 3空格\r\n4空格
return $"(({args1}) in {left.Replace(", \r\n \r\n", $") \r\n OR ({args1}) in (")})";
if (args1.StartsWith("(") && args1.EndsWith(")")) args1 = $"array[{args1.TrimStart('(').TrimEnd(')')}]";
else args1 = $"array[{args1}]";
if (objExp != null)
{
var dbinfo = _common._orm.CodeFirst.GetDbInfo(objExp.Type);
if (dbinfo != null) args1 = $"{args1}::{dbinfo.dbtype}";
}
return $"({left} @> {args1})";
case "Concat":
left = objExp == null ? null : getExp(objExp);
if (left.StartsWith("(") || left.EndsWith(")")) left = $"array[{left.TrimStart('(').TrimEnd(')')}]";
var right2 = getExp(callExp.Arguments[argIndex]);
if (right2.StartsWith("(") || right2.EndsWith(")")) right2 = $"array[{right2.TrimStart('(').TrimEnd(')')}]";
return $"({left} || {right2})";
case "GetLength":
case "GetLongLength":
case "Length":
case "Count":
left = objExp == null ? null : getExp(objExp);
if (left.StartsWith("(") || left.EndsWith(")")) left = $"array[{left.TrimStart('(').TrimEnd(')')}]";
return $"case when {left} is null then 0 else array_length({left},1) end";
}
}
break;
case ExpressionType.MemberAccess:
var memExp = exp as MemberExpression;
var memParentExp = memExp.Expression?.Type;
if (memParentExp?.FullName == "System.Byte[]") return null;
if (memParentExp != null)
{
if (memParentExp.IsArray == true)
{
var left = getExp(memExp.Expression);
if (left.StartsWith("(") || left.EndsWith(")")) left = $"array[{left.TrimStart('(').TrimEnd(')')}]";
switch (memExp.Member.Name)
{
case "Length":
case "Count": return $"case when {left} is null then 0 else array_length({left},1) end";
}
}
switch (memParentExp.FullName)
{
case "Newtonsoft.Json.Linq.JToken":
case "Newtonsoft.Json.Linq.JObject":
case "Newtonsoft.Json.Linq.JArray":
var left = getExp(memExp.Expression);
switch (memExp.Member.Name)
{
case "Count": return $"jsonb_array_length(coalesce({left},'[]'))";
}
break;
}
if (memParentExp == typeof(Dictionary<string, string>))
{
var left = getExp(memExp.Expression);
switch (memExp.Member.Name)
{
case "Count": return $"case when {left} is null then 0 else array_length(akeys({left}),1) end";
case "Keys": return $"akeys({left})";
case "Values": return $"avals({left})";
}
}
}
break;
case ExpressionType.NewArrayInit:
var arrExp = exp as NewArrayExpression;
var arrSb = new StringBuilder();
arrSb.Append("array[");
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 $"char_length({left})";
}
return null;
}
public override string ExpressionLambdaToSqlMemberAccessDateTime(MemberExpression exp, ExpTSC tsc)
{
if (exp.Expression == null)
{
switch (exp.Member.Name)
{
case "Now": return _common.Now;
case "UtcNow": return _common.NowUtc;
case "Today": return "current_date";
case "MinValue": return "'0001/1/1 0:00:00'::timestamp";
case "MaxValue": return "'9999/12/31 23:59:59'::timestamp";
}
return null;
}
var left = ExpressionLambdaToSql(exp.Expression, tsc);
switch (exp.Member.Name)
{
case "Date": return $"({left})::date";
case "TimeOfDay": return $"(extract(epoch from ({left})::time)*1000000)";
case "DayOfWeek": return $"extract(dow from ({left})::timestamp)";
case "Day": return $"extract(day from ({left})::timestamp)";
case "DayOfYear": return $"extract(doy from ({left})::timestamp)";
case "Month": return $"extract(month from ({left})::timestamp)";
case "Year": return $"extract(year from ({left})::timestamp)";
case "Hour": return $"extract(hour from ({left})::timestamp)";
case "Minute": return $"extract(minute from ({left})::timestamp)";
case "Second": return $"extract(second from ({left})::timestamp)";
case "Millisecond": return $"(extract(milliseconds from ({left})::timestamp)-extract(second from ({left})::timestamp)*1000)";
case "Ticks": return $"(extract(epoch from ({left})::timestamp)*10000000+621355968000000000)";
}
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 $"floor(({left})/{(long)1000000 * 60 * 60 * 24})";
case "Hours": return $"floor(({left})/{(long)1000000 * 60 * 60}%24)";
case "Milliseconds": return $"(floor(({left})/1000)::int8%1000)";
case "Minutes": return $"(floor(({left})/{(long)1000000 * 60})::int8%60)";
case "Seconds": return $"(floor(({left})/1000000)::int8%60)";
case "Ticks": return $"(({left})*10)";
case "TotalDays": return $"(({left})/{(long)1000000 * 60 * 60 * 24})";
case "TotalHours": return $"(({left})/{(long)1000000 * 60 * 60})";
case "TotalMilliseconds": return $"(({left})/1000)";
case "TotalMinutes": return $"(({left})/{(long)1000000 * 60})";
case "TotalSeconds": return $"(({left})/1000000)";
}
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":
var arg1 = getExp(exp.Arguments[0]);
return $"({arg1} is null or {arg1} = '')";
case "IsNullOrWhiteSpace":
var arg2 = getExp(exp.Arguments[0]);
return $"({arg2} is null or {arg2} = '' or ltrim({arg2}) = '')";
case "Concat":
if (exp.Arguments.Count == 1 && exp.Arguments[0].NodeType == ExpressionType.NewArrayInit && exp.Arguments[0] is NewArrayExpression concatNewArrExp)
return _common.StringConcat(concatNewArrExp.Expressions.Select(a => getExp(a)).ToArray(), null);
return _common.StringConcat(exp.Arguments.Select(a => getExp(a)).ToArray(), null);
case "Format":
if (exp.Arguments[0].NodeType != ExpressionType.Constant) throw new Exception(CoreStrings.Not_Implemented_Expression_ParameterUseConstant(exp,exp.Arguments[0]));
var expArgsHack = exp.Arguments.Count == 2 && exp.Arguments[1].NodeType == ExpressionType.NewArrayInit ?
(exp.Arguments[1] as NewArrayExpression).Expressions : exp.Arguments.Where((a, z) => z > 0);
//3个 {} 时Arguments 解析出来是分开的
//4个 {} 时Arguments[1] 只能解析这个出来,然后里面是 NewArray []
var expArgs = expArgsHack.Select(a =>
{
var atype = (a as UnaryExpression)?.Operand.Type.NullableTypeOrThis() ?? a.Type.NullableTypeOrThis();
if (atype == typeof(string)) return $"'||{_common.IsNull(ExpressionLambdaToSql(a, tsc), "''")}||'";
return $"'||{_common.IsNull($"({ExpressionLambdaToSql(a, tsc)})::text", "''")}||'";
}).ToArray();
return string.Format(ExpressionLambdaToSql(exp.Arguments[0], tsc), expArgs);
case "Join":
if (exp.IsStringJoin(out var tolistObjectExp, out var toListMethod, out var toListArgs1))
{
var newToListArgs0 = Expression.Call(tolistObjectExp, toListMethod,
Expression.Lambda(
Expression.Call(
typeof(SqlExtExtensions).GetMethod("StringJoinPgsqlGroupConcat"),
Expression.Convert(toListArgs1.Body, typeof(object)),
Expression.Convert(exp.Arguments[0], typeof(object))),
toListArgs1.Parameters));
var newToListSql = getExp(newToListArgs0);
return newToListSql;
}
break;
}
}
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 (args0Value.Contains("%"))
{
if (exp.Method.Name == "StartsWith") return $"strpos({left}, {args0Value}) = 1";
if (exp.Method.Name == "EndsWith") return $"strpos({left}, {args0Value}) = char_length({left})-char_length({args0Value})+1";
return $"strpos({left}, {args0Value}) > 0";
}
var likeOpt = "LIKE";
if (exp.Arguments.Count > 1)
{
if (exp.Arguments[1].Type == typeof(bool) ||
exp.Arguments[1].Type == typeof(StringComparison)) likeOpt = "ILIKE";
}
if (exp.Method.Name == "StartsWith") return $"({left}) {likeOpt} {(args0Value.EndsWith("'") ? args0Value.Insert(args0Value.Length - 1, "%") : $"(({args0Value})::text || '%')")}";
if (exp.Method.Name == "EndsWith") return $"({left}) {likeOpt} {(args0Value.StartsWith("'") ? args0Value.Insert(1, "%") : $"('%' || ({args0Value})::text)")}";
if (args0Value.StartsWith("'") && args0Value.EndsWith("'")) return $"({left}) {likeOpt} {args0Value.Insert(1, "%").Insert(args0Value.Length, "%")}";
return $"({left}) {likeOpt} ('%' || ({args0Value})::text || '%')";
case "ToLower": return $"lower({left})";
case "ToUpper": return $"upper({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 $"substr({left}, {substrArgs1})";
return $"substr({left}, {substrArgs1}, {getExp(exp.Arguments[1])})";
case "IndexOf": return $"(strpos({left}, {getExp(exp.Arguments[0])})-1)";
case "PadLeft":
if (exp.Arguments.Count == 1) return $"lpad({left}, {getExp(exp.Arguments[0])})";
return $"lpad({left}, {getExp(exp.Arguments[0])}, {getExp(exp.Arguments[1])})";
case "PadRight":
if (exp.Arguments.Count == 1) return $"rpad({left}, {getExp(exp.Arguments[0])})";
return $"rpad({left}, {getExp(exp.Arguments[0])}, {getExp(exp.Arguments[1])})";
case "Trim":
case "TrimStart":
case "TrimEnd":
if (exp.Arguments.Count == 0)
{
if (exp.Method.Name == "Trim") return $"trim({left})";
if (exp.Method.Name == "TrimStart") return $"ltrim({left})";
if (exp.Method.Name == "TrimEnd") return $"rtrim({left})";
}
var trimArg1 = "";
var trimArg2 = "";
foreach (var argsTrim02 in exp.Arguments)
{
var argsTrim01s = new[] { argsTrim02 };
if (argsTrim02.NodeType == ExpressionType.NewArrayInit)
{
var arritem = argsTrim02 as NewArrayExpression;
argsTrim01s = arritem.Expressions.ToArray();
}
foreach (var argsTrim01 in argsTrim01s)
{
var trimChr = getExp(argsTrim01).Trim('\'');
if (trimChr.Length == 1) trimArg1 += trimChr;
else trimArg2 += $" || ({trimChr})";
}
}
if (exp.Method.Name == "Trim") left = $"trim({left}, {_common.FormatSql("{0}", trimArg1)}{trimArg2})";
if (exp.Method.Name == "TrimStart") left = $"ltrim({left}, {_common.FormatSql("{0}", trimArg1)}{trimArg2})";
if (exp.Method.Name == "TrimEnd") left = $"rtrim({left}, {_common.FormatSql("{0}", trimArg1)}{trimArg2})";
return left;
case "Replace": return $"replace({left}, {getExp(exp.Arguments[0])}, {getExp(exp.Arguments[1])})";
case "CompareTo": return $"case when {left} = {getExp(exp.Arguments[0])} then 0 when {left} > {getExp(exp.Arguments[0])} then 1 else -1 end";
case "Equals": return $"({left} = ({getExp(exp.Arguments[0])})::text)";
}
}
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 $"abs({getExp(exp.Arguments[0])})";
case "Sign": return $"sign({getExp(exp.Arguments[0])})";
case "Floor": return $"floor({getExp(exp.Arguments[0])})";
case "Ceiling": return $"ceiling({getExp(exp.Arguments[0])})";
case "Round":
if (exp.Arguments.Count > 1 && exp.Arguments[1].Type.FullName == "System.Int32") return $"round({getExp(exp.Arguments[0])}, {getExp(exp.Arguments[1])})";
return $"round({getExp(exp.Arguments[0])})";
case "Exp": return $"exp({getExp(exp.Arguments[0])})";
case "Log": return $"log({getExp(exp.Arguments[0])})";
case "Log10": return $"log10({getExp(exp.Arguments[0])})";
case "Pow": return $"pow({getExp(exp.Arguments[0])}, {getExp(exp.Arguments[1])})";
case "Sqrt": return $"sqrt({getExp(exp.Arguments[0])})";
case "Cos": return $"cos({getExp(exp.Arguments[0])})";
case "Sin": return $"sin({getExp(exp.Arguments[0])})";
case "Tan": return $"tan({getExp(exp.Arguments[0])})";
case "Acos": return $"acos({getExp(exp.Arguments[0])})";
case "Asin": return $"asin({getExp(exp.Arguments[0])})";
case "Atan": return $"atan({getExp(exp.Arguments[0])})";
case "Atan2": return $"atan2({getExp(exp.Arguments[0])}, {getExp(exp.Arguments[1])})";
case "Truncate": return $"trunc({getExp(exp.Arguments[0])}, 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 $"extract(epoch from ({getExp(exp.Arguments[0])})::timestamp-({getExp(exp.Arguments[1])})::timestamp)";
case "DaysInMonth": return $"extract(day from ({getExp(exp.Arguments[0])} || '-' || {getExp(exp.Arguments[1])} || '-01')::timestamp+'1 month'::interval-'1 day'::interval)";
case "Equals": return $"(({getExp(exp.Arguments[0])})::timestamp = ({getExp(exp.Arguments[1])})::timestamp)";
case "IsLeapYear":
var isLeapYearArgs1 = getExp(exp.Arguments[0]);
return $"(({isLeapYearArgs1})::int8%4=0 AND ({isLeapYearArgs1})::int8%100<>0 OR ({isLeapYearArgs1})::int8%400=0)";
case "Parse": return ExpressionConstDateTime(exp.Arguments[0]) ?? $"({getExp(exp.Arguments[0])})::timestamp";
case "ParseExact":
case "TryParse":
case "TryParseExact": return ExpressionConstDateTime(exp.Arguments[0]) ?? $"({getExp(exp.Arguments[0])})::timestamp";
}
}
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})::timestamp+((({args1})/1000)||' milliseconds')::interval)";
case "AddDays": return $"(({left})::timestamp+(({args1})||' day')::interval)";
case "AddHours": return $"(({left})::timestamp+(({args1})||' hour')::interval)";
case "AddMilliseconds": return $"(({left})::timestamp+(({args1})||' milliseconds')::interval)";
case "AddMinutes": return $"(({left})::timestamp+(({args1})||' minute')::interval)";
case "AddMonths": return $"(({left})::timestamp+(({args1})||' month')::interval)";
case "AddSeconds": return $"(({left})::timestamp+(({args1})||' second')::interval)";
case "AddTicks": return $"(({left})::timestamp+(({args1})/10||' microseconds')::interval)";
case "AddYears": return $"(({left})::timestamp+(({args1})||' year')::interval)";
case "Subtract":
switch ((exp.Arguments[0].Type.IsNullableType() ? exp.Arguments[0].Type.GetGenericArguments().FirstOrDefault() : exp.Arguments[0].Type).FullName)
{
case "System.DateTime": return $"(extract(epoch from ({left})::timestamp-({args1})::timestamp)*1000000)";
case "System.TimeSpan": return $"(({left})::timestamp-((({args1})/1000)||' milliseconds')::interval)";
}
break;
case "Equals": return $"({left} = ({args1})::timestamp)";
case "CompareTo": return $"extract(epoch from ({left})::timestamp-({args1})::timestamp)";
case "ToString":
if (left.EndsWith("::timestamp") == false) left = $"({left})::timestamp";
if (exp.Arguments.Count == 0) return $"to_char({left},'YYYY-MM-DD HH24:MI:SS.US')";
switch (args1)
{
case "'yyyy-MM-dd HH:mm:ss'": return $"to_char({left},'YYYY-MM-DD HH24:MI:SS')";
case "'yyyy-MM-dd HH:mm'": return $"to_char({left},'YYYY-MM-DD HH24:MI')";
case "'yyyy-MM-dd HH'": return $"to_char({left},'YYYY-MM-DD HH24')";
case "'yyyy-MM-dd'": return $"to_char({left},'YYYY-MM-DD')";
case "'yyyy-MM'": return $"to_char({left},'YYYY-MM')";
case "'yyyyMMddHHmmss'": return $"to_char({left},'YYYYMMDDHH24MISS')";
case "'yyyyMMddHHmm'": return $"to_char({left},'YYYYMMDDHH24MI')";
case "'yyyyMMddHH'": return $"to_char({left},'YYYYMMDDHH24')";
case "'yyyyMMdd'": return $"to_char({left},'YYYYMMDD')";
case "'yyyyMM'": return $"to_char({left},'YYYYMM')";
case "'yyyy'": return $"to_char({left},'YYYY')";
case "'HH:mm:ss'": return $"to_char({left},'HH24:MI:SS')";
}
args1 = Regex.Replace(args1, "(yyyy|yy|MM|dd|HH|hh|mm|ss|tt)", m =>
{
switch (m.Groups[1].Value)
{
case "yyyy": return $"YYYY";
case "yy": return $"YY";
case "MM": return $"%_a1";
case "dd": return $"%_a2";
case "HH": return $"%_a3";
case "hh": return $"%_a4";
case "mm": return $"%_a5";
case "ss": return $"SS";
case "tt": return $"%_a6";
}
return m.Groups[0].Value;
});
var argsFinds = new[] { "YYYY", "YY", "%_a1", "%_a2", "%_a3", "%_a4", "%_a5", "SS", "%_a6" };
var argsSpts = Regex.Split(args1, "(M|d|H|h|m|s|t)");
for (var a = 0; a < argsSpts.Length; a++)
{
switch (argsSpts[a])
{
case "M": argsSpts[a] = $"ltrim(to_char({left},'MM'),'0')"; break;
case "d": argsSpts[a] = $"case when substr(to_char({left},'DD'),1,1) = '0' then substr(to_char({left},'DD'),2,1) else to_char({left},'DD') end"; break;
case "H": argsSpts[a] = $"case when substr(to_char({left},'HH24'),1,1) = '0' then substr(to_char({left},'HH24'),2,1) else to_char({left},'HH24') end"; break;
case "h": argsSpts[a] = $"case when substr(to_char({left},'HH12'),1,1) = '0' then substr(to_char({left},'HH12'),2,1) else to_char({left},'HH12') end"; break;
case "m": argsSpts[a] = $"case when substr(to_char({left},'MI'),1,1) = '0' then substr(to_char({left},'MI'),2,1) else to_char({left},'MI') end"; break;
case "s": argsSpts[a] = $"case when substr(to_char({left},'SS'),1,1) = '0' then substr(to_char({left},'SS'),2,1) else to_char({left},'SS') end"; break;
case "t": argsSpts[a] = $"rtrim(to_char({left},'AM'),'M')"; break;
default:
var argsSptsA = argsSpts[a];
if (argsSptsA.StartsWith("'")) argsSptsA = argsSptsA.Substring(1);
if (argsSptsA.EndsWith("'")) argsSptsA = argsSptsA.Remove(argsSptsA.Length - 1);
argsSpts[a] = argsFinds.Any(m => argsSptsA.Contains(m)) ? $"to_char({left},'{argsSptsA}')" : $"'{argsSptsA}'";
break;
}
}
if (argsSpts.Length > 0) args1 = $"({string.Join(" || ", argsSpts.Where(a => a != "''"))})";
return args1.Replace("%_a1", "MM").Replace("%_a2", "DD").Replace("%_a3", "HH24").Replace("%_a4", "HH12").Replace("%_a5", "MI").Replace("%_a6", "AM");
}
}
return null;
}
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])})*{(long)1000000 * 60 * 60 * 24})";
case "FromHours": return $"(({getExp(exp.Arguments[0])})*{(long)1000000 * 60 * 60})";
case "FromMilliseconds": return $"(({getExp(exp.Arguments[0])})*1000)";
case "FromMinutes": return $"(({getExp(exp.Arguments[0])})*{(long)1000000 * 60})";
case "FromSeconds": return $"(({getExp(exp.Arguments[0])})*1000000)";
case "FromTicks": return $"(({getExp(exp.Arguments[0])})/10)";
case "Parse": return $"({getExp(exp.Arguments[0])})::int8";
case "ParseExact":
case "TryParse":
case "TryParseExact": return $"({getExp(exp.Arguments[0])})::int8";
}
}
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 $"({left})::varchar";
}
}
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 $"(({getExp(exp.Arguments[0])})::varchar not in ('0','false','f','no'))";
case "ToByte": return $"({getExp(exp.Arguments[0])})::int2";
case "ToChar": return $"substr(({getExp(exp.Arguments[0])})::char, 1, 1)";
case "ToDateTime": return ExpressionConstDateTime(exp.Arguments[0]) ?? $"({getExp(exp.Arguments[0])})::timestamp";
case "ToDecimal": return $"({getExp(exp.Arguments[0])})::numeric";
case "ToDouble": return $"({getExp(exp.Arguments[0])})::float8";
case "ToInt16": return $"({getExp(exp.Arguments[0])})::int2";
case "ToInt32": return $"({getExp(exp.Arguments[0])})::int4";
case "ToInt64": return $"({getExp(exp.Arguments[0])})::int8";
case "ToSByte": return $"({getExp(exp.Arguments[0])})::int2";
case "ToSingle": return $"({getExp(exp.Arguments[0])})::float4";
case "ToString": return $"({getExp(exp.Arguments[0])})::text";
case "ToUInt16": return $"({getExp(exp.Arguments[0])})::int2";
case "ToUInt32": return $"({getExp(exp.Arguments[0])})::int4";
case "ToUInt64": return $"({getExp(exp.Arguments[0])})::int8";
}
}
return null;
}
}
}

View File

@ -0,0 +1,45 @@
using FreeSql.Internal.CommonProvider;
using System;
using System.Data.Common;
using System.Threading;
namespace FreeSql.Custom.PostgreSQL
{
public class CustomPostgreSQLProvider<TMark> : BaseDbProvider, IFreeSql<TMark>
{
public override ISelect<T1> CreateSelectProvider<T1>(object dywhere) => new CustomPostgreSQLSelect<T1>(this, this.InternalCommonUtils, this.InternalCommonExpression, dywhere);
public override IInsert<T1> CreateInsertProvider<T1>() => new CustomPostgreSQLInsert<T1>(this, this.InternalCommonUtils, this.InternalCommonExpression);
public override IUpdate<T1> CreateUpdateProvider<T1>(object dywhere) => new CustomPostgreSQLUpdate<T1>(this, this.InternalCommonUtils, this.InternalCommonExpression, dywhere);
public override IDelete<T1> CreateDeleteProvider<T1>(object dywhere) => new CustomPostgreSQLDelete<T1>(this, this.InternalCommonUtils, this.InternalCommonExpression, dywhere);
public override IInsertOrUpdate<T1> CreateInsertOrUpdateProvider<T1>() => new CustomPostgreSQLInsertOrUpdate<T1>(this, this.InternalCommonUtils, this.InternalCommonExpression);
public CustomPostgreSQLProvider(string masterConnectionString, string[] slaveConnectionString, Func<DbConnection> connectionFactory = null)
{
this.InternalCommonUtils = new CustomPostgreSQLUtils(this);
this.InternalCommonExpression = new CustomPostgreSQLExpression(this.InternalCommonUtils);
this.Ado = new CustomPostgreSQLAdo(this.InternalCommonUtils, masterConnectionString, slaveConnectionString, connectionFactory);
this.Aop = new AopProvider();
this.DbFirst = new CustomPostgreSQLDbFirst(this, this.InternalCommonUtils, this.InternalCommonExpression);
this.CodeFirst = new CustomPostgreSQLCodeFirst(this, this.InternalCommonUtils, this.InternalCommonExpression);
}
~CustomPostgreSQLProvider() => 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);
FreeSqlCustomAdapterGlobalExtensions._dicDbProviderFactory.TryRemove(Ado.Identifier, out var trydbpf);
}
}
}
}

View File

@ -0,0 +1,168 @@
using FreeSql.Internal;
using FreeSql.Internal.Model;
using System;
using System.Collections.Generic;
using System.Data;
using System.Data.Common;
using System.Globalization;
using System.Linq;
using System.Text;
namespace FreeSql.Custom.PostgreSQL
{
class CustomPostgreSQLUtils : CommonUtils
{
DbProviderFactory Factory => FreeSqlCustomAdapterGlobalExtensions.GetDbProviderFactory(_orm);
public CustomPostgreSQLUtils(IFreeSql orm) : base(orm)
{
}
static Array getParamterArrayValue(Type arrayType, object value, object defaultValue)
{
var valueArr = value as Array;
var len = valueArr.GetLength(0);
var ret = Array.CreateInstance(arrayType, len);
for (var a = 0; a < len; a++)
{
var item = valueArr.GetValue(a);
ret.SetValue(item == null ? defaultValue : getParamterValue(item.GetType(), item, 1), a);
}
return ret;
}
static Dictionary<string, Func<object, object>> dicGetParamterValue = new Dictionary<string, Func<object, object>> {
{ typeof(uint).FullName, a => long.Parse(string.Concat(a)) }, { typeof(uint[]).FullName, a => getParamterArrayValue(typeof(long), a, 0) }, { typeof(uint?[]).FullName, a => getParamterArrayValue(typeof(long?), a, null) },
{ typeof(ulong).FullName, a => decimal.Parse(string.Concat(a)) }, { typeof(ulong[]).FullName, a => getParamterArrayValue(typeof(decimal), a, 0) }, { typeof(ulong?[]).FullName, a => getParamterArrayValue(typeof(decimal?), a, null) },
{ typeof(ushort).FullName, a => int.Parse(string.Concat(a)) }, { typeof(ushort[]).FullName, a => getParamterArrayValue(typeof(int), a, 0) }, { typeof(ushort?[]).FullName, a => getParamterArrayValue(typeof(int?), a, null) },
{ typeof(byte).FullName, a => short.Parse(string.Concat(a)) }, { typeof(byte[]).FullName, a => getParamterArrayValue(typeof(short), a, 0) }, { typeof(byte?[]).FullName, a => getParamterArrayValue(typeof(short?), a, null) },
{ typeof(sbyte).FullName, a => short.Parse(string.Concat(a)) }, { typeof(sbyte[]).FullName, a => getParamterArrayValue(typeof(short), a, 0) }, { typeof(sbyte?[]).FullName, a => getParamterArrayValue(typeof(short?), a, null) },
{ typeof(char).FullName, a => string.Concat(a).Replace('\0', ' ').ToCharArray().FirstOrDefault() },
};
static object getParamterValue(Type type, object value, int level = 0)
{
if (type.FullName == "System.Byte[]") return value;
if (type.IsArray && level == 0)
{
var elementType = type.GetElementType();
Type enumType = null;
if (elementType.IsEnum) enumType = elementType;
else if (elementType.IsNullableType())
{
var genericTypesFirst = elementType.GetGenericArguments().First();
if (genericTypesFirst.IsEnum) enumType = genericTypesFirst;
}
if (enumType != null) return enumType.GetCustomAttributes(typeof(FlagsAttribute), false).Any() ?
getParamterArrayValue(typeof(long), value, elementType.IsEnum ? null : enumType.CreateInstanceGetDefaultValue()) :
getParamterArrayValue(typeof(int), value, elementType.IsEnum ? null : enumType.CreateInstanceGetDefaultValue());
return dicGetParamterValue.TryGetValue(type.FullName, out var trydicarr) ? trydicarr(value) : value;
}
if (type.IsNullableType()) type = type.GetGenericArguments().First();
if (type.IsEnum) return (int)value;
if (dicGetParamterValue.TryGetValue(type.FullName, out var trydic)) return trydic(value);
return value;
}
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 != null) value = getParamterValue(type, value);
var ret = Factory.CreateParameter();
ret.ParameterName = QuoteParamterName(parameterName);
ret.Value = value;
//if (value.GetType().IsEnum || value.GetType().GenericTypeArguments.FirstOrDefault()?.IsEnum == true) {
// ret.DataTypeName = "";
//} else {
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 != null) value = getParamterValue(type, value);
var ret = Factory.CreateParameter();
ret.ParameterName = $"@{name}";
ret.Value = value;
//if (value.GetType().IsEnum || value.GetType().GenericTypeArguments.FirstOrDefault()?.IsEnum == true) {
// ret.DataTypeName = "";
//} else {
var tp = _orm.CodeFirst.GetDbInfo(type)?.type;
if (tp != null) ret.DbType = (DbType)tp.Value;
//}
return ret;
});
public override string FormatSql(string sql, params object[] args) => sql?.FormatCustomPostgreSQL(args);
public override string QuoteSqlNameAdapter(params string[] name)
{
if (name.Length == 1)
{
var nametrim = name[0].Trim();
if (nametrim.StartsWith("(") && nametrim.EndsWith(")"))
return nametrim; //原生SQL
if (nametrim.StartsWith("\"") && nametrim.EndsWith("\""))
return nametrim;
return $"\"{nametrim.Replace(".", "\".\"")}\"";
}
return $"\"{string.Join("\".\"", name)}\"";
}
public override string TrimQuoteSqlName(string name)
{
var nametrim = name.Trim();
if (nametrim.StartsWith("(") && nametrim.EndsWith(")"))
return nametrim; //原生SQL
return $"{nametrim.Trim('"').Replace("\".\"", ".").Replace(".\"", ".")}";
}
public override string[] SplitTableName(string name) => GetSplitTableNames(name, '"', '"', 2);
public override string QuoteParamterName(string name) => $"@{(name.ToLower())}";
public override string IsNull(string sql, object value) => $"coalesce({sql}, {value})";
public override string StringConcat(string[] objs, Type[] types) => $"{string.Join(" || ", objs)}";
public override string Mod(string left, string right, Type leftType, Type rightType) => $"{left} % {right}";
public override string Div(string left, string right, Type leftType, Type rightType) => $"{left} / {right}";
public override string Now => "current_timestamp";
public override string NowUtc => "(current_timestamp at time zone 'UTC')";
public override string QuoteWriteParamterAdapter(Type type, string paramterName) => paramterName;
protected override string QuoteReadColumnAdapter(Type type, Type mapType, string columnName) => 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);
value = getParamterValue(type, value);
var type2 = value.GetType();
if (type2 == typeof(byte[])) return $"'\\x{CommonUtils.BytesSqlRaw(value as byte[])}'";
if (type2 == typeof(TimeSpan) || type2 == typeof(TimeSpan?))
{
var ts = (TimeSpan)value;
return $"'{Math.Min(24, (int)Math.Floor(ts.TotalHours))}:{ts.Minutes}:{ts.Seconds}'";
}
else if (value is Array)
{
var valueArr = value as Array;
var eleType = type2.GetElementType();
var len = valueArr.GetLength(0);
var sb = new StringBuilder().Append("ARRAY[");
for (var a = 0; a < len; a++)
{
var item = valueArr.GetValue(a);
if (a > 0) sb.Append(",");
sb.Append(GetNoneParamaterSqlValue(specialParams, specialParamFlag, col, eleType, item));
}
sb.Append("]");
var dbinfo = _orm.CodeFirst.GetDbInfo(type);
if (dbinfo != null) sb.Append("::").Append(dbinfo.dbtype);
return sb.ToString();
}
else if (dicGetParamterValue.ContainsKey(type2.FullName))
{
value = string.Concat(value);
}
return FormatSql("{0}", value, 1);
}
}
}

View File

@ -0,0 +1,133 @@
using FreeSql.Internal;
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.SqlServer
{
class CustomSqlServerDelete<T1> : Internal.CommonProvider.DeleteProvider<T1>
{
public CustomSqlServerDelete(IFreeSql orm, CommonUtils commonUtils, CommonExpression commonExpression, object dywhere)
: base(orm, commonUtils, commonExpression, dywhere)
{
}
public override List<T1> ExecuteDeleted()
{
var ret = new List<T1>();
DbParameter[] dbParms = null;
StringBuilder sbret = null;
ToSqlFetch(sb =>
{
if (dbParms == null)
{
dbParms = _params.ToArray();
sbret = new StringBuilder();
sbret.Append(" OUTPUT ");
var colidx = 0;
foreach (var col in _table.Columns.Values)
{
if (colidx > 0) sbret.Append(", ");
sbret.Append(_commonUtils.RereadColumn(col, $"DELETED.{_commonUtils.QuoteSqlName(col.Attribute.Name)}")).Append(" as ").Append(_commonUtils.QuoteSqlName(col.CsName));
++colidx;
}
}
var sql = sb.ToString();
var validx = sql.IndexOf(" WHERE ");
if (validx == -1) throw new ArgumentException(CoreStrings.S_NotFound_Name("WHERE"));
sql = sb.Clear().Append(sql.Substring(0, validx))
.Append(sbret)
.Append(sql.Substring(validx)).ToString();
var before = new Aop.CurdBeforeEventArgs(_table.Type, _table, Aop.CurdType.Delete, sql, dbParms);
_orm.Aop.CurdBeforeHandler?.Invoke(this, before);
Exception exception = null;
try
{
ret.AddRange(_orm.Ado.Query<T1>(_table.TypeLazy ?? _table.Type, _connection, _transaction, CommandType.Text, sql, _commandTimeout, dbParms));
}
catch (Exception ex)
{
exception = ex;
throw ex;
}
finally
{
var after = new Aop.CurdAfterEventArgs(before, exception, ret);
_orm.Aop.CurdAfterHandler?.Invoke(this, after);
}
});
if (dbParms != null)
{
this.ClearData();
sbret.Clear();
}
return ret;
}
#if net40
#else
async public override Task<List<T1>> ExecuteDeletedAsync(CancellationToken cancellationToken = default)
{
var ret = new List<T1>();
DbParameter[] dbParms = null;
StringBuilder sbret = null;
await ToSqlFetchAsync(async sb =>
{
if (dbParms == null)
{
dbParms = _params.ToArray();
sbret = new StringBuilder();
sbret.Append(" OUTPUT ");
var colidx = 0;
foreach (var col in _table.Columns.Values)
{
if (colidx > 0) sbret.Append(", ");
sbret.Append(_commonUtils.RereadColumn(col, $"DELETED.{_commonUtils.QuoteSqlName(col.Attribute.Name)}")).Append(" as ").Append(_commonUtils.QuoteSqlName(col.CsName));
++colidx;
}
}
var sql = sb.ToString();
var validx = sql.IndexOf(" WHERE ");
if (validx == -1) throw new ArgumentException(CoreStrings.S_NotFound_Name("WHERE"));
sql = sb.Clear().Append(sql.Substring(0, validx))
.Append(sbret)
.Append(sql.Substring(validx)).ToString();
var before = new Aop.CurdBeforeEventArgs(_table.Type, _table, Aop.CurdType.Delete, sql, dbParms);
_orm.Aop.CurdBeforeHandler?.Invoke(this, before);
Exception exception = null;
try
{
ret.AddRange(await _orm.Ado.QueryAsync<T1>(_table.TypeLazy ?? _table.Type, _connection, _transaction, CommandType.Text, sql, _commandTimeout, dbParms, cancellationToken));
}
catch (Exception ex)
{
exception = ex;
throw ex;
}
finally
{
var after = new Aop.CurdAfterEventArgs(before, exception, ret);
_orm.Aop.CurdAfterHandler?.Invoke(this, after);
}
});
if (dbParms != null)
{
this.ClearData();
sbret.Clear();
}
return ret;
}
#endif
}
}

View File

@ -0,0 +1,191 @@
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.SqlServer
{
class CustomSqlServerInsert<T1> : Internal.CommonProvider.InsertProvider<T1> where T1 : class
{
public CustomSqlServerInsert(IFreeSql orm, CommonUtils commonUtils, CommonExpression commonExpression)
: base(orm, commonUtils, commonExpression)
{
}
public override int ExecuteAffrows() => base.SplitExecuteAffrows(_batchValuesLimit > 0 ? _batchValuesLimit : 1000, _batchParameterLimit > 0 ? _batchParameterLimit : 2100);
public override long ExecuteIdentity() => base.SplitExecuteIdentity(_batchValuesLimit > 0 ? _batchValuesLimit : 1000, _batchParameterLimit > 0 ? _batchParameterLimit : 2100);
public override List<T1> ExecuteInserted() => base.SplitExecuteInserted(_batchValuesLimit > 0 ? _batchValuesLimit : 1000, _batchParameterLimit > 0 ? _batchParameterLimit : 2100);
public override string ToSql()
{
var versionGreaterThan10 = (_commonUtils as CustomSqlServerUtils).ServerVersion > 10;
return this.ToSqlValuesOrSelectUnionAll(versionGreaterThan10);
}
protected override long RawExecuteIdentity()
{
var sql = this.ToSql();
if (string.IsNullOrEmpty(sql)) return 0;
sql = string.Concat(sql, "; SELECT SCOPE_IDENTITY();");
var before = new Aop.CurdBeforeEventArgs(_table.Type, _table, Aop.CurdType.Insert, sql, _params);
_orm.Aop.CurdBeforeHandler?.Invoke(this, before);
long ret = 0;
Exception exception = null;
try
{
long.TryParse(string.Concat(_orm.Ado.ExecuteScalar(_connection, _transaction, CommandType.Text, sql, _commandTimeout, _params)), out ret);
}
catch (Exception ex)
{
exception = ex;
throw ex;
}
finally
{
var after = new Aop.CurdAfterEventArgs(before, exception, ret);
_orm.Aop.CurdAfterHandler?.Invoke(this, after);
}
return ret;
}
protected override List<T1> RawExecuteInserted()
{
var sql = this.ToSql();
if (string.IsNullOrEmpty(sql)) return new List<T1>();
var sb = new StringBuilder();
sb.Append(" OUTPUT ");
var colidx = 0;
foreach (var col in _table.Columns.Values)
{
if (colidx > 0) sb.Append(", ");
sb.Append(_commonUtils.RereadColumn(col, $"INSERTED.{_commonUtils.QuoteSqlName(col.Attribute.Name)}")).Append(" as ").Append(_commonUtils.QuoteSqlName(col.CsName));
++colidx;
}
if ((_commonUtils as CustomSqlServerUtils).ServerVersion > 10)
{
var validx = sql.IndexOf(") VALUES");
if (validx == -1) throw new ArgumentException(CoreStrings.S_NotFound_Name("VALUES"));
sb.Insert(0, sql.Substring(0, validx + 1));
sb.Append(sql.Substring(validx + 1));
}
else
{
var validx = sql.IndexOf(") SELECT ");
if (validx == -1) throw new ArgumentException(CoreStrings.S_NotFound_Name("SELECT"));
sb.Insert(0, sql.Substring(0, validx + 1));
sb.Append(sql.Substring(validx + 1));
}
sql = sb.ToString();
var before = new Aop.CurdBeforeEventArgs(_table.Type, _table, Aop.CurdType.Insert, sql, _params);
_orm.Aop.CurdBeforeHandler?.Invoke(this, before);
var ret = new List<T1>();
Exception exception = null;
try
{
ret = _orm.Ado.Query<T1>(_table.TypeLazy ?? _table.Type, _connection, _transaction, CommandType.Text, sql, _commandTimeout, _params);
}
catch (Exception ex)
{
exception = ex;
throw ex;
}
finally
{
var after = new Aop.CurdAfterEventArgs(before, exception, ret);
_orm.Aop.CurdAfterHandler?.Invoke(this, after);
}
return ret;
}
#if net40
#else
public override Task<int> ExecuteAffrowsAsync(CancellationToken cancellationToken = default) => base.SplitExecuteAffrowsAsync(_batchValuesLimit > 0 ? _batchValuesLimit : 1000, _batchParameterLimit > 0 ? _batchParameterLimit : 2100, cancellationToken);
public override Task<long> ExecuteIdentityAsync(CancellationToken cancellationToken = default) => base.SplitExecuteIdentityAsync(_batchValuesLimit > 0 ? _batchValuesLimit : 1000, _batchParameterLimit > 0 ? _batchParameterLimit : 2100, cancellationToken);
public override Task<List<T1>> ExecuteInsertedAsync(CancellationToken cancellationToken = default) => base.SplitExecuteInsertedAsync(_batchValuesLimit > 0 ? _batchValuesLimit : 1000, _batchParameterLimit > 0 ? _batchParameterLimit : 2100, cancellationToken);
async protected override Task<long> RawExecuteIdentityAsync(CancellationToken cancellationToken = default)
{
var sql = this.ToSql();
if (string.IsNullOrEmpty(sql)) return 0;
sql = string.Concat(sql, "; SELECT SCOPE_IDENTITY();");
var before = new Aop.CurdBeforeEventArgs(_table.Type, _table, Aop.CurdType.Insert, sql, _params);
_orm.Aop.CurdBeforeHandler?.Invoke(this, before);
long ret = 0;
Exception exception = null;
try
{
long.TryParse(string.Concat(await _orm.Ado.ExecuteScalarAsync(_connection, _transaction, CommandType.Text, sql, _commandTimeout, _params, cancellationToken)), out ret);
}
catch (Exception ex)
{
exception = ex;
throw ex;
}
finally
{
var after = new Aop.CurdAfterEventArgs(before, exception, ret);
_orm.Aop.CurdAfterHandler?.Invoke(this, after);
}
return ret;
}
async protected override Task<List<T1>> RawExecuteInsertedAsync(CancellationToken cancellationToken = default)
{
var sql = this.ToSql();
if (string.IsNullOrEmpty(sql)) return new List<T1>();
var sb = new StringBuilder();
sb.Append(" OUTPUT ");
var colidx = 0;
foreach (var col in _table.Columns.Values)
{
if (colidx > 0) sb.Append(", ");
sb.Append(_commonUtils.RereadColumn(col, $"INSERTED.{_commonUtils.QuoteSqlName(col.Attribute.Name)}")).Append(" as ").Append(_commonUtils.QuoteSqlName(col.CsName));
++colidx;
}
if ((_commonUtils as CustomSqlServerUtils).ServerVersion > 10)
{
var validx = sql.IndexOf(") VALUES");
if (validx == -1) throw new ArgumentException(CoreStrings.S_NotFound_Name("VALUES"));
sb.Insert(0, sql.Substring(0, validx + 1));
sb.Append(sql.Substring(validx + 1));
}
else
{
var validx = sql.IndexOf(") SELECT ");
if (validx == -1) throw new ArgumentException(CoreStrings.S_NotFound_Name("SELECT"));
sb.Insert(0, sql.Substring(0, validx + 1));
sb.Append(sql.Substring(validx + 1));
}
sql = sb.ToString();
var before = new Aop.CurdBeforeEventArgs(_table.Type, _table, Aop.CurdType.Insert, sql, _params);
_orm.Aop.CurdBeforeHandler?.Invoke(this, before);
var ret = new List<T1>();
Exception exception = null;
try
{
ret = await _orm.Ado.QueryAsync<T1>(_table.TypeLazy ?? _table.Type, _connection, _transaction, CommandType.Text, sql, _commandTimeout, _params, cancellationToken);
}
catch (Exception ex)
{
exception = ex;
throw ex;
}
finally
{
var after = new Aop.CurdAfterEventArgs(before, exception, ret);
_orm.Aop.CurdAfterHandler?.Invoke(this, after);
}
return ret;
}
#endif
}
}

View File

@ -0,0 +1,89 @@
using FreeSql.Internal;
using System;
using System.Collections.Generic;
using System.Data.Common;
using System.Linq;
using System.Text;
namespace FreeSql.Custom.SqlServer
{
class CustomSqlServerInsertOrUpdate<T1> : Internal.CommonProvider.InsertOrUpdateProvider<T1> where T1 : class
{
public CustomSqlServerInsertOrUpdate(IFreeSql orm, CommonUtils commonUtils, CommonExpression commonExpression)
: base(orm, commonUtils, commonExpression)
{
}
public override string ToSql()
{
var dbParams = new List<DbParameter>();
if (_sourceSql != null) return getMergeSql(null);
if (_source?.Any() != true) return null;
var sqls = new string[2];
var ds = SplitSourceByIdentityValueIsNull(_source);
if (ds.Item1.Any()) sqls[0] = string.Join("\r\n\r\n;\r\n\r\n", ds.Item1.Select(a => getMergeSql(a)));
if (ds.Item2.Any()) sqls[1] = string.Join("\r\n\r\n;\r\n\r\n", ds.Item2.Select(a => getInsertSql(a)));
_params = dbParams.ToArray();
if (ds.Item2.Any() == false) return sqls[0];
if (ds.Item1.Any() == false) return sqls[1];
return string.Join("\r\n\r\n;\r\n\r\n", sqls);
string getMergeSql(List<T1> data)
{
if (_tempPrimarys.Any() == false) throw new Exception(CoreStrings.InsertOrUpdate_Must_Primary_Key(_table.CsName));
var tempPrimaryIsIdentity = _tempPrimarys.Any(b => b.Attribute.IsIdentity);
var sb = new StringBuilder();
if (IdentityColumn != null && tempPrimaryIsIdentity) sb.Append("SET IDENTITY_INSERT ").Append(_commonUtils.QuoteSqlName(TableRuleInvoke())).Append(" ON;\r\n");
sb.Append("MERGE INTO ").Append(_commonUtils.QuoteSqlName(TableRuleInvoke())).Append(" t1 \r\nUSING (");
WriteSourceSelectUnionAll(data, sb, dbParams);
sb.Append(" ) t2 ON (").Append(string.Join(" AND ", _tempPrimarys.Select(a => $"t1.{_commonUtils.QuoteSqlName(a.Attribute.Name)} = t2.{_commonUtils.QuoteSqlName(a.Attribute.Name)}"))).Append(") \r\n");
var cols = _table.Columns.Values.Where(a => _updateSetDict.ContainsKey(a.Attribute.Name) ||
_tempPrimarys.Contains(a) == false && a.Attribute.CanUpdate == true && a.Attribute.IsIdentity == false && _updateIgnore.ContainsKey(a.Attribute.Name) == false);
if (_doNothing == false && cols.Any())
sb.Append("WHEN MATCHED THEN \r\n")
.Append(" update set ").Append(string.Join(", ", cols.Select(a =>
{
if (_updateSetDict.TryGetValue(a.Attribute.Name, out var valsql))
return $"{_commonUtils.QuoteSqlName(a.Attribute.Name)} = {valsql}";
return a.Attribute.IsVersion && a.Attribute.MapType != typeof(byte[]) ?
$"{_commonUtils.QuoteSqlName(a.Attribute.Name)} = t1.{_commonUtils.QuoteSqlName(a.Attribute.Name)} + 1" :
$"{_commonUtils.QuoteSqlName(a.Attribute.Name)} = t2.{_commonUtils.QuoteSqlName(a.Attribute.Name)}";
}))).Append(" \r\n");
cols = _table.Columns.Values.Where(a => a.Attribute.CanInsert == true);
if (tempPrimaryIsIdentity == false) cols = cols.Where(a => a.Attribute.IsIdentity == false || string.IsNullOrEmpty(a.DbInsertValue) == false);
if (cols.Any())
sb.Append("WHEN NOT MATCHED THEN \r\n")
.Append(" insert (").Append(string.Join(", ", cols.Select(a => _commonUtils.QuoteSqlName(a.Attribute.Name)))).Append(") \r\n")
.Append(" values (").Append(string.Join(", ", cols.Select(a =>
{
//InsertValueSql = "seq.nextval"
if (tempPrimaryIsIdentity == false && a.Attribute.IsIdentity && string.IsNullOrEmpty(a.DbInsertValue) == false) return a.DbInsertValue;
return $"t2.{_commonUtils.QuoteSqlName(a.Attribute.Name)}";
}))).Append(");");
if (IdentityColumn != null && tempPrimaryIsIdentity) sb.Append(";\r\nSET IDENTITY_INSERT ").Append(_commonUtils.QuoteSqlName(TableRuleInvoke())).Append(" OFF;");
return sb.ToString();
}
string getInsertSql(List<T1> data)
{
var insert = _orm.Insert<T1>()
.AsTable(_tableRule).AsType(_table.Type)
.WithConnection(_connection)
.WithTransaction(_transaction)
.NoneParameter(true) as Internal.CommonProvider.InsertProvider<T1>;
insert._source = data;
insert._table = _table;
var sql = insert.ToSql();
if (string.IsNullOrEmpty(sql)) return null;
if (insert._params?.Any() == true) dbParams.AddRange(insert._params);
return sql;
}
}
}
}

View File

@ -0,0 +1,408 @@
using FreeSql.Internal;
using FreeSql.Internal.Model;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Linq.Expressions;
using System.Text;
using System.Text.RegularExpressions;
namespace FreeSql.Custom.SqlServer
{
class CustomSqlServerSelect<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)
=> (_commonUtils as CustomSqlServerUtils).IsSelectRowNumber ?
ToSqlStaticRowNumber(_commonUtils, _commonExpression, _select, _distinct, field, _join, _where, _groupby, _having, _orderby, _skip, _limit, _tables, tbUnions, _aliasRule, _tosqlAppendContent, _whereGlobalFilter, _orm) :
ToSqlStaticOffsetFetchNext(_commonUtils, _commonExpression, _select, _distinct, field, _join, _where, _groupby, _having, _orderby, _skip, _limit, _tables, tbUnions, _aliasRule, _tosqlAppendContent, _whereGlobalFilter, _orm);
#region SqlServer 2005 row_number
internal static string ToSqlStaticRowNumber(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)
{
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.Where(a => a.Before == false), true);
tb.CascadeBefore = _commonExpression.GetWhereCascadeSql(tb, _whereGlobalFilter.Where(a => a.Before == true), 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) sb.Append("TOP ").Append(_skip + _limit).Append(" "); //TOP 会引发 __rownum__ 无序的问题
if (_skip <= 0 && _limit > 0) sb.Append("TOP ").Append(_limit).Append(" ");
var rownum = "";
if (_limit > 0 || _skip > 0)
{
if (string.IsNullOrEmpty(_orderby) && (_limit > 1 || _skip > 0)) //TOP 1 不自动 order by
{
if (string.IsNullOrEmpty(_groupby))
{
var pktb = _tables.Where(a => a.Table.Primarys.Any()).FirstOrDefault();
if (pktb != null) _orderby = string.Concat(" \r\nORDER BY ", pktb.Alias, ".", _commonUtils.QuoteSqlName(pktb?.Table.Primarys.First().Attribute.Name));
else if (_tables.FirstOrDefault()?.Table?.Columns?.Any() == true) _orderby = string.Concat(" \r\nORDER BY ", _tables.First().Alias, ".", _commonUtils.QuoteSqlName(_tables.First().Table.Columns.First().Value.Attribute.Name));
else _orderby = " \r\nORDER BY getdate()";
}
else
_orderby = _groupby.Replace("GROUP BY ", "ORDER BY ");
}
if (_skip > 0) // 注意这个判断,大于 0 才使用 ROW_NUMBER ,否则属于第一页直接使用 TOP
rownum = $", ROW_NUMBER() OVER({_orderby.Trim('\r', '\n', ' ')}) AS __rownum__";
}
var tbsjoin = _tables.Where(a => a.Type != SelectTableInfoType.From).ToArray();
var tbsfrom = _tables.Where(a => a.Type == SelectTableInfoType.From).ToArray();
if (string.IsNullOrEmpty(rownum) == false && field == "*")
sb.Append(tbsfrom[0].Alias).Append("."); //#1519 bug
sb.Append(field).Append(rownum);
sb.Append(" \r\nFROM ");
for (var a = 0; a < tbsfrom.Length; a++)
{
var alias = LocalGetTableAlias(tbsfrom[a].Table.Type, tbUnion[tbsfrom[a].Table.Type], tbsfrom[a].Alias, _aliasRule);
sb.Append(_commonUtils.QuoteSqlName(tbUnion[tbsfrom[a].Table.Type])).Append(" ").Append(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++)
{
alias = LocalGetTableAlias(tbsfrom[b].Table.Type, tbUnion[tbsfrom[b].Table.Type], tbsfrom[b].Alias, _aliasRule);
sb.Append(" \r\nLEFT JOIN ").Append(_commonUtils.QuoteSqlName(tbUnion[tbsfrom[b].Table.Type])).Append(" ").Append(alias);
if (string.IsNullOrEmpty(tbsfrom[b].NavigateCondition) &&
string.IsNullOrEmpty(tbsfrom[b].On) &&
string.IsNullOrEmpty(tbsfrom[b].Cascade) &&
string.IsNullOrEmpty(tbsfrom[b].CascadeBefore)) sb.Append(" ON 1 = 1");
else sb.Append(" ON ").Append(string.Join(" AND ", new[]
{
tbsfrom[b].CascadeBefore,
tbsfrom[b].NavigateCondition ?? tbsfrom[b].On,
tbsfrom[b].Cascade
}.Where(sql => string.IsNullOrEmpty(sql) == false)));
}
break;
}
else
{
if (a > 0 && !string.IsNullOrEmpty(tbsfrom[a].CascadeBefore)) sbnav.Append(" AND ").Append(tbsfrom[a].CascadeBefore);
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)
{
switch (tb.Type)
{
case SelectTableInfoType.Parent:
case SelectTableInfoType.RawJoin:
continue;
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;
}
var alias = LocalGetTableAlias(tb.Table.Type, tbUnion[tb.Table.Type], tb.Alias, _aliasRule);
sb.Append(_commonUtils.QuoteSqlName(tbUnion[tb.Table.Type])).Append(" ").Append(alias)
.Append(" ON ").Append(string.Join(" AND ", new[]
{
tb.CascadeBefore,
tb.On ?? tb.NavigateCondition,
tb.Cascade
}.Where(sql => string.IsNullOrEmpty(sql) == false)));
if (!string.IsNullOrEmpty(tb.On) && !string.IsNullOrEmpty(tb.NavigateCondition)) sbnav.Append(" AND (").Append(tb.NavigateCondition).Append(")");
}
if (_join.Length > 0) sb.Append(_join);
if (!string.IsNullOrEmpty(_tables[0].CascadeBefore)) sbnav.Append(" AND ").Append(_tables[0].CascadeBefore);
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));
}
if (_skip <= 0)
sb.Append(_orderby);
else
{
sb.Insert(0, "WITH t AS ( ").Append(" ) SELECT t.* FROM t where __rownum__");
if (_limit > 0)
sb.Append(" between ").Append(_skip + 1).Append(" and ").Append(_skip + _limit);
else
sb.Append(" > ").Append(_skip);
}
sbnav.Clear();
if (tbUnionsGt0) sb.Append(") ftb");
}
return sb.Append(_tosqlAppendContent).ToString();
}
#endregion
#region SqlServer 2012+ offset feach next
internal static string ToSqlStaticOffsetFetchNext(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)
{
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.Where(a => a.Before == false), true);
tb.CascadeBefore = _commonExpression.GetWhereCascadeSql(tb, _whereGlobalFilter.Where(a => a.Before == true), 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 (_skip <= 0 && _limit > 0) sb.Append("TOP ").Append(_limit).Append(" ");
sb.Append(field);
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++)
{
var alias = LocalGetTableAlias(tbsfrom[a].Table.Type, tbUnion[tbsfrom[a].Table.Type], tbsfrom[a].Alias, _aliasRule);
sb.Append(_commonUtils.QuoteSqlName(tbUnion[tbsfrom[a].Table.Type])).Append(" ").Append(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++)
{
alias = LocalGetTableAlias(tbsfrom[b].Table.Type, tbUnion[tbsfrom[b].Table.Type], tbsfrom[b].Alias, _aliasRule);
sb.Append(" \r\nLEFT JOIN ").Append(_commonUtils.QuoteSqlName(tbUnion[tbsfrom[b].Table.Type])).Append(" ").Append(alias);
if (string.IsNullOrEmpty(tbsfrom[b].NavigateCondition) &&
string.IsNullOrEmpty(tbsfrom[b].On) &&
string.IsNullOrEmpty(tbsfrom[b].Cascade) &&
string.IsNullOrEmpty(tbsfrom[b].CascadeBefore)) sb.Append(" ON 1 = 1");
else sb.Append(" ON ").Append(string.Join(" AND ", new[]
{
tbsfrom[b].CascadeBefore,
tbsfrom[b].NavigateCondition ?? tbsfrom[b].On,
tbsfrom[b].Cascade
}.Where(sql => string.IsNullOrEmpty(sql) == false)));
}
break;
}
else
{
if (a > 0 && !string.IsNullOrEmpty(tbsfrom[a].CascadeBefore)) sbnav.Append(" AND ").Append(tbsfrom[a].CascadeBefore);
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)
{
switch (tb.Type)
{
case SelectTableInfoType.Parent:
case SelectTableInfoType.RawJoin:
continue;
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;
}
var alias = LocalGetTableAlias(tb.Table.Type, tbUnion[tb.Table.Type], tb.Alias, _aliasRule);
sb.Append(_commonUtils.QuoteSqlName(tbUnion[tb.Table.Type])).Append(" ").Append(alias)
.Append(" ON ").Append(string.Join(" AND ", new[]
{
tb.CascadeBefore,
tb.On ?? tb.NavigateCondition,
tb.Cascade
}.Where(sql => string.IsNullOrEmpty(sql) == false)));
if (!string.IsNullOrEmpty(tb.On) && !string.IsNullOrEmpty(tb.NavigateCondition)) sbnav.Append(" AND (").Append(tb.NavigateCondition).Append(")");
}
if (_join.Length > 0) sb.Append(_join);
if (!string.IsNullOrEmpty(_tables[0].CascadeBefore)) sbnav.Append(" AND ").Append(_tables[0].CascadeBefore);
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));
}
if (_skip > 0)
{
if (string.IsNullOrEmpty(_orderby))
{
if (string.IsNullOrEmpty(_groupby))
{
var pktb = _tables.Where(a => a.Table.Primarys.Any()).FirstOrDefault();
if (pktb != null) _orderby = string.Concat(" \r\nORDER BY ", pktb.Alias, ".", _commonUtils.QuoteSqlName(pktb?.Table.Primarys.First().Attribute.Name));
else if (_tables.FirstOrDefault()?.Table?.Columns?.Any() == true) _orderby = string.Concat(" \r\nORDER BY ", _tables.First().Alias, ".", _commonUtils.QuoteSqlName(_tables.First().Table.Columns.First().Value.Attribute.Name));
else _orderby = " \r\nORDER BY getdate()";
}
else
_orderby = _groupby.Replace("GROUP BY ", "ORDER BY ");
}
sb.Append(_orderby).Append($" \r\nOFFSET {_skip} ROW");
if (_limit > 0) sb.Append($" \r\nFETCH NEXT {_limit} ROW ONLY");
}
else
{
sb.Append(_orderby);
}
sbnav.Clear();
if (tbUnionsGt0) sb.Append(") ftb");
}
return sb.Append(_tosqlAppendContent).ToString();
}
#endregion
static string LocalGetTableAlias(Type entityType, string tbname, string alias, Func<Type, string, string> aliasRule)
{
if (aliasRule != null)
{
alias = aliasRule(entityType, alias);
if (tbname.IndexOf(' ') != -1) //还可以这样select.AsTable((a, b) => "(select * from tb_topic where clicks > 10)").Page(1, 10).ToList()
alias = Regex.Replace(alias, @" With\([^\)]+\)", ""); //替换 WithLock、WithIndex
}
return alias;
}
public CustomSqlServerSelect(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 OdbcSqlServerSelect<T1, T2>(_orm, _commonUtils, _commonExpression, null); CustomSqlServerSelect<T1>.CopyData(this, 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 OdbcSqlServerSelect<T1, T2, T3>(_orm, _commonUtils, _commonExpression, null); CustomSqlServerSelect<T1>.CopyData(this, 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 OdbcSqlServerSelect<T1, T2, T3, T4>(_orm, _commonUtils, _commonExpression, null); CustomSqlServerSelect<T1>.CopyData(this, 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 OdbcSqlServerSelect<T1, T2, T3, T4, T5>(_orm, _commonUtils, _commonExpression, null); CustomSqlServerSelect<T1>.CopyData(this, 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 OdbcSqlServerSelect<T1, T2, T3, T4, T5, T6>(_orm, _commonUtils, _commonExpression, null); CustomSqlServerSelect<T1>.CopyData(this, 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 OdbcSqlServerSelect<T1, T2, T3, T4, T5, T6, T7>(_orm, _commonUtils, _commonExpression, null); CustomSqlServerSelect<T1>.CopyData(this, 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 OdbcSqlServerSelect<T1, T2, T3, T4, T5, T6, T7, T8>(_orm, _commonUtils, _commonExpression, null); CustomSqlServerSelect<T1>.CopyData(this, 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 OdbcSqlServerSelect<T1, T2, T3, T4, T5, T6, T7, T8, T9>(_orm, _commonUtils, _commonExpression, null); CustomSqlServerSelect<T1>.CopyData(this, 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 OdbcSqlServerSelect<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10>(_orm, _commonUtils, _commonExpression, null); CustomSqlServerSelect<T1>.CopyData(this, 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 OdbcSqlServerSelect<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11>(_orm, _commonUtils, _commonExpression, null); CustomSqlServerSelect<T1>.CopyData(this, 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 OdbcSqlServerSelect<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12>(_orm, _commonUtils, _commonExpression, null); CustomSqlServerSelect<T1>.CopyData(this, 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 OdbcSqlServerSelect<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13>(_orm, _commonUtils, _commonExpression, null); CustomSqlServerSelect<T1>.CopyData(this, 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 OdbcSqlServerSelect<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14>(_orm, _commonUtils, _commonExpression, null); CustomSqlServerSelect<T1>.CopyData(this, 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 OdbcSqlServerSelect<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15>(_orm, _commonUtils, _commonExpression, null); CustomSqlServerSelect<T1>.CopyData(this, 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 OdbcSqlServerSelect<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15, T16>(_orm, _commonUtils, _commonExpression, null); CustomSqlServerSelect<T1>.CopyData(this, 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 OdbcSqlServerSelect<T1, T2> : FreeSql.Internal.CommonProvider.Select2Provider<T1, T2> where T2 : class
{
public OdbcSqlServerSelect(IFreeSql orm, CommonUtils commonUtils, CommonExpression commonExpression, object dywhere) : base(orm, commonUtils, commonExpression, dywhere) { }
public override string ToSql(string field = null) => CustomSqlServerSelect<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 OdbcSqlServerSelect<T1, T2, T3> : FreeSql.Internal.CommonProvider.Select3Provider<T1, T2, T3> where T2 : class where T3 : class
{
public OdbcSqlServerSelect(IFreeSql orm, CommonUtils commonUtils, CommonExpression commonExpression, object dywhere) : base(orm, commonUtils, commonExpression, dywhere) { }
public override string ToSql(string field = null) => CustomSqlServerSelect<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 OdbcSqlServerSelect<T1, T2, T3, T4> : FreeSql.Internal.CommonProvider.Select4Provider<T1, T2, T3, T4> where T2 : class where T3 : class where T4 : class
{
public OdbcSqlServerSelect(IFreeSql orm, CommonUtils commonUtils, CommonExpression commonExpression, object dywhere) : base(orm, commonUtils, commonExpression, dywhere) { }
public override string ToSql(string field = null) => CustomSqlServerSelect<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 OdbcSqlServerSelect<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 OdbcSqlServerSelect(IFreeSql orm, CommonUtils commonUtils, CommonExpression commonExpression, object dywhere) : base(orm, commonUtils, commonExpression, dywhere) { }
public override string ToSql(string field = null) => CustomSqlServerSelect<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 OdbcSqlServerSelect<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 OdbcSqlServerSelect(IFreeSql orm, CommonUtils commonUtils, CommonExpression commonExpression, object dywhere) : base(orm, commonUtils, commonExpression, dywhere) { }
public override string ToSql(string field = null) => CustomSqlServerSelect<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 OdbcSqlServerSelect<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 OdbcSqlServerSelect(IFreeSql orm, CommonUtils commonUtils, CommonExpression commonExpression, object dywhere) : base(orm, commonUtils, commonExpression, dywhere) { }
public override string ToSql(string field = null) => CustomSqlServerSelect<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 OdbcSqlServerSelect<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 OdbcSqlServerSelect(IFreeSql orm, CommonUtils commonUtils, CommonExpression commonExpression, object dywhere) : base(orm, commonUtils, commonExpression, dywhere) { }
public override string ToSql(string field = null) => CustomSqlServerSelect<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 OdbcSqlServerSelect<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 OdbcSqlServerSelect(IFreeSql orm, CommonUtils commonUtils, CommonExpression commonExpression, object dywhere) : base(orm, commonUtils, commonExpression, dywhere) { }
public override string ToSql(string field = null) => CustomSqlServerSelect<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 OdbcSqlServerSelect<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 OdbcSqlServerSelect(IFreeSql orm, CommonUtils commonUtils, CommonExpression commonExpression, object dywhere) : base(orm, commonUtils, commonExpression, dywhere) { }
public override string ToSql(string field = null) => CustomSqlServerSelect<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 OdbcSqlServerSelect<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 OdbcSqlServerSelect(IFreeSql orm, CommonUtils commonUtils, CommonExpression commonExpression, object dywhere) : base(orm, commonUtils, commonExpression, dywhere) { }
public override string ToSql(string field = null) => CustomSqlServerSelect<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 OdbcSqlServerSelect<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 OdbcSqlServerSelect(IFreeSql orm, CommonUtils commonUtils, CommonExpression commonExpression, object dywhere) : base(orm, commonUtils, commonExpression, dywhere) { }
public override string ToSql(string field = null) => CustomSqlServerSelect<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 OdbcSqlServerSelect<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 OdbcSqlServerSelect(IFreeSql orm, CommonUtils commonUtils, CommonExpression commonExpression, object dywhere) : base(orm, commonUtils, commonExpression, dywhere) { }
public override string ToSql(string field = null) => CustomSqlServerSelect<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 OdbcSqlServerSelect<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 OdbcSqlServerSelect(IFreeSql orm, CommonUtils commonUtils, CommonExpression commonExpression, object dywhere) : base(orm, commonUtils, commonExpression, dywhere) { }
public override string ToSql(string field = null) => CustomSqlServerSelect<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 OdbcSqlServerSelect<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 OdbcSqlServerSelect(IFreeSql orm, CommonUtils commonUtils, CommonExpression commonExpression, object dywhere) : base(orm, commonUtils, commonExpression, dywhere) { }
public override string ToSql(string field = null) => CustomSqlServerSelect<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 OdbcSqlServerSelect<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 OdbcSqlServerSelect(IFreeSql orm, CommonUtils commonUtils, CommonExpression commonExpression, object dywhere) : base(orm, commonUtils, commonExpression, dywhere) { }
public override string ToSql(string field = null) => CustomSqlServerSelect<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,175 @@
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.Threading;
using System.Threading.Tasks;
namespace FreeSql.Custom.SqlServer
{
class CustomSqlServerUpdate<T1> : Internal.CommonProvider.UpdateProvider<T1>
{
public CustomSqlServerUpdate(IFreeSql orm, CommonUtils commonUtils, CommonExpression commonExpression, object dywhere)
: base(orm, commonUtils, commonExpression, dywhere)
{
}
public override int ExecuteAffrows() => base.SplitExecuteAffrows(_batchRowsLimit > 0 ? _batchRowsLimit : 500, _batchParameterLimit > 0 ? _batchParameterLimit : 2100);
protected override List<TReturn> ExecuteUpdated<TReturn>(IEnumerable<ColumnInfo> columns) => base.SplitExecuteUpdated<TReturn>(_batchRowsLimit > 0 ? _batchRowsLimit : 500, _batchParameterLimit > 0 ? _batchParameterLimit : 2100, columns);
protected override List<TReturn> RawExecuteUpdated<TReturn>(IEnumerable<ColumnInfo> columns)
{
var ret = new List<TReturn>();
DbParameter[] dbParms = null;
StringBuilder sbret = null;
ToSqlFetch(sb =>
{
if (dbParms == null)
{
dbParms = _params.Concat(_paramsSource).ToArray();
sbret = new StringBuilder();
sbret.Append(" OUTPUT ");
var colidx = 0;
foreach (var col in columns)
{
if (colidx > 0) sbret.Append(", ");
sbret.Append(_commonUtils.RereadColumn(col, $"INSERTED.{_commonUtils.QuoteSqlName(col.Attribute.Name)}")).Append(" as ").Append(_commonUtils.QuoteSqlName(col.CsName));
++colidx;
}
}
var sql = sb.ToString();
var validx = sql.IndexOf(" \r\nWHERE ");
if (validx == -1) throw new ArgumentException(CoreStrings.S_NotFound_Name("WHERE"));
sql = sb.Clear().Append(sql.Substring(0, validx))
.Append(sbret)
.Append(sql.Substring(validx)).ToString();
var before = new Aop.CurdBeforeEventArgs(_table.Type, _table, Aop.CurdType.Update, sql, dbParms);
_orm.Aop.CurdBeforeHandler?.Invoke(this, before);
Exception exception = null;
try
{
var queryType = typeof(TReturn) == typeof(T1) ? (_table.TypeLazy ?? _table.Type) : null;
var rettmp = _orm.Ado.Query<TReturn>(queryType, _connection, _transaction, CommandType.Text, sql, _commandTimeout, dbParms);
ValidateVersionAndThrow(rettmp.Count, sql, dbParms);
ret.AddRange(rettmp);
}
catch (Exception ex)
{
exception = ex;
throw;
}
finally
{
var after = new Aop.CurdAfterEventArgs(before, exception, ret);
_orm.Aop.CurdAfterHandler?.Invoke(this, after);
}
});
sbret?.Clear();
return ret;
}
protected override void ToSqlCase(StringBuilder caseWhen, ColumnInfo[] primarys)
{
if (primarys.Length == 1)
{
var pk = primarys.First();
caseWhen.Append(_commonUtils.RereadColumn(pk, _commonUtils.QuoteSqlName(pk.Attribute.Name)));
return;
}
caseWhen.Append("(");
var pkidx = 0;
foreach (var pk in primarys)
{
if (pkidx > 0) caseWhen.Append(" + '+' + ");
caseWhen.Append("cast(").Append(_commonUtils.RereadColumn(pk, _commonUtils.QuoteSqlName(pk.Attribute.Name))).Append(" as varchar(2000))");
++pkidx;
}
caseWhen.Append(")");
}
protected override void ToSqlWhen(StringBuilder sb, ColumnInfo[] primarys, object d)
{
if (primarys.Length == 1)
{
sb.Append(_commonUtils.FormatSql("{0}", primarys[0].GetDbValue(d)));
return;
}
var pkidx = 0;
foreach (var pk in primarys)
{
if (pkidx > 0) sb.Append(" + '+' + ");
sb.Append("cast(").Append(_commonUtils.FormatSql("{0}", pk.GetDbValue(d))).Append(" as varchar(2000))");
++pkidx;
}
}
#if net40
#else
public override Task<int> ExecuteAffrowsAsync(CancellationToken cancellationToken = default) => base.SplitExecuteAffrowsAsync(_batchRowsLimit > 0 ? _batchRowsLimit : 500, _batchParameterLimit > 0 ? _batchParameterLimit : 2100, cancellationToken);
protected override Task<List<TReturn>> ExecuteUpdatedAsync<TReturn>(IEnumerable<ColumnInfo> columns, CancellationToken cancellationToken = default) => base.SplitExecuteUpdatedAsync<TReturn>(_batchRowsLimit > 0 ? _batchRowsLimit : 500, _batchParameterLimit > 0 ? _batchParameterLimit : 2100, columns, cancellationToken);
async protected override Task<List<TReturn>> RawExecuteUpdatedAsync<TReturn>(IEnumerable<ColumnInfo> columns, CancellationToken cancellationToken = default)
{
var ret = new List<TReturn>();
DbParameter[] dbParms = null;
StringBuilder sbret = null;
await ToSqlFetchAsync(async sb =>
{
if (dbParms == null)
{
dbParms = _params.Concat(_paramsSource).ToArray();
sbret = new StringBuilder();
sbret.Append(" OUTPUT ");
var colidx = 0;
foreach (var col in columns)
{
if (colidx > 0) sbret.Append(", ");
sbret.Append(_commonUtils.RereadColumn(col, $"INSERTED.{_commonUtils.QuoteSqlName(col.Attribute.Name)}")).Append(" as ").Append(_commonUtils.QuoteSqlName(col.CsName));
++colidx;
}
}
var sql = sb.ToString();
var validx = sql.IndexOf(" \r\nWHERE ");
if (validx == -1) throw new ArgumentException(CoreStrings.S_NotFound_Name("WHERE"));
sql = sb.Clear().Append(sql.Substring(0, validx))
.Append(sbret)
.Append(sql.Substring(validx)).ToString();
var before = new Aop.CurdBeforeEventArgs(_table.Type, _table, Aop.CurdType.Update, sql, dbParms);
_orm.Aop.CurdBeforeHandler?.Invoke(this, before);
Exception exception = null;
try
{
var queryType = typeof(TReturn) == typeof(T1) ? (_table.TypeLazy ?? _table.Type) : null;
var rettmp = await _orm.Ado.QueryAsync<TReturn>(queryType, _connection, _transaction, CommandType.Text, sql, _commandTimeout, dbParms, cancellationToken);
ValidateVersionAndThrow(rettmp.Count, sql, dbParms);
ret.AddRange(rettmp);
}
catch (Exception ex)
{
exception = ex;
throw;
}
finally
{
var after = new Aop.CurdAfterEventArgs(before, exception, ret);
_orm.Aop.CurdAfterHandler?.Invoke(this, after);
}
});
sbret?.Clear();
return ret;
}
#endif
}
}

View File

@ -0,0 +1,95 @@
using FreeSql.Internal;
using FreeSql.Internal.Model;
using FreeSql.Internal.ObjectPool;
using System;
using System.Collections;
using System.Data.Common;
using System.Linq;
using System.Text;
using System.Threading;
namespace FreeSql.Custom.SqlServer
{
class CustomSqlServerAdo : FreeSql.Internal.CommonProvider.AdoProvider
{
DbProviderFactory Factory => FreeSqlCustomAdapterGlobalExtensions.GetDbProviderFactory(_util._orm);
public CustomSqlServerAdo() : base(DataType.OdbcSqlServer, null, null) { }
public CustomSqlServerAdo(CommonUtils util, string masterConnectionString, string[] slaveConnectionStrings, Func<DbConnection> connectionFactory) : base(DataType.OdbcSqlServer, masterConnectionString, slaveConnectionStrings)
{
base._util = util;
if (connectionFactory != null)
{
var pool = new FreeSql.Internal.CommonProvider.DbConnectionPool(DataType.SqlServer, connectionFactory);
ConnectionString = pool.TestConnection?.ConnectionString;
MasterPool = pool;
return;
}
throw new Exception(CoreStrings.S_CustomAdapter_OnlySuppport_UseConnectionFactory);
}
string[] ncharDbTypes = new[] { "NVARCHAR", "NCHAR", "NTEXT" };
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)
{
if (mapColumn != null && mapColumn.CsType.NullableTypeOrThis() == typeof(string) && !string.IsNullOrWhiteSpace(mapColumn.Attribute.DbType) && ncharDbTypes.Any(a => mapColumn.Attribute.DbType.Contains(a)) == false)
return string.Concat("'", param.ToString().Replace("'", "''"), "'");
return string.Concat("N'", param.ToString().Replace("'", "''"), "'");
}
else if (param is char)
return string.Concat("'", param.ToString().Replace("'", "''").Replace('\0', ' '), "'");
else if (param is Enum)
return AddslashesTypeHandler(param.GetType(), param) ?? ((Enum)param).ToInt64();
else if (decimal.TryParse(string.Concat(param), out var trydec))
return param;
else if (param is DateTime)
{
var result = AddslashesTypeHandler(typeof(DateTime), param);
if (result != null) return result;
if (param.Equals(DateTime.MinValue) == true) param = new DateTime(1970, 1, 1);
return string.Concat("'", ((DateTime)param).ToString("yyyy-MM-dd HH:mm:ss.fff"), "'");
}
else if (param is DateTime?)
{
var result = AddslashesTypeHandler(typeof(DateTime?), param);
if (result != null) return result;
if (param.Equals(DateTime.MinValue) == true) param = new DateTime(1970, 1, 1);
return string.Concat("'", ((DateTime)param).ToString("yyyy-MM-dd HH:mm:ss.fff"), "'");
}
else if (param is DateTimeOffset || param is DateTimeOffset?)
{
if (param.Equals(DateTimeOffset.MinValue) == true) param = new DateTimeOffset(new DateTime(1970, 1, 1), TimeSpan.Zero);
return string.Concat("'", ((DateTimeOffset)param).ToString("yyyy-MM-dd HH:mm:ss.fff zzzz"), "'");
}
else if (param is TimeSpan || param is TimeSpan?)
return ((TimeSpan)param).TotalSeconds;
else if (param is byte[])
return $"0x{CommonUtils.BytesSqlRaw(param as byte[])}";
else if (param is IEnumerable)
return AddslashesIEnumerable(param, mapType, mapColumn);
return string.Concat("'", param.ToString().Replace("'", "''"), "'");
}
public override DbCommand CreateCommand()
{
return Factory.CreateCommand();
}
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,514 @@
using FreeSql.Internal;
using FreeSql.Internal.Model;
using FreeSql.Internal.ObjectPool;
using System;
using System.Collections.Generic;
using System.Data;
using System.Data.Common;
using System.Linq;
using System.Text;
namespace FreeSql.Custom.SqlServer
{
class CustomSqlServerCodeFirst : Internal.CommonProvider.CodeFirstProvider
{
public override bool IsNoneCommandParameter { get => true; set => base.IsNoneCommandParameter = true; }
public CustomSqlServerCodeFirst(IFreeSql orm, CommonUtils commonUtils, CommonExpression commonExpression) : base(orm, commonUtils, commonExpression) { }
static object _dicCsToDbLock = new object();
static Dictionary<string, CsToDb<DbType>> _dicCsToDb = new Dictionary<string, CsToDb<DbType>>() {
{ typeof(bool).FullName, CsToDb.New(DbType.Boolean, "bit","bit NOT NULL", null, false, false) },{ typeof(bool?).FullName, CsToDb.New(DbType.Boolean, "bit","bit", null, true, null) },
{ typeof(sbyte).FullName, CsToDb.New(DbType.SByte, "smallint", "smallint NOT NULL", false, false, 0) },{ typeof(sbyte?).FullName, CsToDb.New(DbType.SByte, "smallint", "smallint", false, true, null) },
{ typeof(short).FullName, CsToDb.New(DbType.Int16, "smallint","smallint NOT NULL", false, false, 0) },{ typeof(short?).FullName, CsToDb.New(DbType.Int16, "smallint", "smallint", false, true, null) },
{ typeof(int).FullName, CsToDb.New(DbType.Int32, "int", "int NOT NULL", false, false, 0) },{ typeof(int?).FullName, CsToDb.New(DbType.Int32, "int", "int", false, true, null) },
{ typeof(long).FullName, CsToDb.New(DbType.Int64, "bigint","bigint NOT NULL", false, false, 0) },{ typeof(long?).FullName, CsToDb.New(DbType.Int64, "bigint","bigint", false, true, null) },
{ typeof(byte).FullName, CsToDb.New(DbType.Byte, "tinyint","tinyint NOT NULL", true, false, 0) },{ typeof(byte?).FullName, CsToDb.New(DbType.Byte, "tinyint","tinyint", true, true, null) },
{ typeof(ushort).FullName, CsToDb.New(DbType.UInt16, "int","int NOT NULL", true, false, 0) },{ typeof(ushort?).FullName, CsToDb.New(DbType.UInt16, "int", "int", true, true, null) },
{ typeof(uint).FullName, CsToDb.New(DbType.UInt32, "bigint", "bigint NOT NULL", true, false, 0) },{ typeof(uint?).FullName, CsToDb.New(DbType.UInt32, "bigint", "bigint", true, true, null) },
{ typeof(ulong).FullName, CsToDb.New(DbType.UInt64, "decimal", "decimal(20,0) NOT NULL", true, false, 0) },{ typeof(ulong?).FullName, CsToDb.New(DbType.UInt64, "decimal", "decimal(20,0)", true, true, null) },
{ typeof(double).FullName, CsToDb.New(DbType.Double, "float", "float NOT NULL", false, false, 0) },{ typeof(double?).FullName, CsToDb.New(DbType.Double, "float", "float", false, true, null) },
{ typeof(float).FullName, CsToDb.New(DbType.Single, "real","real NOT NULL", false, false, 0) },{ typeof(float?).FullName, CsToDb.New(DbType.Single, "real","real", false, true, null) },
{ typeof(decimal).FullName, CsToDb.New(DbType.Decimal, "decimal", "decimal(10,2) NOT NULL", false, false, 0) },{ typeof(decimal?).FullName, CsToDb.New(DbType.Decimal, "decimal", "decimal(10,2)", false, true, null) },
{ typeof(TimeSpan).FullName, CsToDb.New(DbType.Time, "time","time NOT NULL", false, false, 0) },{ typeof(TimeSpan?).FullName, CsToDb.New(DbType.Time, "time", "time",false, true, null) },
{ typeof(DateTime).FullName, CsToDb.New(DbType.DateTime, "datetime", "datetime NOT NULL", false, false, new DateTime(1970,1,1)) },{ typeof(DateTime?).FullName, CsToDb.New(DbType.DateTime, "datetime", "datetime", false, true, null) },
{ typeof(DateTimeOffset).FullName, CsToDb.New(DbType.DateTimeOffset, "datetimeoffset", "datetimeoffset NOT NULL", false, false, new DateTimeOffset(new DateTime(1970,1,1), TimeSpan.Zero)) },{ typeof(DateTimeOffset?).FullName, CsToDb.New(DbType.DateTimeOffset, "datetimeoffset", "datetimeoffset", false, true, null) },
{ typeof(byte[]).FullName, CsToDb.New(DbType.Binary, "varbinary", "varbinary(255)", false, null, new byte[0]) },
{ typeof(string).FullName, CsToDb.New(DbType.String, "nvarchar", "nvarchar(255)", false, null, "") },
{ typeof(char).FullName, CsToDb.New(DbType.AnsiString, "char", "char(1) NULL", false, null, '\0') },
{ typeof(Guid).FullName, CsToDb.New(DbType.Guid, "uniqueidentifier", "uniqueidentifier NOT NULL", false, false, Guid.Empty) },{ typeof(Guid?).FullName, CsToDb.New(DbType.Guid, "uniqueidentifier", "uniqueidentifier", false, true, null) },
};
public override DbInfoResult GetDbInfo(Type type)
{
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.Int32, "bigint", $"bigint{(type.IsEnum ? " NOT NULL" : "")}", false, type.IsEnum ? false : true, enumType.CreateInstanceGetDefaultValue()) :
CsToDb.New(DbType.Int64, "int", $"int{(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;
}
void AddOrUpdateMS_Description(StringBuilder sb, string schema, string table, string comment)
{
if (string.IsNullOrEmpty(comment))
{
sb.AppendFormat(@"
IF ((SELECT COUNT(1) from fn_listextendedproperty('MS_Description',
'SCHEMA', N'{0}',
'TABLE', N'{1}',
NULL, NULL)) > 0)
EXEC sp_dropextendedproperty @name = N'MS_Description'
, @level0type = 'SCHEMA', @level0name = N'{0}'
, @level1type = 'TABLE', @level1name = N'{1}'
", schema.Replace("'", "''"), table.Replace("'", "''"));
return;
}
sb.AppendFormat(@"
IF ((SELECT COUNT(1) from fn_listextendedproperty('MS_Description',
'SCHEMA', N'{0}',
'TABLE', N'{1}',
NULL, NULL)) > 0)
EXEC sp_updateextendedproperty @name = N'MS_Description', @value = N'{2}'
, @level0type = 'SCHEMA', @level0name = N'{0}'
, @level1type = 'TABLE', @level1name = N'{1}'
ELSE
EXEC sp_addextendedproperty @name = N'MS_Description', @value = N'{2}'
, @level0type = 'SCHEMA', @level0name = N'{0}'
, @level1type = 'TABLE', @level1name = N'{1}'
", schema.Replace("'", "''"), table.Replace("'", "''"), comment?.Replace("'", "''") ?? "");
}
void AddOrUpdateMS_Description(StringBuilder sb, string schema, string table, string column, string comment)
{
if (string.IsNullOrEmpty(comment))
{
sb.AppendFormat(@"
IF ((SELECT COUNT(1) from fn_listextendedproperty('MS_Description',
'SCHEMA', N'{0}',
'TABLE', N'{1}',
'COLUMN', N'{2}')) > 0)
EXEC sp_dropextendedproperty @name = N'MS_Description'
, @level0type = 'SCHEMA', @level0name = N'{0}'
, @level1type = 'TABLE', @level1name = N'{1}'
, @level2type = 'COLUMN', @level2name = N'{2}'
", schema.Replace("'", "''"), table.Replace("'", "''"), column.Replace("'", "''"));
return;
}
sb.AppendFormat(@"
IF ((SELECT COUNT(1) from fn_listextendedproperty('MS_Description',
'SCHEMA', N'{0}',
'TABLE', N'{1}',
'COLUMN', N'{2}')) > 0)
EXEC sp_updateextendedproperty @name = N'MS_Description', @value = N'{3}'
, @level0type = 'SCHEMA', @level0name = N'{0}'
, @level1type = 'TABLE', @level1name = N'{1}'
, @level2type = 'COLUMN', @level2name = N'{2}'
ELSE
EXEC sp_addextendedproperty @name = N'MS_Description', @value = N'{3}'
, @level0type = 'SCHEMA', @level0name = N'{0}'
, @level1type = 'TABLE', @level1name = N'{1}'
, @level2type = 'COLUMN', @level2name = N'{2}'
", schema.Replace("'", "''"), table.Replace("'", "''"), column.Replace("'", "''"), comment?.Replace("'", "''") ?? "");
}
protected override string GetComparisonDDLStatements(params TypeSchemaAndName[] objects)
{
Object<DbConnection> conn = null;
string database = null;
try
{
conn = _orm.Ado.MasterPool.Get(TimeSpan.FromSeconds(5));
database = conn.Value.Database;
var sb = new StringBuilder();
foreach (var obj in objects)
{
if (sb.Length > 0) sb.Append("\r\n");
var tb = obj.tableSchema;
if (tb == null) throw new Exception(CoreStrings.S_Type_IsNot_Migrable(obj.tableSchema.Type.FullName));
if (tb.Columns.Any() == false) throw new Exception(CoreStrings.S_Type_IsNot_Migrable_0Attributes(obj.tableSchema.Type.FullName));
var tbname = _commonUtils.SplitTableName(tb.DbName);
if (tbname?.Length == 1) tbname = new[] { database, "dbo", tbname[0] };
if (tbname?.Length == 2) tbname = new[] { database, tbname[0], tbname[1] };
var tboldname = _commonUtils.SplitTableName(tb.DbOldName); //旧表名
if (tboldname?.Length == 1) tboldname = new[] { database, "dbo", tboldname[0] };
if (tboldname?.Length == 2) tboldname = new[] { database, tboldname[0], tboldname[1] };
if (string.IsNullOrEmpty(obj.tableName) == false)
{
var tbtmpname = _commonUtils.SplitTableName(obj.tableName);
if (tbtmpname?.Length == 1) tbtmpname = new[] { database, "dbo", tbtmpname[0] };
if (tbtmpname?.Length == 2) tbtmpname = new[] { database, tbtmpname[0], tbtmpname[1] };
if (tbname[0] != tbtmpname[0] || tbname[1] != tbtmpname[1] || tbname[2] != tbtmpname[2])
{
tbname = tbtmpname;
tboldname = null;
}
}
//codefirst 不支持表名、模式名、数据库名中带 .
if (string.Compare(tbname[0], database, true) != 0 && LocalExecuteScalar(database, $" select 1 from sys.databases where name='{tbname[0]}'") == null) //创建数据库
LocalExecuteScalar(database, $"if not exists(select 1 from sys.databases where name='{tbname[0]}')\r\n\tcreate database [{tbname[0]}];");
if (string.Compare(tbname[1], "dbo", true) != 0 && LocalExecuteScalar(tbname[0], $" select 1 from sys.schemas where name='{tbname[1]}'") == null) //创建模式
LocalExecuteScalar(tbname[0], $"create schema [{tbname[1]}] authorization [dbo]");
var sbalter = new StringBuilder();
var istmpatler = false; //创建临时表,导入数据,删除旧表,修改
if (LocalExecuteScalar(tbname[0], $" select 1 from dbo.sysobjects where id = object_id(N'[{tbname[1]}].[{tbname[2]}]') and OBJECTPROPERTY(id, N'IsUserTable') = 1") == null)
{ //表不存在
if (tboldname != null)
{
if (string.Compare(tboldname[0], tbname[0], true) != 0 && LocalExecuteScalar(database, $" select 1 from sys.databases where name='{tboldname[0]}'") == null ||
string.Compare(tboldname[1], tbname[1], true) != 0 && LocalExecuteScalar(tboldname[0], $" select 1 from sys.schemas where name='{tboldname[1]}'") == null ||
LocalExecuteScalar(tboldname[0], $" select 1 from dbo.sysobjects where id = object_id(N'[{tboldname[1]}].[{tboldname[2]}]') and OBJECTPROPERTY(id, N'IsUserTable') = 1") == null)
//数据库或模式或表不存在
tboldname = null;
}
if (tboldname == null)
{
//创建表
var createTableName = _commonUtils.QuoteSqlName(tbname[1], tbname[2]);
sb.Append("use [").Append(tbname[0]).Append("];\r\nCREATE TABLE ").Append(createTableName).Append(" ( ");
var pkidx = 0;
foreach (var tbcol in tb.ColumnsByPosition)
{
sb.Append(" \r\n ").Append(_commonUtils.QuoteSqlName(tbcol.Attribute.Name)).Append(" ").Append(tbcol.Attribute.DbType);
if (tbcol.Attribute.IsIdentity == true && tbcol.Attribute.DbType.IndexOf("identity", StringComparison.CurrentCultureIgnoreCase) == -1) sb.Append(" identity(1,1)");
if (tbcol.Attribute.IsPrimary == true)
{
if (tb.Primarys.Length > 1)
{
if (pkidx == tb.Primarys.Length - 1)
sb.Append(" primary key (").Append(string.Join(", ", tb.Primarys.Select(a => _commonUtils.QuoteSqlName(a.Attribute.Name)))).Append(")");
}
else
sb.Append(" primary key");
pkidx++;
}
sb.Append(",");
}
sb.Remove(sb.Length - 1, 1).Append("\r\n);\r\n");
//创建表的索引
foreach (var uk in tb.Indexes)
{
sb.Append("CREATE ");
if (uk.IsUnique) sb.Append("UNIQUE ");
sb.Append("INDEX ").Append(_commonUtils.QuoteSqlName(ReplaceIndexName(uk.Name, tbname[1]))).Append(" ON ").Append(createTableName).Append("(");
foreach (var tbcol in uk.Columns)
{
sb.Append(_commonUtils.QuoteSqlName(tbcol.Column.Attribute.Name));
if (tbcol.IsDesc) sb.Append(" DESC");
sb.Append(", ");
}
sb.Remove(sb.Length - 2, 2).Append(");\r\n");
}
//备注
foreach (var tbcol in tb.ColumnsByPosition)
{
if (string.IsNullOrEmpty(tbcol.Comment) == false)
AddOrUpdateMS_Description(sb, tbname[1], tbname[2], tbcol.Attribute.Name, tbcol.Comment);
}
if (string.IsNullOrEmpty(tb.Comment) == false)
AddOrUpdateMS_Description(sb, tbname[1], tbname[2], tb.Comment);
continue;
}
//如果新表,旧表在一个数据库和模式下,直接修改表名
if (string.Compare(tbname[0], tboldname[0], true) == 0 &&
string.Compare(tbname[1], tboldname[1], true) == 0)
sbalter.Append("use [").Append(tbname[0]).Append(_commonUtils.FormatSql("];\r\nEXEC sp_rename {0}, {1};\r\n", _commonUtils.QuoteSqlName(tboldname[0], tboldname[1], tboldname[2]), tbname[2]));
else
{
//如果新表,旧表不在一起,创建新表,导入数据,删除旧表
istmpatler = true;
}
}
else
tboldname = null; //如果新表已经存在,不走改表名逻辑
//对比字段,只可以修改类型、增加字段、有限的修改字段名;保证安全不删除字段
var sql = string.Format(@"
use [{0}];
select
a.name 'column'
,b.name + case
when b.name in ('char', 'varchar', 'nchar', 'nvarchar', 'binary', 'varbinary') then '(' +
case when a.max_length = -1 then 'MAX'
when b.name in ('nchar', 'nvarchar') then cast(a.max_length / 2 as varchar)
else cast(a.max_length as varchar) end + ')'
when b.name in ('numeric', 'decimal') then '(' + cast(a.precision as varchar) + ',' + cast(a.scale as varchar) + ')'
else '' end as 'sqltype'
,case when a.is_nullable = 1 then '1' else '0' end 'isnullable'
,case when a.is_identity = 1 then '1' else '0' end 'isidentity'
,(select value from sys.extended_properties where major_id = a.object_id AND minor_id = a.column_id AND name = 'MS_Description') 'comment'
from sys.columns a
inner join sys.types b on b.user_type_id = a.user_type_id
left join sys.tables d on d.object_id = a.object_id
left join sys.schemas e on e.schema_id = d.schema_id
where a.object_id in (object_id(N'[{1}].[{2}]'));
use [" + database + "];", tboldname ?? tbname);
var ds = _orm.Ado.ExecuteArray(CommandType.Text, sql);
var tbstruct = ds.ToDictionary(a => string.Concat(a[0]), a => new
{
column = string.Concat(a[0]),
sqlType = string.Concat(a[1]),
is_nullable = string.Concat(a[2]) == "1",
is_identity = string.Concat(a[3]) == "1",
comment = string.Concat(a[4])
}, StringComparer.CurrentCultureIgnoreCase);
if (istmpatler == false)
{
foreach (var tbcol in tb.ColumnsByPosition)
{
if (tbstruct.TryGetValue(tbcol.Attribute.Name, out var tbstructcol) ||
string.IsNullOrEmpty(tbcol.Attribute.OldName) == false && tbstruct.TryGetValue(tbcol.Attribute.OldName, out tbstructcol))
{
var isCommentChanged = tbstructcol.comment != (tbcol.Comment ?? "");
if (tbcol.Attribute.DbType.StartsWith(tbstructcol.sqlType, StringComparison.CurrentCultureIgnoreCase) == false ||
tbcol.Attribute.IsNullable != tbstructcol.is_nullable ||
tbcol.Attribute.IsIdentity != tbstructcol.is_identity)
{
istmpatler = true;
break;
}
if (string.Compare(tbstructcol.column, tbcol.Attribute.OldName, true) == 0)
//修改列名
sbalter.Append(_commonUtils.FormatSql("EXEC sp_rename {0}, {1}, 'COLUMN';\r\n", $"{tbname[0]}.{tbname[1]}.{tbname[2]}.{tbstructcol.column}", tbcol.Attribute.Name));
if (isCommentChanged)
//修改备备注
AddOrUpdateMS_Description(sbalter, tbname[1], tbname[2], tbcol.Attribute.Name, tbcol.Comment);
continue;
}
//添加列
sbalter.Append("ALTER TABLE ").Append(_commonUtils.QuoteSqlName(tbname[0], tbname[1], tbname[2])).Append(" ADD ").Append(_commonUtils.QuoteSqlName(tbcol.Attribute.Name)).Append(" ").Append(tbcol.Attribute.DbType);
if (tbcol.Attribute.IsIdentity == true && tbcol.Attribute.DbType.IndexOf("identity", StringComparison.CurrentCultureIgnoreCase) == -1) sbalter.Append(" identity(1,1)");
if (tbcol.Attribute.IsNullable == false && tbcol.DbDefaultValue != "NULL" && tbcol.Attribute.IsIdentity == false) sbalter.Append(" default(").Append(GetTransferDbDefaultValue(tbcol)).Append(")");
sbalter.Append(";\r\n");
if (string.IsNullOrEmpty(tbcol.Comment) == false) AddOrUpdateMS_Description(sbalter, tbname[1], tbname[2], tbcol.Attribute.Name, tbcol.Comment);
}
}
if (istmpatler == false)
{
var dsuksql = string.Format(@"
use [{0}];
select
c.name
,b.name
,case when a.is_descending_key = 1 then 1 else 0 end
,case when b.is_unique = 1 then 1 else 0 end
from sys.index_columns a
inner join sys.indexes b on b.object_id = a.object_id and b.index_id = a.index_id
left join sys.columns c on c.object_id = a.object_id and c.column_id = a.column_id
where a.object_id in (object_id(N'[{1}].[{2}]')) and b.is_primary_key = 0;
use [" + database + "];", tboldname ?? tbname);
var dsuk = _orm.Ado.ExecuteArray(CommandType.Text, dsuksql).Select(a => new[] { string.Concat(a[0]), string.Concat(a[1]), string.Concat(a[2]), string.Concat(a[3]) });
foreach (var uk in tb.Indexes)
{
if (string.IsNullOrEmpty(uk.Name) || uk.Columns.Any() == false) continue;
var ukname = ReplaceIndexName(uk.Name, tbname[1]);
var dsukfind1 = dsuk.Where(a => string.Compare(a[1], ukname, true) == 0).ToArray();
if (dsukfind1.Any() == false || dsukfind1.Length != uk.Columns.Length || dsukfind1.Where(a => (a[3] == "1") == uk.IsUnique && uk.Columns.Where(b => string.Compare(b.Column.Attribute.Name, a[0], true) == 0 && (a[2] == "1") == b.IsDesc).Any()).Count() != uk.Columns.Length)
{
if (dsukfind1.Any()) sbalter.Append("DROP INDEX ").Append(_commonUtils.QuoteSqlName(ukname)).Append(" ON ").Append(_commonUtils.QuoteSqlName(tbname[1], tbname[2])).Append(";\r\n");
sbalter.Append("CREATE ");
if (uk.IsUnique) sbalter.Append("UNIQUE ");
sbalter.Append("INDEX ").Append(_commonUtils.QuoteSqlName(ukname)).Append(" ON ").Append(_commonUtils.QuoteSqlName(tbname[1], tbname[2])).Append("(");
foreach (var tbcol in uk.Columns)
{
sbalter.Append(_commonUtils.QuoteSqlName(tbcol.Column.Attribute.Name));
if (tbcol.IsDesc) sbalter.Append(" DESC");
sbalter.Append(", ");
}
sbalter.Remove(sbalter.Length - 2, 2).Append(");\r\n");
}
}
}
if (istmpatler == false)
{
var dbcommentsql = $" SELECT value from fn_listextendedproperty('MS_Description', 'schema', N'{tbname[1].Replace("'", "''")}', 'table', N'{tbname[2].Replace("'", "''")}', NULL, NULL)";
if (string.Compare(tbname[0], database, true) != 0) dbcommentsql = $"use [{tbname[0]}];{dbcommentsql};use [{database}];";
var dbcomment = string.Concat(_orm.Ado.ExecuteScalar(CommandType.Text, dbcommentsql));
if (dbcomment != (tb.Comment ?? ""))
AddOrUpdateMS_Description(sbalter, tbname[1], tbname[2], tb.Comment);
if (sbalter.Length > 0)
sb.Append($"use [{tbname[0]}];").Append(sbalter).Append("\r\nuse [").Append(database).Append("];");
continue;
}
//创建临时表,数据导进临时表,然后删除原表,将临时表改名为原表名
bool idents = false;
var tablename = tboldname == null ? _commonUtils.QuoteSqlName(tbname[0], tbname[1], tbname[2]) : _commonUtils.QuoteSqlName(tboldname[0], tboldname[1], tboldname[2]);
var tmptablename = _commonUtils.QuoteSqlName(tbname[0], tbname[1], $"FreeSqlTmp_{tbname[2]}");
sb.Append("BEGIN TRANSACTION\r\n")
.Append("SET QUOTED_IDENTIFIER ON\r\n")
.Append("SET ARITHABORT ON\r\n")
.Append("SET NUMERIC_ROUNDABORT OFF\r\n")
.Append("SET CONCAT_NULL_YIELDS_NULL ON\r\n")
.Append("SET ANSI_NULLS ON\r\n")
.Append("SET ANSI_PADDING ON\r\n")
.Append("SET ANSI_WARNINGS ON\r\n")
.Append("COMMIT\r\n");
sb.Append("BEGIN TRANSACTION;\r\n");
//创建临时表
sb.Append("CREATE TABLE ").Append(tmptablename).Append(" ( ");
var pkidx2 = 0;
foreach (var tbcol in tb.ColumnsByPosition)
{
sb.Append(" \r\n ").Append(_commonUtils.QuoteSqlName(tbcol.Attribute.Name)).Append(" ").Append(tbcol.Attribute.DbType);
if (tbcol.Attribute.IsIdentity == true && tbcol.Attribute.DbType.IndexOf("identity", StringComparison.CurrentCultureIgnoreCase) == -1) sb.Append(" identity(1,1)");
if (tbcol.Attribute.IsPrimary == true)
{
if (tb.Primarys.Length > 1)
{
if (pkidx2 == tb.Primarys.Length - 1)
sb.Append(" primary key (").Append(string.Join(", ", tb.Primarys.Select(a => _commonUtils.QuoteSqlName(a.Attribute.Name)))).Append(")");
}
else
sb.Append(" primary key");
pkidx2++;
}
sb.Append(",");
idents = idents || tbcol.Attribute.IsIdentity == true;
}
sb.Remove(sb.Length - 1, 1).Append("\r\n);\r\n");
//备注
foreach (var tbcol in tb.ColumnsByPosition)
{
if (string.IsNullOrEmpty(tbcol.Comment) == false)
AddOrUpdateMS_Description(sb, tbname[1], $"FreeSqlTmp_{tbname[2]}", tbcol.Attribute.Name, tbcol.Comment);
}
if (string.IsNullOrEmpty(tb.Comment) == false)
AddOrUpdateMS_Description(sb, tbname[1], $"FreeSqlTmp_{tbname[2]}", tb.Comment);
if ((_commonUtils as CustomSqlServerUtils).ServerVersion > 9) //SqlServer 2008+
sb.Append("ALTER TABLE ").Append(tmptablename).Append(" SET (LOCK_ESCALATION = TABLE);\r\n");
if (idents) sb.Append("SET IDENTITY_INSERT ").Append(tmptablename).Append(" ON;\r\n");
sb.Append("IF EXISTS(SELECT 1 FROM ").Append(tablename).Append(")\r\n");
sb.Append("\tEXEC('INSERT INTO ").Append(tmptablename).Append(" (");
foreach (var tbcol in tb.ColumnsByPosition)
sb.Append(_commonUtils.QuoteSqlName(tbcol.Attribute.Name)).Append(", ");
sb.Remove(sb.Length - 2, 2).Append(")\r\n\t\tSELECT ");
foreach (var tbcol in tb.ColumnsByPosition)
{
var insertvalue = "NULL";
if (tbstruct.TryGetValue(tbcol.Attribute.Name, out var tbstructcol) ||
string.IsNullOrEmpty(tbcol.Attribute.OldName) == false && tbstruct.TryGetValue(tbcol.Attribute.OldName, out tbstructcol))
{
insertvalue = _commonUtils.QuoteSqlName(tbstructcol.column);
if (tbcol.Attribute.DbType.StartsWith(tbstructcol.sqlType, StringComparison.CurrentCultureIgnoreCase) == false)
insertvalue = $"cast({insertvalue} as {tbcol.Attribute.DbType.Split(' ').First()})";
if (tbcol.Attribute.IsNullable != tbstructcol.is_nullable)
insertvalue = $"isnull({insertvalue},{GetTransferDbDefaultValue(tbcol)})";
}
else if (tbcol.Attribute.IsNullable == false)
if (tbcol.DbDefaultValue != "NULL" && tbcol.Attribute.IsIdentity == false)
insertvalue = GetTransferDbDefaultValue(tbcol);
sb.Append(insertvalue.Replace("'", "''")).Append(", ");
}
sb.Remove(sb.Length - 2, 2).Append(" FROM ").Append(tablename).Append(" WITH (HOLDLOCK TABLOCKX)');\r\n");
if (idents) sb.Append("SET IDENTITY_INSERT ").Append(tmptablename).Append(" OFF;\r\n");
sb.Append("DROP TABLE ").Append(tablename).Append(";\r\n");
sb.Append("EXECUTE sp_rename N'").Append(tmptablename).Append("', N'").Append(tbname[2]).Append("', 'OBJECT';\r\n");
//创建表的索引
foreach (var uk in tb.Indexes)
{
sb.Append("CREATE ");
if (uk.IsUnique) sb.Append("UNIQUE ");
sb.Append("INDEX ").Append(_commonUtils.QuoteSqlName(ReplaceIndexName(uk.Name, tbname[1]))).Append(" ON ").Append(tablename).Append("(");
foreach (var tbcol in uk.Columns)
{
sb.Append(_commonUtils.QuoteSqlName(tbcol.Column.Attribute.Name));
if (tbcol.IsDesc) sb.Append(" DESC");
sb.Append(", ");
}
sb.Remove(sb.Length - 2, 2).Append(");\r\n");
}
sb.Append("COMMIT;\r\n");
}
return sb.Length == 0 ? null : sb.ToString();
}
finally
{
try
{
if (string.IsNullOrEmpty(database) == false)
conn.Value.ChangeDatabase(database);
_orm.Ado.MasterPool.Return(conn);
}
catch
{
_orm.Ado.MasterPool.Return(conn, true);
}
}
object LocalExecuteScalar(string db, string sql)
{
if (string.Compare(database, db) != 0) conn.Value.ChangeDatabase(db);
try
{
using (var cmd = conn.Value.CreateCommand())
{
cmd.CommandText = sql;
cmd.CommandType = CommandType.Text;
var before = new Aop.CommandBeforeEventArgs(cmd);
this._orm?.Aop.CommandBeforeHandler?.Invoke(this._orm, before);
Exception afterException = null;
try
{
return cmd.ExecuteScalar();
}
catch (Exception ex)
{
afterException = ex;
throw;
}
finally
{
this._orm?.Aop.CommandAfterHandler?.Invoke(this._orm, new Aop.CommandAfterEventArgs(before, afterException, null));
}
}
}
finally
{
if (string.Compare(database, db) != 0) conn.Value.ChangeDatabase(database);
}
}
}
string GetTransferDbDefaultValue(ColumnInfo col)
{
var ddv = col.DbDefaultValue;
if (string.IsNullOrEmpty(ddv) || ddv == "NULL") return ddv;
if (col.Attribute.MapType.NullableTypeOrThis() == typeof(DateTime) && DateTime.TryParse(ddv, out var trydt))
{
if (col.Attribute.DbType.Contains("SMALLDATETIME") && trydt < new DateTime(1900, 1, 1)) ddv = _commonUtils.FormatSql("{0}", new DateTime(1900, 1, 1));
else if (col.Attribute.DbType.Contains("DATETIME") && trydt < new DateTime(1753, 1, 1)) ddv = _commonUtils.FormatSql("{0}", new DateTime(1753, 1, 1));
else if (col.Attribute.DbType.Contains("DATE") && trydt < new DateTime(0001, 1, 1)) ddv = _commonUtils.FormatSql("{0}", new DateTime(0001, 1, 1));
}
return ddv;
}
}
}

View File

@ -0,0 +1,521 @@
using FreeSql.DatabaseModel;
using FreeSql.Internal;
using FreeSql.Internal.Model;
using System;
using System.Collections.Generic;
using System.Data;
using System.Linq;
using System.Text;
namespace FreeSql.Custom.SqlServer
{
class CustomSqlServerDbFirst : IDbFirst
{
IFreeSql _orm;
protected CommonUtils _commonUtils;
protected CommonExpression _commonExpression;
public CustomSqlServerDbFirst(IFreeSql orm, CommonUtils commonUtils, CommonExpression commonExpression)
{
_orm = orm;
_commonUtils = commonUtils;
_commonExpression = commonExpression;
}
public int GetDbType(DbColumnInfo column) => (int)GetSqlDbType(column);
DbType GetSqlDbType(DbColumnInfo column)
{
switch (column.DbTypeText?.ToLower())
{
case "bit": return DbType.Boolean;
case "tinyint": return DbType.Byte;
case "smallint": return DbType.Int16;
case "int": return DbType.Int32;
case "bigint": return DbType.Int64;
case "numeric":
case "decimal": return DbType.Decimal;
case "smallmoney": return DbType.Decimal;
case "money": return DbType.Decimal;
case "float": return DbType.Double;
case "real": return DbType.Single;
case "date": return DbType.Date;
case "datetime": return DbType.DateTime;
case "datetime2": return DbType.DateTime2;
case "datetimeoffset": return DbType.DateTime;
case "smalldatetime": return DbType.DateTime;
case "time": return DbType.Time;
case "char": return DbType.AnsiString;
case "varchar": return DbType.String;
case "text": return DbType.String;
case "nchar": return DbType.String;
case "nvarchar": return DbType.String;
case "ntext": return DbType.String;
case "binary": return DbType.Binary;
case "varbinary": return DbType.Binary;
case "image": return DbType.Binary;
case "timestamp": return DbType.Binary;
case "uniqueidentifier": return DbType.Guid;
default: return DbType.String;
}
}
static readonly Dictionary<int, DbToCs> _dicDbToCs = new Dictionary<int, DbToCs>() {
{ (int)DbType.Boolean, new DbToCs("(bool?)", "{0} == \"1\"", "{0} == true ? \"1\" : \"0\"", "bool?", typeof(bool), typeof(bool?), "{0}.Value", "GetBoolean") },
{ (int)DbType.SByte, new DbToCs("(sbyte?)", "sbyte.Parse({0})", "{0}.ToString()", "sbyte?", typeof(sbyte), typeof(sbyte?), "{0}.Value", "GetInt16") },
{ (int)DbType.Int16, new DbToCs("(short?)", "short.Parse({0})", "{0}.ToString()", "short?", typeof(short), typeof(short?), "{0}.Value", "GetInt16") },
{ (int)DbType.Int32, new DbToCs("(int?)", "int.Parse({0})", "{0}.ToString()", "int?", typeof(int), typeof(int?), "{0}.Value", "GetInt32") },
{ (int)DbType.Int64, new DbToCs("(long?)", "long.Parse({0})", "{0}.ToString()", "long?", typeof(long), typeof(long?), "{0}.Value", "GetInt64") },
{ (int)DbType.Byte, new DbToCs("(byte?)", "byte.Parse({0})", "{0}.ToString()", "byte?", typeof(byte), typeof(byte?), "{0}.Value", "GetByte") },
{ (int)DbType.UInt16, new DbToCs("(ushort?)", "ushort.Parse({0})", "{0}.ToString()", "ushort?", typeof(ushort), typeof(ushort?), "{0}.Value", "GetInt32") },
{ (int)DbType.UInt32, new DbToCs("(uint?)", "uint.Parse({0})", "{0}.ToString()", "uint?", typeof(uint), typeof(uint?), "{0}.Value", "GetInt64") },
{ (int)DbType.UInt64, new DbToCs("(ulong?)", "ulong.Parse({0})", "{0}.ToString()", "ulong?", typeof(ulong), typeof(ulong?), "{0}.Value", "GetInt64") },
{ (int)DbType.Decimal, new DbToCs("(decimal?)", "decimal.Parse({0})", "{0}.ToString()", "decimal?", typeof(decimal), typeof(decimal?), "{0}.Value", "GetDecimal") },
{ (int)DbType.Double, new DbToCs("(double?)", "double.Parse({0})", "{0}.ToString()", "double?", typeof(double), typeof(double?), "{0}.Value", "GetDouble") },
{ (int)DbType.Single, new DbToCs("(float?)", "float.Parse({0})", "{0}.ToString()", "float?", typeof(float), typeof(float?), "{0}.Value", "GetFloat") },
{ (int)DbType.Time, new DbToCs("(TimeSpan?)", "TimeSpan.Parse(double.Parse({0}))", "{0}.Ticks.ToString()", "TimeSpan?", typeof(TimeSpan), typeof(TimeSpan?), "{0}.Value", "GetValue") },
{ (int)DbType.Date, new DbToCs("(DateTime?)", "new DateTime(long.Parse({0}))", "{0}.Ticks.ToString()", "DateTime?", typeof(DateTime), typeof(DateTime?), "{0}.Value", "GetDateTime") },
{ (int)DbType.DateTime, new DbToCs("(DateTime?)", "new DateTime(long.Parse({0}))", "{0}.Ticks.ToString()", "DateTime?", typeof(DateTime), typeof(DateTime?), "{0}.Value", "GetDateTime") },
{ (int)DbType.DateTime2, new DbToCs("(DateTime?)", "new DateTime(long.Parse({0}))", "{0}.Ticks.ToString()", "DateTime?", typeof(DateTime), typeof(DateTime?), "{0}.Value", "GetDateTime") },
{ (int)DbType.Binary, new DbToCs("(byte[])", "Convert.FromBase64String({0})", "Convert.ToBase64String({0})", "byte[]", typeof(byte[]), typeof(byte[]), "{0}", "GetValue") },
{ (int)DbType.AnsiString, new DbToCs("", "{0}.Replace(StringifySplit, \"|\")", "{0}.Replace(\"|\", StringifySplit)", "string", typeof(string), typeof(string), "{0}", "GetString") },
{ (int)DbType.String, new DbToCs("", "{0}.Replace(StringifySplit, \"|\")", "{0}.Replace(\"|\", StringifySplit)", "string", typeof(string), typeof(string), "{0}", "GetString") },
{ (int)DbType.Guid, new DbToCs("(Guid?)", "Guid.Parse({0})", "{0}.ToString()", "Guid?", typeof(Guid), typeof(Guid?), "{0}.Value", "GetGuid") },
};
public string GetCsConvert(DbColumnInfo column) => _dicDbToCs.TryGetValue(column.DbType, out var trydc) ? (column.IsNullable ? trydc.csConvert : trydc.csConvert.Replace("?", "")) : null;
public string GetCsParse(DbColumnInfo column) => _dicDbToCs.TryGetValue(column.DbType, out var trydc) ? trydc.csParse : null;
public string GetCsStringify(DbColumnInfo column) => _dicDbToCs.TryGetValue(column.DbType, out var trydc) ? trydc.csStringify : null;
public string GetCsType(DbColumnInfo column) => _dicDbToCs.TryGetValue(column.DbType, out var trydc) ? (column.IsNullable ? trydc.csType : trydc.csType.Replace("?", "")) : null;
public Type GetCsTypeInfo(DbColumnInfo column) => _dicDbToCs.TryGetValue(column.DbType, out var trydc) ? trydc.csTypeInfo : null;
public string GetCsTypeValue(DbColumnInfo column) => _dicDbToCs.TryGetValue(column.DbType, out var trydc) ? trydc.csTypeValue : null;
public string GetDataReaderMethod(DbColumnInfo column) => _dicDbToCs.TryGetValue(column.DbType, out var trydc) ? trydc.dataReaderMethod : null;
public List<string> GetDatabases()
{
var sql = @" select name from sys.databases where name not in ('master','tempdb','model','msdb')";
var ds = _orm.Ado.ExecuteArray(CommandType.Text, sql);
return ds.Select(a => a.FirstOrDefault()?.ToString()).ToList();
}
public bool ExistsTable(string name, bool ignoreCase)
{
if (string.IsNullOrEmpty(name)) return false;
var olddatabase = "";
using (var conn = _orm.Ado.MasterPool.Get(TimeSpan.FromSeconds(5)))
{
olddatabase = conn.Value.Database;
}
var tbname = _commonUtils.SplitTableName(name);
if (tbname?.Length == 1) tbname = new[] { olddatabase, "dbo", tbname[0] };
if (tbname?.Length == 2) tbname = new[] { olddatabase, tbname[0], tbname[1] };
tbname = tbname.Select(a => a.ToLower()).ToArray();
var sql = $@"
use [{tbname[0]}];
select
1
from sys.tables a
inner join sys.schemas b on b.schema_id = a.schema_id
where lower(b.name)={_commonUtils.FormatSql("{0}", tbname[1])} and lower(a.name)={_commonUtils.FormatSql("{0}", tbname[2])}
;
use [{olddatabase}];
";
return string.Concat(_orm.Ado.ExecuteScalar(CommandType.Text, sql)) == "1";
}
public DbTableInfo GetTableByName(string name, bool ignoreCase = true) => GetTables(null, name, ignoreCase)?.FirstOrDefault();
public List<DbTableInfo> GetTablesByDatabase(params string[] database) => GetTables(database, null, false);
public List<DbTableInfo> GetTables(string[] database, string tablename, bool ignoreCase)
{
var olddatabase = "";
using (var conn = _orm.Ado.MasterPool.Get(TimeSpan.FromSeconds(5)))
{
olddatabase = conn.Value.Database;
}
string[] tbname = null;
string[] dbs = database == null || database.Any() == false ? new[] { olddatabase } : database;
if (string.IsNullOrEmpty(tablename) == false)
{
tbname = _commonUtils.SplitTableName(tablename);
if (tbname?.Length == 1) tbname = new[] { olddatabase, "dbo", tbname[0] };
if (tbname?.Length == 2) tbname = new[] { olddatabase, tbname[0], tbname[1] };
tbname = tbname.Select(a => a.ToLower()).ToArray();
dbs = new[] { tbname[0] };
}
var tables = new List<DbTableInfo>();
foreach (var db in dbs)
{
if (string.IsNullOrEmpty(db)) continue;
var loc1 = new List<DbTableInfo>();
var loc2 = new Dictionary<int, DbTableInfo>();
var loc3 = new Dictionary<int, Dictionary<string, DbColumnInfo>>();
var sql = $@"
use [{db}];
select * from (
select
a.object_id
,b.name 'owner'
,a.name 'name'
,(select value from sys.extended_properties where major_id = a.object_id AND minor_id = 0 AND name = 'MS_Description') 'comment'
,'TABLE' type
from sys.tables a
inner join sys.schemas b on b.schema_id = a.schema_id
where not(b.name = 'dbo' and a.name = 'sysdiagrams')
union all
select
a.object_id
,b.name 'owner'
,a.name 'name'
,(select value from sys.extended_properties where major_id = a.object_id AND minor_id = 0 AND name = 'MS_Description') 'comment'
,'VIEW' type
from sys.views a
inner join sys.schemas b on b.schema_id = a.schema_id
union all
select
a.object_id
,b.name 'owner'
,a.name 'name'
,(select value from sys.extended_properties where major_id = a.object_id AND minor_id = 0 AND name = 'MS_Description') 'comment'
,'StoreProcedure' type
from sys.procedures a
inner join sys.schemas b on b.schema_id = a.schema_id
where a.type = 'P' and charindex('diagram', a.name) = 0
) ft_dbf{(tbname == null ? "" : _commonUtils.FormatSql(" where lower([owner])={0} and lower([name])={1}", new[] { tbname[1], tbname[2] }))}
order by type desc, [owner], [name];
use [{olddatabase}];
";
var ds = _orm.Ado.ExecuteArray(CommandType.Text, sql);
if (ds == null) return loc1;
var loc6 = new List<int[]>();
var loc66 = new List<int[]>();
var loc6_1000 = new List<int>();
var loc66_1000 = new List<int>();
foreach (object[] row in ds)
{
int object_id = int.Parse(string.Concat(row[0]));
var owner = string.Concat(row[1]);
var table = string.Concat(row[2]);
var comment = string.Concat(row[3]);
Enum.TryParse<DbTableType>(string.Concat(row[4]), out var type);
loc2.Add(object_id, new DbTableInfo { Id = object_id.ToString(), Schema = owner, Name = table, Comment = comment, Type = type });
loc3.Add(object_id, new Dictionary<string, DbColumnInfo>());
switch (type)
{
case DbTableType.VIEW:
case DbTableType.TABLE:
loc6_1000.Add(object_id);
if (loc6_1000.Count >= 500)
{
loc6.Add(loc6_1000.ToArray());
loc6_1000.Clear();
}
break;
case DbTableType.StoreProcedure:
loc66_1000.Add(object_id);
if (loc66_1000.Count >= 500)
{
loc66.Add(loc66_1000.ToArray());
loc66_1000.Clear();
}
break;
}
}
if (loc6_1000.Count > 0) loc6.Add(loc6_1000.ToArray());
if (loc66_1000.Count > 0) loc66.Add(loc66_1000.ToArray());
if (loc6.Count == 0) return loc1;
Func<List<int[]>, StringBuilder> getloc8Sb = loclist =>
{
if (loclist.Count == 0) return new StringBuilder();
var loc8sb = new StringBuilder().Append("(");
for (var loc8sbidx = 0; loc8sbidx < loclist.Count; loc8sbidx++)
{
if (loc8sbidx > 0) loc8sb.Append(" OR ");
loc8sb.Append("a.table_name in (");
for (var loc8sbidx2 = 0; loc8sbidx2 < loclist[loc8sbidx].Length; loc8sbidx2++)
{
if (loc8sbidx2 > 0) loc8sb.Append(",");
loc8sb.Append(loclist[loc8sbidx][loc8sbidx2]);
}
loc8sb.Append(")");
}
loc8sb.Append(")");
return loc8sb;
};
var loc8 = getloc8Sb(loc6);
var loc88 = getloc8Sb(loc66);
var tsql_place = @"
select
isnull(e.name,'') + '.' + isnull(d.name,'')
,a.object_id
,a.name 'column'
,b.name 'type'
,case
when b.name in ('text', 'ntext', 'image') then -1
when b.name in ('nchar', 'nvarchar') then a.max_length / 2
else a.max_length end 'length'
,b.name + case
when b.name in ('char', 'varchar', 'nchar', 'nvarchar', 'binary', 'varbinary') then '(' +
case when a.max_length = -1 then 'MAX'
when b.name in ('nchar', 'nvarchar') then cast(a.max_length / 2 as varchar)
else cast(a.max_length as varchar) end + ')'
when b.name in ('numeric', 'decimal') then '(' + cast(a.precision as varchar) + ',' + cast(a.scale as varchar) + ')'
else '' end as 'sqltype'
,( select value from sys.extended_properties where major_id = a.object_id AND minor_id = a.column_id AND name = 'MS_Description') 'comment'
{0} a
inner join sys.types b on b.user_type_id = a.user_type_id
left join sys.tables d on d.object_id = a.object_id
left join sys.schemas e on e.schema_id = d.schema_id{2}
where {1}
";
sql = string.Format(tsql_place, @"
,a.is_nullable 'isnullable'
,a.is_identity 'isidentity'
,f.text as 'defaultvalue'
from sys.columns", loc8.ToString().Replace("a.table_name", "a.object_id"), @"
left join syscomments f on f.id = a.default_object_id
");
if (loc88.Length > 0)
{
sql += "union all" +
string.Format(tsql_place.Replace(
" select value from sys.extended_properties where major_id = a.object_id AND minor_id = a.column_id",
" select value from sys.extended_properties where major_id = a.object_id AND minor_id = a.parameter_id"), @"
,cast(0 as bit) 'isnullable'
,a.is_output 'isidentity'
,'' as 'defaultvalue'
from sys.parameters", loc88.ToString().Replace("a.table_name", "a.object_id"), "");
}
sql = $"use [{db}];{sql};use [{olddatabase}]; ";
ds = _orm.Ado.ExecuteArray(CommandType.Text, sql);
if (ds == null) return loc1;
var position = 0;
foreach (object[] row in ds)
{
var table_id = string.Concat(row[0]);
var object_id = int.Parse(string.Concat(row[1]));
var column = string.Concat(row[2]);
var type = string.Concat(row[3]);
var max_length = int.Parse(string.Concat(row[4]));
var sqlType = string.Concat(row[5]);
var comment = string.Concat(row[6]);
var is_nullable = bool.Parse(string.Concat(row[7]));
var is_identity = bool.Parse(string.Concat(row[8]));
var defaultValue = string.Concat(row[9]);
if (max_length == 0) max_length = -1;
loc3[object_id].Add(column, new DbColumnInfo
{
Name = column,
MaxLength = max_length,
IsIdentity = is_identity,
IsNullable = is_nullable,
IsPrimary = false,
DbTypeText = type,
DbTypeTextFull = sqlType,
Table = loc2[object_id],
Comment = comment,
DefaultValue = defaultValue,
Position = ++position
});
loc3[object_id][column].DbType = this.GetDbType(loc3[object_id][column]);
loc3[object_id][column].CsType = this.GetCsTypeInfo(loc3[object_id][column]);
}
sql = $@"
use [{db}];
select
a.object_id 'object_id'
,c.name 'column'
,b.name 'index_id'
,b.is_unique 'isunique'
,b.is_primary_key 'isprimarykey'
,cast(case when b.type_desc = 'CLUSTERED' then 1 else 0 end as bit) 'isclustered'
,case when a.is_descending_key = 1 then 1 else 0 end 'isdesc'
from sys.index_columns a
inner join sys.indexes b on b.object_id = a.object_id and b.index_id = a.index_id
left join sys.columns c on c.object_id = a.object_id and c.column_id = a.column_id
where {loc8.ToString().Replace("a.table_name", "a.object_id")}
;
use [{olddatabase}];
";
ds = _orm.Ado.ExecuteArray(CommandType.Text, sql);
if (ds == null) return loc1;
var indexColumns = new Dictionary<int, Dictionary<string, DbIndexInfo>>();
var uniqueColumns = new Dictionary<int, Dictionary<string, DbIndexInfo>>();
foreach (object[] row in ds)
{
int object_id = int.Parse(string.Concat(row[0]));
string column = string.Concat(row[1]);
string index_id = string.Concat(row[2]);
bool is_unique = bool.Parse(string.Concat(row[3]));
bool is_primary_key = bool.Parse(string.Concat(row[4]));
bool is_clustered = bool.Parse(string.Concat(row[5]));
bool is_desc = string.Concat(row[6]) == "1";
if (loc3.ContainsKey(object_id) == false || loc3[object_id].ContainsKey(column) == false) continue;
DbColumnInfo loc9 = loc3[object_id][column];
if (loc9.IsPrimary == false && is_primary_key) loc9.IsPrimary = is_primary_key;
Dictionary<string, DbIndexInfo> loc10 = null;
DbIndexInfo loc11 = null;
if (!indexColumns.TryGetValue(object_id, out loc10))
indexColumns.Add(object_id, loc10 = new Dictionary<string, DbIndexInfo>());
if (!loc10.TryGetValue(index_id, out loc11))
loc10.Add(index_id, loc11 = new DbIndexInfo());
loc11.Columns.Add(new DbIndexColumnInfo { Column = loc9, IsDesc = is_desc });
if (is_unique && !is_primary_key)
{
if (!uniqueColumns.TryGetValue(object_id, out loc10))
uniqueColumns.Add(object_id, loc10 = new Dictionary<string, DbIndexInfo>());
if (!loc10.TryGetValue(index_id, out loc11))
loc10.Add(index_id, loc11 = new DbIndexInfo());
loc11.Columns.Add(new DbIndexColumnInfo { Column = loc9, IsDesc = is_desc });
}
}
foreach (var object_id in indexColumns.Keys)
{
foreach (var column in indexColumns[object_id])
loc2[object_id].IndexesDict.Add(column.Key, column.Value);
}
foreach (var object_id in uniqueColumns.Keys)
{
foreach (var column in uniqueColumns[object_id])
{
column.Value.Columns.Sort((c1, c2) => c1.Column.Name.CompareTo(c2.Column.Name));
loc2[object_id].UniquesDict.Add(column.Key, column.Value);
}
}
if (tbname == null)
{
sql = $@"
use [{db}];
select
b.object_id 'object_id'
,c.name 'column'
,e.name 'fkid'
,a.referenced_object_id
,cast(1 as bit) 'isforeignkey'
,d.name 'referenced_column'
,null 'referenced_sln'
,null 'referenced_table'
from sys.foreign_key_columns a
inner join sys.tables b on b.object_id = a.parent_object_id
inner join sys.columns c on c.object_id = a.parent_object_id and c.column_id = a.parent_column_id
inner join sys.columns d on d.object_id = a.referenced_object_id and d.column_id = a.referenced_column_id
left join sys.foreign_keys e on e.object_id = a.constraint_object_id
where {loc8.ToString().Replace("a.table_name", "b.object_id")}
;
use [{olddatabase}];
";
ds = _orm.Ado.ExecuteArray(CommandType.Text, sql);
if (ds == null) return loc1;
var fkColumns = new Dictionary<int, Dictionary<string, DbForeignInfo>>();
foreach (object[] row in ds)
{
int object_id, referenced_object_id;
int.TryParse(string.Concat(row[0]), out object_id);
var column = string.Concat(row[1]);
string fk_id = string.Concat(row[2]);
int.TryParse(string.Concat(row[3]), out referenced_object_id);
var is_foreign_key = bool.Parse(string.Concat(row[4]));
var referenced_column = string.Concat(row[5]);
var referenced_db = string.Concat(row[6]);
var referenced_table = string.Concat(row[7]);
DbColumnInfo loc9 = loc3[object_id][column];
DbTableInfo loc10 = null;
DbColumnInfo loc11 = null;
bool isThisSln = referenced_object_id != 0;
if (isThisSln)
{
loc10 = loc2[referenced_object_id];
loc11 = loc3[referenced_object_id][referenced_column];
}
else
{
}
Dictionary<string, DbForeignInfo> loc12 = null;
DbForeignInfo loc13 = null;
if (!fkColumns.TryGetValue(object_id, out loc12))
fkColumns.Add(object_id, loc12 = new Dictionary<string, DbForeignInfo>());
if (!loc12.TryGetValue(fk_id, out loc13))
loc12.Add(fk_id, loc13 = new DbForeignInfo { Table = loc2[object_id], ReferencedTable = loc10 });
loc13.Columns.Add(loc9);
loc13.ReferencedColumns.Add(loc11);
}
foreach (var table_id in fkColumns.Keys)
foreach (var fk in fkColumns[table_id])
loc2[table_id].ForeignsDict.Add(fk.Key, fk.Value);
}
foreach (var table_id in loc3.Keys)
{
foreach (var loc5 in loc3[table_id].Values)
{
loc2[table_id].Columns.Add(loc5);
if (loc5.IsIdentity) loc2[table_id].Identitys.Add(loc5);
if (loc5.IsPrimary) loc2[table_id].Primarys.Add(loc5);
}
}
foreach (var loc4 in loc2.Values)
{
//if (loc4.Primarys.Count == 0 && loc4.UniquesDict.Count > 0)
//{
// foreach (var loc5 in loc4.UniquesDict.First().Value.Columns)
// {
// loc5.Column.IsPrimary = true;
// loc4.Primarys.Add(loc5.Column);
// }
//}
loc4.Primarys.Sort((c1, c2) => c1.Name.CompareTo(c2.Name));
loc4.Columns.Sort((c1, c2) =>
{
int compare = c2.IsPrimary.CompareTo(c1.IsPrimary);
if (compare == 0)
{
bool b1 = loc4.ForeignsDict.Values.Where(fk => fk.Columns.Where(c3 => c3.Name == c1.Name).Any()).Any();
bool b2 = loc4.ForeignsDict.Values.Where(fk => fk.Columns.Where(c3 => c3.Name == c2.Name).Any()).Any();
compare = b2.CompareTo(b1);
}
if (compare == 0) compare = c1.Name.CompareTo(c2.Name);
return compare;
});
loc1.Add(loc4);
}
loc1.Sort((t1, t2) =>
{
var ret = t1.Schema.CompareTo(t2.Schema);
if (ret == 0) ret = t1.Name.CompareTo(t2.Name);
return ret;
});
loc2.Clear();
loc3.Clear();
tables.AddRange(loc1);
}
return tables;
}
public List<DbEnumInfo> GetEnumsByDatabase(params string[] database)
{
return new List<DbEnumInfo>();
}
}
}

View File

@ -0,0 +1,573 @@
using FreeSql.Internal;
using System;
using System.Collections;
using System.Linq;
using System.Linq.Expressions;
using System.Text;
using System.Text.RegularExpressions;
namespace FreeSql.Custom.SqlServer
{
class CustomSqlServerExpression : CommonExpression
{
public CustomSqlServerExpression(CommonUtils common) : base(common) { }
public override string ExpressionLambdaToSqlOther(Expression exp, ExpTSC tsc)
{
Func<Expression, string> getExp = exparg => ExpressionLambdaToSql(exparg, tsc);
switch (exp.NodeType)
{
case ExpressionType.ArrayLength:
var arrOper = (exp as UnaryExpression)?.Operand;
if (arrOper.Type == typeof(byte[])) return $"datalength({getExp(arrOper)})";
break;
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 $"(cast({getExp(operandExp)} as varchar) not in ('0','false'))";
case "System.Byte": return $"cast({getExp(operandExp)} as tinyint)";
case "System.Char": return $"substring(cast({getExp(operandExp)} as nvarchar),1,1)";
case "System.DateTime": return ExpressionConstDateTime(operandExp) ?? $"cast({getExp(operandExp)} as datetime)";
case "System.Decimal": return $"cast({getExp(operandExp)} as decimal(36,18))";
case "System.Double": return $"cast({getExp(operandExp)} as decimal(32,16))";
case "System.Int16": return $"cast({getExp(operandExp)} as smallint)";
case "System.Int32": return $"cast({getExp(operandExp)} as int)";
case "System.Int64": return $"cast({getExp(operandExp)} as bigint)";
case "System.SByte": return $"cast({getExp(operandExp)} as tinyint)";
case "System.Single": return $"cast({getExp(operandExp)} as decimal(14,7))";
case "System.String":
return gentype == typeof(Guid) ?
$"cast({getExp(operandExp)} as varchar(36))" :
$"cast({getExp(operandExp)} as nvarchar{(gentype.IsNumberType() || gentype.IsEnum ? "(100)" : "(max)")})";
case "System.UInt16": return $"cast({getExp(operandExp)} as smallint)";
case "System.UInt32": return $"cast({getExp(operandExp)} as int)";
case "System.UInt64": return $"cast({getExp(operandExp)} as bigint)";
case "System.Guid": return $"cast({getExp(operandExp)} as uniqueidentifier)";
}
}
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 $"(cast({getExp(callExp.Arguments[0])} as varchar) not in ('0','false'))";
case "System.Byte": return $"cast({getExp(callExp.Arguments[0])} as tinyint)";
case "System.Char": return $"substring(cast({getExp(callExp.Arguments[0])} as nvarchar),1,1)";
case "System.DateTime": return ExpressionConstDateTime(callExp.Arguments[0]) ?? $"cast({getExp(callExp.Arguments[0])} as datetime)";
case "System.Decimal": return $"cast({getExp(callExp.Arguments[0])} as decimal(36,18))";
case "System.Double": return $"cast({getExp(callExp.Arguments[0])} as decimal(32,16))";
case "System.Int16": return $"cast({getExp(callExp.Arguments[0])} as smallint)";
case "System.Int32": return $"cast({getExp(callExp.Arguments[0])} as int)";
case "System.Int64": return $"cast({getExp(callExp.Arguments[0])} as bigint)";
case "System.SByte": return $"cast({getExp(callExp.Arguments[0])} as tinyint)";
case "System.Single": return $"cast({getExp(callExp.Arguments[0])} as decimal(14,7))";
case "System.UInt16": return $"cast({getExp(callExp.Arguments[0])} as smallint)";
case "System.UInt32": return $"cast({getExp(callExp.Arguments[0])} as int)";
case "System.UInt64": return $"cast({getExp(callExp.Arguments[0])} as bigint)";
case "System.Guid": return $"cast({getExp(callExp.Arguments[0])} as uniqueidentifier)";
}
return null;
case "NewGuid":
switch (callExp.Method.DeclaringType.NullableTypeOrThis().ToString())
{
case "System.Guid": return $"newid()";
}
return null;
case "Next":
if (callExp.Object?.Type == typeof(Random)) return "cast(rand()*1000000000 as int)";
return null;
case "NextDouble":
if (callExp.Object?.Type == typeof(Random)) return "rand()";
return null;
case "Random":
if (callExp.Method.DeclaringType.IsNumberType()) return "rand()";
return null;
case "ToString":
if (callExp.Object != null)
{
var gentype2 = callExp.Object.Type.NullableTypeOrThis();
if (gentype2.IsEnum)
{
tsc.SetMapColumnTmp(null);
var oldMapType = tsc.SetMapTypeReturnOld(typeof(string));
var enumStr = ExpressionLambdaToSql(callExp.Object, tsc);
tsc.SetMapColumnTmp(null).SetMapTypeReturnOld(oldMapType);
return enumStr;
}
var value = ExpressionGetValue(callExp.Object, out var success);
if (success) return formatSql(value, typeof(string), null, null);
return callExp.Arguments.Count == 0 ? (gentype2 == typeof(Guid) ?
$"cast({getExp(callExp.Object)} as varchar(36))" :
$"cast({getExp(callExp.Object)} as nvarchar{(gentype2.IsNumberType() || gentype2.IsEnum ? "(100)" : "(max)")})") : 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 $"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 = objExp?.NodeType == ExpressionType.MemberAccess ? tsc.SetDbParamsReturnOld(null) : null; //#900 UseGenerateCommandParameterWithLambda(true) 子查询 bug、以及 #1173 参数化 bug
tsc.isNotSetMapColumnTmp = true;
var left = objExp == null ? null : getExp(objExp);
tsc.isNotSetMapColumnTmp = false;
tsc.SetMapColumnTmp(null).SetMapTypeReturnOld(oldMapType);
if (oldDbParams != null) 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(",");
if (a % 500 == 499) arrSb.Append(" \r\n \r\n"); //500元素分割, 3空格\r\n4空格
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 $"len({left})";
}
return null;
}
public override string ExpressionLambdaToSqlMemberAccessDateTime(MemberExpression exp, ExpTSC tsc)
{
if (exp.Expression == null)
{
switch (exp.Member.Name)
{
case "Now": return _common.Now;
case "UtcNow": return _common.NowUtc;
case "Today": return "convert(char(10),getdate(),120)";
case "MinValue": return "'1753/1/1 0:00:00'";
case "MaxValue": return "'9999/12/31 23:59:59'";
}
return null;
}
var left = ExpressionLambdaToSql(exp.Expression, tsc);
switch (exp.Member.Name)
{
case "Date": return $"convert(char(10),{left},120)";
case "TimeOfDay": return $"datediff(second, convert(char(10),{left},120), {left})";
case "DayOfWeek": return $"(datepart(weekday, {left})-1)";
case "Day": return $"datepart(day, {left})";
case "DayOfYear": return $"datepart(dayofyear, {left})";
case "Month": return $"datepart(month, {left})";
case "Year": return $"datepart(year, {left})";
case "Hour": return $"datepart(hour, {left})";
case "Minute": return $"datepart(minute, {left})";
case "Second": return $"datepart(second, {left})";
case "Millisecond": return $"(datepart(millisecond, {left})/1000)";
case "Ticks": return $"(cast(datediff(second, '1970-1-1', {left}) as bigint)*10000000+621355968000000000)";
}
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 $"floor(({left})/{60 * 60 * 24})";
case "Hours": return $"floor(({left})/{60 * 60}%24)";
case "Milliseconds": return $"(cast({left} as bigint)*1000)";
case "Minutes": return $"floor(({left})/60%60)";
case "Seconds": return $"(({left})%60)";
case "Ticks": return $"(cast({left} as bigint)*10000000)";
case "TotalDays": return $"(({left})/{60 * 60 * 24})";
case "TotalHours": return $"(({left})/{60 * 60})";
case "TotalMilliseconds": return $"(cast({left} as bigint)*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":
var arg1 = getExp(exp.Arguments[0]);
return $"({arg1} is null or {arg1} = '')";
case "IsNullOrWhiteSpace":
var arg2 = getExp(exp.Arguments[0]);
return $"({arg2} is null or {arg2} = '' or ltrim({arg2}) = '')";
case "Concat":
if (exp.Arguments.Count == 1 && exp.Arguments[0].NodeType == ExpressionType.NewArrayInit && exp.Arguments[0] is NewArrayExpression concatNewArrExp)
return _common.StringConcat(concatNewArrExp.Expressions.Select(a => getExp(a)).ToArray(), concatNewArrExp.Expressions.Select(a => a.Type).ToArray());
return _common.StringConcat(exp.Arguments.Select(a => getExp(a)).ToArray(), exp.Arguments.Select(a => a.Type).ToArray());
case "Format":
if (exp.Arguments[0].NodeType != ExpressionType.Constant) throw new Exception(CoreStrings.Not_Implemented_Expression_ParameterUseConstant(exp,exp.Arguments[0]));
var expArgs0 = ExpressionLambdaToSql(exp.Arguments[0], tsc);
if (exp.Arguments.Count == 1) return expArgs0;
var nchar = expArgs0.StartsWith("N'") ? "N" : "";
var expArgsHack = exp.Arguments.Count == 2 && exp.Arguments[1].NodeType == ExpressionType.NewArrayInit ?
(exp.Arguments[1] as NewArrayExpression).Expressions : exp.Arguments.Where((a, z) => z > 0);
//3个 {} 时Arguments 解析出来是分开的
//4个 {} 时Arguments[1] 只能解析这个出来,然后里面是 NewArray []
var expArgs = expArgsHack.Select(a =>
{
var atype = (a as UnaryExpression)?.Operand.Type.NullableTypeOrThis() ?? a.Type.NullableTypeOrThis();
if (atype == typeof(string)) return $"'+{_common.IsNull(ExpressionLambdaToSql(a, tsc), "''")}+{nchar}'";
if (atype == typeof(Guid)) return $"'+{_common.IsNull($"cast({ExpressionLambdaToSql(a, tsc)} as char(36))", "''")}+{nchar}'";
if (atype.IsNumberType()) return $"'+{_common.IsNull($"cast({ExpressionLambdaToSql(a, tsc)} as varchar)", "''")}+{nchar}'";
return $"'+{_common.IsNull($"cast({ExpressionLambdaToSql(a, tsc)} as nvarchar(max))", "''")}+{nchar}'";
}).ToArray();
return string.Format(expArgs0, expArgs);
case "Join":
if (exp.IsStringJoin(out var tolistObjectExp, out var toListMethod, out var toListArgs1))
{
var newToListArgs0 = Expression.Call(tolistObjectExp, toListMethod,
Expression.Lambda(
Expression.Call(
typeof(string).GetMethod("Concat", new[] { typeof(object), typeof(object) }),
Expression.Convert(exp.Arguments[0], typeof(object)),
Expression.Convert(toListArgs1.Body, typeof(object))),
toListArgs1.Parameters));
var newToListSql = getExp(newToListArgs0);
if (string.IsNullOrEmpty(newToListSql) == false && newToListSql.StartsWith("(") && newToListSql.EndsWith(")"))
{
newToListSql = $"stuff({newToListSql.Substring(0, newToListSql.Length - 1)} FOR XML PATH('')),1,len({getExp(exp.Arguments[0])}),'')";
return newToListSql;
}
}
break;
}
}
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 (args0Value.Contains("%"))
{
if (exp.Method.Name == "StartsWith") return $"charindex({args0Value}, {left}) = 1";
if (exp.Method.Name == "EndsWith") return $"charindex({args0Value}, {left}) = len({left})-len({args0Value})+1";
return $"charindex({args0Value}, {left}) > 0";
}
if (exp.Method.Name == "StartsWith") return $"({left}) LIKE {(args0Value.EndsWith("'") ? args0Value.Insert(args0Value.Length - 1, "%") : $"(cast({args0Value} as nvarchar(max))+'%')")}";
if (exp.Method.Name == "EndsWith") return $"({left}) LIKE {(args0Value.StartsWith("'") ? args0Value.Insert(1, "%") : $"('%'+cast({args0Value} as nvarchar(max)))")}";
if (args0Value.StartsWith("'") && args0Value.EndsWith("'")) return $"({left}) LIKE {args0Value.Insert(1, "%").Insert(args0Value.Length, "%")}";
return $"({left}) LIKE ('%'+cast({args0Value} as nvarchar(max))+'%')";
case "ToLower": return $"lower({left})";
case "ToUpper": return $"upper({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 $"left({left}, {substrArgs1})";
return $"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 $"(charindex({indexOfFindStr}, {left}, {locateArgs1})-1)";
}
return $"(charindex({indexOfFindStr}, {left})-1)";
case "PadLeft":
if (exp.Arguments.Count == 1) return $"lpad({left}, {getExp(exp.Arguments[0])})";
return $"lpad({left}, {getExp(exp.Arguments[0])}, {getExp(exp.Arguments[1])})";
case "PadRight":
if (exp.Arguments.Count == 1) return $"rpad({left}, {getExp(exp.Arguments[0])})";
return $"rpad({left}, {getExp(exp.Arguments[0])}, {getExp(exp.Arguments[1])})";
case "Trim": return $"ltrim(rtrim({left}))";
case "TrimStart": return $"ltrim({left})";
case "TrimEnd": return $"rtrim({left})";
case "Replace": return $"replace({left}, {getExp(exp.Arguments[0])}, {getExp(exp.Arguments[1])})";
case "CompareTo": return $"({left} - {getExp(exp.Arguments[0])})";
case "Equals": return $"({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 $"abs({getExp(exp.Arguments[0])})";
case "Sign": return $"sign({getExp(exp.Arguments[0])})";
case "Floor": return $"floor({getExp(exp.Arguments[0])})";
case "Ceiling": return $"ceiling({getExp(exp.Arguments[0])})";
case "Round":
if (exp.Arguments.Count > 1 && exp.Arguments[1].Type.FullName == "System.Int32") return $"round({getExp(exp.Arguments[0])}, {getExp(exp.Arguments[1])})";
return $"round({getExp(exp.Arguments[0])}, 0)";
case "Exp": return $"exp({getExp(exp.Arguments[0])})";
case "Log": return $"log({getExp(exp.Arguments[0])})";
case "Log10": return $"log10({getExp(exp.Arguments[0])})";
case "Pow": return $"power({getExp(exp.Arguments[0])}, {getExp(exp.Arguments[1])})";
case "Sqrt": return $"sqrt({getExp(exp.Arguments[0])})";
case "Cos": return $"cos({getExp(exp.Arguments[0])})";
case "Sin": return $"sin({getExp(exp.Arguments[0])})";
case "Tan": return $"tan({getExp(exp.Arguments[0])})";
case "Acos": return $"acos({getExp(exp.Arguments[0])})";
case "Asin": return $"asin({getExp(exp.Arguments[0])})";
case "Atan": return $"atan({getExp(exp.Arguments[0])})";
case "Atan2": return $"atan2({getExp(exp.Arguments[0])}, {getExp(exp.Arguments[1])})";
case "Truncate": return $"floor({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 $"({getExp(exp.Arguments[0])} - ({getExp(exp.Arguments[1])}))";
case "DaysInMonth": return $"datepart(day, dateadd(day, -1, dateadd(month, 1, cast({getExp(exp.Arguments[0])} as varchar(100)) + '-' + cast({getExp(exp.Arguments[1])} as varchar(100)) + '-1')))";
case "Equals": return $"({getExp(exp.Arguments[0])} = {getExp(exp.Arguments[1])})";
case "IsLeapYear":
var isLeapYearArgs1 = getExp(exp.Arguments[0]);
return $"(({isLeapYearArgs1})%4=0 AND ({isLeapYearArgs1})%100<>0 OR ({isLeapYearArgs1})%400=0)";
case "Parse": return ExpressionConstDateTime(exp.Arguments[0]) ?? $"cast({getExp(exp.Arguments[0])} as datetime)";
case "ParseExact":
case "TryParse":
case "TryParseExact": return ExpressionConstDateTime(exp.Arguments[0]) ?? $"cast({getExp(exp.Arguments[0])} as datetime)";
}
}
else
{
var left = getExp(exp.Object);
var args1 = exp.Arguments.Count == 0 ? null : getExp(exp.Arguments[0]);
switch (exp.Method.Name)
{
case "Add": return $"dateadd(second, {args1}, {left})";
case "AddDays": return $"dateadd(day, {args1}, {left})";
case "AddHours": return $"dateadd(hour, {args1}, {left})";
case "AddMilliseconds": return $"dateadd(second, ({args1})/1000, {left})";
case "AddMinutes": return $"dateadd(minute, {args1}, {left})";
case "AddMonths": return $"dateadd(month, {args1}, {left})";
case "AddSeconds": return $"dateadd(second, {args1}, {left})";
case "AddTicks": return $"dateadd(second, ({args1})/10000000, {left})";
case "AddYears": return $"dateadd(year, {args1}, {left})";
case "Subtract":
switch ((exp.Arguments[0].Type.IsNullableType() ? exp.Arguments[0].Type.GetGenericArguments().FirstOrDefault() : exp.Arguments[0].Type).FullName)
{
case "System.DateTime": return $"datediff(second, {args1}, {left})";
case "System.TimeSpan": return $"dateadd(second, ({args1})*-1, {left})";
}
break;
case "Equals": return $"({left} = {args1})";
case "CompareTo": return $"datediff(second,{args1},{left})";
case "ToString":
if (left.EndsWith(" as datetime)") == false) left = $"cast({left} as datetime)";
if (exp.Arguments.Count == 0) return $"convert(varchar, {left}, 121)";
switch (args1.TrimStart('N'))
{
case "'yyyy-MM-dd HH:mm:ss'": return $"convert(char(19), {left}, 120)";
case "'yyyy-MM-dd HH:mm'": return $"substring(convert(char(19), {left}, 120), 1, 16)";
case "'yyyy-MM-dd HH'": return $"substring(convert(char(19), {left}, 120), 1, 13)";
case "'yyyy-MM-dd'": return $"convert(char(10), {left}, 23)";
case "'yyyy-MM'": return $"substring(convert(char(10), {left}, 23), 1, 7)";
case "'yyyyMMdd'": return $"convert(char(8), {left}, 112)";
case "'yyyyMM'": return $"substring(convert(char(8), {left}, 112), 1, 6)";
case "'yyyy'": return $"substring(convert(char(8), {left}, 112), 1, 4)";
case "'HH:mm:ss'": return $"convert(char(8), {left}, 24)";
}
var isMatched = false;
var nchar = args1.StartsWith("N'") ? "N" : "";
args1 = Regex.Replace(args1, "(yyyy|yy|MM|M|dd|d|HH|H|hh|h|mm|m|ss|s|tt|t)", m =>
{
isMatched = true;
switch (m.Groups[1].Value)
{
case "yyyy": return $"' + substring(convert(char(8), {left}, 112), 1, 4) + {nchar}'";
case "yy": return $"' + substring(convert(char(6), {left}, 12), 1, 2) + {nchar}'";
case "MM": return $"' + substring(convert(char(6), {left}, 12), 3, 2) + {nchar}'";
case "M": return $"' + case when substring(convert(char(6), {left}, 12), 3, 1) = '0' then substring(convert(char(6), {left}, 12), 4, 1) else substring(convert(char(6), {left}, 12), 3, 2) end + {nchar}'";
case "dd": return $"' + substring(convert(char(6), {left}, 12), 5, 2) + {nchar}'";
case "d": return $"' + case when substring(convert(char(6), {left}, 12), 5, 1) = '0' then substring(convert(char(6), {left}, 12), 6, 1) else substring(convert(char(6), {left}, 12), 5, 2) end + {nchar}'";
case "HH": return $"' + substring(convert(char(8), {left}, 24), 1, 2) + {nchar}'";
case "H": return $"' + case when substring(convert(char(8), {left}, 24), 1, 1) = '0' then substring(convert(char(8), {left}, 24), 2, 1) else substring(convert(char(8), {left}, 24), 1, 2) end + {nchar}'";
case "hh":
return $"' + case cast(case when substring(convert(char(8), {left}, 24), 1, 1) = '0' then substring(convert(char(8), {left}, 24), 2, 1) else substring(convert(char(8), {left}, 24), 1, 2) end as int) % 12" +
$"when 0 then '12' when 1 then '01' when 2 then '02' when 3 then '03' when 4 then '04' when 5 then '05' when 6 then '06' when 7 then '07' when 8 then '08' when 9 then '09' when 10 then '10' when 11 then '11' end + {nchar}'";
case "h":
return $"' + case cast(case when substring(convert(char(8), {left}, 24), 1, 1) = '0' then substring(convert(char(8), {left}, 24), 2, 1) else substring(convert(char(8), {left}, 24), 1, 2) end as int) % 12" +
$"when 0 then '12' when 1 then '1' when 2 then '2' when 3 then '3' when 4 then '4' when 5 then '5' when 6 then '6' when 7 then '7' when 8 then '8' when 9 then '9' when 10 then '10' when 11 then '11' end + {nchar}'";
case "mm": return $"' + substring(convert(char(8), {left}, 24), 4, 2) + {nchar}'";
case "m": return $"' + case when substring(convert(char(8), {left}, 24), 4, 1) = '0' then substring(convert(char(8), {left}, 24), 5, 1) else substring(convert(char(8), {left}, 24), 4, 2) end + {nchar}'";
case "ss": return $"' + substring(convert(char(8), {left}, 24), 7, 2) + {nchar}'";
case "s": return $"' + case when substring(convert(char(8), {left}, 24), 7, 1) = '0' then substring(convert(char(8), {left}, 24), 8, 1) else substring(convert(char(8), {left}, 24), 7, 2) end + {nchar}'";
case "tt": return $"' + case when cast(case when substring(convert(char(8), {left}, 24), 1, 1) = '0' then substring(convert(char(8), {left}, 24), 2, 1) else substring(convert(char(8), {left}, 24), 1, 2) end as int) >= 12 then 'PM' else 'AM' end + {nchar}'";
case "t": return $"' + case when cast(case when substring(convert(char(8), {left}, 24), 1, 1) = '0' then substring(convert(char(8), {left}, 24), 2, 1) else substring(convert(char(8), {left}, 24), 1, 2) end as int) >= 12 then 'P' else 'A' end + {nchar}'";
}
return m.Groups[0].Value;
});
return isMatched == false ? args1 : $"({args1})";
}
}
return null;
}
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 $"cast({getExp(exp.Arguments[0])} as bigint)";
case "ParseExact":
case "TryParse":
case "TryParseExact": return $"cast({getExp(exp.Arguments[0])} as bigint)";
}
}
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 $"cast({left} as varchar(100))";
}
}
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 $"(cast({getExp(exp.Arguments[0])} as varchar) not in ('0','false'))";
case "ToByte": return $"cast({getExp(exp.Arguments[0])} as tinyint)";
case "ToChar": return $"substring(cast({getExp(exp.Arguments[0])} as nvarchar),1,1)";
case "ToDateTime": return ExpressionConstDateTime(exp.Arguments[0]) ?? $"cast({getExp(exp.Arguments[0])} as datetime)";
case "ToDecimal": return $"cast({getExp(exp.Arguments[0])} as decimal(36,18))";
case "ToDouble": return $"cast({getExp(exp.Arguments[0])} as decimal(32,16))";
case "ToInt16": return $"cast({getExp(exp.Arguments[0])} as smallint)";
case "ToInt32": return $"cast({getExp(exp.Arguments[0])} as int)";
case "ToInt64": return $"cast({getExp(exp.Arguments[0])} as bigint)";
case "ToSByte": return $"cast({getExp(exp.Arguments[0])} as tinyint)";
case "ToSingle": return $"cast({getExp(exp.Arguments[0])} as decimal(14,7))";
case "ToString":
var gentype = exp.Arguments[0].Type.NullableTypeOrThis();
return gentype == typeof(Guid) ?
$"cast({getExp(exp.Arguments[0])} as varchar(36))" :
$"cast({getExp(exp.Arguments[0])} as nvarchar{(gentype.IsNumberType() || gentype.IsEnum ? "(100)" : "(max)")})";
case "ToUInt16": return $"cast({getExp(exp.Arguments[0])} as smallint)";
case "ToUInt32": return $"cast({getExp(exp.Arguments[0])} as int)";
case "ToUInt64": return $"cast({getExp(exp.Arguments[0])} as bigint)";
}
}
return null;
}
}
}

View File

@ -0,0 +1,57 @@
using FreeSql.Internal.CommonProvider;
using System;
using System.Data.Common;
using System.Threading;
namespace FreeSql.Custom.SqlServer
{
public class CustomSqlServerProvider<TMark> : BaseDbProvider, IFreeSql<TMark>
{
public override ISelect<T1> CreateSelectProvider<T1>(object dywhere) => new CustomSqlServerSelect<T1>(this, this.InternalCommonUtils, this.InternalCommonExpression, dywhere);
public override IInsert<T1> CreateInsertProvider<T1>() => new CustomSqlServerInsert<T1>(this, this.InternalCommonUtils, this.InternalCommonExpression);
public override IUpdate<T1> CreateUpdateProvider<T1>(object dywhere) => new CustomSqlServerUpdate<T1>(this, this.InternalCommonUtils, this.InternalCommonExpression, dywhere);
public override IDelete<T1> CreateDeleteProvider<T1>(object dywhere) => new CustomSqlServerDelete<T1>(this, this.InternalCommonUtils, this.InternalCommonExpression, dywhere);
public override IInsertOrUpdate<T1> CreateInsertOrUpdateProvider<T1>() => new CustomSqlServerInsertOrUpdate<T1>(this, this.InternalCommonUtils, this.InternalCommonExpression);
public CustomSqlServerProvider(string masterConnectionString, string[] slaveConnectionString, Func<DbConnection> connectionFactory = null)
{
this.InternalCommonUtils = new CustomSqlServerUtils(this);
this.InternalCommonExpression = new CustomSqlServerExpression(this.InternalCommonUtils);
this.Ado = new CustomSqlServerAdo(this.InternalCommonUtils, masterConnectionString, slaveConnectionString, connectionFactory);
this.Aop = new AopProvider();
this.DbFirst = new CustomSqlServerDbFirst(this, this.InternalCommonUtils, this.InternalCommonExpression);
this.CodeFirst = new CustomSqlServerCodeFirst(this, this.InternalCommonUtils, this.InternalCommonExpression);
if (this.Ado.MasterPool != null)
try
{
using (var conn = this.Ado.MasterPool.Get())
{
(this.InternalCommonUtils as CustomSqlServerUtils).ServerVersion = int.Parse(conn.Value.ServerVersion.Split('.')[0]);
}
}
catch
{
}
}
~CustomSqlServerProvider() => 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);
FreeSqlCustomAdapterGlobalExtensions._dicDbProviderFactory.TryRemove(Ado.Identifier, out var trydbpf);
}
}
}
}

View File

@ -0,0 +1,109 @@
using FreeSql.Internal;
using FreeSql.Internal.CommonProvider;
using FreeSql.Internal.Model;
using System;
using System.Collections.Generic;
using System.Data;
using System.Data.Common;
using System.Globalization;
using System.Text;
namespace FreeSql.Custom.SqlServer
{
public class CustomSqlServerUtils : CommonUtils
{
DbProviderFactory Factory => FreeSqlCustomAdapterGlobalExtensions.GetDbProviderFactory(_orm);
public CustomSqlServerUtils(IFreeSql orm) : base(orm)
{
}
public bool IsSelectRowNumber => ServerVersion <= 10;
public bool IsSqlServer2005 => ServerVersion == 9;
public int ServerVersion = 0;
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 = Factory.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 = Factory.CreateParameter();
ret.ParameterName = $"@{name}";
ret.Value = value;
var tp = _orm.CodeFirst.GetDbInfo(type)?.type;
if (tp != null) ret.DbType = (DbType)tp.Value;
return ret;
});
public override string FormatSql(string sql, params object[] args) => sql?.FormatCustomSqlServer(args);
public override string QuoteSqlNameAdapter(params string[] name)
{
if (name.Length == 1)
{
var nametrim = name[0].Trim();
if (nametrim.StartsWith("(") && nametrim.EndsWith(")"))
return nametrim; //原生SQL
if (nametrim.StartsWith("[") && nametrim.EndsWith("]"))
return nametrim;
return $"[{nametrim.Replace(".", "].[")}]";
}
return $"[{string.Join("].[", name)}]";
}
public override string TrimQuoteSqlName(string name)
{
var nametrim = name.Trim();
if (nametrim.StartsWith("(") && nametrim.EndsWith(")"))
return nametrim; //原生SQL
return $"{nametrim.TrimStart('[').TrimEnd(']').Replace("].[", ".").Replace(".[", ".")}";
}
public override string[] SplitTableName(string name) => GetSplitTableNames(name, '[', ']', 3);
public override string QuoteParamterName(string name) => $"@{name}";
public override string IsNull(string sql, object value) => $"isnull({sql}, {value})";
public override string StringConcat(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 if (types[a].IsNumberType()) news[a] = $"cast({objs[a]} as varchar)";
else news[a] = $"cast({objs[a]} as nvarchar(max))";
}
return string.Join(" + ", news);
}
public override string Mod(string left, string right, Type leftType, Type rightType) => $"{left} % {right}";
public override string Div(string left, string right, Type leftType, Type rightType) => $"{left} / {right}";
public override string Now => "getdate()";
public override string NowUtc => "getutcdate()";
public override string QuoteWriteParamterAdapter(Type type, string paramterName) => paramterName;
protected override string QuoteReadColumnAdapter(Type type, Type mapType, string columnName) => 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 $"0x{CommonUtils.BytesSqlRaw(value as byte[])}";
if (type == typeof(TimeSpan) || type == typeof(TimeSpan?))
{
var ts = (TimeSpan)value;
value = $"{ts.Hours}:{ts.Minutes}:{ts.Seconds}.{ts.Milliseconds}";
}
return string.Format(CultureInfo.InvariantCulture, "{0}", (_orm.Ado as AdoProvider).AddslashesProcessParam(value, type, col));
}
}
}

Binary file not shown.

View File

@ -0,0 +1,63 @@
# 国产数据库
| 数据库名称 | 提供者 | 系列风格 |
| --- | --- | --- |
| 达梦 | FreeSql.Provider.Dameng | Oracle |
| 神州通用 | FreeSql.Provider.ShenTong | PostgreSQL |
| 人大金仓 | FreeSql.Provider.KingbaseES | PostgreSQL |
| 南大通用 | FreeSql.Provider.GBase | Informix |
| 翰高 | FreeSql.Provider.Custom、FreeSql.Provider.Odbc | PostgreSQL |
由于太多,在此不一一列举,它们大多数语法兼容 MySql、Oracle、SqlServer、PostgreSQL 四种常用数据库之一。
FreeSql.Provider.Custom 提供了这四种数据库适配,并且支持 CodeFirst/DbFirst 以及完整的 FreeSql 功能。
FreeSql.Provider.Custom 不依赖具体 ado.net/odbc/oledb dll 驱动,使用者在外部自行引用 dll 驱动。
访问 MySql 数据库为例:
```csharp
var fsql = new FreeSqlBuilder()
.UseConnectionFactory(DataType.CustomMySql, () =>
new MySqlConnection("Data Source=..."))
.UseNoneParameter(true)
.UseMonitorCommand(Console.WriteLine(cmd.CommandText))
.Build();
fsql.SetDbProviderFactory(MySqlConnectorFactory.Instance);
```
若某国产数据库兼容 MySql SQL先引用对方提供的 DLL然后
- 将上面 new MySqlConnection 替换成 new XxxConnection
- 将上面 MySqlConnectorFactory.Instance 替换成对应的 DbProviderFactory
提示:对方 DLL 一般都会提供这两个现实类
# 自定义适配
除了上面,还提供了自定义适配更多的数据库,比如 mssql2000、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 FreeSqlBuilder()
.UseConnectionString(DataType.Custom, () => new SqlConnection(@"Data Source=..."))
.Build(); //be sure to define as singleton mode
fsql.SetCustomAdapter(new Mssql2000Adapter());
```
适配好新的 CustomAdapter 后,请在 FreeSqlBuilder.Build 之后调用 IFreeSql.SetCustomAdapter 方法生效。

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.Dameng.Curd
{
class DamengDelete<T1> : Internal.CommonProvider.DeleteProvider<T1>
{
public DamengDelete(IFreeSql orm, CommonUtils commonUtils, CommonExpression commonExpression, object dywhere)
: base(orm, commonUtils, commonExpression, dywhere)
{
}
public override List<T1> ExecuteDeleted() => throw new NotImplementedException($"FreeSql.Provider.Dameng {CoreStrings.S_Not_Implemented_Feature}");
#if net40
#else
public override Task<List<T1>> ExecuteDeletedAsync(CancellationToken cancellationToken = default) => throw new NotImplementedException($"FreeSql.Provider.Dameng {CoreStrings.S_Not_Implemented_Feature}");
#endif
}
}

View File

@ -0,0 +1,228 @@
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.Threading;
using System.Threading.Tasks;
namespace FreeSql.Dameng.Curd
{
class DamengInsert<T1> : Internal.CommonProvider.InsertProvider<T1> where T1 : class
{
public DamengInsert(IFreeSql orm, CommonUtils commonUtils, CommonExpression commonExpression)
: base(orm, commonUtils, commonExpression)
{
}
internal IFreeSql InternalOrm => _orm as IFreeSql;
internal DbConnection InternalConnection => _connection;
internal DbTransaction InternalTransaction => _transaction;
public override int ExecuteAffrows() => base.SplitExecuteAffrows(_batchValuesLimit > 0 ? _batchValuesLimit : 500, _batchParameterLimit > 0 ? _batchParameterLimit : 999);
public override long ExecuteIdentity() => base.SplitExecuteIdentity(_batchValuesLimit > 0 ? _batchValuesLimit : 500, _batchParameterLimit > 0 ? _batchParameterLimit : 999);
public override List<T1> ExecuteInserted() => base.SplitExecuteInserted(_batchValuesLimit > 0 ? _batchValuesLimit : 500, _batchParameterLimit > 0 ? _batchParameterLimit : 999);
public override string ToSql()
{
if (_source == null || _source.Any() == false) return null;
var sb = new StringBuilder();
sb.Append("INSERT ");
if (_source.Count > 1) sb.Append("ALL");
_identCol = null;
var sbtb = new StringBuilder();
sbtb.Append("INTO ");
sbtb.Append(_commonUtils.QuoteSqlName(TableRuleInvoke())).Append("(");
var colidx = 0;
foreach (var col in _table.Columns.Values)
{
if (col.Attribute.IsIdentity) _identCol = col;
if (col.Attribute.IsIdentity && _insertIdentity == false && string.IsNullOrEmpty(col.DbInsertValue)) continue;
if (col.Attribute.IsIdentity == false && _ignore.ContainsKey(col.Attribute.Name)) continue;
if (colidx > 0) sbtb.Append(", ");
sbtb.Append(_commonUtils.QuoteSqlName(col.Attribute.Name));
++colidx;
}
sbtb.Append(") ");
_params = _noneParameter ? new DbParameter[0] : new DbParameter[colidx * _source.Count];
var specialParams = new List<DbParameter>();
var didx = 0;
foreach (var d in _source)
{
if (_source.Count > 1) sb.Append("\r\n");
sb.Append(sbtb);
sb.Append("VALUES");
sb.Append("(");
var colidx2 = 0;
foreach (var col in _table.Columns.Values)
{
if (col.Attribute.IsIdentity && _insertIdentity == false && string.IsNullOrEmpty(col.DbInsertValue)) continue;
if (col.Attribute.IsIdentity == false && _ignore.ContainsKey(col.Attribute.Name)) continue;
if (colidx2 > 0) sb.Append(", ");
if (string.IsNullOrEmpty(col.DbInsertValue) == false && _ignoreInsertValueSql.ContainsKey(col.Attribute.Name) == false)
sb.Append(col.DbInsertValue);
else
{
object val = col.GetDbValue(d);
if (val == null && col.Attribute.IsNullable == false) val = col.CsType == typeof(string) ? "" : Utils.GetDataReaderValue(col.CsType.NullableTypeOrThis(), null);//#384
var colsql = _noneParameter ? _commonUtils.GetNoneParamaterSqlValue(specialParams, _noneParameterFlag, col, col.Attribute.MapType, val) :
_commonUtils.QuoteWriteParamterAdapter(col.Attribute.MapType, _commonUtils.QuoteParamterName($"{col.CsName}_{didx}"));
sb.Append(_commonUtils.RewriteColumn(col, colsql));
if (_noneParameter == false)
_params[didx * colidx + colidx2] = _commonUtils.AppendParamter(null, $"{col.CsName}_{didx}", col, col.Attribute.MapType, val);
}
++colidx2;
}
sb.Append(")");
++didx;
}
if (_noneParameter && specialParams.Any()) _params = specialParams.ToArray();
if (_source.Count > 1) sb.Append("\r\n SELECT 1 FROM DUAL");
return sb.ToString();
}
ColumnInfo _identCol;
protected override long RawExecuteIdentity()
{
var sql = this.ToSql();
if (string.IsNullOrEmpty(sql)) return 0;
long ret = 0;
Exception exception = null;
Aop.CurdBeforeEventArgs before = null;
if (_identCol == null || _source.Count > 1)
{
before = new Aop.CurdBeforeEventArgs(_table.Type, _table, Aop.CurdType.Insert, sql, _params);
_orm.Aop.CurdBeforeHandler?.Invoke(this, before);
try
{
ret = _orm.Ado.ExecuteNonQuery(_connection, _transaction, CommandType.Text, sql, _commandTimeout, _params);
}
catch (Exception ex)
{
exception = ex;
throw;
}
finally
{
var after = new Aop.CurdAfterEventArgs(before, exception, ret);
_orm.Aop.CurdAfterHandler?.Invoke(this, after);
}
return 0;
}
var identColName = _commonUtils.QuoteSqlName(_identCol.Attribute.Name);
var identParam = _commonUtils.AppendParamter(null, $"{_identCol.CsName}99", _identCol, _identCol.Attribute.MapType, 0);
identParam.Direction = ParameterDirection.Output;
sql = $"{sql} RETURNING {identColName} INTO {identParam.ParameterName}";
var dbParms = _params.Concat(new[] { identParam }).ToArray();
before = new Aop.CurdBeforeEventArgs(_table.Type, _table, Aop.CurdType.Insert, sql, dbParms);
_orm.Aop.CurdBeforeHandler?.Invoke(this, before);
try
{
_orm.Ado.ExecuteNonQuery(_connection, _transaction, CommandType.Text, sql, _commandTimeout, dbParms);
long.TryParse(string.Concat(identParam.Value), out ret);
}
catch (Exception ex)
{
exception = ex;
throw;
}
finally
{
var after = new Aop.CurdAfterEventArgs(before, exception, ret);
_orm.Aop.CurdAfterHandler?.Invoke(this, after);
}
return ret;
}
protected override List<T1> RawExecuteInserted()
{
var sql = this.ToSql();
if (string.IsNullOrEmpty(sql)) return new List<T1>();
var ret = _source.ToList();
this.RawExecuteAffrows();
return ret;
}
#if net40
#else
public override Task<int> ExecuteAffrowsAsync(CancellationToken cancellationToken = default) => base.SplitExecuteAffrowsAsync(_batchValuesLimit > 0 ? _batchValuesLimit : 500, _batchParameterLimit > 0 ? _batchParameterLimit : 999, cancellationToken);
public override Task<long> ExecuteIdentityAsync(CancellationToken cancellationToken = default) => base.SplitExecuteIdentityAsync(_batchValuesLimit > 0 ? _batchValuesLimit : 500, _batchParameterLimit > 0 ? _batchParameterLimit : 999, cancellationToken);
public override Task<List<T1>> ExecuteInsertedAsync(CancellationToken cancellationToken = default) => base.SplitExecuteInsertedAsync(_batchValuesLimit > 0 ? _batchValuesLimit : 500, _batchParameterLimit > 0 ? _batchParameterLimit : 999, cancellationToken);
async protected override Task<long> RawExecuteIdentityAsync(CancellationToken cancellationToken = default)
{
var sql = this.ToSql();
if (string.IsNullOrEmpty(sql)) return 0;
long ret = 0;
Exception exception = null;
Aop.CurdBeforeEventArgs before = null;
if (_identCol == null || _source.Count > 1)
{
before = new Aop.CurdBeforeEventArgs(_table.Type, _table, Aop.CurdType.Insert, sql, _params);
_orm.Aop.CurdBeforeHandler?.Invoke(this, before);
try
{
ret = await _orm.Ado.ExecuteNonQueryAsync(_connection, _transaction, CommandType.Text, sql, _commandTimeout, _params, cancellationToken);
}
catch (Exception ex)
{
exception = ex;
throw;
}
finally
{
var after = new Aop.CurdAfterEventArgs(before, exception, ret);
_orm.Aop.CurdAfterHandler?.Invoke(this, after);
}
return 0;
}
var identColName = _commonUtils.QuoteSqlName(_identCol.Attribute.Name);
var identParam = _commonUtils.AppendParamter(null, $"{_identCol.CsName}99", _identCol, _identCol.Attribute.MapType, 0);
identParam.Direction = ParameterDirection.Output;
sql = $"{sql} RETURNING {identColName} INTO {identParam.ParameterName}";
var dbParms = _params.Concat(new[] { identParam }).ToArray();
before = new Aop.CurdBeforeEventArgs(_table.Type, _table, Aop.CurdType.Insert, sql, dbParms);
_orm.Aop.CurdBeforeHandler?.Invoke(this, before);
try
{
await _orm.Ado.ExecuteNonQueryAsync(_connection, _transaction, CommandType.Text, sql, _commandTimeout, dbParms, cancellationToken);
long.TryParse(string.Concat(identParam.Value), out ret);
}
catch (Exception ex)
{
exception = ex;
throw;
}
finally
{
var after = new Aop.CurdAfterEventArgs(before, exception, ret);
_orm.Aop.CurdAfterHandler?.Invoke(this, after);
}
return ret;
}
async protected override Task<List<T1>> RawExecuteInsertedAsync(CancellationToken cancellationToken = default)
{
var sql = this.ToSql();
if (string.IsNullOrEmpty(sql)) return new List<T1>();
var ret = _source.ToList();
await this.RawExecuteAffrowsAsync(cancellationToken);
return ret;
}
#endif
}
}

View File

@ -0,0 +1,85 @@
using FreeSql.Internal;
using System;
using System.Collections.Generic;
using System.Data.Common;
using System.Linq;
using System.Text;
namespace FreeSql.Dameng.Curd
{
class DamengInsertOrUpdate<T1> : Internal.CommonProvider.InsertOrUpdateProvider<T1> where T1 : class
{
public DamengInsertOrUpdate(IFreeSql orm, CommonUtils commonUtils, CommonExpression commonExpression)
: base(orm, commonUtils, commonExpression)
{
}
public override string ToSql()
{
var dbParams = new List<DbParameter>();
if (_sourceSql != null) return getMergeSql(null);
if (_source?.Any() != true) return null;
var sqls = new string[2];
var ds = SplitSourceByIdentityValueIsNull(_source);
if (ds.Item1.Any()) sqls[0] = string.Join("\r\n\r\n;\r\n\r\n", ds.Item1.Select(a => getMergeSql(a)));
if (ds.Item2.Any()) sqls[1] = string.Join("\r\n\r\n;\r\n\r\n", ds.Item2.Select(a => getInsertSql(a)));
_params = dbParams.ToArray();
if (ds.Item2.Any() == false) return sqls[0];
if (ds.Item1.Any() == false) return sqls[1];
return string.Join("\r\n\r\n;\r\n\r\n", sqls);
string getMergeSql(List<T1> data)
{
if (_tempPrimarys.Any() == false) throw new Exception(CoreStrings.InsertOrUpdate_Must_Primary_Key(_table.CsName));
var tempPrimaryIsIdentity = _tempPrimarys.Any(b => b.Attribute.IsIdentity);
var sb = new StringBuilder().Append("MERGE INTO ").Append(_commonUtils.QuoteSqlName(TableRuleInvoke())).Append(" t1 \r\nUSING (");
WriteSourceSelectUnionAll(data, sb, dbParams);
sb.Append(" ) t2 ON (").Append(string.Join(" AND ", _tempPrimarys.Select(a => $"t1.{_commonUtils.QuoteSqlName(a.Attribute.Name)} = t2.{_commonUtils.QuoteSqlName(a.Attribute.Name)}"))).Append(") \r\n");
var cols = _table.Columns.Values.Where(a => _updateSetDict.ContainsKey(a.Attribute.Name) ||
_tempPrimarys.Contains(a) == false && a.Attribute.CanUpdate == true && a.Attribute.IsIdentity == false && _updateIgnore.ContainsKey(a.Attribute.Name) == false);
if (_doNothing == false && cols.Any())
sb.Append("WHEN MATCHED THEN \r\n")
.Append(" update set ").Append(string.Join(", ", cols.Select(a =>
{
if (_updateSetDict.TryGetValue(a.Attribute.Name, out var valsql))
return $"{_commonUtils.QuoteSqlName(a.Attribute.Name)} = {valsql}";
return a.Attribute.IsVersion && a.Attribute.MapType != typeof(byte[]) ?
$"{_commonUtils.QuoteSqlName(a.Attribute.Name)} = t1.{_commonUtils.QuoteSqlName(a.Attribute.Name)} + 1" :
$"{_commonUtils.QuoteSqlName(a.Attribute.Name)} = t2.{_commonUtils.QuoteSqlName(a.Attribute.Name)}";
}))).Append(" \r\n");
cols = _table.Columns.Values.Where(a => a.Attribute.CanInsert == true);
if (tempPrimaryIsIdentity == false) cols = cols.Where(a => a.Attribute.IsIdentity == false || string.IsNullOrEmpty(a.DbInsertValue) == false);
if (cols.Any())
sb.Append("WHEN NOT MATCHED THEN \r\n")
.Append(" insert (").Append(string.Join(", ", cols.Select(a => _commonUtils.QuoteSqlName(a.Attribute.Name)))).Append(") \r\n")
.Append(" values (").Append(string.Join(", ", cols.Select(a =>
{
//InsertValueSql = "seq.nextval"
if (tempPrimaryIsIdentity == false && a.Attribute.IsIdentity && string.IsNullOrEmpty(a.DbInsertValue) == false) return a.DbInsertValue;
return $"t2.{_commonUtils.QuoteSqlName(a.Attribute.Name)}";
}))).Append(")");
return sb.ToString();
}
string getInsertSql(List<T1> data)
{
var insert = _orm.Insert<T1>()
.AsTable(_tableRule).AsType(_table.Type)
.WithConnection(_connection)
.WithTransaction(_transaction)
.NoneParameter(true) as Internal.CommonProvider.InsertProvider<T1>;
insert._source = data;
insert._table = _table;
var sql = insert.ToSql();
if (string.IsNullOrEmpty(sql)) return null;
if (insert._params?.Any() == true) dbParams.AddRange(insert._params);
return sql;
}
}
}
}

View File

@ -0,0 +1,243 @@
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.Dameng.Curd
{
class DamengSelect<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)
{
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.Where(a => a.Before == false), true);
tb.CascadeBefore = _commonExpression.GetWhereCascadeSql(tb, _whereGlobalFilter.Where(a => a.Before == true), true);
}
var sb = new StringBuilder();
var sbunion = new StringBuilder();
var sbnav = 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");
var tbUnion = tbUnions[tbUnionsIdx];
sbunion.Append(_select);
if (_distinct) sbunion.Append("DISTINCT ");
var tbsjoin = _tables.Where(a => a.Type != SelectTableInfoType.From).ToArray();
var tbsfrom = _tables.Where(a => a.Type == SelectTableInfoType.From).ToArray();
var isRownum = string.IsNullOrEmpty(_orderby) && _skip > 0;
if (isRownum && field == "*") sbunion.Append(tbsfrom[0].Alias).Append("."); //#1519 bug
sbunion.Append(field);
if (isRownum) sbunion.Append(", ROWNUM AS \"__rownum__\"");
sbunion.Append(" \r\nFROM ");
for (var a = 0; a < tbsfrom.Length; a++)
{
sbunion.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++)
{
sbunion.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) &&
string.IsNullOrEmpty(tbsfrom[b].CascadeBefore)) sbunion.Append(" ON 1 = 1");
else sbunion.Append(" ON ").Append(string.Join(" AND ", new[]
{
tbsfrom[b].CascadeBefore,
tbsfrom[b].NavigateCondition ?? tbsfrom[b].On,
tbsfrom[b].Cascade
}.Where(onSql => string.IsNullOrEmpty(onSql) == false)));
}
break;
}
else
{
if (a > 0 && !string.IsNullOrEmpty(tbsfrom[a].CascadeBefore)) sbnav.Append(" AND ").Append(tbsfrom[a].CascadeBefore);
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) sbunion.Append(", ");
}
foreach (var tb in tbsjoin)
{
switch (tb.Type)
{
case SelectTableInfoType.Parent:
case SelectTableInfoType.RawJoin:
continue;
case SelectTableInfoType.LeftJoin:
sbunion.Append(" \r\nLEFT JOIN ");
break;
case SelectTableInfoType.InnerJoin:
sbunion.Append(" \r\nINNER JOIN ");
break;
case SelectTableInfoType.RightJoin:
sbunion.Append(" \r\nRIGHT JOIN ");
break;
}
sbunion.Append(_commonUtils.QuoteSqlName(tbUnion[tb.Table.Type])).Append(" ").Append(_aliasRule?.Invoke(tb.Table.Type, tb.Alias) ?? tb.Alias)
.Append(" ON ").Append(string.Join(" AND ", new[]
{
tb.CascadeBefore,
tb.On ?? tb.NavigateCondition,
tb.Cascade
}.Where(onSql => string.IsNullOrEmpty(onSql) == false)));
if (!string.IsNullOrEmpty(tb.On) && !string.IsNullOrEmpty(tb.NavigateCondition)) sbnav.Append(" AND (").Append(tb.NavigateCondition).Append(")");
}
if (_join.Length > 0) sbunion.Append(_join);
if (!string.IsNullOrEmpty(_tables[0].CascadeBefore)) sbnav.Append(" AND ").Append(_tables[0].CascadeBefore);
sbnav.Append(_where);
if (!string.IsNullOrEmpty(_tables[0].Cascade)) sbnav.Append(" AND ").Append(_tables[0].Cascade);
if (string.IsNullOrEmpty(_orderby) && (_skip > 0 || _limit > 0))
sbnav.Append(" AND ROWNUM < ").Append(_skip + _limit + 1);
if (sbnav.Length > 0)
sbunion.Append(" \r\nWHERE ").Append(sbnav.Remove(0, 5));
if (string.IsNullOrEmpty(_groupby) == false)
{
sbunion.Append(_groupby);
if (string.IsNullOrEmpty(_having) == false)
sbunion.Append(" \r\nHAVING ").Append(_having.Substring(5));
}
sbunion.Append(_orderby);
if (string.IsNullOrEmpty(_orderby))
{
if (_skip > 0)
sbunion.Insert(0, $"{_select}t.* FROM (").Append(") t WHERE t.\"__rownum__\" > ").Append(_skip);
}
else
{
if (_skip > 0 && _limit > 0) sbunion.Insert(0, $"{_select}t.* FROM (SELECT rt.*, ROWNUM AS \"__rownum__\" FROM (").Append(") rt WHERE ROWNUM < ").Append(_skip + _limit + 1).Append(") t WHERE t.\"__rownum__\" > ").Append(_skip);
else if (_skip > 0) sbunion.Insert(0, $"{_select}t.* FROM (").Append(") t WHERE ROWNUM > ").Append(_skip);
else if (_limit > 0) sbunion.Insert(0, $"{_select}t.* FROM (").Append(") t WHERE ROWNUM < ").Append(_limit + 1);
}
if (tbUnionsGt0) sbunion.Insert(0, $"{_select}* from (").Append(") ftb");
sb.Append(sbunion);
sbnav.Clear();
sbunion.Clear();
}
var sql = sb.Append(_tosqlAppendContent).ToString();
var aliasGreater30 = 0;
foreach (var tb in _tables)
if (tb.Alias.Length > 30) sql = sql.Replace(tb.Alias, $"than30_{aliasGreater30++}");
return sql;
}
public DamengSelect(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 DamengSelect<T1, T2>(_orm, _commonUtils, _commonExpression, null); DamengSelect<T1>.CopyData(this, 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 DamengSelect<T1, T2, T3>(_orm, _commonUtils, _commonExpression, null); DamengSelect<T1>.CopyData(this, 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 DamengSelect<T1, T2, T3, T4>(_orm, _commonUtils, _commonExpression, null); DamengSelect<T1>.CopyData(this, 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 DamengSelect<T1, T2, T3, T4, T5>(_orm, _commonUtils, _commonExpression, null); DamengSelect<T1>.CopyData(this, 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 DamengSelect<T1, T2, T3, T4, T5, T6>(_orm, _commonUtils, _commonExpression, null); DamengSelect<T1>.CopyData(this, 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 DamengSelect<T1, T2, T3, T4, T5, T6, T7>(_orm, _commonUtils, _commonExpression, null); DamengSelect<T1>.CopyData(this, 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 DamengSelect<T1, T2, T3, T4, T5, T6, T7, T8>(_orm, _commonUtils, _commonExpression, null); DamengSelect<T1>.CopyData(this, 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 DamengSelect<T1, T2, T3, T4, T5, T6, T7, T8, T9>(_orm, _commonUtils, _commonExpression, null); DamengSelect<T1>.CopyData(this, 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 DamengSelect<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10>(_orm, _commonUtils, _commonExpression, null); DamengSelect<T1>.CopyData(this, 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 DamengSelect<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11>(_orm, _commonUtils, _commonExpression, null); DamengSelect<T1>.CopyData(this, 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 DamengSelect<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12>(_orm, _commonUtils, _commonExpression, null); DamengSelect<T1>.CopyData(this, 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 DamengSelect<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13>(_orm, _commonUtils, _commonExpression, null); DamengSelect<T1>.CopyData(this, 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 DamengSelect<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14>(_orm, _commonUtils, _commonExpression, null); DamengSelect<T1>.CopyData(this, 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 DamengSelect<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15>(_orm, _commonUtils, _commonExpression, null); DamengSelect<T1>.CopyData(this, 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 DamengSelect<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15, T16>(_orm, _commonUtils, _commonExpression, null); DamengSelect<T1>.CopyData(this, 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 DamengSelect<T1, T2> : FreeSql.Internal.CommonProvider.Select2Provider<T1, T2> where T2 : class
{
public DamengSelect(IFreeSql orm, CommonUtils commonUtils, CommonExpression commonExpression, object dywhere) : base(orm, commonUtils, commonExpression, dywhere) { }
public override string ToSql(string field = null) => DamengSelect<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 DamengSelect<T1, T2, T3> : FreeSql.Internal.CommonProvider.Select3Provider<T1, T2, T3> where T2 : class where T3 : class
{
public DamengSelect(IFreeSql orm, CommonUtils commonUtils, CommonExpression commonExpression, object dywhere) : base(orm, commonUtils, commonExpression, dywhere) { }
public override string ToSql(string field = null) => DamengSelect<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 DamengSelect<T1, T2, T3, T4> : FreeSql.Internal.CommonProvider.Select4Provider<T1, T2, T3, T4> where T2 : class where T3 : class where T4 : class
{
public DamengSelect(IFreeSql orm, CommonUtils commonUtils, CommonExpression commonExpression, object dywhere) : base(orm, commonUtils, commonExpression, dywhere) { }
public override string ToSql(string field = null) => DamengSelect<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 DamengSelect<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 DamengSelect(IFreeSql orm, CommonUtils commonUtils, CommonExpression commonExpression, object dywhere) : base(orm, commonUtils, commonExpression, dywhere) { }
public override string ToSql(string field = null) => DamengSelect<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 DamengSelect<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 DamengSelect(IFreeSql orm, CommonUtils commonUtils, CommonExpression commonExpression, object dywhere) : base(orm, commonUtils, commonExpression, dywhere) { }
public override string ToSql(string field = null) => DamengSelect<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 DamengSelect<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 DamengSelect(IFreeSql orm, CommonUtils commonUtils, CommonExpression commonExpression, object dywhere) : base(orm, commonUtils, commonExpression, dywhere) { }
public override string ToSql(string field = null) => DamengSelect<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 DamengSelect<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 DamengSelect(IFreeSql orm, CommonUtils commonUtils, CommonExpression commonExpression, object dywhere) : base(orm, commonUtils, commonExpression, dywhere) { }
public override string ToSql(string field = null) => DamengSelect<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 DamengSelect<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 DamengSelect(IFreeSql orm, CommonUtils commonUtils, CommonExpression commonExpression, object dywhere) : base(orm, commonUtils, commonExpression, dywhere) { }
public override string ToSql(string field = null) => DamengSelect<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 DamengSelect<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 DamengSelect(IFreeSql orm, CommonUtils commonUtils, CommonExpression commonExpression, object dywhere) : base(orm, commonUtils, commonExpression, dywhere) { }
public override string ToSql(string field = null) => DamengSelect<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 DamengSelect<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 DamengSelect(IFreeSql orm, CommonUtils commonUtils, CommonExpression commonExpression, object dywhere) : base(orm, commonUtils, commonExpression, dywhere) { }
public override string ToSql(string field = null) => DamengSelect<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 DamengSelect<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 DamengSelect(IFreeSql orm, CommonUtils commonUtils, CommonExpression commonExpression, object dywhere) : base(orm, commonUtils, commonExpression, dywhere) { }
public override string ToSql(string field = null) => DamengSelect<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 DamengSelect<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 DamengSelect(IFreeSql orm, CommonUtils commonUtils, CommonExpression commonExpression, object dywhere) : base(orm, commonUtils, commonExpression, dywhere) { }
public override string ToSql(string field = null) => DamengSelect<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 DamengSelect<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 DamengSelect(IFreeSql orm, CommonUtils commonUtils, CommonExpression commonExpression, object dywhere) : base(orm, commonUtils, commonExpression, dywhere) { }
public override string ToSql(string field = null) => DamengSelect<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 DamengSelect<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 DamengSelect(IFreeSql orm, CommonUtils commonUtils, CommonExpression commonExpression, object dywhere) : base(orm, commonUtils, commonExpression, dywhere) { }
public override string ToSql(string field = null) => DamengSelect<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 DamengSelect<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 DamengSelect(IFreeSql orm, CommonUtils commonUtils, CommonExpression commonExpression, object dywhere) : base(orm, commonUtils, commonExpression, dywhere) { }
public override string ToSql(string field = null) => DamengSelect<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.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
namespace FreeSql.Dameng.Curd
{
class DamengUpdate<T1> : Internal.CommonProvider.UpdateProvider<T1>
{
public DamengUpdate(IFreeSql orm, CommonUtils commonUtils, CommonExpression commonExpression, object dywhere)
: base(orm, commonUtils, commonExpression, dywhere)
{
}
public override int ExecuteAffrows() => base.SplitExecuteAffrows(_batchRowsLimit > 0 ? _batchRowsLimit : 200, _batchParameterLimit > 0 ? _batchParameterLimit : 999);
protected override List<TReturn> ExecuteUpdated<TReturn>(IEnumerable<ColumnInfo> columns) => base.SplitExecuteUpdated<TReturn>(_batchRowsLimit > 0 ? _batchRowsLimit : 200, _batchParameterLimit > 0 ? _batchParameterLimit : 999, columns);
protected override List<TReturn> RawExecuteUpdated<TReturn>(IEnumerable<ColumnInfo> columns) => throw new NotImplementedException($"FreeSql.Provider.Dameng {CoreStrings.S_Not_Implemented_Feature}");
protected override void ToSqlCase(StringBuilder caseWhen, ColumnInfo[] primarys)
{
if (primarys.Length == 1)
{
var pk = primarys.First();
caseWhen.Append(_commonUtils.RereadColumn(pk, _commonUtils.QuoteSqlName(pk.Attribute.Name)));
return;
}
caseWhen.Append("(");
var pkidx = 0;
foreach (var pk in primarys)
{
if (pkidx > 0) caseWhen.Append(" || '+' || ");
caseWhen.Append(_commonUtils.RereadColumn(pk, _commonUtils.QuoteSqlName(pk.Attribute.Name)));
++pkidx;
}
caseWhen.Append(")");
}
protected override void ToSqlWhen(StringBuilder sb, ColumnInfo[] primarys, object d)
{
if (primarys.Length == 1)
{
sb.Append(_commonUtils.FormatSql("{0}", primarys[0].GetDbValue(d)));
return;
}
sb.Append("(");
var pkidx = 0;
foreach (var pk in primarys)
{
if (pkidx > 0) sb.Append(" || '+' || ");
sb.Append(_commonUtils.FormatSql("{0}", pk.GetDbValue(d)));
++pkidx;
}
sb.Append(")");
}
#if net40
#else
public override Task<int> ExecuteAffrowsAsync(CancellationToken cancellationToken = default) => base.SplitExecuteAffrowsAsync(_batchRowsLimit > 0 ? _batchRowsLimit : 200, _batchParameterLimit > 0 ? _batchParameterLimit : 999, cancellationToken);
protected override Task<List<TReturn>> ExecuteUpdatedAsync<TReturn>(IEnumerable<ColumnInfo> columns, CancellationToken cancellationToken = default) => base.SplitExecuteUpdatedAsync<TReturn>(_batchRowsLimit > 0 ? _batchRowsLimit : 200, _batchParameterLimit > 0 ? _batchParameterLimit : 999, columns, cancellationToken);
protected override Task<List<TReturn>> RawExecuteUpdatedAsync<TReturn>(IEnumerable<ColumnInfo> columns, CancellationToken cancellationToken = default) => throw new NotImplementedException($"FreeSql.Provider.Dameng {CoreStrings.S_Not_Implemented_Feature}");
#endif
}
}

View File

@ -0,0 +1,90 @@
using Dm;
using FreeSql.Internal;
using FreeSql.Internal.CommonProvider;
using FreeSql.Internal.Model;
using FreeSql.Internal.ObjectPool;
using System;
using System.Collections;
using System.Data.Common;
using System.Linq;
using System.Threading;
namespace FreeSql.Dameng
{
class DamengAdo : FreeSql.Internal.CommonProvider.AdoProvider
{
public DamengAdo() : base(DataType.Dameng, null, null) { }
public DamengAdo(CommonUtils util, string masterConnectionString, string[] slaveConnectionStrings, Func<DbConnection> connectionFactory) : base(DataType.Dameng, masterConnectionString, slaveConnectionStrings)
{
base._util = util;
if (connectionFactory != null)
{
var pool = new FreeSql.Internal.CommonProvider.DbConnectionPool(DataType.Dameng, connectionFactory);
ConnectionString = pool.TestConnection?.ConnectionString;
MasterPool = pool;
return;
}
var isAdoPool = masterConnectionString?.StartsWith("AdoConnectionPool,") ?? false;
if (isAdoPool) masterConnectionString = masterConnectionString.Substring("AdoConnectionPool,".Length);
if (!string.IsNullOrEmpty(masterConnectionString))
MasterPool = isAdoPool ?
new DbConnectionStringPool(base.DataType, CoreStrings.S_MasterDatabase, () => new DmConnection(masterConnectionString)) as IObjectPool<DbConnection> :
new DamengConnectionPool(CoreStrings.S_MasterDatabase, masterConnectionString, null, null);
slaveConnectionStrings?.ToList().ForEach(slaveConnectionString =>
{
var slavePool = isAdoPool ?
new DbConnectionStringPool(base.DataType, $"{CoreStrings.S_SlaveDatabase}{SlavePools.Count + 1}", () => new DmConnection(slaveConnectionString)) as IObjectPool<DbConnection> :
new DamengConnectionPool($"{CoreStrings.S_SlaveDatabase}{SlavePools.Count + 1}", slaveConnectionString, () => Interlocked.Decrement(ref slaveUnavailables), () => Interlocked.Increment(ref slaveUnavailables));
SlavePools.Add(slavePool);
});
}
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 byte[])
return $"hextoraw('{CommonUtils.BytesSqlRaw(param as byte[])}')";
else if (param is bool || param is bool?)
return (bool)param ? 1 : 0;
else if (param is string)
return string.Concat("'", param.ToString().Replace("'", "''"), "'");
else if (param is char)
return string.Concat("'", param.ToString().Replace("'", "''").Replace('\0', ' '), "'");
else if (param is Enum)
return AddslashesTypeHandler(param.GetType(), param) ?? ((Enum)param).ToInt64();
else if (decimal.TryParse(string.Concat(param), out var trydec))
return param;
else if (param is DateTime)
return AddslashesTypeHandler(typeof(DateTime), param) ?? string.Concat("to_timestamp('", ((DateTime)param).ToString("yyyy-MM-dd HH:mm:ss.ffffff"), "','YYYY-MM-DD HH24:MI:SS.FF6')");
else if (param is DateTime?)
return AddslashesTypeHandler(typeof(DateTime?), param) ?? string.Concat("to_timestamp('", ((DateTime)param).ToString("yyyy-MM-dd HH:mm:ss.ffffff"), "','YYYY-MM-DD HH24:MI:SS.FF6')");
else if (param is TimeSpan || param is TimeSpan?)
return $"numtodsinterval({((TimeSpan)param).Ticks * 1.0 / 10000000},'second')";
else if (param is IEnumerable)
return AddslashesIEnumerable(param, mapType, mapColumn);
return string.Concat("'", param.ToString().Replace("'", "''"), "'");
//if (param is string) return string.Concat('N', nparms[a]);
}
public override DbCommand CreateCommand()
{
return new DmCommand();
}
public override void ReturnConnection(IObjectPool<DbConnection> pool, Object<DbConnection> conn, Exception ex)
{
var rawPool = pool as DamengConnectionPool;
if (rawPool != null) rawPool.Return(conn, ex);
else pool.Return(conn);
}
public override DbParameter[] GetDbParamtersByObject(string sql, object obj) => _util.GetDbParamtersByObject(sql, obj);
}
}

View File

@ -0,0 +1,249 @@
using Dm;
using FreeSql.Internal.ObjectPool;
using System;
using System.Collections.Concurrent;
using System.Data;
using System.Data.Common;
using System.Text.RegularExpressions;
using System.Threading.Tasks;
namespace FreeSql.Dameng
{
class DamengConnectionPool : ObjectPool<DbConnection>
{
internal Action availableHandler;
internal Action unavailableHandler;
internal string UserId { get; set; }
public DamengConnectionPool(string name, string connectionString, Action availableHandler, Action unavailableHandler) : base(null)
{
this.UserId = DamengConnectionPool.GetUserId(connectionString);
this.availableHandler = availableHandler;
this.unavailableHandler = unavailableHandler;
var policy = new DamengConnectionPoolPolicy
{
_pool = this,
Name = name
};
this.Policy = policy;
policy.ConnectionString = connectionString;
}
public static string GetUserId(string connectionString)
{
var userIdMatch = Regex.Match(connectionString, @"(User\s+Id|Uid|User)\s*=\s*([^;]+)", RegexOptions.IgnoreCase);
if (userIdMatch.Success == false) throw new Exception(@"从 ConnectionString 中无法匹配 (User\s+Id|Uid|User)\s*=\s*([^;]+)");
return userIdMatch.Groups[2].Value.Trim().ToUpper();
}
public void Return(Object<DbConnection> obj, Exception exception, bool isRecreate = false)
{
if (exception != null && exception is DmException)
{
if (obj.Value.Ping() == false)
base.SetUnavailable(exception, obj.LastGetTimeCopy);
}
base.Return(obj, isRecreate);
}
}
class DamengConnectionPoolPolicy : IPolicy<DbConnection>
{
internal DamengConnectionPool _pool;
public string Name { get; set; } = $"Dameng DmConnection {CoreStrings.S_ObjectPool}";
public int PoolSize { get; set; } = 100;
public TimeSpan SyncGetTimeout { get; set; } = TimeSpan.FromSeconds(10);
public TimeSpan IdleTimeout { get; set; } = TimeSpan.FromSeconds(20);
public int AsyncGetCapacity { get; set; } = 10000;
public bool IsThrowGetTimeoutException { get; set; } = true;
public bool IsAutoDisposeWithSystem { get; set; } = true;
public int CheckAvailableInterval { get; set; } = 2;
public int Weight { get; set; } = 1;
static ConcurrentDictionary<string, int> dicConnStrIncr = new ConcurrentDictionary<string, int>(StringComparer.CurrentCultureIgnoreCase);
private string _connectionString;
public string ConnectionString
{
get => _connectionString;
set
{
_connectionString = value ?? "";
var minPoolSize = 0;
var pattern = @"Min\s*pool\s*size\s*=\s*(\d+)";
var m = Regex.Match(_connectionString, pattern, RegexOptions.IgnoreCase);
if (m.Success)
{
minPoolSize = int.Parse(m.Groups[1].Value);
_connectionString = Regex.Replace(_connectionString, pattern, "", RegexOptions.IgnoreCase);
}
pattern = @"(Max\s*)?pool\s*size\s*=\s*(\d+)";
m = Regex.Match(_connectionString, pattern, RegexOptions.IgnoreCase);
if (m.Success == false || int.TryParse(m.Groups[2].Value, out var poolsize) == false || poolsize <= 0) poolsize = Math.Max(100, minPoolSize);
var connStrIncr = dicConnStrIncr.AddOrUpdate(_connectionString, 1, (oldkey, oldval) => Math.Min(5, oldval + 1));
PoolSize = poolsize + connStrIncr;
_connectionString = m.Success ?
Regex.Replace(_connectionString, pattern, $"poolsize={PoolSize}", RegexOptions.IgnoreCase) :
$"{_connectionString};poolsize={PoolSize}"; //NotSupportedException
//if (m.Success) _connectionString = Regex.Replace(_connectionString, pattern, "", RegexOptions.IgnoreCase);
pattern = @"Connection\s*LifeTime\s*=\s*(\d+)";
m = Regex.Match(_connectionString, pattern, RegexOptions.IgnoreCase);
if (m.Success)
{
IdleTimeout = TimeSpan.FromSeconds(int.Parse(m.Groups[1].Value));
_connectionString = Regex.Replace(_connectionString, pattern, "", RegexOptions.IgnoreCase);
}
FreeSql.Internal.CommonUtils.PrevReheatConnectionPool(_pool, minPoolSize);
}
}
public bool OnCheckAvailable(Object<DbConnection> obj)
{
if (obj.Value == null) return false;
if (obj.Value.State == ConnectionState.Closed) obj.Value.Open();
return obj.Value.Ping(true);
}
public DbConnection OnCreate()
{
var conn = new DmConnection(_connectionString);
return conn;
}
public void OnDestroy(DbConnection obj)
{
if (obj.State != ConnectionState.Closed) obj.Close();
obj.Dispose();
}
public void OnGet(Object<DbConnection> obj)
{
if (_pool.IsAvailable)
{
if (obj.Value == null)
{
_pool.SetUnavailable(new Exception(CoreStrings.S_ConnectionStringError), obj.LastGetTimeCopy);
throw new Exception(CoreStrings.S_ConnectionStringError_Check(this.Name));
}
if (obj.Value.State != ConnectionState.Open || DateTime.Now.Subtract(obj.LastReturnTime).TotalSeconds > 60 && obj.Value.Ping() == false)
{
try
{
obj.Value.Open();
}
catch (Exception ex)
{
if (_pool.SetUnavailable(ex, obj.LastGetTimeCopy) == true)
throw new Exception($"【{this.Name}】Block access and wait for recovery: {ex.Message}");
throw;
}
}
}
}
#if net40
#else
async public Task OnGetAsync(Object<DbConnection> obj)
{
if (_pool.IsAvailable)
{
if (obj.Value == null)
{
_pool.SetUnavailable(new Exception(CoreStrings.S_ConnectionStringError), obj.LastGetTimeCopy);
throw new Exception(CoreStrings.S_ConnectionStringError_Check(this.Name));
}
if (obj.Value.State != ConnectionState.Open || DateTime.Now.Subtract(obj.LastReturnTime).TotalSeconds > 60 && (await obj.Value.PingAsync()) == false)
{
try
{
await obj.Value.OpenAsync();
}
catch (Exception ex)
{
if (_pool.SetUnavailable(ex, obj.LastGetTimeCopy) == true)
throw new Exception($"【{this.Name}】Block access and wait for recovery: {ex.Message}");
throw;
}
}
}
}
#endif
public void OnGetTimeout()
{
}
public void OnReturn(Object<DbConnection> obj)
{
//if (obj?.Value != null && obj.Value.State != ConnectionState.Closed) try { obj.Value.Close(); } catch { }
}
public void OnAvailable()
{
_pool.availableHandler?.Invoke();
}
public void OnUnavailable()
{
_pool.unavailableHandler?.Invoke();
}
}
static class DbConnectionExtensions
{
static DbCommand PingCommand(DbConnection conn)
{
var cmd = conn.CreateCommand();
cmd.CommandTimeout = 5;
cmd.CommandText = "select 1 from dual";
return cmd;
}
public static bool Ping(this DbConnection that, bool isThrow = false)
{
try
{
PingCommand(that).ExecuteNonQuery();
return true;
}
catch
{
if (that.State != ConnectionState.Closed) try { that.Close(); } catch { }
if (isThrow) throw;
return false;
}
}
#if net40
#else
async public static Task<bool> PingAsync(this DbConnection that, bool isThrow = false)
{
try
{
await PingCommand(that).ExecuteNonQueryAsync();
return true;
}
catch
{
if (that.State != ConnectionState.Closed) try { that.Close(); } catch { }
if (isThrow) throw;
return false;
}
}
#endif
}
}

View File

@ -0,0 +1,490 @@
using Dm;
using FreeSql.DataAnnotations;
using FreeSql.Internal;
using FreeSql.Internal.Model;
using System;
using System.Collections.Generic;
using System.Data;
using System.Linq;
using System.Reflection;
using System.Text;
using System.Text.RegularExpressions;
namespace FreeSql.Dameng
{
class DamengCodeFirst : Internal.CommonProvider.CodeFirstProvider
{
public DamengCodeFirst(IFreeSql orm, CommonUtils commonUtils, CommonExpression commonExpression) : base(orm, commonUtils, commonExpression) { }
static object _dicCsToDbLock = new object();
static Dictionary<string, CsToDb<DmDbType>> _dicCsToDb = new Dictionary<string, CsToDb<DmDbType>>() {
{ typeof(bool).FullName, CsToDb.New(DmDbType.Bit, "number","number(1) NOT NULL", null, false, false) },{ typeof(bool?).FullName, CsToDb.New(DmDbType.Bit, "number","number(1) NULL", null, true, null) },
{ typeof(sbyte).FullName, CsToDb.New(DmDbType.SByte, "number", "number(4) NOT NULL", false, false, 0) },{ typeof(sbyte?).FullName, CsToDb.New(DmDbType.SByte, "number", "number(4) NULL", false, true, null) },
{ typeof(short).FullName, CsToDb.New(DmDbType.Int16, "number","number(6) NOT NULL", false, false, 0) },{ typeof(short?).FullName, CsToDb.New(DmDbType.Int16, "number", "number(6) NULL", false, true, null) },
{ typeof(int).FullName, CsToDb.New(DmDbType.Int32, "number", "number(11) NOT NULL", false, false, 0) },{ typeof(int?).FullName, CsToDb.New(DmDbType.Int32, "number", "number(11) NULL", false, true, null) },
{ typeof(long).FullName, CsToDb.New(DmDbType.Int64, "number","number(21) NOT NULL", false, false, 0) },{ typeof(long?).FullName, CsToDb.New(DmDbType.Int64, "number","number(21) NULL", false, true, null) },
{ typeof(byte).FullName, CsToDb.New(DmDbType.Byte, "number","number(3) NOT NULL", true, false, 0) },{ typeof(byte?).FullName, CsToDb.New(DmDbType.Byte, "number","number(3) NULL", true, true, null) },
{ typeof(ushort).FullName, CsToDb.New(DmDbType.UInt16, "number","number(5) NOT NULL", true, false, 0) },{ typeof(ushort?).FullName, CsToDb.New(DmDbType.UInt16, "number", "number(5) NULL", true, true, null) },
{ typeof(uint).FullName, CsToDb.New(DmDbType.UInt32, "number", "number(10) NOT NULL", true, false, 0) },{ typeof(uint?).FullName, CsToDb.New(DmDbType.UInt32, "number", "number(10) NULL", true, true, null) },
{ typeof(ulong).FullName, CsToDb.New(DmDbType.UInt64, "number", "number(20) NOT NULL", true, false, 0) },{ typeof(ulong?).FullName, CsToDb.New(DmDbType.UInt64, "number", "number(20) NULL", true, true, null) },
{ typeof(double).FullName, CsToDb.New(DmDbType.Double, "double", "double NOT NULL", false, false, 0) },{ typeof(double?).FullName, CsToDb.New(DmDbType.Double, "double", "double NULL", false, true, null) },
{ typeof(float).FullName, CsToDb.New(DmDbType.Float, "real","real NOT NULL", false, false, 0) },{ typeof(float?).FullName, CsToDb.New(DmDbType.Float, "real","real NULL", false, true, null) },
{ typeof(decimal).FullName, CsToDb.New(DmDbType.Decimal, "number", "number(10,2) NOT NULL", false, false, 0) },{ typeof(decimal?).FullName, CsToDb.New(DmDbType.Decimal, "number", "number(10,2) NULL", false, true, null) },
//达梦8 ODBC 不支持 TimeSpan
//{ typeof(TimeSpan).FullName, CsToDb.NewInfo(DmDbType.Time, "interval day to second","interval day(2) to second(6) NOT NULL", false, false, 0) },{ typeof(TimeSpan?).FullName, (DmDbType.Time, "interval day to second", "interval day(2) to second(6) NULL",false, true, null) },
{ typeof(DateTime).FullName, CsToDb.New(DmDbType.DateTime, "timestamp", "timestamp(6) NOT NULL", false, false, new DateTime(1970,1,1)) },{ typeof(DateTime?).FullName, CsToDb.New(DmDbType.DateTime, "timestamp", "timestamp(6) NULL", false, true, null) },
{ typeof(DateTimeOffset).FullName, CsToDb.New(DmDbType.DateTime, "timestamp", "timestamp(6) NOT NULL", false, false, new DateTime(1970,1,1)) },{ typeof(DateTimeOffset?).FullName, CsToDb.New(DmDbType.DateTime, "timestamp", "timestamp(6) NULL", false, true, null) },
{ typeof(byte[]).FullName, CsToDb.New(DmDbType.VarBinary, "blob", "blob NULL", false, null, new byte[0]) },
{ typeof(string).FullName, CsToDb.New(DmDbType.VarChar, "nvarchar2", "nvarchar2(255) NULL", false, null, "") },
{ typeof(char).FullName, CsToDb.New(DmDbType.Char, "char", "char(1) NULL", false, null, '\0') },
{ typeof(Guid).FullName, CsToDb.New(DmDbType.Char, "char", "char(36) NOT NULL", false, false, Guid.Empty) },{ typeof(Guid?).FullName, CsToDb.New(DmDbType.Char, "char", "char(36) NULL", false, true, null) },
};
public override DbInfoResult GetDbInfo(Type type)
{
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(DmDbType.Int32, "number", $"number(32){(type.IsEnum ? " NOT NULL" : "")}", false, type.IsEnum ? false : true, enumType.CreateInstanceGetDefaultValue()) :
CsToDb.New(DmDbType.Int64, "number", $"number(16){(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 TypeSchemaAndName[] objects)
{
var userId = (_orm.Ado.MasterPool as DamengConnectionPool)?.UserId;
if (string.IsNullOrEmpty(userId))
using (var conn = _orm.Ado.MasterPool.Get())
{
userId = DamengConnectionPool.GetUserId(conn.Value.ConnectionString);
}
var seqcols = new List<NativeTuple<ColumnInfo, string[], bool>>(); //序列:列,表,自增
var seqnameDel = new List<string>(); //要删除的序列+触发器
var sb = new StringBuilder();
var sbDeclare = new StringBuilder();
foreach (var obj in objects)
{
if (sb.Length > 0) sb.Append("\r\n");
var tb = obj.tableSchema;
if (tb == null) throw new Exception(CoreStrings.S_Type_IsNot_Migrable(obj.tableSchema.Type.FullName));
if (tb.Columns.Any() == false) throw new Exception(CoreStrings.S_Type_IsNot_Migrable_0Attributes(obj.tableSchema.Type.FullName));
var tbname = _commonUtils.SplitTableName(tb.DbName);
if (tbname?.Length == 1) tbname = new[] { userId, tbname[0] };
var tboldname = _commonUtils.SplitTableName(tb.DbOldName); //旧表名
if (tboldname?.Length == 1) tboldname = new[] { userId, tboldname[0] };
var primaryKeyName = (obj.tableSchema.Type.GetCustomAttributes(typeof(OraclePrimaryKeyNameAttribute), false)?.FirstOrDefault() as OraclePrimaryKeyNameAttribute)?.Name;
if (string.IsNullOrEmpty(obj.tableName) == false)
{
var tbtmpname = _commonUtils.SplitTableName(obj.tableName);
if (tbtmpname?.Length == 1) tbtmpname = new[] { userId, tbtmpname[0] };
if (tbname[0] != tbtmpname[0] || tbname[1] != tbtmpname[1])
{
tbname = tbtmpname;
tboldname = null;
primaryKeyName = null;
}
}
//codefirst 不支持表名中带 .
if (string.Compare(tbname[0], userId) != 0 && _orm.Ado.ExecuteScalar(CommandType.Text, _commonUtils.FormatSql(" select 1 from sys.dba_users where username={0}", tbname[0])) == null) //创建数据库
throw new NotImplementedException(CoreStrings.S_Dameng_NotSupport_TablespaceSchemas(tbname[0]));
var sbalter = new StringBuilder();
var istmpatler = false; //创建临时表,导入数据,删除旧表,修改
if (_orm.Ado.ExecuteScalar(CommandType.Text, _commonUtils.FormatSql(" select 1 from all_tab_comments where owner={0} and table_name={1}", tbname)) == null)
{ //表不存在
if (tboldname != null)
{
if (_orm.Ado.ExecuteScalar(CommandType.Text, _commonUtils.FormatSql(" select 1 from all_tab_comments where owner={0} and table_name={1}", tboldname)) == null)
//模式或表不存在
tboldname = null;
}
if (tboldname == null)
{
//创建表
var createTableName = _commonUtils.QuoteSqlName($"{tbname[0]}.{tbname[1]}");
sb.Append("execute immediate 'CREATE TABLE ").Append(createTableName).Append(" ( ");
foreach (var tbcol in tb.ColumnsByPosition)
{
sb.Append(" \r\n ").Append(_commonUtils.QuoteSqlName(tbcol.Attribute.Name)).Append(" ").Append(tbcol.Attribute.DbType).Append(",");
if (tbcol.Attribute.IsIdentity == true) seqcols.Add(NativeTuple.Create(tbcol, tbname, true));
}
if (tb.Primarys.Any())
{
var pkname = primaryKeyName ?? $"{tbname[0]}_{tbname[1]}_pk1";
sb.Append(" \r\n CONSTRAINT ").Append(_commonUtils.QuoteSqlName(pkname)).Append(" PRIMARY KEY (");
foreach (var tbcol in tb.Primarys) sb.Append(_commonUtils.QuoteSqlName(tbcol.Attribute.Name)).Append(", ");
sb.Remove(sb.Length - 2, 2).Append("),");
}
sb.Remove(sb.Length - 1, 1);
sb.Append("\r\n) LOGGING ';\r\n");
//创建表的索引
foreach (var uk in tb.Indexes)
{
sb.Append("execute immediate 'CREATE ");
if (uk.IsUnique) sb.Append("UNIQUE ");
sb.Append("INDEX ").Append(_commonUtils.QuoteSqlName(ReplaceIndexName(uk.Name, tbname[1]))).Append(" ON ").Append(createTableName).Append("(");
foreach (var tbcol in uk.Columns)
{
sb.Append(_commonUtils.QuoteSqlName(tbcol.Column.Attribute.Name));
if (tbcol.IsDesc) sb.Append(" DESC");
sb.Append(", ");
}
sb.Remove(sb.Length - 2, 2).Append(")';\r\n");
}
//备注
foreach (var tbcol in tb.ColumnsByPosition)
{
if (string.IsNullOrEmpty(tbcol.Comment) == false)
sb.Append("execute immediate 'COMMENT ON COLUMN ").Append(_commonUtils.QuoteSqlName($"{tbname[0]}.{tbname[1]}.{tbcol.Attribute.Name}")).Append(" IS ").Append(_commonUtils.FormatSql("{0}", tbcol.Comment).Replace("'", "''")).Append("';\r\n");
}
if (string.IsNullOrEmpty(tb.Comment) == false)
sb.Append("execute immediate 'COMMENT ON TABLE ").Append(_commonUtils.QuoteSqlName($"{tbname[0]}.{tbname[1]}")).Append(" IS ").Append(_commonUtils.FormatSql("{0}", tb.Comment).Replace("'", "''")).Append("';\r\n");
continue;
}
//如果新表,旧表在一个模式下,直接修改表名
if (string.Compare(tbname[0], tboldname[0], true) == 0)
sbalter.Append("execute immediate 'ALTER TABLE ").Append(_commonUtils.QuoteSqlName($"{tboldname[0]}.{tboldname[1]}")).Append(" RENAME TO ").Append(_commonUtils.QuoteSqlName($"{tbname[1]}")).Append("';\r\n");
else
{
//如果新表,旧表不在一起,创建新表,导入数据,删除旧表
istmpatler = true;
}
}
else
tboldname = null; //如果新表已经存在,不走改表名逻辑
//对比字段,只可以修改类型、增加字段、有限的修改字段名;保证安全不删除字段
var sql = _commonUtils.FormatSql($@"
select
a.column_name,
a.data_type,
a.data_length,
a.data_precision,
a.data_scale,
a.char_used,
case when a.nullable = 'N' then 0 else 1 end,
nvl((select 1 from user_sequences where upper(sequence_name)=upper('{Utils.GetCsName((tboldname ?? tbname).Last())}_seq_'||a.column_name) and rownum < 2), 0),
nvl((select 1 from user_triggers where upper(trigger_name)=upper('{Utils.GetCsName((tboldname ?? tbname).Last())}_seq_'||a.column_name||'TI') and rownum < 2), 0),
b.comments
from all_tab_columns a
left join all_col_comments b on b.owner = a.owner and b.table_name = a.table_name and b.column_name = a.column_name
where a.owner={{0}} and a.table_name={{1}}", tboldname ?? tbname);
var ds = _orm.Ado.ExecuteArray(CommandType.Text, sql);
var tbstruct = ds.ToDictionary(a => string.Concat(a[0]), a =>
{
var sqlType = GetDamengSqlTypeFullName(a);
return new
{
column = string.Concat(a[0]),
sqlType,
is_nullable = string.Concat(a[6]) == "1",
is_identity = string.Concat(a[7]) == "1" && string.Concat(a[8]) == "1",
comment = string.Concat(a[9])
};
}, StringComparer.CurrentCultureIgnoreCase);
if (istmpatler == false)
{
foreach (var tbcol in tb.ColumnsByPosition)
{
var dbtypeNoneNotNull = Regex.Replace(tbcol.Attribute.DbType, @"NOT\s+NULL", "NULL");
if (tbstruct.TryGetValue(tbcol.Attribute.Name, out var tbstructcol) ||
string.IsNullOrEmpty(tbcol.Attribute.OldName) == false && tbstruct.TryGetValue(tbcol.Attribute.OldName, out tbstructcol))
{
var isCommentChanged = tbstructcol.comment != (tbcol.Comment ?? "");
if (tbcol.Attribute.DbType.StartsWith(tbstructcol.sqlType, StringComparison.CurrentCultureIgnoreCase) == false)
{
istmpatler = true;
if (istmpatler && tbcol.Attribute.DbType.StartsWith("varchar", StringComparison.CurrentCultureIgnoreCase) && tbstructcol.sqlType.StartsWith("varchar2", StringComparison.CurrentCultureIgnoreCase)
&& Regex.Match(tbcol.Attribute.DbType, @"\(\d+").Groups[0].Value == Regex.Match(tbstructcol.sqlType, @"\(\d+").Groups[0].Value)
istmpatler = false;
if (istmpatler && Regex.IsMatch(tbcol.Attribute.DbType, @"\(\d+") == false && Regex.IsMatch(tbstructcol.sqlType, @"\(\d+")
&& string.Compare(tbcol.Attribute.DbType, Regex.Replace(tbstructcol.sqlType, @"\([^\)]+\)", ""), StringComparison.CurrentCultureIgnoreCase) == 0)
istmpatler = false;
if (istmpatler) break;
}
//sbalter.Append("execute immediate 'ALTER TABLE ").Append(_commonUtils.QuoteSqlName($"{tbname[0]}.{tbname[1]}")).Append(" MODIFY (").Append(_commonUtils.QuoteSqlName(tbstructcol.column)).Append(" ").Append(dbtypeNoneNotNull).Append(")';\r\n");
if (tbcol.Attribute.IsNullable != tbstructcol.is_nullable)
{
if (tbcol.Attribute.IsNullable == false)
sbalter.Append("execute immediate 'UPDATE ").Append(_commonUtils.QuoteSqlName($"{tbname[0]}.{tbname[1]}")).Append(" SET ").Append(_commonUtils.QuoteSqlName(tbstructcol.column)).Append(" = ").Append(tbcol.DbDefaultValue.Replace("'", "''")).Append(" WHERE ").Append(_commonUtils.QuoteSqlName(tbstructcol.column)).Append(" IS NULL';\r\n");
sbalter.Append("execute immediate 'ALTER TABLE ").Append(_commonUtils.QuoteSqlName($"{tbname[0]}.{tbname[1]}")).Append(" MODIFY ").Append(_commonUtils.QuoteSqlName(tbstructcol.column)).Append(" ").Append(tbcol.Attribute.IsNullable == true ? "" : "NOT").Append(" NULL';\r\n");
}
if (string.Compare(tbstructcol.column, tbcol.Attribute.OldName, true) == 0)
{
if (tbstructcol.is_identity)
seqnameDel.Add(Utils.GetCsName($"{tbname[1]}_seq_{tbstructcol.column}"));
//修改列名
sbalter.Append("execute immediate 'ALTER TABLE ").Append(_commonUtils.QuoteSqlName($"{tbname[0]}.{tbname[1]}")).Append(" RENAME COLUMN ").Append(_commonUtils.QuoteSqlName(tbstructcol.column)).Append(" TO ").Append(_commonUtils.QuoteSqlName(tbcol.Attribute.Name)).Append("';\r\n");
if (tbcol.Attribute.IsIdentity)
seqcols.Add(NativeTuple.Create(tbcol, tbname, tbcol.Attribute.IsIdentity == true));
}
else if (tbcol.Attribute.IsIdentity != tbstructcol.is_identity)
seqcols.Add(NativeTuple.Create(tbcol, tbname, tbcol.Attribute.IsIdentity == true));
if (isCommentChanged)
sbalter.Append("execute immediate 'COMMENT ON COLUMN ").Append(_commonUtils.QuoteSqlName($"{tbname[0]}.{tbname[1]}.{tbcol.Attribute.Name}")).Append(" IS ").Append(_commonUtils.FormatSql("{0}", tbcol.Comment ?? "").Replace("'", "''")).Append("';\r\n");
continue;
}
//添加列
sbalter.Append("execute immediate 'ALTER TABLE ").Append(_commonUtils.QuoteSqlName($"{tbname[0]}.{tbname[1]}")).Append(" ADD (").Append(_commonUtils.QuoteSqlName(tbcol.Attribute.Name)).Append(" ").Append(dbtypeNoneNotNull).Append(")';\r\n");
if (tbcol.Attribute.IsNullable == false)
{
sbalter.Append("execute immediate 'UPDATE ").Append(_commonUtils.QuoteSqlName($"{tbname[0]}.{tbname[1]}")).Append(" SET ").Append(_commonUtils.QuoteSqlName(tbcol.Attribute.Name)).Append(" = ").Append(tbcol.DbDefaultValue.Replace("'", "''")).Append("';\r\n");
sbalter.Append("execute immediate 'ALTER TABLE ").Append(_commonUtils.QuoteSqlName($"{tbname[0]}.{tbname[1]}")).Append(" MODIFY ").Append(_commonUtils.QuoteSqlName(tbcol.Attribute.Name)).Append(" NOT NULL';\r\n");
}
if (tbcol.Attribute.IsIdentity == true) seqcols.Add(NativeTuple.Create(tbcol, tbname, tbcol.Attribute.IsIdentity == true));
if (string.IsNullOrEmpty(tbcol.Comment) == false) sbalter.Append("execute immediate 'COMMENT ON COLUMN ").Append(_commonUtils.QuoteSqlName($"{tbname[0]}.{tbname[1]}.{tbcol.Attribute.Name}")).Append(" IS ").Append(_commonUtils.FormatSql("{0}", tbcol.Comment ?? "").Replace("'", "''")).Append("';\r\n");
}
}
if (istmpatler == false)
{
var dsuksql = _commonUtils.FormatSql(@"
select
c.column_name,
a.index_name,
case when c.descend = 'DESC' then 1 else 0 end,
case when a.uniqueness = 'UNIQUE' then 1 else 0 end
from all_indexes a,
all_ind_columns c
where a.index_name = c.index_name
and a.table_owner = c.table_owner
and a.table_name = c.table_name
and a.owner in ({0}) and a.table_name in ({1})
and not exists(select 1 from all_constraints where index_name = a.index_name and constraint_type = 'P')", tboldname ?? tbname);
var dsuk = _orm.Ado.ExecuteArray(CommandType.Text, dsuksql).Select(a => new[] { string.Concat(a[0]).Trim('"'), string.Concat(a[1]), string.Concat(a[2]), string.Concat(a[3]) }).ToArray();
foreach (var uk in tb.Indexes)
{
if (string.IsNullOrEmpty(uk.Name) || uk.Columns.Any() == false) continue;
var ukname = ReplaceIndexName(uk.Name, tbname[1]);
var dsukfind1 = dsuk.Where(a => string.Compare(a[1], ukname, true) == 0).ToArray();
if (dsukfind1.Any() == false || dsukfind1.Length != uk.Columns.Length || dsukfind1.Where(a => uk.Columns.Where(b => (a[3] == "1") == uk.IsUnique && string.Compare(b.Column.Attribute.Name, a[0], true) == 0 && (a[2] == "1") == b.IsDesc).Any()).Count() != uk.Columns.Length)
{
if (dsukfind1.Any()) sbalter.Append("execute immediate 'DROP INDEX ").Append(_commonUtils.QuoteSqlName(ukname)).Append("';\r\n");
sbalter.Append("execute immediate 'CREATE ");
if (uk.IsUnique) sbalter.Append("UNIQUE ");
sbalter.Append("INDEX ").Append(_commonUtils.QuoteSqlName(ukname)).Append(" ON ").Append(_commonUtils.QuoteSqlName($"{tbname[0]}.{tbname[1]}")).Append("(");
foreach (var tbcol in uk.Columns)
{
sbalter.Append(_commonUtils.QuoteSqlName(tbcol.Column.Attribute.Name));
if (tbcol.IsDesc) sbalter.Append(" DESC");
sbalter.Append(", ");
}
sbalter.Remove(sbalter.Length - 2, 2).Append(")';\r\n");
}
}
}
if (istmpatler == false)
{
var dbcomment = string.Concat(_orm.Ado.ExecuteScalar(CommandType.Text, _commonUtils.FormatSql(@" select comments from all_tab_comments where owner = {0} and table_name = {1} and table_type = 'TABLE'", tbname[0], tbname[1])));
if (dbcomment != (tb.Comment ?? ""))
sb.Append("execute immediate 'COMMENT ON TABLE ").Append(_commonUtils.QuoteSqlName($"{tbname[0]}.{tbname[1]}")).Append(" IS ").Append(_commonUtils.FormatSql("{0}", tb.Comment).Replace("'", "''")).Append("';\r\n");
sb.Append(sbalter);
continue;
}
var oldpk = _orm.Ado.ExecuteScalar(CommandType.Text, _commonUtils.FormatSql(@" select constraint_name from user_constraints where owner={0} and table_name={1} and constraint_type='P'", tbname))?.ToString();
//if (string.IsNullOrEmpty(oldpk) == false)
// sb.Append("execute immediate 'ALTER TABLE ").Append(_commonUtils.QuoteSqlName($"{tbname[0]}.{tbname[1]}")).Append(" DROP CONSTRAINT ").Append(_commonUtils.QuoteSqlName(oldpk)).Append("';\r\n");
//执行失败(语句1) 试图删除聚集主键
//创建临时表,数据导进临时表,然后删除原表,将临时表改名为原表名
var tablename = tboldname == null ? _commonUtils.QuoteSqlName($"{tbname[0]}.{tbname[1]}") : _commonUtils.QuoteSqlName($"{tboldname[0]}.{tboldname[1]}");
var tmptablename = _commonUtils.QuoteSqlName($"{tbname[0]}.FTmp_{tbname[1]}");
//创建临时表
sb.Append("execute immediate 'CREATE TABLE ").Append(tmptablename).Append(" ( ");
foreach (var tbcol in tb.ColumnsByPosition)
{
sb.Append(" \r\n ").Append(_commonUtils.QuoteSqlName(tbcol.Attribute.Name)).Append(" ").Append(tbcol.Attribute.DbType).Append(",");
if (tbcol.Attribute.IsIdentity == true) seqcols.Add(NativeTuple.Create(tbcol, tbname, true));
}
if (tb.Primarys.Any())
{
var pkname = primaryKeyName ?? $"{tbname[0]}_{tbname[1]}_pk1";
if (string.IsNullOrEmpty(oldpk) == false && oldpk == pkname) pkname = $"{pkname}1";
sb.Append(" \r\n CONSTRAINT ").Append(_commonUtils.QuoteSqlName(pkname)).Append(" PRIMARY KEY (");
foreach (var tbcol in tb.Primarys) sb.Append(_commonUtils.QuoteSqlName(tbcol.Attribute.Name)).Append(", ");
sb.Remove(sb.Length - 2, 2).Append("),");
}
sb.Remove(sb.Length - 1, 1);
sb.Append("\r\n) LOGGING ';\r\n");
//备注
foreach (var tbcol in tb.ColumnsByPosition)
{
if (string.IsNullOrEmpty(tbcol.Comment) == false)
sb.Append("execute immediate 'COMMENT ON COLUMN ").Append(_commonUtils.QuoteSqlName($"{tbname[0]}.FTmp_{tbname[1]}.{tbcol.Attribute.Name}")).Append(" IS ").Append(_commonUtils.FormatSql("{0}", tbcol.Comment).Replace("'", "''")).Append("';\r\n");
}
if (string.IsNullOrEmpty(tb.Comment) == false)
sb.Append("execute immediate 'COMMENT ON TABLE ").Append(_commonUtils.QuoteSqlName($"{tbname[0]}.FTmp_{tbname[1]}")).Append(" IS ").Append(_commonUtils.FormatSql("{0}", tb.Comment).Replace("'", "''")).Append("';\r\n");
sb.Append("execute immediate 'INSERT INTO ").Append(tmptablename).Append(" (");
foreach (var tbcol in tb.ColumnsByPosition)
sb.Append(_commonUtils.QuoteSqlName(tbcol.Attribute.Name)).Append(", ");
sb.Remove(sb.Length - 2, 2).Append(")\r\nSELECT ");
foreach (var tbcol in tb.ColumnsByPosition)
{
var insertvalue = "NULL";
if (tbstruct.TryGetValue(tbcol.Attribute.Name, out var tbstructcol) ||
string.IsNullOrEmpty(tbcol.Attribute.OldName) == false && tbstruct.TryGetValue(tbcol.Attribute.OldName, out tbstructcol))
{
insertvalue = _commonUtils.QuoteSqlName(tbstructcol.column);
if (tbcol.Attribute.DbType.StartsWith(tbstructcol.sqlType, StringComparison.CurrentCultureIgnoreCase) == false)
{
var dbtypeNoneNotNull = Regex.Replace(tbcol.Attribute.DbType, @"(NOT\s+)?NULL", "");
insertvalue = $"cast({insertvalue} as {dbtypeNoneNotNull})";
}
if (tbcol.Attribute.IsNullable != tbstructcol.is_nullable)
insertvalue = $"nvl({insertvalue},{tbcol.DbDefaultValue})";
}
else if (tbcol.Attribute.IsNullable == false)
insertvalue = tbcol.DbDefaultValue;
sb.Append(insertvalue.Replace("'", "''")).Append(", ");
}
sb.Remove(sb.Length - 2, 2).Append(" FROM ").Append(tablename).Append("';\r\n");
sb.Append("execute immediate 'DROP TABLE ").Append(tablename).Append("';\r\n");
sb.Append("execute immediate 'ALTER TABLE ").Append(tmptablename).Append(" RENAME TO ").Append(_commonUtils.QuoteSqlName($"{tbname[1]}")).Append("';\r\n");
//创建表的索引
foreach (var uk in tb.Indexes)
{
sb.Append("execute immediate 'CREATE ");
if (uk.IsUnique) sb.Append("UNIQUE ");
sb.Append("INDEX ").Append(_commonUtils.QuoteSqlName(ReplaceIndexName(uk.Name, tbname[1]))).Append(" ON ").Append(tablename).Append("(");
foreach (var tbcol in uk.Columns)
{
sb.Append(_commonUtils.QuoteSqlName(tbcol.Column.Attribute.Name));
if (tbcol.IsDesc) sb.Append(" DESC");
sb.Append(", ");
}
sb.Remove(sb.Length - 2, 2).Append(")';\r\n");
}
}
Dictionary<string, bool> dicDeclare = new Dictionary<string, bool>();
Action<string> dropSequence = seqname =>
{
if (dicDeclare.ContainsKey(seqname) == false)
{
sbDeclare.Append("\r\nIS").Append(seqname).Append(" NUMBER; \r\n");
dicDeclare.Add(seqname, true);
}
sb.Append("IS").Append(seqname).Append(" := 0; \r\n")
.Append(" select count(1) into IS").Append(seqname).Append(_commonUtils.FormatSql(" from user_sequences where sequence_name={0}; \r\n", seqname))
.Append("if IS").Append(seqname).Append(" > 0 then \r\n")
.Append(" execute immediate 'DROP SEQUENCE ").Append(_commonUtils.QuoteSqlName(seqname)).Append("';\r\n")
.Append("end if; \r\n");
};
Action<string> dropTrigger = tiggerName =>
{
if (dicDeclare.ContainsKey(tiggerName) == false)
{
sbDeclare.Append("\r\nIS").Append(tiggerName).Append(" NUMBER; \r\n");
dicDeclare.Add(tiggerName, true);
}
sb.Append("IS").Append(tiggerName).Append(" := 0; \r\n")
.Append(" select count(1) into IS").Append(tiggerName).Append(_commonUtils.FormatSql(" from user_triggers where trigger_name={0}; \r\n", tiggerName))
.Append("if IS").Append(tiggerName).Append(" > 0 then \r\n")
.Append(" execute immediate 'DROP TRIGGER ").Append(_commonUtils.QuoteSqlName(tiggerName)).Append("';\r\n")
.Append("end if; \r\n");
};
foreach (var seqname in seqnameDel)
{
dropSequence(seqname);
dropTrigger(seqname + "TI");
}
foreach (var seqcol in seqcols)
{
var tbname = seqcol.Item2;
var seqname = Utils.GetCsName($"{tbname[1]}_seq_{seqcol.Item1.Attribute.Name}").ToUpper();
var tiggerName = seqname + "TI";
var tbname2 = _commonUtils.QuoteSqlName($"{tbname[0]}.{tbname[1]}");
var colname2 = _commonUtils.QuoteSqlName(seqcol.Item1.Attribute.Name);
dropSequence(seqname);
if (seqcol.Item3)
{
var startWith = _orm.Ado.ExecuteScalar(CommandType.Text, _commonUtils.FormatSql(" select 1 from all_tab_columns where owner={0} and table_name={1} and column_name={2}", tbname[0], tbname[1], seqcol.Item1.Attribute.Name)) == null ? 1 :
_orm.Ado.ExecuteScalar(CommandType.Text, $" select nvl(max({colname2})+1,1) from {tbname2}");
sb.Append("execute immediate 'CREATE SEQUENCE ").Append(_commonUtils.QuoteSqlName(seqname)).Append(" start with ").Append(startWith).Append("';\r\n");
sb.Append("execute immediate 'CREATE OR REPLACE TRIGGER ").Append(_commonUtils.QuoteSqlName(tiggerName))
.Append(" \r\nbefore insert on ").Append(tbname2)
.Append(" \r\nfor each row \r\nbegin\r\nselect ").Append(_commonUtils.QuoteSqlName(seqname))
.Append(".nextval into :new.").Append(colname2).Append(" from dual;\r\nend;';\r\n");
}
else
dropTrigger(tiggerName);
}
if (sbDeclare.Length > 0) sbDeclare.Insert(0, "declare ");
return sb.Length == 0 ? null : sb.Insert(0, "BEGIN \r\n").Insert(0, sbDeclare.ToString()).Append("END;").ToString();
}
internal static string GetDamengSqlTypeFullName(object[] row)
{
var a = row;
var sqlType = string.Concat(a[1]).ToUpper();
var data_length = long.Parse(string.Concat(a[2]));
long.TryParse(string.Concat(a[3]), out var data_precision);
long.TryParse(string.Concat(a[4]), out var data_scale);
//var char_used = string.Concat(a[5]);
if (sqlType.StartsWith("INTERVAL DAY TO SECOND"))
sqlType = $"INTERVAL DAY({(data_scale - 1536) / 16}) TO SECOND({(data_scale - 1536) % 16})";
else if (Regex.IsMatch(sqlType, @"INTERVAL YEAR\(\d+\) TO MONTH", RegexOptions.IgnoreCase))
{
}
else if (sqlType.StartsWith("TIMESTAMP", StringComparison.CurrentCultureIgnoreCase))
sqlType += data_scale <= 0 ? "" : $"({data_scale})";
else if (sqlType.StartsWith("BLOB"))
{
}
else if (sqlType.StartsWith("CLOB"))
{
}
else if (sqlType.StartsWith("NCLOB"))
{
}
else if (sqlType.StartsWith("RAW"))
{
}
else if (sqlType.StartsWith("LONG RAW"))
{
}
else if (sqlType.StartsWith("TEXT"))
{
}
else if (sqlType == "REAL" || sqlType == "DOUBLE" || sqlType == "FLOAT")
{
}
else if (data_precision > 0 && data_scale > 0)
sqlType += $"({data_precision},{data_scale})";
else if (data_precision > 0)
sqlType += $"({data_precision})";
else
sqlType += $"({data_length})";
return sqlType;
}
}
}

View File

@ -0,0 +1,616 @@
using Dm;
using FreeSql.DatabaseModel;
using FreeSql.Internal;
using FreeSql.Internal.Model;
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Data;
using System.Linq;
using System.Text;
using System.Text.RegularExpressions;
namespace FreeSql.Dameng
{
class DamengDbFirst : IDbFirst
{
IFreeSql _orm;
protected CommonUtils _commonUtils;
protected CommonExpression _commonExpression;
public DamengDbFirst(IFreeSql orm, CommonUtils commonUtils, CommonExpression commonExpression)
{
_orm = orm;
_commonUtils = commonUtils;
_commonExpression = commonExpression;
}
public int GetDbType(DbColumnInfo column) => (int)GetSqlDbType(column);
DmDbType GetSqlDbType(DbColumnInfo column)
{
var dbfull = column.DbTypeTextFull?.ToLower();
switch (dbfull)
{
case "number(1)": return DmDbType.Bit;
case "number(4)": return DmDbType.SByte;
case "number(6)": return DmDbType.Int16;
case "number(11)": return DmDbType.Int32;
case "number(21)": return DmDbType.Int64;
case "number(3)": return DmDbType.Byte;
case "number(5)": return DmDbType.UInt16;
case "number(10)": return DmDbType.UInt32;
case "number(20)": return DmDbType.UInt64;
case "float(126)": return DmDbType.Double;
case "float(63)": return DmDbType.Float;
case "number(10,2)": return DmDbType.Decimal;
case "interval day(2) to second(6)": return DmDbType.Time;
case "timestamp(6)": return DmDbType.DateTime;
case "timestamp(6) with local time zone": return DmDbType.DateTime;
case "blob": return DmDbType.VarBinary;
case "nvarchar2(255)": return DmDbType.VarChar;
case "char(36)": return DmDbType.Char;
}
if (dbfull?.StartsWith("datetime(") == true)
{
_dicDbToCs.TryAdd(dbfull, _dicDbToCs["timestamp(6)"]);
return DmDbType.DateTime;
}
switch (column.DbTypeText?.ToLower())
{
case "bit":
_dicDbToCs.TryAdd(dbfull, _dicDbToCs["number(1)"]);
return DmDbType.Bit;
case "smallint":
_dicDbToCs.TryAdd(dbfull, _dicDbToCs["number(4)"]);
return DmDbType.UInt16;
case "byte":
_dicDbToCs.TryAdd(dbfull, _dicDbToCs["number(3)"]);
return DmDbType.Byte;
case "tinyint":
_dicDbToCs.TryAdd(dbfull, _dicDbToCs["number(3)"]);
return DmDbType.Byte;
case "int":
case "integer":
_dicDbToCs.TryAdd(dbfull, _dicDbToCs["number(11)"]);
return DmDbType.Int32;
case "bigint":
_dicDbToCs.TryAdd(dbfull, _dicDbToCs["number(21)"]);
return DmDbType.Int64;
case "dec":
case "decimal":
case "numeric":
case "number":
_dicDbToCs.TryAdd(dbfull, _dicDbToCs["number(10,2)"]);
return DmDbType.Decimal;
case "time":
case "interval day to second":
case "interval year to month":
case "interval year":
case "interval month":
case "interval day":
case "interval day to hour":
case "interval day to minute":
case "interval hour":
case "interval hour to minute":
case "interval hour to second":
case "interval minute":
case "interval minute to second":
case "interval second":
case "time with time zone":
_dicDbToCs.TryAdd(dbfull, _dicDbToCs["interval day(2) to second(6)"]);
return DmDbType.Time;
case "date":
_dicDbToCs.TryAdd(dbfull, _dicDbToCs["date"]);
return DmDbType.DateTime;
case "timestamp":
_dicDbToCs.TryAdd(dbfull, _dicDbToCs["timestamp(6)"]);
return DmDbType.DateTime;
case "timestamp with local time zone":
case "timestamp with time zone":
_dicDbToCs.TryAdd(dbfull, _dicDbToCs["timestamp(6) with local time zone"]);
return DmDbType.DateTime;
case "binary":
case "varbinary":
case "blob":
case "image":
case "longvarbinary":
case "bfile":
_dicDbToCs.TryAdd(dbfull, _dicDbToCs["blob"]);
return DmDbType.VarBinary;
case "nvarchar2":
_dicDbToCs.TryAdd(dbfull, _dicDbToCs["nvarchar2(255)"]);
return DmDbType.VarChar;
case "varchar":
case "varchar2":
case "text":
case "longvarchar":
_dicDbToCs.TryAdd(dbfull, _dicDbToCs["nvarchar2(255)"]);
return DmDbType.VarChar;
case "character":
case "char":
_dicDbToCs.TryAdd(dbfull, _dicDbToCs["nvarchar2(255)"]);
return DmDbType.Char;
case "nchar":
_dicDbToCs.TryAdd(dbfull, _dicDbToCs["nvarchar2(255)"]);
return DmDbType.Char;
case "clob":
_dicDbToCs.TryAdd(dbfull, _dicDbToCs["nvarchar2(255)"]);
return DmDbType.VarChar;
case "nclob":
_dicDbToCs.TryAdd(dbfull, _dicDbToCs["nvarchar2(255)"]);
return DmDbType.VarChar;
case "raw":
_dicDbToCs.TryAdd(dbfull, _dicDbToCs["blob"]);
return DmDbType.VarBinary;
case "long raw":
_dicDbToCs.TryAdd(dbfull, _dicDbToCs["blob"]);
return DmDbType.VarBinary;
case "real":
case "binary_float":
_dicDbToCs.TryAdd(dbfull, _dicDbToCs["float(63)"]);
return DmDbType.Float;
case "double":
case "float":
case "double precision":
case "binary_double":
_dicDbToCs.TryAdd(dbfull, _dicDbToCs["float(126)"]);
return DmDbType.Double;
case "rowid":
default:
if (dbfull != null) _dicDbToCs.TryAdd(dbfull, _dicDbToCs["nvarchar2(255)"]);
return DmDbType.VarChar;
}
throw new NotImplementedException(CoreStrings.S_TypeMappingNotImplemented(column.DbTypeTextFull));
}
static ConcurrentDictionary<string, DbToCs> _dicDbToCs = new ConcurrentDictionary<string, DbToCs>(StringComparer.CurrentCultureIgnoreCase);
static DamengDbFirst()
{
var defaultDbToCs = new Dictionary<string, DbToCs>() {
{ "number(1)", new DbToCs("(bool?)", "{0} == \"1\"", "{0} == true ? \"1\" : \"0\"", "bool?", typeof(bool), typeof(bool?), "{0}.Value", "GetBoolean") },
{ "number(4)", new DbToCs("(sbyte?)", "sbyte.Parse({0})", "{0}.ToString()", "sbyte?", typeof(sbyte), typeof(sbyte?), "{0}.Value", "GetInt16") },
{ "number(6)", new DbToCs("(short?)", "short.Parse({0})", "{0}.ToString()", "short?", typeof(short), typeof(short?), "{0}.Value", "GetInt16") },
{ "number(11)", new DbToCs("(int?)", "int.Parse({0})", "{0}.ToString()", "int?", typeof(int), typeof(int?), "{0}.Value", "GetInt32") },
{ "number(21)", new DbToCs("(long?)", "long.Parse({0})", "{0}.ToString()", "long?", typeof(long), typeof(long?), "{0}.Value", "GetInt64") },
{ "number(3)", new DbToCs("(byte?)", "byte.Parse({0})", "{0}.ToString()", "byte?", typeof(byte), typeof(byte?), "{0}.Value", "GetByte") },
{ "number(5)", new DbToCs("(ushort?)", "ushort.Parse({0})", "{0}.ToString()", "ushort?", typeof(ushort), typeof(ushort?), "{0}.Value", "GetInt32") },
{ "number(10)", new DbToCs("(uint?)", "uint.Parse({0})", "{0}.ToString()", "uint?", typeof(uint), typeof(uint?), "{0}.Value", "GetInt64") },
{ "number(20)", new DbToCs("(ulong?)", "ulong.Parse({0})", "{0}.ToString()", "ulong?", typeof(ulong), typeof(ulong?), "{0}.Value", "GetDecimal") },
{ "float(126)", new DbToCs("(double?)", "double.Parse({0})", "{0}.ToString()", "double?", typeof(double), typeof(double?), "{0}.Value", "GetDouble") },
{ "float(63)", new DbToCs("(float?)", "float.Parse({0})", "{0}.ToString()", "float?", typeof(float), typeof(float?), "{0}.Value", "GetFloat") },
{ "number(10,2)", new DbToCs("(decimal?)", "decimal.Parse({0})", "{0}.ToString()", "decimal?", typeof(decimal), typeof(decimal?), "{0}.Value", "GetDecimal") },
{ "interval day(2) to second(6)", new DbToCs("(TimeSpan?)", "TimeSpan.Parse(double.Parse({0}))", "{0}.Ticks.ToString()", "TimeSpan?", typeof(TimeSpan), typeof(TimeSpan?), "{0}.Value", "GetValue") },
{ "date", new DbToCs("(DateTime?)", "new DateTime(long.Parse({0}))", "{0}.Ticks.ToString()", "DateTime?", typeof(DateTime), typeof(DateTime?), "{0}.Value", "GetValue") },
{ "timestamp(6)", new DbToCs("(DateTime?)", "new DateTime(long.Parse({0}))", "{0}.Ticks.ToString()", "DateTime?", typeof(DateTime), typeof(DateTime?), "{0}.Value", "GetValue") },
{ "timestamp(6) with local time zone", new DbToCs("(DateTime?)", "new DateTime(long.Parse({0}))", "{0}.Ticks.ToString()", "DateTime?", typeof(DateTime), typeof(DateTime?), "{0}.Value", "GetValue") },
{ "blob", new DbToCs("(byte[])", "Convert.FromBase64String({0})", "Convert.ToBase64String({0})", "byte[]", typeof(byte[]), typeof(byte[]), "{0}", "GetValue") },
{ "nvarchar2(255)", new DbToCs("", "{0}.Replace(StringifySplit, \"|\")", "{0}.Replace(\"|\", StringifySplit)", "string", typeof(string), typeof(string), "{0}", "GetString") },
{ "char(36 char)", new DbToCs("(Guid?)", "Guid.Parse({0})", "{0}.ToString()", "Guid?", typeof(Guid), typeof(Guid?), "{0}.Value", "GetGuid") },
};
foreach (var kv in defaultDbToCs)
_dicDbToCs.TryAdd(kv.Key, kv.Value);
}
public string GetCsConvert(DbColumnInfo column) => _dicDbToCs.TryGetValue(column.DbTypeTextFull, out var trydc) ? (column.IsNullable ? trydc.csConvert : trydc.csConvert.Replace("?", "")) : null;
public string GetCsParse(DbColumnInfo column) => _dicDbToCs.TryGetValue(column.DbTypeTextFull, out var trydc) ? trydc.csParse : null;
public string GetCsStringify(DbColumnInfo column) => _dicDbToCs.TryGetValue(column.DbTypeTextFull, out var trydc) ? trydc.csStringify : null;
public string GetCsType(DbColumnInfo column) => _dicDbToCs.TryGetValue(column.DbTypeTextFull, out var trydc) ? (column.IsNullable ? trydc.csType : trydc.csType.Replace("?", "")) : null;
public Type GetCsTypeInfo(DbColumnInfo column) => _dicDbToCs.TryGetValue(column.DbTypeTextFull, out var trydc) ? trydc.csTypeInfo : null;
public string GetCsTypeValue(DbColumnInfo column) => _dicDbToCs.TryGetValue(column.DbTypeTextFull, out var trydc) ? trydc.csTypeValue : null;
public string GetDataReaderMethod(DbColumnInfo column) => _dicDbToCs.TryGetValue(column.DbTypeTextFull, out var trydc) ? trydc.dataReaderMethod : null;
public List<string> GetDatabases()
{
var sql = @" select username from all_users";
var ds = _orm.Ado.ExecuteArray(CommandType.Text, sql);
return ds.Select(a => a.FirstOrDefault()?.ToString()).ToList();
}
public bool ExistsTable(string name, bool ignoreCase)
{
if (string.IsNullOrEmpty(name)) return false;
var tbname = _commonUtils.SplitTableName(name);
if (tbname?.Length == 1)
{
var userId = (_orm.Ado.MasterPool as DamengConnectionPool)?.UserId;
if (string.IsNullOrEmpty(userId))
using (var conn = _orm.Ado.MasterPool.Get())
{
userId = DamengConnectionPool.GetUserId(conn.Value.ConnectionString);
}
tbname = new[] { userId, tbname[0] };
}
if (ignoreCase) tbname = tbname.Select(a => a.ToLower()).ToArray();
var sql = $" select 1 from all_tab_comments where {(ignoreCase ? "lower(owner)" : "owner")}={_commonUtils.FormatSql("{0}", tbname[0])} and {(ignoreCase ? "lower(table_name)" : "table_name")}={_commonUtils.FormatSql("{0}", tbname[1])}";
return string.Concat(_orm.Ado.ExecuteScalar(CommandType.Text, sql)) == "1";
}
public DbTableInfo GetTableByName(string name, bool ignoreCase = true) => GetTables(null, name, ignoreCase)?.FirstOrDefault();
public List<DbTableInfo> GetTablesByDatabase(params string[] database) => GetTables(database, null, false);
public List<DbTableInfo> GetTables(string[] database, string tablename, bool ignoreCase)
{
var loc1 = new List<DbTableInfo>();
var loc2 = new Dictionary<string, DbTableInfo>();
var loc3 = new Dictionary<string, Dictionary<string, DbColumnInfo>>();
string[] tbname = null;
if (string.IsNullOrEmpty(tablename) == false)
{
tbname = _commonUtils.SplitTableName(tablename);
if (tbname?.Length == 1)
{
var userUsers = _orm.Ado.ExecuteScalar(" select username from user_users")?.ToString();
if (string.IsNullOrEmpty(userUsers)) return loc1;
tbname = new[] { userUsers, tbname[0] };
}
if (ignoreCase) tbname = tbname.Select(a => a.ToLower()).ToArray();
database = new[] { tbname[0] };
}
else if (database == null || database.Any() == false)
{
var userUsers = _orm.Ado.ExecuteScalar(" select username from user_users")?.ToString();
if (string.IsNullOrEmpty(userUsers)) return loc1;
database = new[] { userUsers };
}
var databaseIn = string.Join(",", database.Select(a => _commonUtils.FormatSql("{0}", a)));
var sql = $@"
select
a.owner || '.' || a.table_name,
a.owner,
a.table_name,
b.comments,
'TABLE'
from all_tables a
left join all_tab_comments b on b.owner = a.owner and b.table_name = a.table_name and b.table_type = 'TABLE'
where {(ignoreCase ? "lower(a.owner)" : "a.owner")} in ({databaseIn}){(tbname == null ? "" : $" and {(ignoreCase ? "lower(a.table_name)" : "a.table_name")}={_commonUtils.FormatSql("{0}", tbname[1])}")}
UNION ALL
select
a.owner || '.' || a.view_name,
a.owner,
a.view_name,
b.comments,
'VIEW' AS tp
from all_views a
left join all_tab_comments b on b.owner = a.owner and b.table_name = a.view_name and b.table_type = 'VIEW'
where {(ignoreCase ? "lower(a.owner)" : "a.owner")} in ({databaseIn}){(tbname == null ? "" : $" and {(ignoreCase ? "lower(a.view_name)" : "a.view_name")}={_commonUtils.FormatSql("{0}", tbname[1])}")}";
var ds = _orm.Ado.ExecuteArray(CommandType.Text, sql);
if (ds == null) return loc1;
var loc6 = new List<string[]>();
var loc66 = new List<string[]>();
var loc6_1000 = new List<string>();
var loc66_1000 = new List<string>();
foreach (var row in ds)
{
var table_id = string.Concat(row[0]);
var schema = string.Concat(row[1]);
var table = string.Concat(row[2]);
var comment = string.Concat(row[3]);
var type = string.Concat(row[4]) == "VIEW" ? DbTableType.VIEW : DbTableType.TABLE;
if (database.Length == 1)
{
table_id = table_id.Substring(table_id.IndexOf('.') + 1);
schema = "";
}
loc2.Add(table_id, new DbTableInfo { Id = table_id, Schema = schema, Name = table, Comment = comment, Type = type });
loc3.Add(table_id, new Dictionary<string, DbColumnInfo>());
switch (type)
{
case DbTableType.TABLE:
case DbTableType.VIEW:
loc6_1000.Add(table.Replace("'", "''"));
if (loc6_1000.Count >= 999)
{
loc6.Add(loc6_1000.ToArray());
loc6_1000.Clear();
}
break;
case DbTableType.StoreProcedure:
loc66_1000.Add(table.Replace("'", "''"));
if (loc66_1000.Count >= 999)
{
loc66.Add(loc66_1000.ToArray());
loc66_1000.Clear();
}
break;
}
}
if (loc6_1000.Count > 0) loc6.Add(loc6_1000.ToArray());
if (loc66_1000.Count > 0) loc66.Add(loc66_1000.ToArray());
if (loc6.Count == 0) return loc1;
var loc8 = new StringBuilder().Append("(");
for (var loc8idx = 0; loc8idx < loc6.Count; loc8idx++)
{
if (loc8idx > 0) loc8.Append(" OR ");
loc8.Append("a.table_name in (");
for (var loc8idx2 = 0; loc8idx2 < loc6[loc8idx].Length; loc8idx2++)
{
if (loc8idx2 > 0) loc8.Append(",");
loc8.Append($"'{loc6[loc8idx][loc8idx2]}'");
}
loc8.Append(")");
}
loc8.Append(")");
sql = $@"
select
a.owner || '.' || a.table_name,
a.column_name,
a.data_type,
a.data_length,
a.data_precision,
a.data_scale,
a.char_used,
case when a.nullable = 'N' then 0 else 1 end,
nvl((select 1 from user_sequences where upper(sequence_name)=upper(a.table_name||'_seq_'||a.column_name) and rownum < 2), 0),
b.comments,
a.data_default
from all_tab_columns a
left join all_col_comments b on b.owner = a.owner and b.table_name = a.table_name and b.column_name = a.column_name
where {(ignoreCase ? "lower(a.owner)" : "a.owner")} in ({databaseIn}) and {loc8}
";
ds = _orm.Ado.ExecuteArray(CommandType.Text, sql);
if (ds == null) return loc1;
var ds2 = new List<object[]>();
foreach (var row in ds)
{
var ds2item = new object[9];
ds2item[0] = row[0];
ds2item[1] = row[1];
ds2item[2] = Regex.Replace(string.Concat(row[2]), @"\(\d+\)", "");
ds2item[4] = DamengCodeFirst.GetDamengSqlTypeFullName(new object[] { row[1], row[2], row[3], row[4], row[5], row[6] });
ds2item[5] = string.Concat(row[7]);
ds2item[6] = string.Concat(row[8]);
ds2item[7] = string.Concat(row[9]);
ds2item[8] = string.Concat(row[10]);
ds2.Add(ds2item);
}
var position = 0;
foreach (var row in ds2)
{
string table_id = string.Concat(row[0]);
string column = string.Concat(row[1]);
string type = string.Concat(row[2]);
//long max_length = long.Parse(string.Concat(row[3]));
string sqlType = string.Concat(row[4]);
var m_len = Regex.Match(sqlType, @"\w+\((\d+)");
int max_length = m_len.Success ? int.Parse(m_len.Groups[1].Value) : -1;
bool is_nullable = string.Concat(row[5]) == "1";
bool is_identity = string.Concat(row[6]) == "1";
string comment = string.Concat(row[7]);
string defaultValue = string.Concat(row[8]);
if (max_length == 0) max_length = -1;
if (database.Length == 1)
{
table_id = table_id.Substring(table_id.IndexOf('.') + 1);
}
loc3[table_id].Add(column, new DbColumnInfo
{
Name = column,
MaxLength = max_length,
IsIdentity = is_identity,
IsNullable = is_nullable,
IsPrimary = false,
DbTypeText = type,
DbTypeTextFull = sqlType,
Table = loc2[table_id],
Comment = comment,
DefaultValue = defaultValue,
Position = ++position
});
loc3[table_id][column].DbType = this.GetDbType(loc3[table_id][column]);
loc3[table_id][column].CsType = this.GetCsTypeInfo(loc3[table_id][column]);
}
sql = $@"
select
a.table_owner || '.' || a.table_name,
c.column_name,
c.index_name,
case when a.uniqueness = 'UNIQUE' then 1 else 0 end,
case when exists(select 1 from all_constraints where index_name = a.index_name and constraint_type = 'P') then 1 else 0 end,
0,
case when c.descend = 'DESC' then 1 else 0 end,
c.column_position
from all_indexes a,
all_ind_columns c
where a.index_name = c.index_name
and a.table_owner = c.table_owner
and a.table_name = c.table_name
and {(ignoreCase ? "lower(a.table_owner)" : "a.table_owner")} in ({databaseIn}) and {loc8}
";
ds = _orm.Ado.ExecuteArray(CommandType.Text, sql);
if (ds == null) return loc1;
var indexColumns = new Dictionary<string, Dictionary<string, DbIndexInfo>>();
var uniqueColumns = new Dictionary<string, Dictionary<string, DbIndexInfo>>();
foreach (var row in ds)
{
string table_id = string.Concat(row[0]);
string column = string.Concat(row[1]).Trim('"');
string index_id = string.Concat(row[2]);
bool is_unique = string.Concat(row[3]) == "1";
bool is_primary_key = string.Concat(row[4]) == "1";
bool is_clustered = string.Concat(row[5]) == "1";
bool is_desc = string.Concat(row[6]) == "1";
if (database.Length == 1)
table_id = table_id.Substring(table_id.IndexOf('.') + 1);
if (loc3.ContainsKey(table_id) == false || loc3[table_id].ContainsKey(column) == false) continue;
var loc9 = loc3[table_id][column];
if (loc9.IsPrimary == false && is_primary_key) loc9.IsPrimary = is_primary_key;
if (is_primary_key) continue;
Dictionary<string, DbIndexInfo> loc10 = null;
DbIndexInfo loc11 = null;
if (!indexColumns.TryGetValue(table_id, out loc10))
indexColumns.Add(table_id, loc10 = new Dictionary<string, DbIndexInfo>());
if (!loc10.TryGetValue(index_id, out loc11))
loc10.Add(index_id, loc11 = new DbIndexInfo());
loc11.Columns.Add(new DbIndexColumnInfo { Column = loc9, IsDesc = is_desc });
if (is_unique && !is_primary_key)
{
if (!uniqueColumns.TryGetValue(table_id, out loc10))
uniqueColumns.Add(table_id, loc10 = new Dictionary<string, DbIndexInfo>());
if (!loc10.TryGetValue(index_id, out loc11))
loc10.Add(index_id, loc11 = new DbIndexInfo());
loc11.Columns.Add(new DbIndexColumnInfo { Column = loc9, IsDesc = is_desc });
}
}
foreach (string table_id in indexColumns.Keys)
{
foreach (var column in indexColumns[table_id])
loc2[table_id].IndexesDict.Add(column.Key, column.Value);
}
foreach (string table_id in uniqueColumns.Keys)
{
foreach (var column in uniqueColumns[table_id])
{
column.Value.Columns.Sort((c1, c2) => c1.Column.Name.CompareTo(c2.Column.Name));
loc2[table_id].UniquesDict.Add(column.Key, column.Value);
}
}
if (tbname == null)
{
sql = $@"
select
a.owner || '.' || a.table_name,
c.column_name,
c.constraint_name,
b.owner || '.' || b.table_name,
1,
d.column_name
-- a.owner 外键拥有者,
-- a.table_name 外键表,
-- c.column_name 外键列,
-- b.owner 主键拥有者,
-- b.table_name 主键表,
-- d.column_name 主键列,
-- c.constraint_name 外键名,
-- d.constraint_name 主键名
from
all_constraints a,
all_constraints b,
all_cons_columns c, --外键表
all_cons_columns d --主键表
where
a.r_constraint_name = b.constraint_name
and a.constraint_type = 'R'
and b.constraint_type = 'P'
and a.r_owner = b.owner
and a.constraint_name = c.constraint_name
and b.constraint_name = d.constraint_name
and a.owner = c.owner
and a.table_name = c.table_name
and b.owner = d.owner
and b.table_name = d.table_name
and {(ignoreCase ? "lower(a.owner)" : "a.owner")} in ({databaseIn}) and {loc8}
";
ds = _orm.Ado.ExecuteArray(CommandType.Text, sql);
if (ds == null) return loc1;
var fkColumns = new Dictionary<string, Dictionary<string, DbForeignInfo>>();
foreach (var row in ds)
{
string table_id = string.Concat(row[0]);
string column = string.Concat(row[1]);
string fk_id = string.Concat(row[2]);
string ref_table_id = string.Concat(row[3]);
bool is_foreign_key = string.Concat(row[4]) == "1";
string referenced_column = string.Concat(row[5]);
if (database.Length == 1)
{
table_id = table_id.Substring(table_id.IndexOf('.') + 1);
ref_table_id = ref_table_id.Substring(ref_table_id.IndexOf('.') + 1);
}
if (loc3.ContainsKey(table_id) == false || loc3[table_id].ContainsKey(column) == false) continue;
var loc9 = loc3[table_id][column];
if (loc2.ContainsKey(ref_table_id) == false) continue;
var loc10 = loc2[ref_table_id];
var loc11 = loc3[ref_table_id][referenced_column];
Dictionary<string, DbForeignInfo> loc12 = null;
DbForeignInfo loc13 = null;
if (!fkColumns.TryGetValue(table_id, out loc12))
fkColumns.Add(table_id, loc12 = new Dictionary<string, DbForeignInfo>());
if (!loc12.TryGetValue(fk_id, out loc13))
loc12.Add(fk_id, loc13 = new DbForeignInfo { Table = loc2[table_id], ReferencedTable = loc10 });
loc13.Columns.Add(loc9);
loc13.ReferencedColumns.Add(loc11);
}
foreach (var table_id in fkColumns.Keys)
foreach (var fk in fkColumns[table_id])
loc2[table_id].ForeignsDict.Add(fk.Key, fk.Value);
}
foreach (var table_id in loc3.Keys)
{
foreach (var loc5 in loc3[table_id].Values)
{
loc2[table_id].Columns.Add(loc5);
if (loc5.IsIdentity) loc2[table_id].Identitys.Add(loc5);
if (loc5.IsPrimary) loc2[table_id].Primarys.Add(loc5);
}
}
foreach (var loc4 in loc2.Values)
{
//if (loc4.Primarys.Count == 0 && loc4.UniquesDict.Count > 0)
//{
// foreach (var loc5 in loc4.UniquesDict.First().Value.Columns)
// {
// loc5.Column.IsPrimary = true;
// loc4.Primarys.Add(loc5.Column);
// }
//}
loc4.Primarys.Sort((c1, c2) => c1.Name.CompareTo(c2.Name));
loc4.Columns.Sort((c1, c2) =>
{
int compare = c2.IsPrimary.CompareTo(c1.IsPrimary);
if (compare == 0)
{
bool b1 = loc4.ForeignsDict.Values.Where(fk => fk.Columns.Where(c3 => c3.Name == c1.Name).Any()).Any();
bool b2 = loc4.ForeignsDict.Values.Where(fk => fk.Columns.Where(c3 => c3.Name == c2.Name).Any()).Any();
compare = b2.CompareTo(b1);
}
if (compare == 0) compare = c1.Name.CompareTo(c2.Name);
return compare;
});
loc1.Add(loc4);
}
loc1.Sort((t1, t2) =>
{
var ret = t1.Schema.CompareTo(t2.Schema);
if (ret == 0) ret = t1.Name.CompareTo(t2.Name);
return ret;
});
loc2.Clear();
loc3.Clear();
return loc1;
}
public List<DbEnumInfo> GetEnumsByDatabase(params string[] database)
{
return new List<DbEnumInfo>();
}
}
}

View File

@ -0,0 +1,585 @@
using FreeSql.Internal;
using System;
using System.Collections;
using System.Linq;
using System.Linq.Expressions;
using System.Text;
using System.Text.RegularExpressions;
namespace FreeSql.Dameng
{
class DamengExpression : CommonExpression
{
public DamengExpression(CommonUtils common) : base(common) { }
public override string ExpressionLambdaToSqlOther(Expression exp, ExpTSC tsc)
{
Func<Expression, string> getExp = exparg => ExpressionLambdaToSql(exparg, tsc);
switch (exp.NodeType)
{
case ExpressionType.ArrayLength:
var arrOper = (exp as UnaryExpression)?.Operand;
if (arrOper.Type == typeof(byte[])) return $"lengthb({getExp(arrOper)})";
break;
case ExpressionType.Convert:
var operandExp = (exp as UnaryExpression)?.Operand;
var gentype = exp.Type.NullableTypeOrThis();
if (gentype != operandExp.Type.NullableTypeOrThis())
{
switch (exp.Type.NullableTypeOrThis().ToString())
{
//case "System.Boolean": return $"({getExp(operandExp)} not in ('0','false'))";
case "System.Byte": return $"cast({getExp(operandExp)} as number)";
case "System.Char": return $"substr(to_char({getExp(operandExp)}), 1, 1)";
case "System.DateTime": return $"to_timestamp({getExp(operandExp)},'YYYY-MM-DD HH24:MI:SS.FF6')";
case "System.Decimal": return $"cast({getExp(operandExp)} as number)";
case "System.Double": return $"cast({getExp(operandExp)} as number)";
case "System.Int16":
case "System.Int32":
case "System.Int64":
case "System.SByte": return $"cast({getExp(operandExp)} as number)";
case "System.Single": return $"cast({getExp(operandExp)} as number)";
case "System.String": return $"to_char({getExp(operandExp)})";
case "System.UInt16":
case "System.UInt32":
case "System.UInt64": return $"cast({getExp(operandExp)} as number)";
case "System.Guid":
if (tsc.mapType == typeof(byte[])) return $"hextoraw({getExp(operandExp)})";
return $"to_char({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 $"({getExp(callExp.Arguments[0])} not in ('0','false'))";
case "System.Byte": return $"cast({getExp(callExp.Arguments[0])} as number)";
case "System.Char": return $"substr(to_char({getExp(callExp.Arguments[0])}), 1, 1)";
case "System.DateTime": return $"to_timestamp({getExp(callExp.Arguments[0])},'YYYY-MM-DD HH24:MI:SS.FF6')";
case "System.Decimal": return $"cast({getExp(callExp.Arguments[0])} as number)";
case "System.Double": return $"cast({getExp(callExp.Arguments[0])} as number)";
case "System.Int16":
case "System.Int32":
case "System.Int64":
case "System.SByte": return $"cast({getExp(callExp.Arguments[0])} as number)";
case "System.Single": return $"cast({getExp(callExp.Arguments[0])} as number)";
case "System.UInt16":
case "System.UInt32":
case "System.UInt64": return $"cast({getExp(callExp.Arguments[0])} as number)";
case "System.Guid":
if (tsc.mapType == typeof(byte[])) return $"hextoraw({getExp(callExp.Arguments[0])})";
return $"to_char({getExp(callExp.Arguments[0])})";
}
return null;
case "NewGuid":
return null;
case "Next":
if (callExp.Object?.Type == typeof(Random)) return "cast(dbms_random.value*1000000000 as number)";
return null;
case "NextDouble":
if (callExp.Object?.Type == typeof(Random)) return "dbms_random.value";
return null;
case "Random":
if (callExp.Method.DeclaringType.IsNumberType()) return "dbms_random.value";
return null;
case "ToString":
if (callExp.Object != null)
{
if (callExp.Object.Type.NullableTypeOrThis().IsEnum)
{
tsc.SetMapColumnTmp(null);
var oldMapType = tsc.SetMapTypeReturnOld(typeof(string));
var enumStr = ExpressionLambdaToSql(callExp.Object, tsc);
tsc.SetMapColumnTmp(null).SetMapTypeReturnOld(oldMapType);
return enumStr;
}
var value = ExpressionGetValue(callExp.Object, out var success);
if (success) return formatSql(value, typeof(string), null, null);
return callExp.Arguments.Count == 0 ? $"to_char({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 $"substr({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 = objExp?.NodeType == ExpressionType.MemberAccess ? tsc.SetDbParamsReturnOld(null) : null; //#900 UseGenerateCommandParameterWithLambda(true) 子查询 bug、以及 #1173 参数化 bug
tsc.isNotSetMapColumnTmp = true;
var left = objExp == null ? null : getExp(objExp);
tsc.isNotSetMapColumnTmp = false;
tsc.SetMapColumnTmp(null).SetMapTypeReturnOld(oldMapType);
if (oldDbParams != null) 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(",");
if (a % 500 == 499) arrSb.Append(" \r\n \r\n"); //500元素分割, 3空格\r\n4空格
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 $"length({left})";
}
return null;
}
public override string ExpressionLambdaToSqlMemberAccessDateTime(MemberExpression exp, ExpTSC tsc)
{
if (exp.Expression == null)
{
switch (exp.Member.Name)
{
case "Now": return _common.Now;
case "UtcNow": return _common.NowUtc;
case "Today": return "trunc(systimestamp)";
case "MinValue": return "to_timestamp('0001-01-01 00:00:00','YYYY-MM-DD HH24:MI:SS.FF6')";
case "MaxValue": return "to_timestamp('9999-12-31 23:59:59','YYYY-MM-DD HH24:MI:SS.FF6')";
}
return null;
}
var left = ExpressionLambdaToSql(exp.Expression, tsc);
switch (exp.Member.Name)
{
case "Date": return $"trunc({left})";
case "TimeOfDay": return $"(cast({left} as timestamp with time zone)-trunc({left}))";
case "DayOfWeek": return $"case when to_char({left},'D')='7' then 0 else cast(to_char({left},'D') as number) end";
case "Day": return $"cast(to_char({left},'DD') as number)";
case "DayOfYear": return $"cast(to_char({left},'DDD') as number)";
case "Month": return $"cast(to_char({left},'MM') as number)";
case "Year": return $"cast(to_char({left},'YYYY') as number)";
case "Hour": return $"cast(to_char({left},'HH24') as number)";
case "Minute": return $"cast(to_char({left},'MI') as number)";
case "Second": return $"cast(to_char({left},'SS') as number)";
case "Millisecond": return $"cast(to_char({left},'FF3') as number)";
case "Ticks": return $"cast(to_char({left},'FF7') as number)";
}
return null;
}
public override string ExpressionLambdaToSqlMemberAccessTimeSpan(MemberExpression exp, ExpTSC tsc)
{
if (exp.Expression == null)
{
switch (exp.Member.Name)
{
case "Zero": return "numtodsinterval(0,'second')";
case "MinValue": return "numtodsinterval(-233720368.5477580,'second')";
case "MaxValue": return "numtodsinterval(233720368.5477580,'second')";
}
return null;
}
var left = ExpressionLambdaToSql(exp.Expression, tsc);
switch (exp.Member.Name)
{
case "Days": return $"extract(day from {left})";
case "Hours": return $"extract(hour from {left})";
case "Milliseconds": return $"cast(substr(extract(second from {left})-floor(extract(second from {left})),3,3) as number)";
case "Minutes": return $"extract(minute from {left})";
case "Seconds": return $"floor(extract(second from {left}))";
case "Ticks": return $"(extract(day from {left})*86400+extract(hour from {left})*3600+extract(minute from {left})*60+extract(second from {left}))*10000000";
case "TotalDays": return $"extract(day from {left})";
case "TotalHours": return $"(extract(day from {left})*24+extract(hour from {left}))";
case "TotalMilliseconds": return $"(extract(day from {left})*86400+extract(hour from {left})*3600+extract(minute from {left})*60+extract(second from {left}))*1000";
case "TotalMinutes": return $"(extract(day from {left})*1440+extract(hour from {left})*60+extract(minute from {left}))";
case "TotalSeconds": return $"(extract(day from {left})*86400+extract(hour from {left})*3600+extract(minute from {left})*60+extract(second from {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":
var arg1 = getExp(exp.Arguments[0]);
return $"({arg1} is null or {arg1} = '')";
case "IsNullOrWhiteSpace":
var arg2 = getExp(exp.Arguments[0]);
return $"({arg2} is null or {arg2} = '' or ltrim({arg2}) = '')";
case "Concat":
if (exp.Arguments.Count == 1 && exp.Arguments[0].NodeType == ExpressionType.NewArrayInit && exp.Arguments[0] is NewArrayExpression concatNewArrExp)
return _common.StringConcat(concatNewArrExp.Expressions.Select(a => getExp(a)).ToArray(), null);
return _common.StringConcat(exp.Arguments.Select(a => getExp(a)).ToArray(), null);
case "Format":
if (exp.Arguments[0].NodeType != ExpressionType.Constant) throw new Exception(CoreStrings.Not_Implemented_Expression_ParameterUseConstant(exp,exp.Arguments[0]));
var expArgsHack = exp.Arguments.Count == 2 && exp.Arguments[1].NodeType == ExpressionType.NewArrayInit ?
(exp.Arguments[1] as NewArrayExpression).Expressions : exp.Arguments.Where((a, z) => z > 0);
//3个 {} 时Arguments 解析出来是分开的
//4个 {} 时Arguments[1] 只能解析这个出来,然后里面是 NewArray []
var expArgs = expArgsHack.Select(a => $"'||{_common.IsNull(ExpressionLambdaToSql(a, tsc), "''")}||'").ToArray();
return string.Format(ExpressionLambdaToSql(exp.Arguments[0], tsc), expArgs);
case "Join":
if (exp.IsStringJoin(out var tolistObjectExp, out var toListMethod, out var toListArgs1))
{
var newToListArgs0 = Expression.Call(tolistObjectExp, toListMethod,
Expression.Lambda(
Expression.Call(
typeof(SqlExtExtensions).GetMethod("StringJoinOracleGroupConcat"),
Expression.Convert(toListArgs1.Body, typeof(object)),
Expression.Convert(exp.Arguments[0], typeof(object))),
toListArgs1.Parameters));
var newToListSql = getExp(newToListArgs0);
return newToListSql;
}
break;
}
}
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 (args0Value.Contains("%"))
{
if (exp.Method.Name == "StartsWith") return $"instr({left}, {args0Value}, 1, 1) = 1";
if (exp.Method.Name == "EndsWith") return $"instr({left}, {args0Value}, 1, 1) = length({left})-length({args0Value})+1";
return $"instr({left}, {args0Value}, 1, 1) > 0";
}
if (exp.Method.Name == "StartsWith") return $"({left}) LIKE {(args0Value.EndsWith("'") ? args0Value.Insert(args0Value.Length - 1, "%") : $"(to_char({args0Value})||'%')")}";
if (exp.Method.Name == "EndsWith") return $"({left}) LIKE {(args0Value.StartsWith("'") ? args0Value.Insert(1, "%") : $"('%'||to_char({args0Value}))")}";
if (args0Value.StartsWith("'") && args0Value.EndsWith("'")) return $"({left}) LIKE {args0Value.Insert(1, "%").Insert(args0Value.Length, "%")}";
return $"({left}) LIKE ('%'||to_char({args0Value})||'%')";
case "ToLower": return $"lower({left})";
case "ToUpper": return $"upper({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 $"substr({left}, {substrArgs1})";
return $"substr({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 $"(instr({left}, {indexOfFindStr}, {locateArgs1}, 1)-1)";
}
return $"(instr({left}, {indexOfFindStr}, 1, 1))-1";
case "PadLeft":
if (exp.Arguments.Count == 1) return $"lpad({left}, {getExp(exp.Arguments[0])}, ' ')";
return $"lpad({left}, {getExp(exp.Arguments[0])}, {getExp(exp.Arguments[1])})";
case "PadRight":
if (exp.Arguments.Count == 1) return $"rpad({left}, {getExp(exp.Arguments[0])}, ' ')";
return $"rpad({left}, {getExp(exp.Arguments[0])}, {getExp(exp.Arguments[1])})";
case "Trim":
case "TrimStart":
case "TrimEnd":
if (exp.Arguments.Count == 0)
{
if (exp.Method.Name == "Trim") return $"trim({left})";
if (exp.Method.Name == "TrimStart") return $"ltrim({left})";
if (exp.Method.Name == "TrimEnd") return $"rtrim({left})";
}
foreach (var argsTrim02 in exp.Arguments)
{
var argsTrim01s = new[] { argsTrim02 };
if (argsTrim02.NodeType == ExpressionType.NewArrayInit)
{
var arritem = argsTrim02 as NewArrayExpression;
argsTrim01s = arritem.Expressions.ToArray();
}
foreach (var argsTrim01 in argsTrim01s)
{
if (exp.Method.Name == "Trim") left = $"trim(both {getExp(argsTrim01)} from {left})";
if (exp.Method.Name == "TrimStart") left = $"ltrim({left},{getExp(argsTrim01)})";
if (exp.Method.Name == "TrimEnd") left = $"rtrim({left},{getExp(argsTrim01)})";
}
}
return left;
case "Replace": return $"replace({left}, {getExp(exp.Arguments[0])}, {getExp(exp.Arguments[1])})";
case "CompareTo": return $"case when {left} = {getExp(exp.Arguments[0])} then 0 when {left} > {getExp(exp.Arguments[0])} then 1 else -1 end";
case "Equals": return $"({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 $"abs({getExp(exp.Arguments[0])})";
case "Sign": return $"sign({getExp(exp.Arguments[0])})";
case "Floor": return $"floor({getExp(exp.Arguments[0])})";
case "Ceiling": return $"ceil({getExp(exp.Arguments[0])})";
case "Round":
if (exp.Arguments.Count > 1 && exp.Arguments[1].Type.FullName == "System.Int32") return $"round({getExp(exp.Arguments[0])}, {getExp(exp.Arguments[1])})";
return $"round({getExp(exp.Arguments[0])})";
case "Exp": return $"exp({getExp(exp.Arguments[0])})";
case "Log":
if (exp.Arguments.Count > 1) return $"log({getExp(exp.Arguments[1])},{getExp(exp.Arguments[0])})";
return $"log(2.7182818284590451,{getExp(exp.Arguments[0])})";
case "Log10": return $"log(10,{getExp(exp.Arguments[0])})";
case "Pow": return $"power({getExp(exp.Arguments[0])}, {getExp(exp.Arguments[1])})";
case "Sqrt": return $"sqrt({getExp(exp.Arguments[0])})";
case "Cos": return $"cos({getExp(exp.Arguments[0])})";
case "Sin": return $"sin({getExp(exp.Arguments[0])})";
case "Tan": return $"tan({getExp(exp.Arguments[0])})";
case "Acos": return $"acos({getExp(exp.Arguments[0])})";
case "Asin": return $"asin({getExp(exp.Arguments[0])})";
case "Atan": return $"atan({getExp(exp.Arguments[0])})";
//case "Atan2": return $"atan2({getExp(exp.Arguments[0])}, {getExp(exp.Arguments[1])})";
case "Truncate": return $"trunc({getExp(exp.Arguments[0])}, 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 $"extract(day from ({getExp(exp.Arguments[0])}-({getExp(exp.Arguments[1])})))";
case "DaysInMonth": return $"cast(to_char(last_day(to_date(({getExp(exp.Arguments[0])})||'-'||({getExp(exp.Arguments[1])})||'-01','yyyy-mm-dd')),'DD') as number)";
case "Equals": return $"({getExp(exp.Arguments[0])} = {getExp(exp.Arguments[1])})";
case "IsLeapYear":
var isLeapYearArgs1 = getExp(exp.Arguments[0]);
return $"(mod({isLeapYearArgs1},4)=0 AND mod({isLeapYearArgs1},100)<>0 OR mod({isLeapYearArgs1},400)=0)";
case "Parse": return $"to_timestamp({getExp(exp.Arguments[0])},'YYYY-MM-DD HH24:MI:SS.FF6')";
case "ParseExact":
case "TryParse":
case "TryParseExact": return $"to_timestamp({getExp(exp.Arguments[0])},'YYYY-MM-DD HH24:MI:SS.FF6')";
}
}
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 "AddDays": return $"({left}+{args1})";
case "AddHours": return $"({left}+({args1})/24)";
case "AddMilliseconds": return $"({left}+({args1})/86400000)";
case "AddMinutes": return $"({left}+({args1})/1440)";
case "AddMonths": return $"add_months({left},{args1})";
case "AddSeconds": return $"({left}+({args1})/86400)";
case "AddTicks": return $"({left}+({args1})/864000000000)";
case "AddYears": return $"add_months({left},({args1})*12)";
case "Subtract":
switch ((exp.Arguments[0].Type.IsNullableType() ? exp.Arguments[0].Type.GetGenericArguments().FirstOrDefault() : exp.Arguments[0].Type).FullName)
{
case "System.DateTime": return $"(cast({left} as timestamp with time zone)-{args1})";
case "System.TimeSpan": return $"({left}-{args1})";
}
break;
case "Equals": return $"({left} = {args1})";
case "CompareTo": return $"extract(day from ({left}-({args1})))";
case "ToString":
if (left.StartsWith("'") || left.EndsWith("'")) left = $"to_timestamp({left},'YYYY-MM-DD HH24:MI:SS.FF6')";
if (exp.Arguments.Count == 0) return $"to_char({left},'YYYY-MM-DD HH24:MI:SS.FF6')";
switch (args1)
{
case "'yyyy-MM-dd HH:mm:ss'": return $"to_char({left},'YYYY-MM-DD HH24:MI:SS')";
case "'yyyy-MM-dd HH:mm'": return $"to_char({left},'YYYY-MM-DD HH24:MI')";
case "'yyyy-MM-dd HH'": return $"to_char({left},'YYYY-MM-DD HH24')";
case "'yyyy-MM-dd'": return $"to_char({left},'YYYY-MM-DD')";
case "'yyyy-MM'": return $"to_char({left},'YYYY-MM')";
case "'yyyyMMddHHmmss'": return $"to_char({left},'YYYYMMDDHH24MISS')";
case "'yyyyMMddHHmm'": return $"to_char({left},'YYYYMMDDHH24MI')";
case "'yyyyMMddHH'": return $"to_char({left},'YYYYMMDDHH24')";
case "'yyyyMMdd'": return $"to_char({left},'YYYYMMDD')";
case "'yyyyMM'": return $"to_char({left},'YYYYMM')";
case "'yyyy'": return $"to_char({left},'YYYY')";
case "'HH:mm:ss'": return $"to_char({left},'HH24:MI:SS')";
}
args1 = Regex.Replace(args1, "(yyyy|yy|MM|dd|HH|hh|mm|ss|tt)", m =>
{
switch (m.Groups[1].Value)
{
case "yyyy": return "YYYY";
case "yy": return "YY";
case "MM": return "%_a1";
case "dd": return "%_a2";
case "HH": return "%_a3";
case "mm": return "%_a4";
case "ss": return "SS";
case "tt": return "%_a5";
}
return m.Groups[0].Value;
});
var argsFinds = new[] { "YYYY", "YY", "%_a1", "%_a2", "%_a3", "%_a4", "SS", "%_a5" };
var argsSpts = Regex.Split(args1, "(M|d|H|hh|h|m|s|t)");
for (var a = 0; a < argsSpts.Length; a++)
{
switch (argsSpts[a])
{
case "M": argsSpts[a] = $"ltrim(to_char({left},'MM'),'0')"; break;
case "d": argsSpts[a] = $"case when substr(to_char({left},'DD'),1,1) = '0' then substr(to_char({left},'DD'),2,1) else to_char({left},'DD') end"; break;
case "H": argsSpts[a] = $"case when substr(to_char({left},'HH24'),1,1) = '0' then substr(to_char({left},'HH24'),2,1) else to_char({left},'HH24') end"; break;
case "hh": argsSpts[a] = $"case mod(cast(case when substr(to_char({left},'HH24'),1,1) = '0' then substr(to_char({left},'HH24'),2,1) else to_char({left},'HH24') end as number),12) when 0 then '12' when 1 then '01' when 2 then '02' when 3 then '03' when 4 then '04' when 5 then '05' when 6 then '06' when 7 then '07' when 8 then '08' when 9 then '09' when 10 then '10' when 11 then '11' end"; break;
case "h": argsSpts[a] = $"case mod(cast(case when substr(to_char({left},'HH24'),1,1) = '0' then substr(to_char({left},'HH24'),2,1) else to_char({left},'HH24') end as number),12) when 0 then '12' when 1 then '1' when 2 then '2' when 3 then '3' when 4 then '4' when 5 then '5' when 6 then '6' when 7 then '7' when 8 then '8' when 9 then '9' when 10 then '10' when 11 then '11' end"; break;
case "m": argsSpts[a] = $"case when substr(to_char({left},'MI'),1,1) = '0' then substr(to_char({left},'MI'),2,1) else to_char({left},'MI') end"; break;
case "s": argsSpts[a] = $"case when substr(to_char({left},'SS'),1,1) = '0' then substr(to_char({left},'SS'),2,1) else to_char({left},'SS') end"; break;
case "t": argsSpts[a] = $"rtrim(to_char({left},'AM'),'M')"; break;
default:
var argsSptsA = argsSpts[a];
if (argsSptsA.StartsWith("'")) argsSptsA = argsSptsA.Substring(1);
if (argsSptsA.EndsWith("'")) argsSptsA = argsSptsA.Remove(argsSptsA.Length - 1);
argsSpts[a] = argsFinds.Any(m => argsSptsA.Contains(m)) ? $"to_char({left},'{argsSptsA}')" : $"'{argsSptsA}'";
break;
//达梦 to_char(to_timestamp('2020-02-01 00:00:00.000000','YYYY-MM-DD HH24:MI:SS.FF6'),' ') 无效
}
}
if (argsSpts.Length > 0) args1 = $"({string.Join(" || ", argsSpts.Where(a => a != "''"))})";
return args1.Replace("%_a1", "MM").Replace("%_a2", "DD").Replace("%_a3", "HH24").Replace("%_a4", "MI").Replace("%_a5", "AM");
}
}
return null;
}
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 $"extract(day from ({getExp(exp.Arguments[0])}-({getExp(exp.Arguments[1])})))";
case "Equals": return $"({getExp(exp.Arguments[0])} = {getExp(exp.Arguments[1])})";
case "FromDays": return $"numtodsinterval(({getExp(exp.Arguments[0])})*{(long)60 * 60 * 24},'second')";
case "FromHours": return $"numtodsinterval(({getExp(exp.Arguments[0])})*{(long)60 * 60},'second')";
case "FromMilliseconds": return $"numtodsinterval(({getExp(exp.Arguments[0])})/1000,'second')";
case "FromMinutes": return $"numtodsinterval(({getExp(exp.Arguments[0])})*60,'second')";
case "FromSeconds": return $"numtodsinterval(({getExp(exp.Arguments[0])}),'second')";
case "FromTicks": return $"numtodsinterval(({getExp(exp.Arguments[0])})/10000000,'second')";
case "Parse": return $"cast({getExp(exp.Arguments[0])} as interval day(9) to second(6))";
case "ParseExact":
case "TryParse":
case "TryParseExact": return $"cast({getExp(exp.Arguments[0])} as interval day(9) to second(6))";
}
}
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 $"extract(day from ({left}-({args1})))";
case "ToString": return $"to_char({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 $"({getExp(exp.Arguments[0])} not in ('0','false'))";
case "ToByte": return $"cast({getExp(exp.Arguments[0])} as number)";
case "ToChar": return $"substr(to_char({getExp(exp.Arguments[0])}), 1, 1)";
case "ToDateTime": return $"to_timestamp({getExp(exp.Arguments[0])},'YYYY-MM-DD HH24:MI:SS.FF6')";
case "ToDecimal": return $"cast({getExp(exp.Arguments[0])} as number)";
case "ToDouble": return $"cast({getExp(exp.Arguments[0])} as number)";
case "ToInt16":
case "ToInt32":
case "ToInt64":
case "ToSByte": return $"cast({getExp(exp.Arguments[0])} as number)";
case "ToSingle": return $"cast({getExp(exp.Arguments[0])} as number)";
case "ToString": return $"to_char({getExp(exp.Arguments[0])})";
case "ToUInt16":
case "ToUInt32":
case "ToUInt64": return $"cast({getExp(exp.Arguments[0])} as number)";
}
}
return null;
}
}
}

View File

@ -0,0 +1,211 @@
using Dm;
using FreeSql;
using FreeSql.Internal.CommonProvider;
using FreeSql.Internal.Model;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
public static partial class FreeSqlDamengGlobalExtensions
{
/// <summary>
/// 特殊处理类似 string.Format 的使用方法,防止注入,以及 IS NULL 转换
/// </summary>
/// <param name="that"></param>
/// <param name="args"></param>
/// <returns></returns>
public static string FormatDameng(this string that, params object[] args) => _damengAdo.Addslashes(that, args);
static FreeSql.Dameng.DamengAdo _damengAdo = new FreeSql.Dameng.DamengAdo();
#region ExecuteDmBulkCopy
/// <summary>
/// 批量插入或更新(操作的字段数量超过 2000 时收益大)<para></para>
/// 实现原理:使用 DmBulkCopy 插入临时表,再执行 MERGE INTO t1 using (select * from #temp) ...
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="that"></param>
/// <returns></returns>
public static int ExecuteDmBulkCopy<T>(this IInsertOrUpdate<T> that) where T : class
{
var upsert = that as InsertOrUpdateProvider<T>;
if (upsert._source.Any() != true || upsert._tempPrimarys.Any() == false) return 0;
var state = ExecuteDmBulkCopyState(upsert);
return UpdateProvider.ExecuteBulkUpsert(upsert, state, insert => insert.ExecuteDmBulkCopy());
}
static NativeTuple<string, string, string, string, string[]> ExecuteDmBulkCopyState<T>(InsertOrUpdateProvider<T> upsert) where T : class
{
if (upsert._source.Any() != true) return null;
var _table = upsert._table;
var _commonUtils = upsert._commonUtils;
var updateTableName = upsert._tableRule?.Invoke(_table.DbName) ?? _table.DbName;
var tempTableName = $"TEMP_{Guid.NewGuid().ToString("N").ToUpper().Substring(0, 24)}";
if (upsert._orm.CodeFirst.IsSyncStructureToLower) tempTableName = tempTableName.ToLower();
if (upsert._orm.CodeFirst.IsSyncStructureToUpper) tempTableName = tempTableName.ToUpper();
if (upsert._connection == null && upsert._orm.Ado.TransactionCurrentThread != null)
upsert.WithTransaction(upsert._orm.Ado.TransactionCurrentThread);
var sb = new StringBuilder().Append("CREATE GLOBAL TEMPORARY TABLE ").Append(_commonUtils.QuoteSqlName(tempTableName)).Append(" ( ");
foreach (var col in _table.Columns.Values)
{
sb.Append(" \r\n ").Append(_commonUtils.QuoteSqlName(col.Attribute.Name)).Append(" ").Append(col.Attribute.DbType.Replace("NOT NULL", ""));
sb.Append(",");
}
var sql1 = sb.Remove(sb.Length - 1, 1).Append("\r\n) ON COMMIT PRESERVE ROWS").ToString();
sb.Clear();
try
{
upsert._sourceSql = $"select * from {tempTableName}";
var sql2 = upsert.ToSql();
var sql3 = $"BEGIN \r\n" +
$"execute immediate 'TRUNCATE TABLE {_commonUtils.QuoteSqlName(tempTableName)}';\r\n" +
$"execute immediate 'DROP TABLE {_commonUtils.QuoteSqlName(tempTableName)}';\r\n" +
$"END;";
return NativeTuple.Create(sql1, sql2, sql3, tempTableName, _table.Columns.Values.Select(a => a.Attribute.Name).ToArray());
}
finally
{
upsert._sourceSql = null;
}
}
/// <summary>
/// 批量更新(更新字段数量超过 2000 时收益大)<para></para>
/// 实现原理:使用 DmBulkCopy 插入临时表,再使用 MERGE INTO 联表更新
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="that"></param>
/// <returns></returns>
public static int ExecuteDmBulkCopy<T>(this IUpdate<T> that) where T : class
{
var update = that as UpdateProvider<T>;
if (update._source.Any() != true || update._tempPrimarys.Any() == false) return 0;
var state = ExecuteDmBulkCopyState(update);
return UpdateProvider.ExecuteBulkUpdate(update, state, insert => insert.ExecuteDmBulkCopy());
}
static NativeTuple<string, string, string, string, string[]> ExecuteDmBulkCopyState<T>(UpdateProvider<T> update) where T : class
{
if (update._source.Any() != true) return null;
var _table = update._table;
var _commonUtils = update._commonUtils;
var updateTableName = update._tableRule?.Invoke(_table.DbName) ?? _table.DbName;
var tempTableName = $"TEMP_{Guid.NewGuid().ToString("N").ToUpper().Substring(0, 24)}";
if (update._orm.CodeFirst.IsSyncStructureToLower) tempTableName = tempTableName.ToLower();
if (update._orm.CodeFirst.IsSyncStructureToUpper) tempTableName = tempTableName.ToUpper();
if (update._connection == null && update._orm.Ado.TransactionCurrentThread != null)
update.WithTransaction(update._orm.Ado.TransactionCurrentThread);
var sb = new StringBuilder().Append("CREATE GLOBAL TEMPORARY TABLE ").Append(_commonUtils.QuoteSqlName(tempTableName)).Append(" ( ");
var setColumns = new List<string>();
var pkColumns = new List<string>();
foreach (var col in _table.Columns.Values)
{
if (update._tempPrimarys.Any(a => a.CsName == col.CsName)) pkColumns.Add(col.Attribute.Name);
else if (col.Attribute.IsIdentity == false && col.Attribute.IsVersion == false && update._ignore.ContainsKey(col.Attribute.Name) == false) setColumns.Add(col.Attribute.Name);
else continue;
sb.Append(" \r\n ").Append(_commonUtils.QuoteSqlName(col.Attribute.Name)).Append(" ").Append(col.Attribute.DbType.Replace("NOT NULL", ""));
sb.Append(",");
}
var sql1 = sb.Remove(sb.Length - 1, 1).Append("\r\n) ON COMMIT PRESERVE ROWS").ToString();
sb.Clear().Append("MERGE INTO ").Append(_commonUtils.QuoteSqlName(updateTableName)).Append(" a ")
.Append(" \r\nUSING ").Append(_commonUtils.QuoteSqlName(tempTableName)).Append(" b ON (").Append(string.Join(" AND ", pkColumns.Select(col => $"a.{_commonUtils.QuoteSqlName(col)} = b.{_commonUtils.QuoteSqlName(col)}")))
.Append(") \r\nWHEN MATCHED THEN")
.Append(" \r\nUPDATE SET ").Append(string.Join(", \r\n ", setColumns.Select(col => $"{_commonUtils.QuoteSqlName(col)} = b.{_commonUtils.QuoteSqlName(col)}")));
var sql2 = sb.ToString();
sb.Clear();
var sql3 = $"BEGIN \r\n" +
$"execute immediate 'TRUNCATE TABLE {_commonUtils.QuoteSqlName(tempTableName)}';\r\n" +
$"execute immediate 'DROP TABLE {_commonUtils.QuoteSqlName(tempTableName)}';\r\n" +
$"END;";
return NativeTuple.Create(sql1, sql2, sql3, tempTableName, pkColumns.Concat(setColumns).ToArray());
}
/// <summary>
/// 达梦 CopyBulk 批量插入功能<para></para>
/// 使用 IgnoreColumns/InsertColumns 设置忽略/指定导入的列<para></para>
/// 使用 WithConnection/WithTransaction 传入连接/事务对象<para></para>
/// 提示:若本方法不能满足,请使用 IInsert&lt;T&gt;.ToDataTable 方法得到 DataTable 对象后,自行处理。
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="that"></param>
/// <param name="copyOptions"></param>
/// <param name="batchSize"></param>
/// <param name="bulkCopyTimeout"></param>
public static void ExecuteDmBulkCopy<T>(this IInsert<T> that, DmBulkCopyOptions copyOptions = DmBulkCopyOptions.Default, int? batchSize = null, int? bulkCopyTimeout = null) where T : class
{
var insert = that as FreeSql.Dameng.Curd.DamengInsert<T>;
if (insert == null) throw new Exception(CoreStrings.S_Features_Unique("ExecuteDmBulkCopy", "Dameng"));
var dt = that.ToDataTable();
if (dt.Rows.Count == 0) return;
Action<DmBulkCopy> writeToServer = bulkCopy =>
{
if (batchSize.HasValue) bulkCopy.BatchSize = batchSize.Value;
if (bulkCopyTimeout.HasValue) bulkCopy.BulkCopyTimeout = bulkCopyTimeout.Value;
bulkCopy.DestinationTableName = dt.TableName;
for (int i = 0; i < dt.Columns.Count; i++)
bulkCopy.ColumnMappings.Add(dt.Columns[i].ColumnName, dt.Columns[i].ColumnName);
bulkCopy.WriteToServer(dt);
};
try
{
if (insert.InternalConnection == null && insert.InternalTransaction == null)
{
if (insert._orm.Ado?.TransactionCurrentThread != null)
using (var bulkCopy = new DmBulkCopy(insert._orm.Ado.TransactionCurrentThread.Connection as DmConnection, copyOptions, insert._orm.Ado.TransactionCurrentThread as DmTransaction))
writeToServer(bulkCopy);
else
using (var conn = insert.InternalOrm.Ado.MasterPool.Get())
{
using (var bulkCopy = copyOptions == DmBulkCopyOptions.Default ?
new DmBulkCopy(conn.Value as DmConnection) :
new DmBulkCopy(conn.Value as DmConnection, copyOptions, insert.InternalTransaction as DmTransaction))
{
writeToServer(bulkCopy);
}
}
}
else if (insert.InternalTransaction != null)
{
using (var bulkCopy = new DmBulkCopy(insert.InternalTransaction.Connection as DmConnection, copyOptions, insert.InternalTransaction as DmTransaction))
{
writeToServer(bulkCopy);
}
}
else if (insert.InternalConnection != null)
{
var conn = insert.InternalConnection as DmConnection;
var isNotOpen = false;
if (conn.State != System.Data.ConnectionState.Open)
{
isNotOpen = true;
conn.Open();
}
try
{
using (var bulkCopy = copyOptions == DmBulkCopyOptions.Default ?
new DmBulkCopy(conn) :
new DmBulkCopy(conn, copyOptions, null))
{
writeToServer(bulkCopy);
}
}
finally
{
if (isNotOpen)
conn.Close();
}
}
else
{
throw new NotImplementedException($"ExecuteDmBulkCopy {CoreStrings.S_Not_Implemented_FeedBack}");
}
}
finally
{
dt.Clear();
}
}
#endregion
}

View File

@ -0,0 +1,38 @@
using FreeSql.Dameng.Curd;
using FreeSql.Internal.CommonProvider;
using System;
using System.Data.Common;
using System.Threading;
namespace FreeSql.Dameng
{
public class DamengProvider<TMark> : BaseDbProvider, IFreeSql<TMark>
{
public override ISelect<T1> CreateSelectProvider<T1>(object dywhere) => new DamengSelect<T1>(this, this.InternalCommonUtils, this.InternalCommonExpression, dywhere);
public override IInsert<T1> CreateInsertProvider<T1>() => new DamengInsert<T1>(this, this.InternalCommonUtils, this.InternalCommonExpression);
public override IUpdate<T1> CreateUpdateProvider<T1>(object dywhere) => new DamengUpdate<T1>(this, this.InternalCommonUtils, this.InternalCommonExpression, dywhere);
public override IDelete<T1> CreateDeleteProvider<T1>(object dywhere) => new DamengDelete<T1>(this, this.InternalCommonUtils, this.InternalCommonExpression, dywhere);
public override IInsertOrUpdate<T1> CreateInsertOrUpdateProvider<T1>() => new DamengInsertOrUpdate<T1>(this, this.InternalCommonUtils, this.InternalCommonExpression);
public DamengProvider(string masterConnectionString, string[] slaveConnectionString, Func<DbConnection> connectionFactory = null)
{
this.InternalCommonUtils = new DamengUtils(this);
this.InternalCommonExpression = new DamengExpression(this.InternalCommonUtils);
this.Ado = new DamengAdo(this.InternalCommonUtils, masterConnectionString, slaveConnectionString, connectionFactory);
this.Aop = new AopProvider();
this.DbFirst = new DamengDbFirst(this, this.InternalCommonUtils, this.InternalCommonExpression);
this.CodeFirst = new DamengCodeFirst(this, this.InternalCommonUtils, this.InternalCommonExpression);
}
~DamengProvider() => this.Dispose();
int _disposeCounter;
public override void Dispose()
{
if (Interlocked.Increment(ref _disposeCounter) != 1) return;
(this.Ado as AdoProvider)?.Dispose();
}
}
}

View File

@ -0,0 +1,134 @@
using Dm;
using FreeSql.Internal;
using FreeSql.Internal.Model;
using System;
using System.Collections.Generic;
using System.Data.Common;
using System.Globalization;
namespace FreeSql.Dameng
{
class DamengUtils : CommonUtils
{
public DamengUtils(IFreeSql orm) : base(orm)
{
}
public override DbParameter AppendParamter(List<DbParameter> _params, string parameterName, ColumnInfo col, Type type, object value)
{
if (string.IsNullOrEmpty(parameterName)) parameterName = $"p_{_params?.Count}";
var dbtype = (DmDbType?)_orm.CodeFirst.GetDbInfo(type)?.type;
switch (dbtype)
{
case DmDbType.Bit:
if (value == null) value = null;
else value = (bool)value == true ? 1 : 0;
dbtype = DmDbType.Int32;
break;
case DmDbType.Char:
case DmDbType.VarChar:
case DmDbType.Text:
if (value == null)
{
value = (string)null;
}
else
{
value = string.Concat(value);
}
break;
}
var ret = new DmParameter { ParameterName = QuoteParamterName(parameterName) };
if (dbtype != null) ret.DmSqlType = dbtype.Value;
ret.Value = value;
_params?.Add(ret);
return ret;
}
public override DbParameter[] GetDbParamtersByObject(string sql, object obj) =>
Utils.GetDbParamtersByObject<DmParameter>(sql, obj, null, (name, type, value) =>
{
var typeint = _orm.CodeFirst.GetDbInfo(type)?.type;
var dbtype = typeint != null ? (DmDbType?)typeint : null;
if (dbtype != null)
{
switch (dbtype)
{
case DmDbType.Bit:
if (value == null) value = null;
else value = (bool)value == true ? 1 : 0;
dbtype = DmDbType.Int32;
break;
case DmDbType.Char:
case DmDbType.VarChar:
case DmDbType.Text:
if (value == null)
{
value = (string)null;
}
else
{
value = string.Concat(value);
}
break;
}
}
var ret = new DmParameter { ParameterName = $":{name}", Value = value };
if (dbtype != null) ret.DmSqlType = dbtype.Value;
return ret;
});
public override string FormatSql(string sql, params object[] args) => sql?.FormatDameng(args);
public override string QuoteSqlNameAdapter(params string[] name)
{
if (name.Length == 1)
{
var nametrim = name[0].Trim();
if (nametrim.StartsWith("(") && nametrim.EndsWith(")"))
return nametrim; //原生SQL
if (nametrim.StartsWith("\"") && nametrim.EndsWith("\""))
return nametrim;
return $"\"{nametrim.Replace(".", "\".\"")}\"";
}
return $"\"{string.Join("\".\"", name)}\"";
}
public override string TrimQuoteSqlName(string name)
{
var nametrim = name.Trim();
if (nametrim.StartsWith("(") && nametrim.EndsWith(")"))
return nametrim; //原生SQL
return $"{nametrim.Trim('"').Replace("\".\"", ".").Replace(".\"", ".")}";
}
public override string[] SplitTableName(string name) => GetSplitTableNames(name, '"', '"', 2);
public override string QuoteParamterName(string name) => $":{name}";
public override string IsNull(string sql, object value) => $"nvl({sql}, {value})";
public override string StringConcat(string[] objs, Type[] types) => $"{string.Join(" || ", objs)}";
public override string Mod(string left, string right, Type leftType, Type rightType) => $"mod({left}, {right})";
public override string Div(string left, string right, Type leftType, Type rightType) => $"trunc({left} / {right})";
public override string Now => "systimestamp";
public override string NowUtc => "getutcdate";
public override string QuoteWriteParamterAdapter(Type type, string paramterName) => paramterName;
protected override string QuoteReadColumnAdapter(Type type, Type mapType, string columnName) => 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[]))
{
var valueBytes = value as byte[];
if (valueBytes != null)
{
if (valueBytes.Length < 2000) return $"hextoraw('{CommonUtils.BytesSqlRaw(valueBytes)}')";
var pam = AppendParamter(specialParams, $"p_{specialParams?.Count}{specialParamFlag}", col, type, value);
return pam.ParameterName;
}
}
return FormatSql("{0}", value, 1);
}
}
}

View File

@ -0,0 +1,63 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFrameworks>net6.0;netcoreapp3.1;netstandard2.0;net45;net40</TargetFrameworks>
<GeneratePackageOnBuild>true</GeneratePackageOnBuild>
<Authors>FreeSql;ncc;YeXiangQin</Authors>
<Description>FreeSql 数据库实现,基于 达梦数据库 Ado.net (DmProvider)</Description>
<PackageProjectUrl>https://github.com/2881099/FreeSql</PackageProjectUrl>
<RepositoryUrl>https://github.com/2881099/FreeSql</RepositoryUrl>
<RepositoryType>git</RepositoryType>
<PackageLicenseExpression>MIT</PackageLicenseExpression>
<PackageTags>FreeSql;ORM;DM8;Dameng;达梦</PackageTags>
<PackageId>$(AssemblyName)</PackageId>
<PackageIcon>logo.png</PackageIcon>
<Title>$(AssemblyName)</Title>
<IsPackable>true</IsPackable>
<GenerateAssemblyInfo>true</GenerateAssemblyInfo>
<Version>3.2.833</Version>
<PackageReadmeFile>readme.md</PackageReadmeFile>
</PropertyGroup>
<ItemGroup>
<None Include="../../readme.md" Pack="true" PackagePath="\" />
<None Include="../../logo.png" Pack="true" PackagePath="\" />
</ItemGroup>
<ItemGroup>
<None Include="lib\DmProvider\net6.0\DmProvider.dll" Pack="true" PackagePath="\lib\net6.0\" />
<None Include="lib\DmProvider\netstandard2.0\DmProvider.dll" Pack="true" PackagePath="\lib\netstandard2.0\" />
<None Include="lib\DmProvider\netcoreapp3.1\DmProvider.dll" Pack="true" PackagePath="\lib\netcoreapp3.1\" />
<None Include="lib\DmProvider\net45\DmProvider.dll" Pack="true" PackagePath="\lib\net45\" />
<None Include="lib\DmProvider\net40\DmProvider.dll" Pack="true" PackagePath="\lib\net40\" />
<None Include="lib/**/*.dll">
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</None>
</ItemGroup>
<ItemGroup>
<PackageReference Include="System.Text.Encoding.CodePages" Version="5.0.0" Condition="'$(TargetFramework)' == 'netcoreapp3.1'" />
<PackageReference Include="System.Text.Encoding.CodePages" Version="5.0.0" Condition="'$(TargetFramework)' == 'netstandard2.0'" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\..\FreeSql\FreeSql.csproj" />
</ItemGroup>
<ItemGroup>
<Reference Include="DmProvider">
<HintPath>lib\DmProvider\netstandard2.0\DmProvider.dll</HintPath>
<Private>false</Private>
</Reference>
</ItemGroup>
<PropertyGroup Condition="'$(TargetFramework)' == 'net6.0' or '$(TargetFramework)' == 'netcoreapp3.1' or '$(TargetFramework)' == 'netstandard2.0'">
<DefineConstants>ns20;netstandard20</DefineConstants>
</PropertyGroup>
<PropertyGroup Condition="'$(TargetFramework)' == 'net40'">
<DefineConstants>net40</DefineConstants>
</PropertyGroup>
</Project>

View File

@ -0,0 +1,24 @@
<?xml version="1.0" encoding="utf-8"?>
<package xmlns="http://schemas.microsoft.com/packaging/2012/06/nuspec.xsd">
<metadata>
<id>DmProvider</id>
<version>1.1.0.17739</version>
<authors>DM</authors>
<description>DM .NET PROVIDER</description>
<copyright>Copy right(C) DM</copyright>
<dependencies>
<group targetFramework=".NETFramework4.0" />
<group targetFramework=".NETFramework4.5" />
<group targetFramework=".NETCoreApp3.1">
<dependency id="System.Text.Encoding.CodePages" version="5.0.0" exclude="Build,Analyzers" />
</group>
<group targetFramework="net6.0" />
<group targetFramework=".NETStandard2.0">
<dependency id="System.Text.Encoding.CodePages" version="5.0.0" exclude="Build,Analyzers" />
</group>
</dependencies>
<frameworkAssemblies>
<frameworkAssembly assemblyName="System.Transactions.dll" targetFramework=".NETFramework4.0, .NETFramework4.5" />
</frameworkAssemblies>
</metadata>
</package>

Some files were not shown because too many files have changed in this diff Show More