mirror of
https://github.com/nsnail/FreeSql.git
synced 2025-06-19 12:28:15 +08:00
- 增加 所有国产数据库支持 CustomMySql、CustomPostgreSQL、CustomOracle、CustomSqlServer 自定义适配;
This commit is contained in:
@ -77,6 +77,7 @@ namespace FreeSql.Custom
|
||||
finally
|
||||
{
|
||||
FreeSqlCustomAdapterGlobalExtensions._dicCustomAdater.TryRemove(Ado.Identifier, out var tryada);
|
||||
FreeSqlCustomAdapterGlobalExtensions._dicDbProviderFactory.TryRemove(Ado.Identifier, out var trydbpf);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -88,4 +89,8 @@ public static class FreeSqlCustomAdapterGlobalExtensions
|
||||
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(..) 方法");
|
||||
}
|
||||
|
@ -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();", _commandTimeout), _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,88 @@
|
||||
using FreeSql.Internal;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Data.Common;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
|
||||
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 => _tempPrimarys.Contains(a) == false && a.Attribute.CanUpdate == true && _updateIgnore.ContainsKey(a.Attribute.Name) == false);
|
||||
sql = new CustomMySqlOnDuplicateKeyUpdate<T1>(insert)
|
||||
.UpdateColumns(cols.Select(a => a.Attribute.Name).ToArray())
|
||||
.ToSql();
|
||||
}
|
||||
else
|
||||
{
|
||||
if (_tempPrimarys.Any() == false) throw new Exception(CoreStrings.Entity_Must_Primary_Key("fsql.InsertOrUpdate + IfExistsDoNothing + MySql ", _table.CsName));
|
||||
sql = insert.ToSqlValuesOrSelectUnionAllExtension101(false, (rowd, idx, sb) =>
|
||||
sb.Append(" \r\n FROM dual WHERE NOT EXISTS(").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,168 @@
|
||||
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))
|
||||
{
|
||||
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,212 @@
|
||||
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, 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)) sb.Append(" ON 1 = 1");
|
||||
else
|
||||
{
|
||||
var onSql = tbsfrom[b].NavigateCondition ?? tbsfrom[b].On;
|
||||
sb.Append(" ON ").Append(onSql);
|
||||
if (string.IsNullOrEmpty(tbsfrom[b].Cascade) == false)
|
||||
{
|
||||
if (string.IsNullOrEmpty(onSql)) sb.Append(tbsfrom[b].Cascade);
|
||||
else sb.Append(" AND ").Append(tbsfrom[b].Cascade);
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!string.IsNullOrEmpty(tbsfrom[a].NavigateCondition)) sbnav.Append(" AND (").Append(tbsfrom[a].NavigateCondition).Append(")");
|
||||
if (!string.IsNullOrEmpty(tbsfrom[a].On)) sbnav.Append(" AND (").Append(tbsfrom[a].On).Append(")");
|
||||
if (a > 0 && !string.IsNullOrEmpty(tbsfrom[a].Cascade)) sbnav.Append(" AND ").Append(tbsfrom[a].Cascade);
|
||||
}
|
||||
if (a < tbsfrom.Length - 1) sb.Append(", ");
|
||||
}
|
||||
foreach (var tb in tbsjoin)
|
||||
{
|
||||
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(tb.On ?? tb.NavigateCondition);
|
||||
if (!string.IsNullOrEmpty(tb.Cascade)) sb.Append(" AND ").Append(tb.Cascade);
|
||||
if (!string.IsNullOrEmpty(tb.On) && !string.IsNullOrEmpty(tb.NavigateCondition)) sbnav.Append(" AND (").Append(tb.NavigateCondition).Append(")");
|
||||
}
|
||||
if (_join.Length > 0) sb.Append(_join);
|
||||
|
||||
sbnav.Append(_where);
|
||||
if (!string.IsNullOrEmpty(_tables[0].Cascade))
|
||||
sbnav.Append(" AND ").Append(_tables[0].Cascade);
|
||||
|
||||
if (sbnav.Length > 0)
|
||||
{
|
||||
sb.Append(" \r\nWHERE ").Append(sbnav.Remove(0, 5));
|
||||
}
|
||||
if (string.IsNullOrEmpty(_groupby) == false)
|
||||
{
|
||||
sb.Append(_groupby);
|
||||
if (string.IsNullOrEmpty(_having) == false)
|
||||
sb.Append(" \r\nHAVING ").Append(_having.Substring(5));
|
||||
}
|
||||
sb.Append(_orderby);
|
||||
if (_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,170 @@
|
||||
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);
|
||||
public override List<T1> ExecuteUpdated() => base.SplitExecuteUpdated(_batchRowsLimit > 0 ? _batchRowsLimit : 500, _batchParameterLimit > 0 ? _batchParameterLimit : 3000);
|
||||
|
||||
protected override List<T1> RawExecuteUpdated()
|
||||
{
|
||||
var ret = new List<T1>();
|
||||
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 _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.Update, sql, dbParms);
|
||||
_orm.Aop.CurdBeforeHandler?.Invoke(this, before);
|
||||
|
||||
Exception exception = null;
|
||||
try
|
||||
{
|
||||
var rettmp = _orm.Ado.Query<T1>(_table.TypeLazy ?? _table.Type, _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);
|
||||
public override Task<List<T1>> ExecuteUpdatedAsync(CancellationToken cancellationToken = default) => base.SplitExecuteUpdatedAsync(_batchRowsLimit > 0 ? _batchRowsLimit : 500, _batchParameterLimit > 0 ? _batchParameterLimit : 3000, cancellationToken);
|
||||
|
||||
async protected override Task<List<T1>> RawExecuteUpdatedAsync(CancellationToken cancellationToken = default)
|
||||
{
|
||||
var ret = new List<T1>();
|
||||
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 _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.Update, sql, dbParms);
|
||||
_orm.Aop.CurdBeforeHandler?.Invoke(this, before);
|
||||
|
||||
Exception exception = null;
|
||||
try
|
||||
{
|
||||
var rettmp = await _orm.Ado.QueryAsync<T1>(_table.TypeLazy ?? _table.Type, _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,68 @@
|
||||
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);
|
||||
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 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 || param is DateTime?)
|
||||
return 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);
|
||||
}
|
||||
}
|
408
Providers/FreeSql.Provider.Custom/MySql/CustomMySqlCodeFirst.cs
Normal file
408
Providers/FreeSql.Provider.Custom/MySql/CustomMySqlCodeFirst.cs
Normal file
@ -0,0 +1,408 @@
|
||||
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 TypeAndName[] 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 = _commonUtils.GetTableByEntity(obj.entityType);
|
||||
if (tb == null) throw new Exception(CoreStrings.S_Type_IsNot_Migrable(obj.entityType.FullName));
|
||||
if (tb.Columns.Any() == false) throw new Exception(CoreStrings.S_Type_IsNot_Migrable_0Attributes(obj.entityType.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.key_column_usage where table_schema={0} and table_name={1} and constraint_name = 'PRIMARY' 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',
|
||||
0 '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;
|
||||
return cmd.ExecuteScalar();
|
||||
}
|
||||
}
|
||||
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',
|
||||
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>();
|
||||
}
|
||||
}
|
||||
}
|
563
Providers/FreeSql.Provider.Custom/MySql/CustomMySqlExpression.cs
Normal file
563
Providers/FreeSql.Provider.Custom/MySql/CustomMySqlExpression.cs
Normal file
@ -0,0 +1,563 @@
|
||||
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) 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":
|
||||
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({args0Value})";
|
||||
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 QuoteSqlName(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)
|
||||
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,74 @@
|
||||
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 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 => _tempPrimarys.Contains(a) == false && a.Attribute.CanUpdate == true && _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 =>
|
||||
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 (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 => $"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,232 @@
|
||||
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, 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 ");
|
||||
sbunion.Append(field);
|
||||
if (string.IsNullOrEmpty(_orderby) && _skip > 0) sbunion.Append(", ROWNUM AS \"__rownum__\"");
|
||||
sbunion.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++)
|
||||
{
|
||||
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)) sbunion.Append(" ON 1 = 1");
|
||||
else
|
||||
{
|
||||
var onSql = tbsfrom[b].NavigateCondition ?? tbsfrom[b].On;
|
||||
sbunion.Append(" ON ").Append(onSql);
|
||||
if (string.IsNullOrEmpty(tbsfrom[b].Cascade) == false)
|
||||
{
|
||||
if (string.IsNullOrEmpty(onSql)) sbunion.Append(tbsfrom[b].Cascade);
|
||||
else sbunion.Append(" AND ").Append(tbsfrom[b].Cascade);
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!string.IsNullOrEmpty(tbsfrom[a].NavigateCondition)) sbnav.Append(" AND (").Append(tbsfrom[a].NavigateCondition).Append(")");
|
||||
if (!string.IsNullOrEmpty(tbsfrom[a].On)) sbnav.Append(" AND (").Append(tbsfrom[a].On).Append(")");
|
||||
if (a > 0 && !string.IsNullOrEmpty(tbsfrom[a].Cascade)) sbnav.Append(" AND ").Append(tbsfrom[a].Cascade);
|
||||
}
|
||||
if (a < tbsfrom.Length - 1) 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(tb.On ?? tb.NavigateCondition);
|
||||
if (!string.IsNullOrEmpty(tb.Cascade)) sbunion.Append(" AND ").Append(tb.Cascade);
|
||||
if (!string.IsNullOrEmpty(tb.On) && !string.IsNullOrEmpty(tb.NavigateCondition)) sbnav.Append(" AND (").Append(tb.NavigateCondition).Append(")");
|
||||
}
|
||||
if (_join.Length > 0) sbunion.Append(_join);
|
||||
|
||||
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);
|
||||
public override List<T1> ExecuteUpdated() => base.SplitExecuteUpdated(_batchRowsLimit > 0 ? _batchRowsLimit : 200, _batchParameterLimit > 0 ? _batchParameterLimit : 999);
|
||||
|
||||
protected override List<T1> RawExecuteUpdated() => throw new NotImplementedException($"FreeSql.Odbc.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);
|
||||
public override Task<List<T1>> ExecuteUpdatedAsync(CancellationToken cancellationToken = default) => base.SplitExecuteUpdatedAsync(_batchRowsLimit > 0 ? _batchRowsLimit : 200, _batchParameterLimit > 0 ? _batchParameterLimit : 999, cancellationToken);
|
||||
|
||||
protected override Task<List<T1>> RawExecuteUpdatedAsync(CancellationToken cancellationToken = default) => throw new NotImplementedException($"FreeSql.Odbc.Oracle {CoreStrings.S_Not_Implemented_Feature}");
|
||||
#endif
|
||||
}
|
||||
}
|
@ -0,0 +1,81 @@
|
||||
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);
|
||||
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 ((Enum)param).ToInt64();
|
||||
else if (decimal.TryParse(string.Concat(param), out var trydec))
|
||||
return param;
|
||||
else if (param is DateTime || param is DateTime?)
|
||||
return 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,503 @@
|
||||
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(16){(type.IsEnum ? " NOT NULL" : "")}", false, type.IsEnum ? false : true, enumType.CreateInstanceGetDefaultValue()) :
|
||||
CsToDb.New(DbType.Int64, "number", $"number(32){(type.IsEnum ? " NOT NULL" : "")}", false, type.IsEnum ? false : true, enumType.CreateInstanceGetDefaultValue());
|
||||
if (_dicCsToDb.ContainsKey(type.FullName) == false)
|
||||
{
|
||||
lock (_dicCsToDbLock)
|
||||
{
|
||||
if (_dicCsToDb.ContainsKey(type.FullName) == false)
|
||||
_dicCsToDb.Add(type.FullName, newItem);
|
||||
}
|
||||
}
|
||||
return new DbInfoResult((int)newItem.type, newItem.dbtype, newItem.dbtypeFull, newItem.isnullable, newItem.defaultValue);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
protected override string GetComparisonDDLStatements(params TypeAndName[] objects)
|
||||
{
|
||||
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 = _commonUtils.GetTableByEntity(obj.entityType);
|
||||
if (tb == null) throw new Exception(CoreStrings.S_Type_IsNot_Migrable(obj.entityType.FullName));
|
||||
if (tb.Columns.Any() == false) throw new Exception(CoreStrings.S_Type_IsNot_Migrable_0Attributes(obj.entityType.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.entityType.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 (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,569 @@
|
||||
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) 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":
|
||||
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({args0Value}, {left}) = 1";
|
||||
if (exp.Method.Name == "EndsWith") return $"instr({args0Value}, {left}) = length({args0Value})";
|
||||
return $"instr({args0Value}, {left}) > 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 QuoteSqlName(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 < 4000) 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,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,72 @@
|
||||
using FreeSql.Internal;
|
||||
using System.Collections.Generic;
|
||||
using System.Data.Common;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
|
||||
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 => _tempPrimarys.Contains(a) == false && a.Attribute.CanUpdate == true && _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 (string.IsNullOrEmpty(sql)) return null;
|
||||
if (insert._params?.Any() == true) dbParams.AddRange(insert._params);
|
||||
return sql;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,209 @@
|
||||
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", "Odbc/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");
|
||||
|
||||
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))
|
||||
{
|
||||
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,214 @@
|
||||
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, 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)) sb.Append(" ON 1 = 1");
|
||||
else
|
||||
{
|
||||
var onSql = tbsfrom[b].NavigateCondition ?? tbsfrom[b].On;
|
||||
sb.Append(" ON ").Append(onSql);
|
||||
if (string.IsNullOrEmpty(tbsfrom[b].Cascade) == false)
|
||||
{
|
||||
if (string.IsNullOrEmpty(onSql)) sb.Append(tbsfrom[b].Cascade);
|
||||
else sb.Append(" AND ").Append(tbsfrom[b].Cascade);
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!string.IsNullOrEmpty(tbsfrom[a].NavigateCondition)) sbnav.Append(" AND (").Append(tbsfrom[a].NavigateCondition).Append(")");
|
||||
if (!string.IsNullOrEmpty(tbsfrom[a].On)) sbnav.Append(" AND (").Append(tbsfrom[a].On).Append(")");
|
||||
if (a > 0 && !string.IsNullOrEmpty(tbsfrom[a].Cascade)) sbnav.Append(" AND ").Append(tbsfrom[a].Cascade);
|
||||
}
|
||||
if (a < tbsfrom.Length - 1) sb.Append(", ");
|
||||
}
|
||||
foreach (var tb in tbsjoin)
|
||||
{
|
||||
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(tb.On ?? tb.NavigateCondition);
|
||||
if (!string.IsNullOrEmpty(tb.Cascade)) sb.Append(" AND ").Append(tb.Cascade);
|
||||
if (!string.IsNullOrEmpty(tb.On) && !string.IsNullOrEmpty(tb.NavigateCondition)) sbnav.Append(" AND (").Append(tb.NavigateCondition).Append(")");
|
||||
}
|
||||
if (_join.Length > 0) sb.Append(_join);
|
||||
|
||||
sbnav.Append(_where);
|
||||
if (!string.IsNullOrEmpty(_tables[0].Cascade))
|
||||
sbnav.Append(" AND ").Append(_tables[0].Cascade);
|
||||
|
||||
if (sbnav.Length > 0)
|
||||
{
|
||||
sb.Append(" \r\nWHERE ").Append(sbnav.Remove(0, 5));
|
||||
}
|
||||
if (string.IsNullOrEmpty(_groupby) == false)
|
||||
{
|
||||
sb.Append(_groupby);
|
||||
if (string.IsNullOrEmpty(_having) == false)
|
||||
sb.Append(" \r\nHAVING ").Append(_having.Substring(5));
|
||||
}
|
||||
sb.Append(_orderby);
|
||||
if (_limit > 0)
|
||||
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,187 @@
|
||||
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);
|
||||
public override List<T1> ExecuteUpdated() => base.SplitExecuteUpdated(_batchRowsLimit > 0 ? _batchRowsLimit : 500, _batchParameterLimit > 0 ? _batchParameterLimit : 3000);
|
||||
|
||||
protected override List<T1> RawExecuteUpdated()
|
||||
{
|
||||
var ret = new List<T1>();
|
||||
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 _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.Update, sql, dbParms);
|
||||
_orm.Aop.CurdBeforeHandler?.Invoke(this, before);
|
||||
|
||||
Exception exception = null;
|
||||
try
|
||||
{
|
||||
var rettmp = _orm.Ado.Query<T1>(_table.TypeLazy ?? _table.Type, _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);
|
||||
public override Task<List<T1>> ExecuteUpdatedAsync(CancellationToken cancellationToken = default) => base.SplitExecuteUpdatedAsync(_batchRowsLimit > 0 ? _batchRowsLimit : 500, _batchParameterLimit > 0 ? _batchParameterLimit : 3000, cancellationToken);
|
||||
|
||||
async protected override Task<List<T1>> RawExecuteUpdatedAsync(CancellationToken cancellationToken = default)
|
||||
{
|
||||
var ret = new List<T1>();
|
||||
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 _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.Update, sql, dbParms);
|
||||
_orm.Aop.CurdBeforeHandler?.Invoke(this, before);
|
||||
|
||||
Exception exception = null;
|
||||
try
|
||||
{
|
||||
var rettmp = await _orm.Ado.QueryAsync<T1>(_table.TypeLazy ?? _table.Type, _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,70 @@
|
||||
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);
|
||||
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 ((Enum)param).ToInt64();
|
||||
else if (decimal.TryParse(string.Concat(param), out var trydec))
|
||||
return param;
|
||||
else if (param is DateTime || param is DateTime?)
|
||||
return 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,480 @@
|
||||
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 TypeAndName[] objects)
|
||||
{
|
||||
var sb = new StringBuilder();
|
||||
var seqcols = new List<NativeTuple<ColumnInfo, string[], bool>>(); //序列
|
||||
|
||||
var isPg96 = true;
|
||||
var isPg10 = (_orm.DbFirst as CustomPostgreSQLDbFirst).IsPg10;
|
||||
using (var conn = _orm.Ado.MasterPool.Get(TimeSpan.FromSeconds(5)))
|
||||
{
|
||||
isPg96 = CustomPostgreSQLDbFirst.PgVersionIs96(conn.Value.ServerVersion);
|
||||
}
|
||||
|
||||
foreach (var obj in objects)
|
||||
{
|
||||
if (sb.Length > 0) sb.Append("\r\n");
|
||||
var tb = _commonUtils.GetTableByEntity(obj.entityType);
|
||||
if (tb == null) throw new Exception(CoreStrings.S_Type_IsNot_Migrable(obj.entityType.FullName));
|
||||
if (tb.Columns.Any() == false) throw new Exception(CoreStrings.S_Type_IsNot_Migrable_0Attributes(obj.entityType.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 ").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]));
|
||||
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 ").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 ").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,554 @@
|
||||
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 = int.Parse(conn.Value.ServerVersion.Split('.')[0]);
|
||||
}
|
||||
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 "int2": ret = DbType.Int16; break;
|
||||
case "int4": ret = DbType.Int32; break;
|
||||
case "int8": ret = DbType.Int64; break;
|
||||
case "numeric": ret = DbType.Decimal; break;
|
||||
case "float4": ret = DbType.Single; break;
|
||||
case "float8": ret = DbType.Double; break;
|
||||
case "money": ret = DbType.Decimal; break;
|
||||
|
||||
case "bpchar": ret = DbType.AnsiString; break;
|
||||
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 = PgVersionIs96(conn.Value.ServerVersion);
|
||||
}
|
||||
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 bool PgVersionIs96(string serverVersion)
|
||||
{
|
||||
int[] version = serverVersion.Split('.').Select(a => int.TryParse(a, out var tryint) ? tryint : 0).ToArray();
|
||||
if (version?.Any() != true) return true;
|
||||
if (version[0] > 9) return true;
|
||||
if (version[0] == 9 && version.Length > 1 && version[1] >= 6) return true;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,658 @@
|
||||
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) 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(')')}]";
|
||||
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":
|
||||
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({args0Value}, {left}) = 1";
|
||||
if (exp.Method.Name == "EndsWith") return $"strpos({args0Value}, {left}) = char_length({args0Value})";
|
||||
return $"strpos({args0Value}, {left}) > 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 QuoteSqlName(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,78 @@
|
||||
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 sb = new StringBuilder();
|
||||
if (IdentityColumn != null) 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 => _tempPrimarys.Contains(a) == false && a.Attribute.CanUpdate == true && _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 =>
|
||||
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 (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 => $"t2.{_commonUtils.QuoteSqlName(a.Attribute.Name)}"))).Append(");");
|
||||
|
||||
if (IdentityColumn != null) 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,369 @@
|
||||
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.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, 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(" ");
|
||||
sb.Append(field);
|
||||
|
||||
if (_limit > 0 || _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 _orderby = string.Concat(" \r\nORDER BY ", _tables.First().Alias, ".", _commonUtils.QuoteSqlName(_tables.First().Table.Columns.First().Value.Attribute.Name));
|
||||
}
|
||||
else
|
||||
_orderby = _groupby.Replace("GROUP BY ", "ORDER BY ");
|
||||
}
|
||||
if (_skip > 0) // 注意这个判断,大于 0 才使用 ROW_NUMBER ,否则属于第一页直接使用 TOP
|
||||
sb.Append(", ROW_NUMBER() OVER(").Append(_orderby.Trim('\r', '\n', ' ')).Append(") AS __rownum__");
|
||||
}
|
||||
sb.Append(" \r\nFROM ");
|
||||
var tbsjoin = _tables.Where(a => a.Type != SelectTableInfoType.From).ToArray();
|
||||
var tbsfrom = _tables.Where(a => a.Type == SelectTableInfoType.From).ToArray();
|
||||
for (var a = 0; a < tbsfrom.Length; a++)
|
||||
{
|
||||
sb.Append(_commonUtils.QuoteSqlName(tbUnion[tbsfrom[a].Table.Type])).Append(" ").Append(_aliasRule?.Invoke(tbsfrom[a].Table.Type, tbsfrom[a].Alias) ?? tbsfrom[a].Alias);
|
||||
if (tbsjoin.Length > 0)
|
||||
{
|
||||
//如果存在 join 查询,则处理 from t1, t2 改为 from t1 inner join t2 on 1 = 1
|
||||
for (var b = 1; b < tbsfrom.Length; b++)
|
||||
{
|
||||
sb.Append(" \r\nLEFT JOIN ").Append(_commonUtils.QuoteSqlName(tbUnion[tbsfrom[b].Table.Type])).Append(" ").Append(_aliasRule?.Invoke(tbsfrom[b].Table.Type, tbsfrom[b].Alias) ?? tbsfrom[b].Alias);
|
||||
|
||||
if (string.IsNullOrEmpty(tbsfrom[b].NavigateCondition) && string.IsNullOrEmpty(tbsfrom[b].On) && string.IsNullOrEmpty(tbsfrom[b].Cascade)) sb.Append(" ON 1 = 1");
|
||||
else
|
||||
{
|
||||
var onSql = tbsfrom[b].NavigateCondition ?? tbsfrom[b].On;
|
||||
sb.Append(" ON ").Append(onSql);
|
||||
if (string.IsNullOrEmpty(tbsfrom[b].Cascade) == false)
|
||||
{
|
||||
if (string.IsNullOrEmpty(onSql)) sb.Append(tbsfrom[b].Cascade);
|
||||
else sb.Append(" AND ").Append(tbsfrom[b].Cascade);
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!string.IsNullOrEmpty(tbsfrom[a].NavigateCondition)) sbnav.Append(" AND (").Append(tbsfrom[a].NavigateCondition).Append(")");
|
||||
if (!string.IsNullOrEmpty(tbsfrom[a].On)) sbnav.Append(" AND (").Append(tbsfrom[a].On).Append(")");
|
||||
if (a > 0 && !string.IsNullOrEmpty(tbsfrom[a].Cascade)) sbnav.Append(" AND ").Append(tbsfrom[a].Cascade);
|
||||
}
|
||||
if (a < tbsfrom.Length - 1) sb.Append(", ");
|
||||
}
|
||||
foreach (var tb in tbsjoin)
|
||||
{
|
||||
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(tb.On ?? tb.NavigateCondition);
|
||||
if (!string.IsNullOrEmpty(tb.Cascade)) sb.Append(" AND ").Append(tb.Cascade);
|
||||
if (!string.IsNullOrEmpty(tb.On) && !string.IsNullOrEmpty(tb.NavigateCondition)) sbnav.Append(" AND (").Append(tb.NavigateCondition).Append(")");
|
||||
}
|
||||
if (_join.Length > 0) sb.Append(_join);
|
||||
|
||||
sbnav.Append(_where);
|
||||
if (!string.IsNullOrEmpty(_tables[0].Cascade))
|
||||
sbnav.Append(" AND ").Append(_tables[0].Cascade);
|
||||
|
||||
if (sbnav.Length > 0)
|
||||
{
|
||||
sb.Append(" \r\nWHERE ").Append(sbnav.Remove(0, 5));
|
||||
}
|
||||
if (string.IsNullOrEmpty(_groupby) == false)
|
||||
{
|
||||
sb.Append(_groupby);
|
||||
if (string.IsNullOrEmpty(_having) == false)
|
||||
sb.Append(" \r\nHAVING ").Append(_having.Substring(5));
|
||||
}
|
||||
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, 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++)
|
||||
{
|
||||
sb.Append(_commonUtils.QuoteSqlName(tbUnion[tbsfrom[a].Table.Type])).Append(" ").Append(_aliasRule?.Invoke(tbsfrom[a].Table.Type, tbsfrom[a].Alias) ?? tbsfrom[a].Alias);
|
||||
if (tbsjoin.Length > 0)
|
||||
{
|
||||
//如果存在 join 查询,则处理 from t1, t2 改为 from t1 inner join t2 on 1 = 1
|
||||
for (var b = 1; b < tbsfrom.Length; b++)
|
||||
{
|
||||
sb.Append(" \r\nLEFT JOIN ").Append(_commonUtils.QuoteSqlName(tbUnion[tbsfrom[b].Table.Type])).Append(" ").Append(_aliasRule?.Invoke(tbsfrom[b].Table.Type, tbsfrom[b].Alias) ?? tbsfrom[b].Alias);
|
||||
|
||||
if (string.IsNullOrEmpty(tbsfrom[b].NavigateCondition) && string.IsNullOrEmpty(tbsfrom[b].On) && string.IsNullOrEmpty(tbsfrom[b].Cascade)) sb.Append(" ON 1 = 1");
|
||||
else
|
||||
{
|
||||
var onSql = tbsfrom[b].NavigateCondition ?? tbsfrom[b].On;
|
||||
sb.Append(" ON ").Append(onSql);
|
||||
if (string.IsNullOrEmpty(tbsfrom[b].Cascade) == false)
|
||||
{
|
||||
if (string.IsNullOrEmpty(onSql)) sb.Append(tbsfrom[b].Cascade);
|
||||
else sb.Append(" AND ").Append(tbsfrom[b].Cascade);
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!string.IsNullOrEmpty(tbsfrom[a].NavigateCondition)) sbnav.Append(" AND (").Append(tbsfrom[a].NavigateCondition).Append(")");
|
||||
if (!string.IsNullOrEmpty(tbsfrom[a].On)) sbnav.Append(" AND (").Append(tbsfrom[a].On).Append(")");
|
||||
if (a > 0 && !string.IsNullOrEmpty(tbsfrom[a].Cascade)) sbnav.Append(" AND ").Append(tbsfrom[a].Cascade);
|
||||
}
|
||||
if (a < tbsfrom.Length - 1) sb.Append(", ");
|
||||
}
|
||||
foreach (var tb in tbsjoin)
|
||||
{
|
||||
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(tb.On ?? tb.NavigateCondition);
|
||||
if (!string.IsNullOrEmpty(tb.Cascade)) sb.Append(" AND ").Append(tb.Cascade);
|
||||
if (!string.IsNullOrEmpty(tb.On) && !string.IsNullOrEmpty(tb.NavigateCondition)) sbnav.Append(" AND (").Append(tb.NavigateCondition).Append(")");
|
||||
}
|
||||
if (_join.Length > 0) sb.Append(_join);
|
||||
|
||||
sbnav.Append(_where);
|
||||
if (!string.IsNullOrEmpty(_tables[0].Cascade))
|
||||
sbnav.Append(" AND ").Append(_tables[0].Cascade);
|
||||
|
||||
if (sbnav.Length > 0)
|
||||
{
|
||||
sb.Append(" \r\nWHERE ").Append(sbnav.Remove(0, 5));
|
||||
}
|
||||
if (string.IsNullOrEmpty(_groupby) == false)
|
||||
{
|
||||
sb.Append(_groupby);
|
||||
if (string.IsNullOrEmpty(_having) == false)
|
||||
sb.Append(" \r\nHAVING ").Append(_having.Substring(5));
|
||||
}
|
||||
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 _orderby = string.Concat(" \r\nORDER BY ", _tables.First().Alias, ".", _commonUtils.QuoteSqlName(_tables.First().Table.Columns.First().Value.Attribute.Name));
|
||||
}
|
||||
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
|
||||
|
||||
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,173 @@
|
||||
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);
|
||||
public override List<T1> ExecuteUpdated() => base.SplitExecuteUpdated(_batchRowsLimit > 0 ? _batchRowsLimit : 500, _batchParameterLimit > 0 ? _batchParameterLimit : 2100);
|
||||
|
||||
protected override List<T1> RawExecuteUpdated()
|
||||
{
|
||||
var ret = new List<T1>();
|
||||
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 _table.Columns.Values)
|
||||
{
|
||||
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 rettmp = _orm.Ado.Query<T1>(_table.TypeLazy ?? _table.Type, _connection, _transaction, CommandType.Text, sql, _commandTimeout, dbParms);
|
||||
ValidateVersionAndThrow(rettmp.Count, sql, dbParms);
|
||||
ret.AddRange(rettmp);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
exception = ex;
|
||||
throw ex;
|
||||
}
|
||||
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)");
|
||||
++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)");
|
||||
++pkidx;
|
||||
}
|
||||
}
|
||||
|
||||
#if net40
|
||||
#else
|
||||
public override Task<int> ExecuteAffrowsAsync(CancellationToken cancellationToken = default) => base.SplitExecuteAffrowsAsync(_batchRowsLimit > 0 ? _batchRowsLimit : 500, _batchParameterLimit > 0 ? _batchParameterLimit : 2100, cancellationToken);
|
||||
public override Task<List<T1>> ExecuteUpdatedAsync(CancellationToken cancellationToken = default) => base.SplitExecuteUpdatedAsync(_batchRowsLimit > 0 ? _batchRowsLimit : 500, _batchParameterLimit > 0 ? _batchParameterLimit : 2100, cancellationToken);
|
||||
|
||||
async protected override Task<List<T1>> RawExecuteUpdatedAsync(CancellationToken cancellationToken = default)
|
||||
{
|
||||
var ret = new List<T1>();
|
||||
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 _table.Columns.Values)
|
||||
{
|
||||
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 rettmp = await _orm.Ado.QueryAsync<T1>(_table.TypeLazy ?? _table.Type, _connection, _transaction, CommandType.Text, sql, _commandTimeout, dbParms, cancellationToken);
|
||||
ValidateVersionAndThrow(rettmp.Count, sql, dbParms);
|
||||
ret.AddRange(rettmp);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
exception = ex;
|
||||
throw ex;
|
||||
}
|
||||
finally
|
||||
{
|
||||
var after = new Aop.CurdAfterEventArgs(before, exception, ret);
|
||||
_orm.Aop.CurdAfterHandler?.Invoke(this, after);
|
||||
}
|
||||
});
|
||||
sbret?.Clear();
|
||||
return ret;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
@ -0,0 +1,83 @@
|
||||
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);
|
||||
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) && 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 ((Enum)param).ToInt64();
|
||||
else if (decimal.TryParse(string.Concat(param), out var trydec))
|
||||
return param;
|
||||
else if (param is DateTime || param is DateTime?)
|
||||
{
|
||||
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,499 @@
|
||||
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 TypeAndName[] 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 = _commonUtils.GetTableByEntity(obj.entityType);
|
||||
if (tb == null) throw new Exception(CoreStrings.S_Type_IsNot_Migrable(obj.entityType.FullName));
|
||||
if (tb.Columns.Any() == false) throw new Exception(CoreStrings.S_Type_IsNot_Migrable_0Attributes(obj.entityType.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;
|
||||
return cmd.ExecuteScalar();
|
||||
}
|
||||
}
|
||||
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,558 @@
|
||||
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":
|
||||
var gentype2 = callExp.Object.Type.NullableTypeOrThis();
|
||||
if (callExp.Object != 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":
|
||||
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({args0Value})";
|
||||
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 QuoteSqlName(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));
|
||||
}
|
||||
}
|
||||
}
|
@ -1,8 +1,39 @@
|
||||
FreeSql.Provider.Custom 实现自定义适配器,访问所有数据库。
|
||||
# 国产数据库
|
||||
|
||||
# 通用实现
|
||||
| 数据库名称 | 提供者 | 系列风格 |
|
||||
| --- | --- | --- |
|
||||
| 达梦 | FreeSql.Provider.Dameng | Oracle |
|
||||
| 神州通用 | FreeSql.Provider.ShenTong | PostgreSQL |
|
||||
| 人大金仓 | FreeSql.Provider.KingbaseES | PostgreSQL |
|
||||
| 南大通用 | FreeSql.Provider.GBase | Informix |
|
||||
| 翰高 | FreeSql.Provider.Custom、FreeSql.Provider.Odbc | PostgreSQL |
|
||||
|
||||
通用实现为了让用户自己适配更多的数据库,比如连接 mssql 2000、db2 等数据库,牺牲了一些功能:
|
||||
由于太多,在此不一一列举,它们大多数有共同特点:语法兼容 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 一般都会提供这两个现实类
|
||||
|
||||
# 自定义适配
|
||||
|
||||
为了让用户自己适配更多的数据库,比如连接 mssql 2000、db2 等数据库,牺牲了一些功能:
|
||||
|
||||
- 不支持 CodeFirst 自动迁移
|
||||
- 不支持 DbFirst 接口方法的实现
|
||||
@ -20,8 +51,8 @@ class Mssql2000Adapter : FreeSql.Custom.CustomAdapter
|
||||
//可以重写更多的设置
|
||||
}
|
||||
|
||||
static IFreeSql fsql = new FreeSql.FreeSqlBuilder()
|
||||
.UseConnectionString(FreeSql.DataType.Custom, () => new SqlConnection(@"Data Source=..."))
|
||||
static IFreeSql fsql = new FreeSqlBuilder()
|
||||
.UseConnectionString(DataType.Custom, () => new SqlConnection(@"Data Source=..."))
|
||||
.Build(); //be sure to define as singleton mode
|
||||
|
||||
fsql.SetCustomAdapter(new Mssql2000Adapter());
|
||||
|
@ -7,7 +7,7 @@
|
||||
/// <param name="that"></param>
|
||||
/// <param name="args"></param>
|
||||
/// <returns></returns>
|
||||
public static string FormatOdbcOracle(this string that, params object[] args) => _odbcOracleAdo.Addslashes(that, args);
|
||||
internal static string FormatOdbcOracle(this string that, params object[] args) => _odbcOracleAdo.Addslashes(that, args);
|
||||
static FreeSql.Odbc.Oracle.OdbcOracleAdo _odbcOracleAdo = new FreeSql.Odbc.Oracle.OdbcOracleAdo();
|
||||
|
||||
/// <summary>
|
||||
@ -16,7 +16,7 @@
|
||||
/// <param name="that"></param>
|
||||
/// <param name="args"></param>
|
||||
/// <returns></returns>
|
||||
public static string FormatOdbcSqlServer(this string that, params object[] args) => _odbcSqlServerAdo.Addslashes(that, args);
|
||||
internal static string FormatOdbcSqlServer(this string that, params object[] args) => _odbcSqlServerAdo.Addslashes(that, args);
|
||||
static FreeSql.Odbc.SqlServer.OdbcSqlServerAdo _odbcSqlServerAdo = new FreeSql.Odbc.SqlServer.OdbcSqlServerAdo();
|
||||
|
||||
/// <summary>
|
||||
@ -25,7 +25,7 @@
|
||||
/// <param name="that"></param>
|
||||
/// <param name="args"></param>
|
||||
/// <returns></returns>
|
||||
public static string FormatOdbcMySql(this string that, params object[] args) => _odbcMySqlAdo.Addslashes(that, args);
|
||||
internal static string FormatOdbcMySql(this string that, params object[] args) => _odbcMySqlAdo.Addslashes(that, args);
|
||||
static FreeSql.Odbc.MySql.OdbcMySqlAdo _odbcMySqlAdo = new FreeSql.Odbc.MySql.OdbcMySqlAdo();
|
||||
|
||||
/// <summary>
|
||||
@ -34,7 +34,7 @@
|
||||
/// <param name="that"></param>
|
||||
/// <param name="args"></param>
|
||||
/// <returns></returns>
|
||||
public static string FormatOdbcPostgreSQL(this string that, params object[] args) => _odbcPostgreSQLAdo.Addslashes(that, args);
|
||||
internal static string FormatOdbcPostgreSQL(this string that, params object[] args) => _odbcPostgreSQLAdo.Addslashes(that, args);
|
||||
static FreeSql.Odbc.PostgreSQL.OdbcPostgreSQLAdo _odbcPostgreSQLAdo = new FreeSql.Odbc.PostgreSQL.OdbcPostgreSQLAdo();
|
||||
|
||||
/// <summary>
|
||||
@ -43,7 +43,7 @@
|
||||
/// <param name="that"></param>
|
||||
/// <param name="args"></param>
|
||||
/// <returns></returns>
|
||||
public static string FormatOdbc(this string that, params object[] args) => _odbcAdo.Addslashes(that, args);
|
||||
internal static string FormatOdbc(this string that, params object[] args) => _odbcAdo.Addslashes(that, args);
|
||||
static FreeSql.Odbc.Default.OdbcAdo _odbcAdo = new FreeSql.Odbc.Default.OdbcAdo();
|
||||
|
||||
/// <summary>
|
||||
@ -52,7 +52,7 @@
|
||||
/// <param name="that"></param>
|
||||
/// <param name="args"></param>
|
||||
/// <returns></returns>
|
||||
public static string FormatOdbcDameng(this string that, params object[] args) => _odbcDamengAdo.Addslashes(that, args);
|
||||
internal static string FormatOdbcDameng(this string that, params object[] args) => _odbcDamengAdo.Addslashes(that, args);
|
||||
static FreeSql.Odbc.Dameng.OdbcDamengAdo _odbcDamengAdo = new FreeSql.Odbc.Dameng.OdbcDamengAdo();
|
||||
|
||||
/// <summary>
|
||||
@ -61,6 +61,6 @@
|
||||
/// <param name="that"></param>
|
||||
/// <param name="args"></param>
|
||||
/// <returns></returns>
|
||||
public static string FormatOdbcKingbaseES(this string that, params object[] args) => _odbcKingbaseESAdo.Addslashes(that, args);
|
||||
internal static string FormatOdbcKingbaseES(this string that, params object[] args) => _odbcKingbaseESAdo.Addslashes(that, args);
|
||||
static FreeSql.Odbc.KingbaseES.OdbcKingbaseESAdo _odbcKingbaseESAdo = new FreeSql.Odbc.KingbaseES.OdbcKingbaseESAdo();
|
||||
}
|
||||
|
@ -1,12 +1,14 @@
|
||||
FreeSql.Provider.Odbc 实现 ODBC 访问数据库,ODBC 属于比较原始的技术,更新慢,各大数据库厂支持得标准不一,不到万不得已最好别用 odbc,坑比较多。
|
||||
|
||||
FreeSql.Provider.Odbc 做了四种数据库的专用实现:SqlServer、PostgreSQL、Oracle、MySql、达梦、人大金仓,和一种通用实现。
|
||||
FreeSql.Provider.Odbc 做了多种数据库的专用实现:SqlServer、PostgreSQL、Oracle、MySql、达梦、人大金仓,和一种通用实现。
|
||||
|
||||
专用实现比较有针对性,和原来的 FreeSql.Provider.SqlServer ado.net 相比,只支持较少的基础类型,其他功能几乎都有,包括 CodeFirst 自动迁移。
|
||||
和原来的 FreeSql.Provider.SqlServer 等 ado.net 相比,只支持较少的基础类型,其他功能几乎都有,包括 CodeFirst 自动迁移。
|
||||
|
||||
# 通用实现
|
||||
国产数据库大多数都兼容 SqlServer、PostgreSQL、Oracle、MySql 这四种数据库,所以它们也可以用来访问国产数据库。
|
||||
|
||||
通用实现为了让用户自己适配更多的数据库,比如连接 mssql 2000、db2 等数据库,牺牲了一些功能:
|
||||
# 自定义适配
|
||||
|
||||
为了让用户自己适配更多的数据库,比如连接 mssql 2000、db2 等数据库,牺牲了一些功能:
|
||||
|
||||
- 不支持 CodeFirst 自动迁移
|
||||
- 不支持 DbFirst 接口方法的实现
|
||||
|
Reference in New Issue
Block a user