mirror of
https://github.com/nsnail/FreeSql.git
synced 2026-02-04 02:39:59 +08:00
initial commit
This commit is contained in:
@@ -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; }
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
@@ -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
|
||||
}
|
||||
}
|
||||
681
Providers/FreeSql.Provider.ClickHouse/ClickHouseCodeFirst.cs
Normal file
681
Providers/FreeSql.Provider.ClickHouse/ClickHouseCodeFirst.cs
Normal 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; }
|
||||
}
|
||||
}
|
||||
473
Providers/FreeSql.Provider.ClickHouse/ClickHouseDbFirst.cs
Normal file
473
Providers/FreeSql.Provider.ClickHouse/ClickHouseDbFirst.cs
Normal 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>();
|
||||
}
|
||||
}
|
||||
}
|
||||
621
Providers/FreeSql.Provider.ClickHouse/ClickHouseExpression.cs
Normal file
621
Providers/FreeSql.Provider.ClickHouse/ClickHouseExpression.cs
Normal 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;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
42
Providers/FreeSql.Provider.ClickHouse/ClickHouseProvider.cs
Normal file
42
Providers/FreeSql.Provider.ClickHouse/ClickHouseProvider.cs
Normal 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();
|
||||
}
|
||||
}
|
||||
}
|
||||
179
Providers/FreeSql.Provider.ClickHouse/ClickHouseUtils.cs
Normal file
179
Providers/FreeSql.Provider.ClickHouse/ClickHouseUtils.cs
Normal 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);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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
|
||||
}
|
||||
}
|
||||
448
Providers/FreeSql.Provider.ClickHouse/Curd/ClickHouseInsert.cs
Normal file
448
Providers/FreeSql.Provider.ClickHouse/Curd/ClickHouseInsert.cs
Normal 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
|
||||
}
|
||||
}
|
||||
227
Providers/FreeSql.Provider.ClickHouse/Curd/ClickHouseSelect.cs
Normal file
227
Providers/FreeSql.Provider.ClickHouse/Curd/ClickHouseSelect.cs
Normal 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);
|
||||
}
|
||||
}
|
||||
322
Providers/FreeSql.Provider.ClickHouse/Curd/ClickHouseUpdate.cs
Normal file
322
Providers/FreeSql.Provider.ClickHouse/Curd/ClickHouseUpdate.cs
Normal 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
|
||||
}
|
||||
}
|
||||
@@ -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>
|
||||
|
||||
26
Providers/FreeSql.Provider.Custom/Curd/CustomDelete.cs
Normal file
26
Providers/FreeSql.Provider.Custom/Curd/CustomDelete.cs
Normal 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
|
||||
}
|
||||
}
|
||||
113
Providers/FreeSql.Provider.Custom/Curd/CustomInsert.cs
Normal file
113
Providers/FreeSql.Provider.Custom/Curd/CustomInsert.cs
Normal 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
|
||||
}
|
||||
}
|
||||
225
Providers/FreeSql.Provider.Custom/Curd/CustomSelect.cs
Normal file
225
Providers/FreeSql.Provider.Custom/Curd/CustomSelect.cs
Normal 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);
|
||||
}
|
||||
}
|
||||
71
Providers/FreeSql.Provider.Custom/Curd/CustomUpdate.cs
Normal file
71
Providers/FreeSql.Provider.Custom/Curd/CustomUpdate.cs
Normal 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
|
||||
}
|
||||
}
|
||||
173
Providers/FreeSql.Provider.Custom/CustomAdapter.cs
Normal file
173
Providers/FreeSql.Provider.Custom/CustomAdapter.cs
Normal 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})";
|
||||
}
|
||||
}
|
||||
85
Providers/FreeSql.Provider.Custom/CustomAdo/CustomAdo.cs
Normal file
85
Providers/FreeSql.Provider.Custom/CustomAdo/CustomAdo.cs
Normal 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);
|
||||
}
|
||||
}
|
||||
95
Providers/FreeSql.Provider.Custom/CustomCodeFirst.cs
Normal file
95
Providers/FreeSql.Provider.Custom/CustomCodeFirst.cs
Normal 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}");
|
||||
}
|
||||
}
|
||||
477
Providers/FreeSql.Provider.Custom/CustomExpression.cs
Normal file
477
Providers/FreeSql.Provider.Custom/CustomExpression.cs
Normal 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;
|
||||
}
|
||||
}
|
||||
}
|
||||
96
Providers/FreeSql.Provider.Custom/CustomProvider.cs
Normal file
96
Providers/FreeSql.Provider.Custom/CustomProvider.cs
Normal 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(..) 方法");
|
||||
}
|
||||
85
Providers/FreeSql.Provider.Custom/CustomUtils.cs
Normal file
85
Providers/FreeSql.Provider.Custom/CustomUtils.cs
Normal 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);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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>
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
@@ -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
|
||||
}
|
||||
}
|
||||
@@ -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
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
@@ -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
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
423
Providers/FreeSql.Provider.Custom/MySql/CustomMySqlCodeFirst.cs
Normal file
423
Providers/FreeSql.Provider.Custom/MySql/CustomMySqlCodeFirst.cs
Normal 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;
|
||||
}
|
||||
}
|
||||
}
|
||||
457
Providers/FreeSql.Provider.Custom/MySql/CustomMySqlDbFirst.cs
Normal file
457
Providers/FreeSql.Provider.Custom/MySql/CustomMySqlDbFirst.cs
Normal 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>();
|
||||
}
|
||||
}
|
||||
}
|
||||
578
Providers/FreeSql.Provider.Custom/MySql/CustomMySqlExpression.cs
Normal file
578
Providers/FreeSql.Provider.Custom/MySql/CustomMySqlExpression.cs
Normal 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;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
113
Providers/FreeSql.Provider.Custom/MySql/CustomMySqlUtils.cs
Normal file
113
Providers/FreeSql.Provider.Custom/MySql/CustomMySqlUtils.cs
Normal 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);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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
|
||||
}
|
||||
}
|
||||
@@ -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
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
@@ -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
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
@@ -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;");
|
||||
}
|
||||
}
|
||||
}
|
||||
584
Providers/FreeSql.Provider.Custom/Oracle/CustomOracleDbFirst.cs
Normal file
584
Providers/FreeSql.Provider.Custom/Oracle/CustomOracleDbFirst.cs
Normal 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>();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
133
Providers/FreeSql.Provider.Custom/Oracle/CustomOracleUtils.cs
Normal file
133
Providers/FreeSql.Provider.Custom/Oracle/CustomOracleUtils.cs
Normal 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);
|
||||
}
|
||||
}
|
||||
}
|
||||
173
Providers/FreeSql.Provider.Custom/OracleAdapter.cs
Normal file
173
Providers/FreeSql.Provider.Custom/OracleAdapter.cs
Normal 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})";
|
||||
}
|
||||
}
|
||||
@@ -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
|
||||
}
|
||||
}
|
||||
@@ -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
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
@@ -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
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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]);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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
|
||||
}
|
||||
}
|
||||
@@ -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
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
@@ -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
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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>();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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));
|
||||
}
|
||||
}
|
||||
}
|
||||
BIN
Providers/FreeSql.Provider.Custom/key.snk
Normal file
BIN
Providers/FreeSql.Provider.Custom/key.snk
Normal file
Binary file not shown.
63
Providers/FreeSql.Provider.Custom/readme.md
Normal file
63
Providers/FreeSql.Provider.Custom/readme.md
Normal 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 方法生效。
|
||||
26
Providers/FreeSql.Provider.Dameng/Curd/DamengDelete.cs
Normal file
26
Providers/FreeSql.Provider.Dameng/Curd/DamengDelete.cs
Normal 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
|
||||
}
|
||||
}
|
||||
228
Providers/FreeSql.Provider.Dameng/Curd/DamengInsert.cs
Normal file
228
Providers/FreeSql.Provider.Dameng/Curd/DamengInsert.cs
Normal 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
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
243
Providers/FreeSql.Provider.Dameng/Curd/DamengSelect.cs
Normal file
243
Providers/FreeSql.Provider.Dameng/Curd/DamengSelect.cs
Normal 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);
|
||||
}
|
||||
}
|
||||
71
Providers/FreeSql.Provider.Dameng/Curd/DamengUpdate.cs
Normal file
71
Providers/FreeSql.Provider.Dameng/Curd/DamengUpdate.cs
Normal 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
|
||||
}
|
||||
}
|
||||
90
Providers/FreeSql.Provider.Dameng/DamengAdo/DamengAdo.cs
Normal file
90
Providers/FreeSql.Provider.Dameng/DamengAdo/DamengAdo.cs
Normal 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);
|
||||
}
|
||||
}
|
||||
@@ -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
|
||||
}
|
||||
}
|
||||
490
Providers/FreeSql.Provider.Dameng/DamengCodeFirst.cs
Normal file
490
Providers/FreeSql.Provider.Dameng/DamengCodeFirst.cs
Normal 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;
|
||||
}
|
||||
}
|
||||
}
|
||||
616
Providers/FreeSql.Provider.Dameng/DamengDbFirst.cs
Normal file
616
Providers/FreeSql.Provider.Dameng/DamengDbFirst.cs
Normal 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>();
|
||||
}
|
||||
}
|
||||
}
|
||||
585
Providers/FreeSql.Provider.Dameng/DamengExpression.cs
Normal file
585
Providers/FreeSql.Provider.Dameng/DamengExpression.cs
Normal 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;
|
||||
}
|
||||
}
|
||||
}
|
||||
211
Providers/FreeSql.Provider.Dameng/DamengExtensions.cs
Normal file
211
Providers/FreeSql.Provider.Dameng/DamengExtensions.cs
Normal 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<T>.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
|
||||
}
|
||||
38
Providers/FreeSql.Provider.Dameng/DamengProvider.cs
Normal file
38
Providers/FreeSql.Provider.Dameng/DamengProvider.cs
Normal 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();
|
||||
}
|
||||
}
|
||||
}
|
||||
134
Providers/FreeSql.Provider.Dameng/DamengUtils.cs
Normal file
134
Providers/FreeSql.Provider.Dameng/DamengUtils.cs
Normal 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);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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>
|
||||
|
||||
@@ -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>
|
||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user