From 5eb451fc762bc79e5891df6af4454602189aa5fd Mon Sep 17 00:00:00 2001 From: 28810 <28810@YEXIANGQIN> Date: Fri, 4 Jan 2019 19:20:37 +0800 Subject: [PATCH] =?UTF-8?q?pgsql=20DbFirst=20=E5=AE=8C=E6=88=90=E6=9C=AA?= =?UTF-8?q?=E6=B5=8B=E8=AF=95=EF=BC=9Boracle=20=E9=80=82=E9=85=8D=E8=BF=9B?= =?UTF-8?q?=E8=A1=8C=E4=B8=AD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../PostgreSQL/PostgreSQLDbFirstTest.cs | 21 + FreeSql/Extensions/FreeSqlGlobalExtensions.cs | 54 ++ ...tensions.cs => FreeSqlStringExtensions.cs} | 10 +- FreeSql/Extensions/NpgsqlTypesExtensions.cs | 39 - FreeSql/FreeSql.csproj | 1 + FreeSql/FreeSqlBuilder.cs | 3 +- .../Internal/CommonProvider/InsertProvider.cs | 2 +- .../MySql/MySqlAdo/MygisTypesExtensions.cs | 43 -- FreeSql/MySql/MySqlCodeFirst.cs | 19 +- FreeSql/MySql/MySqlDbFirst.cs | 18 +- FreeSql/MySql/MySqlUtils.cs | 4 +- FreeSql/Oracle/Curd/OracleDelete.cs | 45 ++ FreeSql/Oracle/Curd/OracleInsert.cs | 105 +++ FreeSql/Oracle/Curd/OracleSelect.cs | 126 +++ FreeSql/Oracle/Curd/OracleUpdate.cs | 78 ++ FreeSql/Oracle/OracleAdo/OracleAdo.cs | 65 ++ .../Oracle/OracleAdo/OracleConnectionPool.cs | 153 ++++ FreeSql/Oracle/OracleCodeFirst.cs | 297 +++++++ FreeSql/Oracle/OracleDbFirst.cs | 385 +++++++++ FreeSql/Oracle/OracleExpression.cs | 315 ++++++++ FreeSql/Oracle/OracleProvider.cs | 49 ++ FreeSql/Oracle/OracleUtils.cs | 47 ++ FreeSql/PostgreSQL/Curd/PostgreSQLInsert.cs | 14 +- .../PostgreSQL/PostgreSQLAdo/PostgreSQLAdo.cs | 1 + .../PostgreSQLAdo/PostgreSQLConnectionPool.cs | 2 +- .../PostgreSQLTypesExtensions.cs | 32 + FreeSql/PostgreSQL/PostgreSQLCodeFirst.cs | 13 +- FreeSql/PostgreSQL/PostgreSQLDbFirst.cs | 729 +++++++++++------- FreeSql/SqlServer/SqlServerCodeFirst.cs | 14 +- FreeSql/SqlServer/SqlServerDbFirst.cs | 3 +- FreeSql/SqlServer/SqlServerUtils.cs | 4 +- 31 files changed, 2267 insertions(+), 424 deletions(-) create mode 100644 FreeSql.Tests/PostgreSQL/PostgreSQLDbFirstTest.cs create mode 100644 FreeSql/Extensions/FreeSqlGlobalExtensions.cs rename FreeSql/Extensions/{StringExtensions.cs => FreeSqlStringExtensions.cs} (74%) delete mode 100644 FreeSql/Extensions/NpgsqlTypesExtensions.cs create mode 100644 FreeSql/Oracle/Curd/OracleDelete.cs create mode 100644 FreeSql/Oracle/Curd/OracleInsert.cs create mode 100644 FreeSql/Oracle/Curd/OracleSelect.cs create mode 100644 FreeSql/Oracle/Curd/OracleUpdate.cs create mode 100644 FreeSql/Oracle/OracleAdo/OracleAdo.cs create mode 100644 FreeSql/Oracle/OracleAdo/OracleConnectionPool.cs create mode 100644 FreeSql/Oracle/OracleCodeFirst.cs create mode 100644 FreeSql/Oracle/OracleDbFirst.cs create mode 100644 FreeSql/Oracle/OracleExpression.cs create mode 100644 FreeSql/Oracle/OracleProvider.cs create mode 100644 FreeSql/Oracle/OracleUtils.cs diff --git a/FreeSql.Tests/PostgreSQL/PostgreSQLDbFirstTest.cs b/FreeSql.Tests/PostgreSQL/PostgreSQLDbFirstTest.cs new file mode 100644 index 00000000..52aa48bc --- /dev/null +++ b/FreeSql.Tests/PostgreSQL/PostgreSQLDbFirstTest.cs @@ -0,0 +1,21 @@ +using FreeSql.DataAnnotations; +using System; +using Xunit; + +namespace FreeSql.Tests.PostgreSQL { + public class PostgreSQLDbFirstTest { + [Fact] + public void GetDatabases() { + + var t1 = g.pgsql.DbFirst.GetDatabases(); + + } + + [Fact] + public void GetTablesByDatabase() { + + var t2 = g.pgsql.DbFirst.GetTablesByDatabase(g.pgsql.DbFirst.GetDatabases()[1]); + + } + } +} diff --git a/FreeSql/Extensions/FreeSqlGlobalExtensions.cs b/FreeSql/Extensions/FreeSqlGlobalExtensions.cs new file mode 100644 index 00000000..c17fb21c --- /dev/null +++ b/FreeSql/Extensions/FreeSqlGlobalExtensions.cs @@ -0,0 +1,54 @@ +using NpgsqlTypes; +using System; +using System.Collections; +using System.Collections.Generic; +using System.ComponentModel; +using System.Data; +using System.Drawing; +using System.Reflection; + +public static class FreeSqlGlobalExtensions { + + /// + /// 测量两个经纬度的距离,返回单位:米 + /// + /// 经纬坐标1 + /// 经纬坐标2 + /// 返回距离(单位:米) + public static double Distance(this Point that, Point point) { + double radLat1 = (double)(that.Y) * Math.PI / 180d; + double radLng1 = (double)(that.X) * Math.PI / 180d; + double radLat2 = (double)(point.Y) * Math.PI / 180d; + double radLng2 = (double)(point.X) * Math.PI / 180d; + return 2 * Math.Asin(Math.Sqrt(Math.Pow(Math.Sin((radLat1 - radLat2) / 2), 2) + Math.Cos(radLat1) * Math.Cos(radLat2) * Math.Pow(Math.Sin((radLng1 - radLng2) / 2), 2))) * 6378137; + } + + public static object GetEnum(this IDataReader dr, int index) { + string value = dr.GetString(index); + Type t = typeof(T); + foreach (var f in t.GetFields()) + if (f.GetCustomAttribute()?.Description == value || f.Name == value) return Enum.Parse(t, f.Name, true); + return null; + } + + public static string ToDescriptionOrString(this Enum item) { + string name = item.ToString(); + var desc = item.GetType().GetField(name)?.GetCustomAttribute(); + return desc?.Description ?? name; + } + public static long ToInt64(this Enum item) { + return Convert.ToInt64(item); + } + public static IEnumerable ToSet(this long value) { + List ret = new List(); + if (value == 0) return ret; + Type t = typeof(T); + foreach (FieldInfo f in t.GetFields()) { + if (f.FieldType != t) continue; + object o = Enum.Parse(t, f.Name, true); + long v = (long)o; + if ((value & v) == v) ret.Add((T)o); + } + return ret; + } +} \ No newline at end of file diff --git a/FreeSql/Extensions/StringExtensions.cs b/FreeSql/Extensions/FreeSqlStringExtensions.cs similarity index 74% rename from FreeSql/Extensions/StringExtensions.cs rename to FreeSql/Extensions/FreeSqlStringExtensions.cs index a43aecee..05612322 100644 --- a/FreeSql/Extensions/StringExtensions.cs +++ b/FreeSql/Extensions/FreeSqlStringExtensions.cs @@ -1,4 +1,4 @@ -public static class StringExtensions { +public static class FreeSqlStringExtensions { /// /// 特殊处理类似 string.Format 的使用方法,防止注入,以及 IS NULL 转换 @@ -24,6 +24,14 @@ /// public static string FormatPostgreSQL(this string that, params object[] args) => _postgresqlAdo.Addslashes(that, args); static FreeSql.PostgreSQL.PostgreSQLAdo _postgresqlAdo = new FreeSql.PostgreSQL.PostgreSQLAdo(); + /// + /// 特殊处理类似 string.Format 的使用方法,防止注入,以及 IS NULL 转换 + /// + /// + /// + /// + public static string FormatOracleSQL(this string that, params object[] args) => _oracleAdo.Addslashes(that, args); + static FreeSql.Oracle.OracleAdo _oracleAdo = new FreeSql.Oracle.OracleAdo(); } namespace System.Runtime.CompilerServices { diff --git a/FreeSql/Extensions/NpgsqlTypesExtensions.cs b/FreeSql/Extensions/NpgsqlTypesExtensions.cs deleted file mode 100644 index 2ca57bf7..00000000 --- a/FreeSql/Extensions/NpgsqlTypesExtensions.cs +++ /dev/null @@ -1,39 +0,0 @@ -using NpgsqlTypes; -using System; -using System.Collections; - -namespace NpgsqlTypes { - public static class FreeSqlExtensions { - - public static string To1010(this BitArray ba) { - char[] ret = new char[ba.Length]; - for (int a = 0; a < ba.Length; a++) ret[a] = ba[a] ? '1' : '0'; - return new string(ret); - } - - /// - /// 将 1010101010 这样的二进制字符串转换成 BitArray - /// - /// 1010101010 - /// - public static BitArray ToBitArray(this string _1010Str) { - if (_1010Str == null) return null; - BitArray ret = new BitArray(_1010Str.Length); - for (int a = 0; a < _1010Str.Length; a++) ret[a] = _1010Str[a] == '1'; - return ret; - } - - public static NpgsqlRange ToNpgsqlRange(this string that) { - var s = that; - if (string.IsNullOrEmpty(s) || s == "empty") return NpgsqlRange.Empty; - string s1 = s.Trim('(', ')', '[', ']'); - string[] ss = s1.Split(new char[] { ',' }, 2); - if (ss.Length != 2) return NpgsqlRange.Empty; - T t1 = default(T); - T t2 = default(T); - if (!string.IsNullOrEmpty(ss[0])) t1 = (T)Convert.ChangeType(ss[0], typeof(T)); - if (!string.IsNullOrEmpty(ss[1])) t2 = (T)Convert.ChangeType(ss[1], typeof(T)); - return new NpgsqlRange(t1, s[0] == '[', s[0] == '(', t2, s[s.Length - 1] == ']', s[s.Length - 1] == ')'); - } - } -} \ No newline at end of file diff --git a/FreeSql/FreeSql.csproj b/FreeSql/FreeSql.csproj index f8b3a13f..05739388 100644 --- a/FreeSql/FreeSql.csproj +++ b/FreeSql/FreeSql.csproj @@ -20,6 +20,7 @@ + diff --git a/FreeSql/FreeSqlBuilder.cs b/FreeSql/FreeSqlBuilder.cs index 299d30e9..d9cde2e6 100644 --- a/FreeSql/FreeSqlBuilder.cs +++ b/FreeSql/FreeSqlBuilder.cs @@ -92,6 +92,7 @@ namespace FreeSql { case DataType.MySql: ret = new MySql.MySqlProvider(_cache, _logger, _masterConnectionString, _slaveConnectionString); break; case DataType.SqlServer: ret = new SqlServer.SqlServerProvider(_cache, _logger, _masterConnectionString, _slaveConnectionString); break; case DataType.PostgreSQL: ret = new PostgreSQL.PostgreSQLProvider(_cache, _logger, _masterConnectionString, _slaveConnectionString); break; + //case DataType.Oracle: ret = new Oracle.OracleProvider(_cache, _logger, _masterConnectionString, _slaveConnectionString); break; } if (ret != null) { ret.CodeFirst.IsAutoSyncStructure = _isAutoSyncStructure; @@ -104,5 +105,5 @@ namespace FreeSql { } } - public enum DataType { MySql, SqlServer, PostgreSQL } + public enum DataType { MySql, SqlServer, PostgreSQL, /*Oracle*/ } } diff --git a/FreeSql/Internal/CommonProvider/InsertProvider.cs b/FreeSql/Internal/CommonProvider/InsertProvider.cs index c2f6cece..454aaa7f 100644 --- a/FreeSql/Internal/CommonProvider/InsertProvider.cs +++ b/FreeSql/Internal/CommonProvider/InsertProvider.cs @@ -58,7 +58,7 @@ namespace FreeSql.Internal.CommonProvider { return this; } - public string ToSql() { + public virtual string ToSql() { if (_source == null || _source.Any() == false) return null; var sb = new StringBuilder(); sb.Append("INSERT INTO ").Append(_commonUtils.QuoteSqlName(_table.DbName)).Append("("); diff --git a/FreeSql/MySql/MySqlAdo/MygisTypesExtensions.cs b/FreeSql/MySql/MySqlAdo/MygisTypesExtensions.cs index c8f68ff5..5047e62e 100644 --- a/FreeSql/MySql/MySqlAdo/MygisTypesExtensions.cs +++ b/FreeSql/MySql/MySqlAdo/MygisTypesExtensions.cs @@ -20,47 +20,4 @@ public static partial class MygisTypesExtensions { double radLng2 = (double)(point.X) * Math.PI / 180d; return 2 * Math.Asin(Math.Sqrt(Math.Pow(Math.Sin((radLat1 - radLat2) / 2), 2) + Math.Cos(radLat1) * Math.Cos(radLat2) * Math.Pow(Math.Sin((radLng1 - radLng2) / 2), 2))) * 6378137; } - - /// - /// 测量两个经纬度的距离,返回单位:米 - /// - /// 经纬坐标1 - /// 经纬坐标2 - /// 返回距离(单位:米) - public static double Distance(this Point that, Point point) { - double radLat1 = (double)(that.Y) * Math.PI / 180d; - double radLng1 = (double)(that.X) * Math.PI / 180d; - double radLat2 = (double)(point.Y) * Math.PI / 180d; - double radLng2 = (double)(point.X) * Math.PI / 180d; - return 2 * Math.Asin(Math.Sqrt(Math.Pow(Math.Sin((radLat1 - radLat2) / 2), 2) + Math.Cos(radLat1) * Math.Cos(radLat2) * Math.Pow(Math.Sin((radLng1 - radLng2) / 2), 2))) * 6378137; - } - - public static object GetEnum(this IDataReader dr, int index) { - string value = dr.GetString(index); - Type t = typeof(T); - foreach (var f in t.GetFields()) - if (f.GetCustomAttribute()?.Description == value || f.Name == value) return Enum.Parse(t, f.Name, true); - return null; - } - - public static string ToDescriptionOrString(this Enum item) { - string name = item.ToString(); - var desc = item.GetType().GetField(name)?.GetCustomAttribute(); - return desc?.Description ?? name; - } - public static long ToInt64(this Enum item) { - return Convert.ToInt64(item); - } - public static IEnumerable ToSet(this long value) { - List ret = new List(); - if (value == 0) return ret; - Type t = typeof(T); - foreach (FieldInfo f in t.GetFields()) { - if (f.FieldType != t) continue; - object o = Enum.Parse(t, f.Name, true); - long v = (long)o; - if ((value & v) == v) ret.Add((T)o); - } - return ret; - } } \ No newline at end of file diff --git a/FreeSql/MySql/MySqlCodeFirst.cs b/FreeSql/MySql/MySqlCodeFirst.cs index 96d8024e..6fe268db 100644 --- a/FreeSql/MySql/MySqlCodeFirst.cs +++ b/FreeSql/MySql/MySqlCodeFirst.cs @@ -85,7 +85,7 @@ namespace FreeSql.MySql { var conn = _orm.Ado.MasterPool.Get(TimeSpan.FromSeconds(5)); var database = conn.Value.Database; Func ExecuteScalar = (db, sql) => { - if (string.Compare(database, db) != 0) try { conn.Value.ChangeDatabase(db); } catch { } + if (string.Compare(database, db) != 0) conn.Value.ChangeDatabase(db); try { using (var cmd = conn.Value.CreateCommand()) { cmd.CommandText = sql; @@ -107,16 +107,16 @@ namespace FreeSql.MySql { var tboldname = tb.DbOldName?.Split(new[] { '.' }, 2); //旧表名 if (tboldname?.Length == 1) tboldname = new[] { database, tboldname[0] }; - if (string.Compare(tbname[0], database, true) != 0 && ExecuteScalar(database, $"select 1 from pg_database where datname='{tbname[0]}'") == null) //创建数据库 + if (string.Compare(tbname[0], database, true) != 0 && ExecuteScalar(database, " select 1 from pg_database where datname={0}".FormatMySql(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 (ExecuteScalar(tbname[0], "SELECT 1 FROM information_schema.TABLES WHERE table_schema={0} and table_name={1}".FormatMySql(tbname)) == null) { //表不存在 + if (ExecuteScalar(tbname[0], " SELECT 1 FROM information_schema.TABLES WHERE table_schema={0} and table_name={1}".FormatMySql(tbname)) == null) { //表不存在 if (tboldname != null) { - if (string.Compare(tboldname[0], tbname[0], true) != 0 && ExecuteScalar(database, $"select 1 from information_schema.schemata where schema_name='{tboldname[0]}'") == null || - ExecuteScalar(tboldname[0], "SELECT 1 FROM information_schema.TABLES WHERE table_schema={0} and table_name={1}".FormatMySql(tboldname)) == null) - //数据库或模式或表不存在 + if (string.Compare(tboldname[0], tbname[0], true) != 0 && ExecuteScalar(database, " select 1 from information_schema.schemata where schema_name={0}".FormatMySql(tboldname[0])) == null || + ExecuteScalar(tboldname[0], " SELECT 1 FROM information_schema.TABLES WHERE table_schema={0} and table_name={1}".FormatMySql(tboldname)) == null) + //数据库或表不存在 tboldname = null; } if (tboldname == null) { @@ -149,11 +149,8 @@ namespace FreeSql.MySql { tboldname = null; //如果新表已经存在,不走改表名逻辑 //对比字段,只可以修改类型、增加字段、有限的修改字段名;保证安全不删除字段 - var addcols = new Dictionary(StringComparer.CurrentCultureIgnoreCase); - foreach (var tbcol in tb.Columns) addcols.Add(tbcol.Value.Attribute.Name, tbcol.Value); - var surplus = new Dictionary(StringComparer.CurrentCultureIgnoreCase); - var dbcols = new List(); - var sql = @"select + var sql = @" +select a.column_name, a.column_type, case when a.is_nullable = 'YES' then 1 else 0 end 'is_nullable', diff --git a/FreeSql/MySql/MySqlDbFirst.cs b/FreeSql/MySql/MySqlDbFirst.cs index 5221bed1..d9cc5442 100644 --- a/FreeSql/MySql/MySqlDbFirst.cs +++ b/FreeSql/MySql/MySqlDbFirst.cs @@ -116,8 +116,8 @@ namespace FreeSql.MySql { { (int)MySqlDbType.VarString, ("", "{0}.Replace(StringifySplit, \"|\")", "{0}.Replace(\"|\", StringifySplit)", "string", typeof(string), typeof(string), "{0}", "GetString") }, { (int)MySqlDbType.VarChar, ("", "{0}.Replace(StringifySplit, \"|\")", "{0}.Replace(\"|\", StringifySplit)", "string", typeof(string), typeof(string), "{0}", "GetString") }, - { (int)MySqlDbType.Set, ("(long?)", "long.Parse({0})", "{0}.ToInt64().ToString()", "Set", typeof(bool), typeof(Enum), "{0}", "GetInt64") }, - { (int)MySqlDbType.Enum, ("(long?)", "long.Parse({0})", "{0}.ToInt64().ToString()", "Enum", typeof(bool), typeof(Enum), "{0}", "GetInt64") }, + { (int)MySqlDbType.Set, ("(long?)", "long.Parse({0})", "{0}.ToInt64().ToString()", "Set", typeof(Enum), typeof(Enum), "{0}", "GetInt64") }, + { (int)MySqlDbType.Enum, ("(long?)", "long.Parse({0})", "{0}.ToInt64().ToString()", "Enum", typeof(Enum), typeof(Enum), "{0}", "GetInt64") }, { (int)MySqlDbType.Geometry, ("(MygisGeometry)", "MygisGeometry.Parse({0}.Replace(StringifySplit, \"|\"))", "{0}.AsText().Replace(\"|\", StringifySplit)", "MygisGeometry", typeof(MygisGeometry), typeof(MygisGeometry), "{0}", "GetString") }, }; @@ -131,7 +131,7 @@ namespace FreeSql.MySql { public string GetDataReaderMethod(DbColumnInfo column) => _dicDbToCs.TryGetValue(column.DbType, out var trydc) ? trydc.dataReaderMethod : null; public List GetDatabases() { - var sql = @"select schema_name from information_schema.schemata where schema_name not in ('information_schema', 'mysql', 'performance_schema')"; + 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(); } @@ -143,7 +143,8 @@ namespace FreeSql.MySql { if (database == null || database.Any() == false) return loc1; var databaseIn = string.Join(",", database.Select(a => "{0}".FormatMySql(a))); - var sql = string.Format(@"select + var sql = string.Format(@" +select concat(a.table_schema, '.', a.table_name) 'id', a.table_schema 'schema', a.table_name 'table', @@ -180,7 +181,8 @@ where a.table_schema in ({0})", databaseIn); var loc8 = "'" + string.Join("','", loc6.ToArray()) + "'"; var loc88 = "'" + string.Join("','", loc66.ToArray()) + "'"; - sql = string.Format(@"select + sql = string.Format(@" +select concat(a.table_schema, '.', a.table_name), a.column_name, a.data_type, @@ -225,7 +227,8 @@ where a.table_schema in ({1}) and a.table_name in ({0}) loc3[table_id][column].CsType = this.GetCsTypeInfo(loc3[table_id][column]); } - sql = string.Format(@"select + sql = string.Format(@" +select concat(a.constraint_schema, '.', a.table_name) 'table_id', a.column_name, concat(a.constraint_schema, '/', a.table_name, '/', a.constraint_name) 'index_id', @@ -282,7 +285,8 @@ where a.constraint_schema in ({1}) and a.table_name in ({0}) and isnull(position } } - sql = string.Format(@"select + sql = string.Format(@" +select concat(a.constraint_schema, '.', a.table_name) 'table_id', a.column_name, concat(a.constraint_schema, '/', a.constraint_name) 'FKId', diff --git a/FreeSql/MySql/MySqlUtils.cs b/FreeSql/MySql/MySqlUtils.cs index f551694a..99add13c 100644 --- a/FreeSql/MySql/MySqlUtils.cs +++ b/FreeSql/MySql/MySqlUtils.cs @@ -9,8 +9,8 @@ namespace FreeSql.MySql { class MySqlUtils : CommonUtils { IFreeSql _orm; - public MySqlUtils(IFreeSql mysql) { - _orm = mysql; + public MySqlUtils(IFreeSql orm) { + _orm = orm; } internal override DbParameter AppendParamter(List _params, string parameterName, Type type, object value) { diff --git a/FreeSql/Oracle/Curd/OracleDelete.cs b/FreeSql/Oracle/Curd/OracleDelete.cs new file mode 100644 index 00000000..90b0b61a --- /dev/null +++ b/FreeSql/Oracle/Curd/OracleDelete.cs @@ -0,0 +1,45 @@ +using FreeSql.Internal; +using System.Collections.Generic; +using System.Data; +using System.Text; +using System.Threading.Tasks; + +namespace FreeSql.Oracle.Curd { + + class OracleDelete : Internal.CommonProvider.DeleteProvider where T1 : class { + public OracleDelete(IFreeSql orm, CommonUtils commonUtils, CommonExpression commonExpression, object dywhere) + : base(orm, commonUtils, commonExpression, dywhere) { + } + + public override List ExecuteDeleted() { + var sql = this.ToSql(); + if (string.IsNullOrEmpty(sql)) return new List(); + + 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.QuoteReadColumn(col.CsType, _commonUtils.QuoteSqlName(col.Attribute.Name))).Append(" as ").Append(_commonUtils.QuoteSqlName(col.CsName)); + ++colidx; + } + return _orm.Ado.Query(CommandType.Text, sb.ToString(), _params.ToArray()); + } + async public override Task> ExecuteDeletedAsync() { + var sql = this.ToSql(); + if (string.IsNullOrEmpty(sql)) return new List(); + + 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.QuoteReadColumn(col.CsType, _commonUtils.QuoteSqlName(col.Attribute.Name))).Append(" as ").Append(_commonUtils.QuoteSqlName(col.CsName)); + ++colidx; + } + return await _orm.Ado.QueryAsync(CommandType.Text, sb.ToString(), _params.ToArray()); + } + } +} diff --git a/FreeSql/Oracle/Curd/OracleInsert.cs b/FreeSql/Oracle/Curd/OracleInsert.cs new file mode 100644 index 00000000..af8ac146 --- /dev/null +++ b/FreeSql/Oracle/Curd/OracleInsert.cs @@ -0,0 +1,105 @@ +using FreeSql.Internal; +using System.Collections.Generic; +using System.Data; +using System.Data.Common; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace FreeSql.Oracle.Curd { + + class OracleInsert : Internal.CommonProvider.InsertProvider where T1 : class { + public OracleInsert(IFreeSql orm, CommonUtils commonUtils, CommonExpression commonExpression) + : base(orm, commonUtils, commonExpression) { + } + + public override string ToSql() { + if (_source == null || _source.Any() == false) return null; + var sb = new StringBuilder(); + sb.Append("INSERT INTO ").Append(_commonUtils.QuoteSqlName(_table.DbName)).Append("("); + var colidx = 0; + foreach (var col in _table.Columns.Values) + if (_ignore.ContainsKey(col.Attribute.Name) == false) { + if (colidx > 0) sb.Append(", "); + sb.Append(_commonUtils.QuoteSqlName(col.Attribute.Name)); + ++colidx; + } + sb.Append(") VALUES"); + _params = new DbParameter[colidx * _source.Count]; + var didx = 0; + foreach (var d in _source) { + if (didx > 0) sb.Append(", "); + sb.Append("("); + var colidx2 = 0; + foreach (var col in _table.Columns.Values) + if (_ignore.ContainsKey(col.Attribute.Name) == false) { + if (colidx2 > 0) sb.Append(", "); + if (col.Attribute.IsIdentity) { + sb.Append(_commonUtils.QuoteSqlName($"{Utils.GetCsName(_table.DbName)}_seq_{col.Attribute.Name}")).Append(".nextval"); + } else { + sb.Append(_commonUtils.QuoteWriteParamter(col.CsType, $"{_commonUtils.QuoteParamterName(col.CsName)}{didx}")); + _params[didx * colidx + colidx2] = _commonUtils.AppendParamter(null, $"{col.CsName}{didx}", col.CsType, _table.Properties.TryGetValue(col.CsName, out var tryp) ? tryp.GetValue(d) : null); + } + ++colidx2; + } + sb.Append(")"); + ++didx; + } + return sb.ToString(); + } + + public override long ExecuteIdentity() { + var sql = this.ToSql(); + if (string.IsNullOrEmpty(sql)) return 0; + + var identCols = _table.Columns.Where(a => a.Value.Attribute.IsIdentity); + if (identCols.Any() == false) { + _orm.Ado.ExecuteNonQuery(CommandType.Text, sql, _params); + return 0; + } + return long.TryParse(string.Concat(_orm.Ado.ExecuteScalar(CommandType.Text, string.Concat(sql, " RETURNING ", _commonUtils.QuoteSqlName(identCols.First().Value.Attribute.Name)), _params)), out var trylng) ? trylng : 0; + } + async public override Task ExecuteIdentityAsync() { + var sql = this.ToSql(); + if (string.IsNullOrEmpty(sql)) return 0; + + var identCols = _table.Columns.Where(a => a.Value.Attribute.IsIdentity); + if (identCols.Any() == false) { + await _orm.Ado.ExecuteNonQueryAsync(CommandType.Text, sql, _params); + return 0; + } + return long.TryParse(string.Concat(await _orm.Ado.ExecuteScalarAsync(CommandType.Text, string.Concat(sql, " RETURNING ", _commonUtils.QuoteSqlName(identCols.First().Value.Attribute.Name)), _params)), out var trylng) ? trylng : 0; + } + + public override List ExecuteInserted() { + var sql = this.ToSql(); + if (string.IsNullOrEmpty(sql)) return new List(); + + 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.QuoteReadColumn(col.CsType, _commonUtils.QuoteSqlName(col.Attribute.Name))).Append(" as ").Append(_commonUtils.QuoteSqlName(col.CsName)); + ++colidx; + } + return _orm.Ado.Query(CommandType.Text, sb.ToString(), _params); + } + async public override Task> ExecuteInsertedAsync() { + var sql = this.ToSql(); + if (string.IsNullOrEmpty(sql)) return new List(); + + 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.QuoteReadColumn(col.CsType, _commonUtils.QuoteSqlName(col.Attribute.Name))).Append(" as ").Append(_commonUtils.QuoteSqlName(col.CsName)); + ++colidx; + } + return await _orm.Ado.QueryAsync(CommandType.Text, sb.ToString(), _params); + } + } +} diff --git a/FreeSql/Oracle/Curd/OracleSelect.cs b/FreeSql/Oracle/Curd/OracleSelect.cs new file mode 100644 index 00000000..bc5050d3 --- /dev/null +++ b/FreeSql/Oracle/Curd/OracleSelect.cs @@ -0,0 +1,126 @@ +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.Oracle.Curd { + + class OracleSelect : FreeSql.Internal.CommonProvider.Select1Provider where T1 : class { + + internal static string ToSqlStatic(CommonUtils _commonUtils, string _select, string field, StringBuilder _join, StringBuilder _where, string _groupby, string _having, string _orderby, int _skip, int _limit, List _tables, IFreeSql _orm) { + if (_orm.CodeFirst.IsAutoSyncStructure) + _orm.CodeFirst.SyncStructure(_tables.Select(a => a.Table.Type).ToArray()); + + var sb = new StringBuilder(); + sb.Append(_select); + sb.Append(field); + if (string.IsNullOrEmpty(_orderby) == false && (_skip > 0 || _limit > 0)) sb.Append(", ROWNUM 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(tbsfrom[a].Table.DbName)).Append(" ").Append(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(tbsfrom[b].Table.DbName)).Append(" ").Append(tbsfrom[b].Alias).Append(" ON 1 = 1"); + break; + } + if (a < tbsfrom.Length - 1) sb.Append(", "); + } + foreach (var tb in tbsjoin) { + if (tb.Type == SelectTableInfoType.Parent) continue; + switch (tb.Type) { + case SelectTableInfoType.LeftJoin: + sb.Append(" \r\nLEFT JOIN "); + break; + case SelectTableInfoType.InnerJoin: + sb.Append(" \r\nINNER JOIN "); + break; + case SelectTableInfoType.RightJoin: + sb.Append(" \r\nRIGHT JOIN "); + break; + } + sb.Append(_commonUtils.QuoteSqlName(tb.Table.DbName)).Append(" ").Append(tb.Alias).Append(" ON ").Append(tb.On); + } + if (_join.Length > 0) sb.Append(_join); + + var sbqf = new StringBuilder(); + foreach (var tb in _tables) { + if (tb.Type == SelectTableInfoType.Parent) continue; + if (string.IsNullOrEmpty(tb.Table.SelectFilter) == false) + sbqf.Append(" AND (").Append(tb.Table.SelectFilter.Replace("a.", $"{tb.Alias}.")).Append(")"); + } + if (_where.Length > 0) { + sb.Append(" \r\nWHERE ").Append(_where.ToString().Substring(5)); + if (string.IsNullOrEmpty(_orderby) == false && (_skip > 0 || _limit > 0)) sb.Append(" AND ROWNUM < ").Append(_skip + _limit + 1); + if (sbqf.Length > 0) sb.Append(sbqf.ToString()); + } else { + if (string.IsNullOrEmpty(_orderby) == false && (_skip > 0 || _limit > 0)) { + sb.Append(" \r\nWHERE ROWNUM < ").Append(_skip + _limit + 1); + if (sbqf.Length > 0) sb.Append(sbqf.Remove(0, 5)); + } + else if (sbqf.Length > 0) sb.Append(" \r\nWHERE ").Append(sbqf.Remove(0, 5)); + } + if (string.IsNullOrEmpty(_groupby) == false) { + sb.Append(_groupby); + if (string.IsNullOrEmpty(_having) == false) + sb.Append(" \r\nHAVING ").Append(_having.Substring(5)); + } + sb.Append(_orderby); + if (string.IsNullOrEmpty(_orderby) == false) { + if (_skip > 0 && _limit > 0) sb.Insert(0, "SELECT t.* FROM (SELECT ROWNUM AS rt.*, __rownum__ FROM (").Append(") rt WHERE ROWNUM < ").Append(_skip + _limit + 1).Append(") t WHERE t.__rownum__ > ").Append(_skip); + else if (_skip > 0 || _limit > 0) sb.Insert(0, "SELECT t.* FROM (").Append(") t WHERE ROWNUM < ").Append(_skip + _limit + 1); + } else if (_skip > 0) + sb.Insert(0, "SELECT t.* FROM (").Append(") t WHERE t.__rownum__ > ").Append(_skip); + + return sb.ToString(); + } + + public OracleSelect(IFreeSql orm, CommonUtils commonUtils, CommonExpression commonExpression, object dywhere) : base(orm, commonUtils, commonExpression, dywhere) { } + public override ISelect From(Expression, T2, T3, ISelectFromExpression>> exp) { this.InternalFrom(exp?.Body); var ret = new OracleSelect(_orm, _commonUtils, _commonExpression, null); OracleSelect.CopyData(this, ret); return ret; } + public override ISelect From(Expression, T2, T3, T4, ISelectFromExpression>> exp) { this.InternalFrom(exp?.Body); var ret = new OracleSelect(_orm, _commonUtils, _commonExpression, null); OracleSelect.CopyData(this, ret); return ret; } + public override ISelect From(Expression, T2, T3, T4, T5, ISelectFromExpression>> exp) { this.InternalFrom(exp?.Body); var ret = new OracleSelect(_orm, _commonUtils, _commonExpression, null); OracleSelect.CopyData(this, ret); return ret; } + public override ISelect From(Expression, T2, T3, T4, T5, T6, ISelectFromExpression>> exp) { this.InternalFrom(exp?.Body); var ret = new OracleSelect(_orm, _commonUtils, _commonExpression, null); OracleSelect.CopyData(this, ret); return ret; } + public override ISelect From(Expression, T2, T3, T4, T5, T6, T7, ISelectFromExpression>> exp) { this.InternalFrom(exp?.Body); var ret = new OracleSelect(_orm, _commonUtils, _commonExpression, null); OracleSelect.CopyData(this, ret); return ret; } + public override ISelect From(Expression, T2, T3, T4, T5, T6, T7, T8, ISelectFromExpression>> exp) { this.InternalFrom(exp?.Body); var ret = new OracleSelect(_orm, _commonUtils, _commonExpression, null); OracleSelect.CopyData(this, ret); return ret; } + public override ISelect From(Expression, T2, T3, T4, T5, T6, T7, T8, T9, ISelectFromExpression>> exp) { this.InternalFrom(exp?.Body); var ret = new OracleSelect(_orm, _commonUtils, _commonExpression, null); OracleSelect.CopyData(this, ret); return ret; } + public override ISelect From(Expression, T2, T3, T4, T5, T6, T7, T8, T9, T10, ISelectFromExpression>> exp) { this.InternalFrom(exp?.Body); var ret = new OracleSelect(_orm, _commonUtils, _commonExpression, null); OracleSelect.CopyData(this, ret); return ret; } + public override string ToSql(string field = null) => ToSqlStatic(_commonUtils, _select, field ?? this.GetAllField().field, _join, _where, _groupby, _having, _orderby, _skip, _limit, _tables, _orm); + } + class OracleSelect : FreeSql.Internal.CommonProvider.Select3Provider where T1 : class where T2 : class where T3 : class { + public OracleSelect(IFreeSql orm, CommonUtils commonUtils, CommonExpression commonExpression, object dywhere) : base(orm, commonUtils, commonExpression, dywhere) { } + public override string ToSql(string field = null) => OracleSelect.ToSqlStatic(_commonUtils, _select, field ?? this.GetAllField().field, _join, _where, _groupby, _having, _orderby, _skip, _limit, _tables, _orm); + } + class OracleSelect : FreeSql.Internal.CommonProvider.Select4Provider where T1 : class where T2 : class where T3 : class where T4 : class { + public OracleSelect(IFreeSql orm, CommonUtils commonUtils, CommonExpression commonExpression, object dywhere) : base(orm, commonUtils, commonExpression, dywhere) { } + public override string ToSql(string field = null) => OracleSelect.ToSqlStatic(_commonUtils, _select, field ?? this.GetAllField().field, _join, _where, _groupby, _having, _orderby, _skip, _limit, _tables, _orm); + } + class OracleSelect : FreeSql.Internal.CommonProvider.Select5Provider where T1 : class where T2 : class where T3 : class where T4 : class where T5 : class { + public OracleSelect(IFreeSql orm, CommonUtils commonUtils, CommonExpression commonExpression, object dywhere) : base(orm, commonUtils, commonExpression, dywhere) { } + public override string ToSql(string field = null) => OracleSelect.ToSqlStatic(_commonUtils, _select, field ?? this.GetAllField().field, _join, _where, _groupby, _having, _orderby, _skip, _limit, _tables, _orm); + } + class OracleSelect : FreeSql.Internal.CommonProvider.Select6Provider where T1 : class where T2 : class where T3 : class where T4 : class where T5 : class where T6 : class { + public OracleSelect(IFreeSql orm, CommonUtils commonUtils, CommonExpression commonExpression, object dywhere) : base(orm, commonUtils, commonExpression, dywhere) { } + public override string ToSql(string field = null) => OracleSelect.ToSqlStatic(_commonUtils, _select, field ?? this.GetAllField().field, _join, _where, _groupby, _having, _orderby, _skip, _limit, _tables, _orm); + } + class OracleSelect : FreeSql.Internal.CommonProvider.Select7Provider where T1 : class where T2 : class where T3 : class where T4 : class where T5 : class where T6 : class where T7 : class { + public OracleSelect(IFreeSql orm, CommonUtils commonUtils, CommonExpression commonExpression, object dywhere) : base(orm, commonUtils, commonExpression, dywhere) { } + public override string ToSql(string field = null) => OracleSelect.ToSqlStatic(_commonUtils, _select, field ?? this.GetAllField().field, _join, _where, _groupby, _having, _orderby, _skip, _limit, _tables, _orm); + } + class OracleSelect : FreeSql.Internal.CommonProvider.Select8Provider where T1 : class where T2 : class where T3 : class where T4 : class where T5 : class where T6 : class where T7 : class where T8 : class { + public OracleSelect(IFreeSql orm, CommonUtils commonUtils, CommonExpression commonExpression, object dywhere) : base(orm, commonUtils, commonExpression, dywhere) { } + public override string ToSql(string field = null) => OracleSelect.ToSqlStatic(_commonUtils, _select, field ?? this.GetAllField().field, _join, _where, _groupby, _having, _orderby, _skip, _limit, _tables, _orm); + } + class OracleSelect : FreeSql.Internal.CommonProvider.Select9Provider where T1 : class 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 OracleSelect(IFreeSql orm, CommonUtils commonUtils, CommonExpression commonExpression, object dywhere) : base(orm, commonUtils, commonExpression, dywhere) { } + public override string ToSql(string field = null) => OracleSelect.ToSqlStatic(_commonUtils, _select, field ?? this.GetAllField().field, _join, _where, _groupby, _having, _orderby, _skip, _limit, _tables, _orm); + } + class OracleSelect : FreeSql.Internal.CommonProvider.Select10Provider where T1 : class 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 OracleSelect(IFreeSql orm, CommonUtils commonUtils, CommonExpression commonExpression, object dywhere) : base(orm, commonUtils, commonExpression, dywhere) { } + public override string ToSql(string field = null) => OracleSelect.ToSqlStatic(_commonUtils, _select, field ?? this.GetAllField().field, _join, _where, _groupby, _having, _orderby, _skip, _limit, _tables, _orm); + } +} diff --git a/FreeSql/Oracle/Curd/OracleUpdate.cs b/FreeSql/Oracle/Curd/OracleUpdate.cs new file mode 100644 index 00000000..8e7d6d3d --- /dev/null +++ b/FreeSql/Oracle/Curd/OracleUpdate.cs @@ -0,0 +1,78 @@ +using FreeSql.Internal; +using FreeSql.Internal.Model; +using System.Collections.Generic; +using System.Data; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace FreeSql.Oracle.Curd { + + class OracleUpdate : Internal.CommonProvider.UpdateProvider where T1 : class { + + public OracleUpdate(IFreeSql orm, CommonUtils commonUtils, CommonExpression commonExpression, object dywhere) + : base(orm, commonUtils, commonExpression, dywhere) { + } + + public override List ExecuteUpdated() { + var sql = this.ToSql(); + if (string.IsNullOrEmpty(sql)) return new List(); + + 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.QuoteReadColumn(col.CsType, _commonUtils.QuoteSqlName(col.Attribute.Name))).Append(" as ").Append(_commonUtils.QuoteSqlName(col.CsName)); + ++colidx; + } + return _orm.Ado.Query(CommandType.Text, sb.ToString(), _params.Concat(_paramsSource).ToArray()); + } + async public override Task> ExecuteUpdatedAsync() { + var sql = this.ToSql(); + if (string.IsNullOrEmpty(sql)) return new List(); + + 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.QuoteReadColumn(col.CsType, _commonUtils.QuoteSqlName(col.Attribute.Name))).Append(" as ").Append(_commonUtils.QuoteSqlName(col.CsName)); + ++colidx; + } + return await _orm.Ado.QueryAsync(CommandType.Text, sb.ToString(), _params.Concat(_paramsSource).ToArray()); + } + + protected override void ToSqlCase(StringBuilder caseWhen, ColumnInfo[] primarys) { + if (_table.Primarys.Length == 1) { + caseWhen.Append(_commonUtils.QuoteReadColumn(_table.Primarys.First().CsType, _commonUtils.QuoteSqlName(_table.Primarys.First().Attribute.Name))); + return; + } + caseWhen.Append("("); + var pkidx = 0; + foreach (var pk in _table.Primarys) { + if (pkidx > 0) caseWhen.Append(" || "); + caseWhen.Append(_commonUtils.QuoteReadColumn(pk.CsType, _commonUtils.QuoteSqlName(pk.Attribute.Name))); + ++pkidx; + } + caseWhen.Append(")"); + } + + protected override void ToSqlWhen(StringBuilder sb, ColumnInfo[] primarys, object d) { + if (_table.Primarys.Length == 1) { + sb.Append(_commonUtils.FormatSql("{0}", _table.Properties.TryGetValue(_table.Primarys.First().CsName, out var tryp2) ? tryp2.GetValue(d) : null)); + return; + } + sb.Append("("); + var pkidx = 0; + foreach (var pk in _table.Primarys) { + if (pkidx > 0) sb.Append(" || "); + sb.Append(_commonUtils.FormatSql("{0}", _table.Properties.TryGetValue(pk.CsName, out var tryp2) ? tryp2.GetValue(d) : null)); + ++pkidx; + } + sb.Append(")"); + } + } +} diff --git a/FreeSql/Oracle/OracleAdo/OracleAdo.cs b/FreeSql/Oracle/OracleAdo/OracleAdo.cs new file mode 100644 index 00000000..0aee69f9 --- /dev/null +++ b/FreeSql/Oracle/OracleAdo/OracleAdo.cs @@ -0,0 +1,65 @@ +using FreeSql.Internal; +using Microsoft.Extensions.Logging; +using Oracle.ManagedDataAccess.Client; +using SafeObjectPool; +using System; +using System.Collections; +using System.Data.Common; +using System.Text; +using System.Threading; + +namespace FreeSql.Oracle { + class OracleAdo : FreeSql.Internal.CommonProvider.AdoProvider { + CommonUtils _util; + + public OracleAdo() : base(null, null) { } + public OracleAdo(CommonUtils util, ICache cache, ILogger log, string masterConnectionString, string[] slaveConnectionStrings) : base(cache, log) { + this._util = util; + MasterPool = new OracleConnectionPool("主库", masterConnectionString, null, null); + if (slaveConnectionStrings != null) { + foreach (var slaveConnectionString in slaveConnectionStrings) { + var slavePool = new OracleConnectionPool($"从库{SlavePools.Count + 1}", slaveConnectionString, () => Interlocked.Decrement(ref slaveUnavailables), () => Interlocked.Increment(ref slaveUnavailables)); + SlavePools.Add(slavePool); + } + } + } + static DateTime dt1970 = new DateTime(1970, 1, 1); + public override object AddslashesProcessParam(object param) { + if (param == null) return "NULL"; + 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 Enum) + return ((Enum)param).ToInt64(); + else if (decimal.TryParse(string.Concat(param), out var trydec)) + return param; + else if (param is DateTime) + return string.Concat("'", ((DateTime)param).ToString("yyyy-MM-dd HH:mm:ss"), "'"); + else if (param is DateTime?) + return string.Concat("'", (param as DateTime?).Value.ToString("yyyy-MM-dd HH:mm:ss"), "'"); + else if (param is TimeSpan) + return ((TimeSpan)param).Ticks / 10; + else if (param is TimeSpan?) + return (param as TimeSpan?).Value.Ticks / 10; + else if (param is IEnumerable) { + var sb = new StringBuilder(); + var ie = param as IEnumerable; + foreach (var z in ie) sb.Append(",").Append(AddslashesProcessParam(z)); + return sb.Length == 0 ? "(NULL)" : sb.Remove(0, 1).Insert(0, "(").Append(")").ToString(); + } + return string.Concat("'", param.ToString().Replace("'", "''"), "'"); + //if (param is string) return string.Concat('N', nparms[a]); + } + + protected override DbCommand CreateCommand() { + return new OracleCommand(); + } + + protected override void ReturnConnection(ObjectPool pool, Object conn, Exception ex) { + (pool as OracleConnectionPool).Return(conn, ex); + } + + protected override DbParameter[] GetDbParamtersByObject(string sql, object obj) => _util.GetDbParamtersByObject(sql, obj); + } +} diff --git a/FreeSql/Oracle/OracleAdo/OracleConnectionPool.cs b/FreeSql/Oracle/OracleAdo/OracleConnectionPool.cs new file mode 100644 index 00000000..6d973d22 --- /dev/null +++ b/FreeSql/Oracle/OracleAdo/OracleConnectionPool.cs @@ -0,0 +1,153 @@ +using Oracle.ManagedDataAccess.Client; +using SafeObjectPool; +using System; +using System.Collections.Generic; +using System.Data; +using System.Data.Common; +using System.Text; +using System.Text.RegularExpressions; +using System.Threading.Tasks; + +namespace FreeSql.Oracle { + + public class OracleConnectionPool : ObjectPool { + + internal Action availableHandler; + internal Action unavailableHandler; + + public OracleConnectionPool(string name, string connectionString, Action availableHandler, Action unavailableHandler) : base(null) { + var policy = new OracleConnectionPoolPolicy { + _pool = this, + Name = name + }; + this.Policy = policy; + policy.ConnectionString = connectionString; + + this.availableHandler = availableHandler; + this.unavailableHandler = unavailableHandler; + } + + public void Return(Object obj, Exception exception, bool isRecreate = false) { + if (exception != null && exception is OracleException) { + + if (exception is System.IO.IOException) { + + base.SetUnavailable(exception); + + } else if (obj.Value.Ping() == false) { + + base.SetUnavailable(exception); + } + } + base.Return(obj, isRecreate); + } + } + + public class OracleConnectionPoolPolicy : IPolicy { + + internal OracleConnectionPool _pool; + public string Name { get; set; } = "Oracle Connection 对象池"; + public int PoolSize { get; set; } = 100; + public TimeSpan SyncGetTimeout { get; set; } = TimeSpan.FromSeconds(10); + public int AsyncGetCapacity { get; set; } = 10000; + public bool IsThrowGetTimeoutException { get; set; } = true; + public int CheckAvailableInterval { get; set; } = 5; + + private string _connectionString; + public string ConnectionString { + get => _connectionString; + set { + _connectionString = value ?? ""; + Match m = Regex.Match(_connectionString, @"Max\s*pool\s*size\s*=\s*(\d+)", RegexOptions.IgnoreCase); + if (m.Success == false || int.TryParse(m.Groups[1].Value, out var poolsize) == false || poolsize <= 0) poolsize = 100; + PoolSize = poolsize; + + var initConns = new Object[poolsize]; + for (var a = 0; a < poolsize; a++) try { initConns[a] = _pool.Get(); } catch { } + foreach (var conn in initConns) _pool.Return(conn); + } + } + + + public bool OnCheckAvailable(Object obj) { + if (obj.Value.State == ConnectionState.Closed) obj.Value.Open(); + var cmd = obj.Value.CreateCommand(); + cmd.CommandText = "select 1"; + cmd.ExecuteNonQuery(); + return true; + } + + public DbConnection OnCreate() { + var conn = new OracleConnection(_connectionString); + return conn; + } + + public void OnDestroy(DbConnection obj) { + if (obj.State != ConnectionState.Closed) obj.Close(); + obj.Dispose(); + } + + public void OnGet(Object obj) { + + if (_pool.IsAvailable) { + + if (obj.Value.State != ConnectionState.Open || DateTime.Now.Subtract(obj.LastReturnTime).TotalSeconds > 60 && obj.Value.Ping() == false) { + + try { + obj.Value.Open(); + } catch (Exception ex) { + if (_pool.SetUnavailable(ex) == true) + throw new Exception($"【{this.Name}】状态不可用,等待后台检查程序恢复方可使用。{ex.Message}"); + } + } + } + } + + async public Task OnGetAsync(Object obj) { + + if (_pool.IsAvailable) { + + if (obj.Value.State != ConnectionState.Open || DateTime.Now.Subtract(obj.LastReturnTime).TotalSeconds > 60 && obj.Value.Ping() == false) { + + try { + await obj.Value.OpenAsync(); + } catch (Exception ex) { + if (_pool.SetUnavailable(ex) == true) + throw new Exception($"【{this.Name}】状态不可用,等待后台检查程序恢复方可使用。{ex.Message}"); + } + } + } + } + + public void OnGetTimeout() { + + } + + public void OnReturn(Object obj) { + + } + + public void OnAvailable() { + _pool.availableHandler?.Invoke(); + } + + public void OnUnavailable() { + _pool.unavailableHandler?.Invoke(); + } + } + + static class DbConnectionExtensions { + + public static bool Ping(this DbConnection that) { + try { + var cmd = that.CreateCommand(); + cmd.CommandText = "select 1"; + cmd.ExecuteNonQuery(); + return true; + } catch { + try { that.Close(); } catch { } + return false; + } + } + } +} diff --git a/FreeSql/Oracle/OracleCodeFirst.cs b/FreeSql/Oracle/OracleCodeFirst.cs new file mode 100644 index 00000000..97c5bda4 --- /dev/null +++ b/FreeSql/Oracle/OracleCodeFirst.cs @@ -0,0 +1,297 @@ +using FreeSql.DatabaseModel; +using FreeSql.Internal; +using FreeSql.Internal.Model; +using Oracle.ManagedDataAccess.Client; +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.Oracle { + + class OracleCodeFirst : ICodeFirst { + IFreeSql _orm; + protected CommonUtils _commonUtils; + protected CommonExpression _commonExpression; + public OracleCodeFirst(IFreeSql orm, CommonUtils commonUtils, CommonExpression commonExpression) { + _orm = orm; + _commonUtils = commonUtils; + _commonExpression = commonExpression; + } + + public bool IsAutoSyncStructure { get; set; } = true; + public bool IsSyncStructureToLower { get; set; } = false; + + static object _dicCsToDbLock = new object(); + static Dictionary _dicCsToDb = new Dictionary() { + { typeof(bool).FullName, (OracleDbType.Boolean, "number","number(1) NOT NULL", null, false, false) },{ typeof(bool?).FullName, (OracleDbType.Boolean, "number","number(1) NULL", null, true, null) }, + + { typeof(sbyte).FullName, (OracleDbType.Byte, "number", "number(4) NOT NULL", false, false, 0) },{ typeof(sbyte?).FullName, (OracleDbType.Byte, "number", "number(4) NULL", false, true, null) }, + { typeof(short).FullName, (OracleDbType.Int16, "number","number(4) NOT NULL", false, false, 0) },{ typeof(short?).FullName, (OracleDbType.Int16, "number", "number(4) NULL", false, true, null) }, + { typeof(int).FullName, (OracleDbType.Int32, "number", "number(8) NOT NULL", false, false, 0) },{ typeof(int?).FullName, (OracleDbType.Int32, "number", "number(8) NULL", false, true, null) }, + { typeof(long).FullName, (OracleDbType.Int64, "number","number(16) NOT NULL", false, false, 0) },{ typeof(long?).FullName, (OracleDbType.Int64, "bigint","bigint(16) NULL", false, true, null) }, + + { typeof(byte).FullName, (OracleDbType.Byte, "number","number(2) NOT NULL", true, false, 0) },{ typeof(byte?).FullName, (OracleDbType.Byte, "number","number(2) NULL", true, true, null) }, + { typeof(ushort).FullName, (OracleDbType.Int16, "number","number(8) NOT NULL", true, false, 0) },{ typeof(ushort?).FullName, (OracleDbType.Int16, "number", "number(8) NULL", true, true, null) }, + { typeof(uint).FullName, (OracleDbType.Int32, "number", "number(16) NOT NULL", true, false, 0) },{ typeof(uint?).FullName, (OracleDbType.Int32, "number", "number(16) NULL", true, true, null) }, + { typeof(ulong).FullName, (OracleDbType.Int64, "number", "number(32) NOT NULL", true, false, 0) },{ typeof(ulong?).FullName, (OracleDbType.Int64, "number", "number(32) NULL", true, true, null) }, + + { typeof(double).FullName, (OracleDbType.Double, "double", "double(126) NOT NULL", false, false, 0) },{ typeof(double?).FullName, (OracleDbType.Double, "double", "double(126) NULL", false, true, null) }, + { typeof(float).FullName, (OracleDbType.Single, "float","float(63) NOT NULL", false, false, 0) },{ typeof(float?).FullName, (OracleDbType.Single, "float","float(63) NULL", false, true, null) }, + { typeof(decimal).FullName, (OracleDbType.Decimal, "number", "number(10,2) NOT NULL", false, false, 0) },{ typeof(decimal?).FullName, (OracleDbType.Decimal, "number", "number(10,2) NULL", false, true, null) }, + + { typeof(TimeSpan).FullName, (OracleDbType.IntervalDS, "interval day to second","interval day(2) to second(6) NOT NULL", false, false, 0) },{ typeof(TimeSpan?).FullName, (OracleDbType.IntervalDS, "interval day to second", "interval day(2) to second(6) NULL",false, true, null) }, + { typeof(DateTime).FullName, (OracleDbType.TimeStamp, "timestamp", "timestamp(6) NOT NULL", false, false, new DateTime(1970,1,1)) },{ typeof(DateTime?).FullName, (OracleDbType.TimeStamp, "timestamp", "timestamp(6) NULL", false, true, null) }, + { typeof(DateTimeOffset).FullName, (OracleDbType.TimeStampLTZ, "timestamp with local time zone", "timestamp(6) with local time zone NOT NULL", false, false, new DateTime(1970,1,1)) },{ typeof(DateTime?).FullName, (OracleDbType.TimeStamp, "timestamp with local time zone", "timestamp(6) with local time zone NULL", false, true, null) }, + + { typeof(byte[]).FullName, (OracleDbType.Blob, "blog", "blog(4000) NULL", false, null, new byte[0]) }, + { typeof(string).FullName, (OracleDbType.NVarchar2, "nvarchar2", "nvarchar2(255) NULL", false, null, "") }, + + { typeof(Guid).FullName, (OracleDbType.Char, "char", "char(36 BYTE)", false, false, Guid.Empty) },{ typeof(Guid?).FullName, (OracleDbType.Char, "char", "char(36 BYTE) NULL", false, true, null) }, + }; + + public (int type, string dbtype, string dbtypeFull, bool? isnullable, object defaultValue)? GetDbInfo(Type type) { + if (_dicCsToDb.TryGetValue(type.FullName, out var trydc)) return new (int, string, string, bool?, object)?(((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.FullName.StartsWith("System.Nullable`1[") && type.GenericTypeArguments.Length == 1 && type.GenericTypeArguments.First().IsEnum) enumType = type.GenericTypeArguments.First(); + if (enumType != null) { + var newItem = enumType.GetCustomAttributes(typeof(FlagsAttribute), false).Any() ? + (OracleDbType.Int32, "number", $"number(16){(type.IsEnum ? " NOT NULL" : "")}", false, type.IsEnum ? false : true, Enum.GetValues(enumType).GetValue(0)) : + (OracleDbType.Int64, "number", $"number(32){(type.IsEnum ? " NOT NULL" : "")}", false, type.IsEnum ? false : true, Enum.GetValues(enumType).GetValue(0)); + if (_dicCsToDb.ContainsKey(type.FullName) == false) { + lock (_dicCsToDbLock) { + if (_dicCsToDb.ContainsKey(type.FullName) == false) + _dicCsToDb.Add(type.FullName, newItem); + } + } + return ((int)newItem.Item1, newItem.Item2, newItem.Item3, newItem.Item5, newItem.Item6); + } + return null; + } + + public string GetComparisonDDLStatements() => this.GetComparisonDDLStatements(typeof(TEntity)); + public string GetComparisonDDLStatements(params Type[] entityTypes) { + var conn = _orm.Ado.MasterPool.Get(TimeSpan.FromSeconds(5)); + var seqcols = new List<(ColumnInfo, string[], bool)>(); //序列 + + var database = conn.Value.Database; + Func ExecuteScalar = (db, 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); + } + }; + var sb = new StringBuilder(); + try { + foreach (var entityType in entityTypes) { + if (sb.Length > 0) sb.Append("\r\n"); + var tb = _commonUtils.GetTableByEntity(entityType); + var tbname = tb.DbName.Split(new[] { '.' }, 2); + if (tbname?.Length == 1) tbname = new[] { database, tbname[0] }; + + var tboldname = tb.DbOldName?.Split(new[] { '.' }, 2); //旧表名 + if (tboldname?.Length == 1) tboldname = new[] { database, tboldname[0] }; + + if (string.Compare(tbname[0], database, true) != 0 && ExecuteScalar(database, " select 1 from sys.dba_users where username={0}".FormatOracleSQL(tbname[0])) == null) //创建数据库 + throw new NotImplementedException($"Oracle CodeFirst 不支持代码创建 tablespace 与 schemas {tbname[0]}"); + + var sbalter = new StringBuilder(); + var istmpatler = false; //创建临时表,导入数据,删除旧表,修改 + if (ExecuteScalar(tbname[0], " select 1 from all_tab_comments where owner={0} and table_name={1}".FormatOracleSQL(tbname)) == null) { //表不存在 + if (tboldname != null) { + if (ExecuteScalar(tboldname[0], " select 1 from all_tab_comments where owner={0} and table_name={1}".FormatOracleSQL(tboldname)) == null) + //模式或表不存在 + tboldname = null; + } + if (tboldname == null) { + //创建表 + sb.Append("CREATE TABLE ").Append(_commonUtils.QuoteSqlName($"{tbname[0]}.{tbname[1]}")).Append(" ("); + foreach (var tbcol in tb.Columns.Values) { + sb.Append(" \r\n ").Append(_commonUtils.QuoteSqlName(tbcol.Attribute.Name)).Append(" ").Append(tbcol.Attribute.DbType).Append(","); + if (tbcol.Attribute.IsIdentity) seqcols.Add((tbcol, tbname, true)); + } + if (tb.Primarys.Any() == false) + sb.Remove(sb.Length - 1, 1); + else { + sb.Append(" \r\n CONSTRAINT ").Append(tbname[0]).Append("_").Append(tbname[1]).Append("_pk PRIMARY KEY ("); + foreach (var tbcol in tb.Primarys) sb.Append(_commonUtils.QuoteSqlName(tbcol.Attribute.Name)).Append(", "); + sb.Remove(sb.Length - 2, 2).Append(")"); + } + sb.Append("\r\n) LOGGING \r\nNOCOMPRESS \r\nNOCACHE\r\n;\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 addcols = new Dictionary(StringComparer.CurrentCultureIgnoreCase); + foreach (var tbcol in tb.Columns) addcols.Add(tbcol.Value.Attribute.Name, tbcol.Value); + var surplus = new Dictionary(StringComparer.CurrentCultureIgnoreCase); + var dbcols = new List(); + var sql = $@" +select +column_name, +data_type, +data_length, +data_precision, +data_scale, +char_used, +case when nullable = 'Y' then 1 else 0 end, +nvl((select 1 from user_sequences where sequence_name='{Utils.GetCsName(string.Join(".", tboldname ?? tbname))}_seq_'||all_tab_columns.column_name), 0) +from all_tab_columns +where owner={{0}} and table_name={{1}}".FormatOracleSQL(tboldname ?? tbname); + var ds = _orm.Ado.ExecuteArray(CommandType.Text, sql); + var tbstruct = ds.ToDictionary(a => string.Concat(a[0]), a => { + var sqlType = string.Concat(a[1]); + 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 (char_used.ToLower() == "c") { + sqlType += $"({data_length} 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 { + sqlType += $"({data_length})"; + } + return new { + column = string.Concat(a[0]), + sqlType, + is_nullable = string.Concat(a[6]) == "1", + is_identity = string.Concat(a[7]) == "1" + }; + }, StringComparer.CurrentCultureIgnoreCase); + + if (istmpatler == false) { + foreach (var tbcol in tb.Columns.Values) { + if (tbstruct.TryGetValue(tbcol.Attribute.Name, out var tbstructcol) || + string.IsNullOrEmpty(tbcol.Attribute.OldName) == false && tbstruct.TryGetValue(tbcol.Attribute.OldName, out tbstructcol)) { + if (tbcol.Attribute.DbType.StartsWith(tbstructcol.sqlType, StringComparison.CurrentCultureIgnoreCase) == false) + sbalter.Append("ALTER TABLE ").Append(_commonUtils.QuoteSqlName($"{tbname[0]}.{tbname[1]}")).Append(" MODIFY (").Append(_commonUtils.QuoteSqlName(tbstructcol.column)).Append(" ").Append(tbcol.Attribute.DbType).Append(");\r\n"); + if (tbcol.Attribute.IsNullable != tbstructcol.is_nullable) { + if (tbcol.Attribute.IsNullable == false) + sbalter.Append("UPDATE ").Append(_commonUtils.QuoteSqlName($"{tbname[0]}.{tbname[1]}")).Append(" SET ").Append(_commonUtils.QuoteSqlName(tbcol.Attribute.Name)).Append(_commonUtils.FormatSql(" = {0}", tbcol.Attribute.DbDefautValue)).Append(" WHERE ").Append(_commonUtils.QuoteSqlName(tbcol.Attribute.Name)).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.IsNullable ? "" : "NOT").Append(" NULL;\r\n"); + } + if (tbcol.Attribute.IsIdentity != tbstructcol.is_identity) + seqcols.Add((tbcol, tbname, tbcol.Attribute.IsIdentity)); + if (tbstructcol.column == tbcol.Attribute.OldName) + //修改列名 + sbalter.Append("ALTER TABLE ").Append(_commonUtils.QuoteSqlName($"{tbname[0]}.{tbname[1]}")).Append(" RENAME ").Append(_commonUtils.QuoteSqlName(tbcol.Attribute.OldName)).Append(" TO ").Append(_commonUtils.QuoteSqlName(tbcol.Attribute.Name)).Append(";\r\n"); + continue; + } + //添加列 + sbalter.Append("ALTER TABLE ").Append(_commonUtils.QuoteSqlName($"{tbname[0]}.{tbname[1]}")).Append(" ADD COLUMN ").Append(_commonUtils.QuoteSqlName(tbcol.Attribute.Name)).Append(" ").Append(tbcol.Attribute.DbType.Split(' ').First()).Append(";\r\n"); + sbalter.Append("UPDATE ").Append(_commonUtils.QuoteSqlName($"{tbname[0]}.{tbname[1]}")).Append(" SET ").Append(_commonUtils.QuoteSqlName(tbcol.Attribute.Name)).Append(_commonUtils.FormatSql(" = {0};\r\n", tbcol.Attribute.DbDefautValue)); + if (tbcol.Attribute.IsNullable == false) sbalter.Append("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) seqcols.Add((tbcol, tbname, tbcol.Attribute.IsIdentity)); + } + } + if (istmpatler == false) { + sb.Append(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 ").Append(tmptablename).Append(" ("); + foreach (var tbcol in tb.Columns.Values) { + sb.Append(" \r\n ").Append(_commonUtils.QuoteSqlName(tbcol.Attribute.Name)).Append(" ").Append(tbcol.Attribute.DbType).Append(","); + if (tbcol.Attribute.IsIdentity) seqcols.Add((tbcol, tbname, true)); + } + if (tb.Primarys.Any() == false) + sb.Remove(sb.Length - 1, 1); + else { + sb.Append(" \r\n CONSTRAINT ").Append(tbname[0]).Append("_").Append(tbname[1]).Append("_pk PRIMARY KEY ("); + foreach (var tbcol in tb.Primarys) sb.Append(_commonUtils.QuoteSqlName(tbcol.Attribute.Name)).Append(", "); + sb.Remove(sb.Length - 2, 2).Append(")"); + } + sb.Append("\r\n) LOGGING \r\nNOCOMPRESS \r\nNOCACHE\r\n;\r\n"); + sb.Append("INSERT INTO ").Append(tmptablename).Append(" ("); + foreach (var tbcol in tb.Columns.Values) + sb.Append(_commonUtils.QuoteSqlName(tbcol.Attribute.Name)).Append(", "); + sb.Remove(sb.Length - 2, 2).Append(")\r\nSELECT "); + foreach (var tbcol in tb.Columns.Values) { + 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 = $"nvl({insertvalue},{_commonUtils.FormatSql("{0}", tbcol.Attribute.DbDefautValue).Replace("'", "''")})"; + } else if (tbcol.Attribute.IsNullable == false) + insertvalue = _commonUtils.FormatSql("{0}", tbcol.Attribute.DbDefautValue).Replace("'", "''"); + 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 seqcol in seqcols) { + var tbname = seqcol.Item2; + var seqname = Utils.GetCsName($"{tbname[0]}.{tbname[1]}_seq_{seqcol.Item1.Attribute.Name}"); + var tbname2 = _commonUtils.QuoteSqlName($"{tbname[0]}.{tbname[1]}"); + var colname2 = _commonUtils.QuoteSqlName(seqcol.Item1.Attribute.Name); + sb.Append("DROP SEQUENCE ").Append(seqname).Append(";\r\n"); + if (seqcol.Item3) { + var startWith = _orm.Ado.ExecuteScalar(CommandType.Text, $" select nvl({colname2},0) from {tbname2}"); + sb.Append("CREATE SEQUENCE ").Append(seqname).Append(" start with ").Append(startWith).Append(";\r\n"); + } + } + return sb.Length == 0 ? null : sb.ToString(); + } finally { + try { + conn.Value.ChangeDatabase(database); + _orm.Ado.MasterPool.Return(conn); + } catch { + _orm.Ado.MasterPool.Return(conn, true); + } + } + } + + ConcurrentDictionary dicSyced = new ConcurrentDictionary(); + public bool SyncStructure() => this.SyncStructure(typeof(TEntity)); + public bool SyncStructure(params Type[] entityTypes) { + if (entityTypes == null) return true; + var syncTypes = entityTypes.Where(a => dicSyced.ContainsKey(a.FullName) == false).ToArray(); + if (syncTypes.Any() == false) return true; + var ddl = this.GetComparisonDDLStatements(syncTypes); + if (string.IsNullOrEmpty(ddl)) { + foreach (var syncType in syncTypes) dicSyced.TryAdd(syncType.FullName, true); + return true; + } + var affrows = _orm.Ado.ExecuteNonQuery(CommandType.Text, ddl); + foreach (var syncType in syncTypes) dicSyced.TryAdd(syncType.FullName, true); + return affrows > 0; + } + + } +} \ No newline at end of file diff --git a/FreeSql/Oracle/OracleDbFirst.cs b/FreeSql/Oracle/OracleDbFirst.cs new file mode 100644 index 00000000..8966920c --- /dev/null +++ b/FreeSql/Oracle/OracleDbFirst.cs @@ -0,0 +1,385 @@ +using FreeSql.DatabaseModel; +using FreeSql.Internal; +using MySql.Data.MySqlClient; +using System; +using System.Collections.Generic; +using System.Data; +using System.Linq; +using System.Text.RegularExpressions; + +namespace FreeSql.Oracle { + class OracleDbFirst : IDbFirst { + IFreeSql _orm; + protected CommonUtils _commonUtils; + protected CommonExpression _commonExpression; + public OracleDbFirst(IFreeSql orm, CommonUtils commonUtils, CommonExpression commonExpression) { + _orm = orm; + _commonUtils = commonUtils; + _commonExpression = commonExpression; + } + + public int GetDbType(DbColumnInfo column) => (int)GetMySqlDbType(column); + MySqlDbType GetMySqlDbType(DbColumnInfo column) { + var is_unsigned = column.DbTypeTextFull.ToLower().EndsWith(" unsigned"); + switch (column.DbTypeText.ToLower()) { + case "bit": return MySqlDbType.Bit; + + case "tinyint": return is_unsigned ? MySqlDbType.UByte : MySqlDbType.Byte; + case "smallint": return is_unsigned ? MySqlDbType.UInt16 : MySqlDbType.Int16; + case "mediumint": return is_unsigned ? MySqlDbType.UInt24 : MySqlDbType.Int24; + case "int": return is_unsigned ? MySqlDbType.UInt32 : MySqlDbType.Int32; + case "bigint": return is_unsigned ? MySqlDbType.UInt64 : MySqlDbType.Int64; + + case "real": + case "double": return MySqlDbType.Double; + case "float": return MySqlDbType.Float; + case "numeric": + case "decimal": return MySqlDbType.Decimal; + + case "year": return MySqlDbType.Year; + case "time": return MySqlDbType.Time; + case "date": return MySqlDbType.Date; + case "timestamp": return MySqlDbType.Timestamp; + case "datetime": return MySqlDbType.DateTime; + + case "tinyblob": return MySqlDbType.TinyBlob; + case "blob": return MySqlDbType.Blob; + case "mediumblob": return MySqlDbType.MediumBlob; + case "longblob": return MySqlDbType.LongBlob; + + case "binary": return MySqlDbType.Binary; + case "varbinary": return MySqlDbType.VarBinary; + + case "tinytext": return MySqlDbType.TinyText; + case "text": return MySqlDbType.Text; + case "mediumtext": return MySqlDbType.MediumText; + case "longtext": return MySqlDbType.LongText; + + case "char": return column.MaxLength == 36 ? MySqlDbType.Guid : MySqlDbType.String; + case "varchar": return MySqlDbType.VarChar; + + case "set": return MySqlDbType.Set; + case "enum": return MySqlDbType.Enum; + + case "point": return MySqlDbType.Geometry; + case "linestring": return MySqlDbType.Geometry; + case "polygon": return MySqlDbType.Geometry; + case "geometry": return MySqlDbType.Geometry; + case "multipoint": return MySqlDbType.Geometry; + case "multilinestring": return MySqlDbType.Geometry; + case "multipolygon": return MySqlDbType.Geometry; + case "geometrycollection": return MySqlDbType.Geometry; + default: return MySqlDbType.String; + } + } + + static readonly Dictionary _dicDbToCs = new Dictionary() { + { (int)MySqlDbType.Bit, ("(bool?)", "{0} == \"1\"", "{0} == true ? \"1\" : \"0\"", "bool?", typeof(bool), typeof(bool?), "{0}.Value", "GetBoolean") }, + + { (int)MySqlDbType.Byte, ("(sbyte?)", "sbyte.Parse({0})", "{0}.ToString()", "sbyte?", typeof(sbyte), typeof(sbyte?), "{0}.Value", "GetByte") }, + { (int)MySqlDbType.Int16, ("(short?)", "short.Parse({0})", "{0}.ToString()", "short?", typeof(short), typeof(short?), "{0}.Value", "GetInt16") }, + { (int)MySqlDbType.Int24, ("(int?)", "int.Parse({0})", "{0}.ToString()", "int?", typeof(int), typeof(int?), "{0}.Value", "GetInt32") }, + { (int)MySqlDbType.Int32, ("(int?)", "int.Parse({0})", "{0}.ToString()", "int?", typeof(int), typeof(int?), "{0}.Value", "GetInt32") }, + { (int)MySqlDbType.Int64, ("(long?)", "long.Parse({0})", "{0}.ToString()", "long?", typeof(long), typeof(long?), "{0}.Value", "GetInt64") }, + + { (int)MySqlDbType.UByte, ("(byte?)", "byte.Parse({0})", "{0}.ToString()", "byte?", typeof(byte), typeof(byte?), "{0}.Value", "GetByte") }, + { (int)MySqlDbType.UInt16, ("(ushort?)", "ushort.Parse({0})", "{0}.ToString()", "ushort?", typeof(ushort), typeof(ushort?), "{0}.Value", "GetInt16") }, + { (int)MySqlDbType.UInt24, ("(uint?)", "uint.Parse({0})", "{0}.ToString()", "uint?", typeof(uint), typeof(uint?), "{0}.Value", "GetInt32") }, + { (int)MySqlDbType.UInt32, ("(uint?)", "uint.Parse({0})", "{0}.ToString()", "uint?", typeof(uint), typeof(uint?), "{0}.Value", "GetInt32") }, + { (int)MySqlDbType.UInt64, ("(ulong?)", "ulong.Parse({0})", "{0}.ToString()", "ulong?", typeof(ulong), typeof(ulong?), "{0}.Value", "GetInt64") }, + + { (int)MySqlDbType.Double, ("(double?)", "double.Parse({0})", "{0}.ToString()", "double?", typeof(double), typeof(double?), "{0}.Value", "GetDouble") }, + { (int)MySqlDbType.Float, ("(float?)", "float.Parse({0})", "{0}.ToString()", "float?", typeof(float), typeof(float?), "{0}.Value", "GetFloat") }, + { (int)MySqlDbType.Decimal, ("(decimal?)", "decimal.Parse({0})", "{0}.ToString()", "decimal?", typeof(decimal), typeof(decimal?), "{0}.Value", "GetDecimal") }, + + { (int)MySqlDbType.Year, ("(int?)", "int.Parse({0})", "{0}.ToString()", "int?", typeof(int), typeof(int?), "{0}.Value", "GetInt32") }, + { (int)MySqlDbType.Time, ("(TimeSpan?)", "TimeSpan.Parse(double.Parse({0}))", "{0}.Ticks.ToString()", "TimeSpan?", typeof(TimeSpan), typeof(TimeSpan?), "{0}.Value", "GetValue") }, + { (int)MySqlDbType.Date, ("(DateTime?)", "new DateTime(long.Parse({0}))", "{0}.Ticks.ToString()", "DateTime?", typeof(DateTime), typeof(DateTime?), "{0}.Value", "GetDateTime") }, + { (int)MySqlDbType.Timestamp, ("(DateTime?)", "new DateTime(long.Parse({0}))", "{0}.Ticks.ToString()", "DateTime?", typeof(DateTime), typeof(DateTime?), "{0}.Value", "GetDateTime") }, + { (int)MySqlDbType.DateTime, ("(DateTime?)", "new DateTime(long.Parse({0}))", "{0}.Ticks.ToString()", "DateTime?", typeof(DateTime), typeof(DateTime?), "{0}.Value", "GetDateTime") }, + + { (int)MySqlDbType.TinyBlob, ("(byte[])", "Convert.FromBase64String({0})", "Convert.ToBase64String({0})", "byte[]", typeof(byte[]), typeof(byte[]), "{0}", "GetValue") }, + { (int)MySqlDbType.Blob, ("(byte[])", "Convert.FromBase64String({0})", "Convert.ToBase64String({0})", "byte[]", typeof(byte[]), typeof(byte[]), "{0}", "GetValue") }, + { (int)MySqlDbType.MediumBlob, ("(byte[])", "Convert.FromBase64String({0})", "Convert.ToBase64String({0})", "byte[]", typeof(byte[]), typeof(byte[]), "{0}", "GetValue") }, + { (int)MySqlDbType.LongBlob, ("(byte[])", "Convert.FromBase64String({0})", "Convert.ToBase64String({0})", "byte[]", typeof(byte[]), typeof(byte[]), "{0}", "GetValue") }, + + { (int)MySqlDbType.Binary, ("(byte[])", "Convert.FromBase64String({0})", "Convert.ToBase64String({0})", "byte[]", typeof(byte[]), typeof(byte[]), "{0}", "GetValue") }, + { (int)MySqlDbType.VarBinary, ("(byte[])", "Convert.FromBase64String({0})", "Convert.ToBase64String({0})", "byte[]", typeof(byte[]), typeof(byte[]), "{0}", "GetValue") }, + + { (int)MySqlDbType.TinyText, ("", "{0}.Replace(StringifySplit, \"|\")", "{0}.Replace(\"|\", StringifySplit)", "string", typeof(string), typeof(string), "{0}", "GetString") }, + { (int)MySqlDbType.Text, ("", "{0}.Replace(StringifySplit, \"|\")", "{0}.Replace(\"|\", StringifySplit)", "string", typeof(string), typeof(string), "{0}", "GetString") }, + { (int)MySqlDbType.MediumText, ("", "{0}.Replace(StringifySplit, \"|\")", "{0}.Replace(\"|\", StringifySplit)", "string", typeof(string), typeof(string), "{0}", "GetString") }, + { (int)MySqlDbType.LongText, ("", "{0}.Replace(StringifySplit, \"|\")", "{0}.Replace(\"|\", StringifySplit)", "string", typeof(string), typeof(string), "{0}", "GetString") }, + + { (int)MySqlDbType.Guid, ("(Guid?)", "Guid.Parse({0})", "{0}.ToString()", "Guid?", typeof(Guid), typeof(Guid?), "{0}", "GetString") }, + { (int)MySqlDbType.String, ("", "{0}.Replace(StringifySplit, \"|\")", "{0}.Replace(\"|\", StringifySplit)", "string", typeof(string), typeof(string), "{0}", "GetString") }, + { (int)MySqlDbType.VarString, ("", "{0}.Replace(StringifySplit, \"|\")", "{0}.Replace(\"|\", StringifySplit)", "string", typeof(string), typeof(string), "{0}", "GetString") }, + { (int)MySqlDbType.VarChar, ("", "{0}.Replace(StringifySplit, \"|\")", "{0}.Replace(\"|\", StringifySplit)", "string", typeof(string), typeof(string), "{0}", "GetString") }, + + { (int)MySqlDbType.Set, ("(long?)", "long.Parse({0})", "{0}.ToInt64().ToString()", "Set", typeof(bool), typeof(Enum), "{0}", "GetInt64") }, + { (int)MySqlDbType.Enum, ("(long?)", "long.Parse({0})", "{0}.ToInt64().ToString()", "Enum", typeof(bool), typeof(Enum), "{0}", "GetInt64") }, + + { (int)MySqlDbType.Geometry, ("(MygisGeometry)", "MygisGeometry.Parse({0}.Replace(StringifySplit, \"|\"))", "{0}.AsText().Replace(\"|\", StringifySplit)", "MygisGeometry", typeof(MygisGeometry), typeof(MygisGeometry), "{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 GetDatabases() { + var sql = @" select username from sys.dba_users"; + var ds = _orm.Ado.ExecuteArray(CommandType.Text, sql); + return ds.Select(a => a.FirstOrDefault()?.ToString()).ToList(); + } + + public List GetTablesByDatabase(params string[] database) { + var loc1 = new List(); + var loc2 = new Dictionary(); + var loc3 = new Dictionary>(); + + if (database == null || database.Any() == false) return loc1; + var databaseIn = string.Join(",", database.Select(a => "{0}".FormatMySql(a))); + var sql = string.Format(@" +select +concat(a.table_schema, '.', a.table_name) 'id', +a.table_schema 'schema', +a.table_name 'table', +a.table_type 'type' +from information_schema.tables a +where a.table_schema in ({0})", databaseIn); + var ds = _orm.Ado.ExecuteArray(CommandType.Text, sql); + if (ds == null) return loc1; + + var loc6 = new List(); + var loc66 = new List(); + 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 type = string.Concat(row[3]) == "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, Type = type }); + loc3.Add(table_id, new Dictionary()); + switch (type) { + case DbTableType.TABLE: + case DbTableType.VIEW: + loc6.Add(table.Replace("'", "''")); + break; + case DbTableType.StoreProcedure: + loc66.Add(table.Replace("'", "''")); + break; + } + } + if (loc6.Count == 0) return loc1; + var loc8 = "'" + string.Join("','", loc6.ToArray()) + "'"; + var loc88 = "'" + string.Join("','", loc66.ToArray()) + "'"; + + sql = string.Format(@" +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' +from information_schema.columns a +where a.table_schema in ({1}) and a.table_name in ({0}) +", loc8, databaseIn); + 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]); + 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], + Coment = comment + }); + loc3[table_id][column].DbType = this.GetDbType(loc3[table_id][column]); + loc3[table_id][column].CsType = this.GetCsTypeInfo(loc3[table_id][column]); + } + + sql = string.Format(@" +select +concat(a.constraint_schema, '.', a.table_name) 'table_id', +a.column_name, +concat(a.constraint_schema, '/', a.table_name, '/', a.constraint_name) 'index_id', +1 'IsUnique', +case when constraint_name = 'PRIMARY' then 1 else 0 end 'IsPrimaryKey', +0 'IsClustered', +0 'IsDesc' +from information_schema.key_column_usage a +where a.constraint_schema in ({1}) and a.table_name in ({0}) and isnull(position_in_unique_constraint) +", loc8, databaseIn); + ds = _orm.Ado.ExecuteArray(CommandType.Text, sql); + if (ds == null) return loc1; + + var indexColumns = new Dictionary>>(); + var uniqueColumns = new Dictionary>>(); + 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"; + int is_desc = int.Parse(string.Concat(row[6])); + 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> loc10 = null; + List loc11 = null; + if (!indexColumns.TryGetValue(table_id, out loc10)) + indexColumns.Add(table_id, loc10 = new Dictionary>()); + if (!loc10.TryGetValue(index_id, out loc11)) + loc10.Add(index_id, loc11 = new List()); + loc11.Add(loc9); + if (is_unique) { + if (!uniqueColumns.TryGetValue(table_id, out loc10)) + uniqueColumns.Add(table_id, loc10 = new Dictionary>()); + if (!loc10.TryGetValue(index_id, out loc11)) + loc10.Add(index_id, loc11 = new List()); + loc11.Add(loc9); + } + } + foreach (string table_id in indexColumns.Keys) { + foreach (var columns in indexColumns[table_id].Values) + loc2[table_id].Indexes.Add(columns); + } + foreach (string table_id in uniqueColumns.Keys) { + foreach (var columns in uniqueColumns[table_id].Values) { + columns.Sort((c1, c2) => c1.Name.CompareTo(c2.Name)); + loc2[table_id].Uniques.Add(columns); + } + } + + sql = string.Format(@" +select +concat(a.constraint_schema, '.', a.table_name) 'table_id', +a.column_name, +concat(a.constraint_schema, '/', 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 a.constraint_schema in ({1}) and a.table_name in ({0}) and not isnull(position_in_unique_constraint) +", loc8, databaseIn); + ds = _orm.Ado.ExecuteArray(CommandType.Text, sql); + if (ds == null) return loc1; + + var fkColumns = new Dictionary>(); + 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 loc12 = null; + DbForeignInfo loc13 = null; + if (!fkColumns.TryGetValue(table_id, out loc12)) + fkColumns.Add(table_id, loc12 = new Dictionary()); + 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].Values) + loc2[table_id].Foreigns.Add(fk); + + 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.Uniques.Count > 0) { + foreach (var loc5 in loc4.Uniques[0]) { + loc5.IsPrimary = true; + loc4.Primarys.Add(loc5); + } + } + 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.Foreigns.Find(fk => fk.Columns.Find(c3 => c3.Name == c1.Name) != null) != null; + bool b2 = loc4.Foreigns.Find(fk => fk.Columns.Find(c3 => c3.Name == c2.Name) != null) != null; + 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; + }); + foreach(var loc4 in loc1) { + var dicUniques = new Dictionary>(); + if (loc4.Primarys.Count > 0) dicUniques.Add(string.Join(",", loc4.Primarys.Select(a => a.Name)), loc4.Primarys); + foreach(var loc5 in loc4.Uniques) { + var dickey = string.Join(",", loc5.Select(a => a.Name)); + if (dicUniques.ContainsKey(dickey)) continue; + dicUniques.Add(dickey, loc5); + } + loc4.Uniques = dicUniques.Values.ToList(); + } + + loc2.Clear(); + loc3.Clear(); + return loc1; + } + + public List GetEnumsByDatabase(params string[] database) { + return new List(); + } + } +} \ No newline at end of file diff --git a/FreeSql/Oracle/OracleExpression.cs b/FreeSql/Oracle/OracleExpression.cs new file mode 100644 index 00000000..e8d5c180 --- /dev/null +++ b/FreeSql/Oracle/OracleExpression.cs @@ -0,0 +1,315 @@ +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.Oracle { + class OracleExpression : CommonExpression { + + public OracleExpression(CommonUtils common) : base(common) { } + + internal override string ExpressionLambdaToSqlOther(Expression exp, List _tables, List _selectColumnMap, Func getSelectGroupingMapString, SelectTableInfoType tbtype, bool isQuoteName) { + Func getExp = exparg => ExpressionLambdaToSql(exparg, _tables, _selectColumnMap, getSelectGroupingMapString, tbtype, isQuoteName); + switch (exp.NodeType) { + case ExpressionType.Call: + var callExp = exp as MethodCallExpression; + var objExp = callExp.Object; + var objType = objExp?.Type; + if (objType?.FullName == "System.Byte[]") return null; + + var argIndex = 0; + if (objType == null && callExp.Method.DeclaringType.FullName == typeof(Enumerable).FullName) { + objExp = callExp.Arguments.FirstOrDefault(); + objType = objExp?.Type; + argIndex++; + } + if (objType == null) objType = callExp.Method.DeclaringType; + if (objType != null) { + var left = objExp == null ? null : getExp(objExp); + if (objType.IsArray == true) { + switch (callExp.Method.Name) { + case "Contains": + //判断 in + return $"({getExp(callExp.Arguments[argIndex])}) in {left}"; + } + } + } + break; + case ExpressionType.NewArrayInit: + var arrExp = exp as NewArrayExpression; + var arrSb = new StringBuilder(); + arrSb.Append("("); + for (var a = 0; a < arrExp.Expressions.Count; a++) { + if (a > 0) arrSb.Append(","); + arrSb.Append(getExp(arrExp.Expressions[a])); + } + return arrSb.Append(")").ToString(); + } + return null; + } + + internal override string ExpressionLambdaToSqlMemberAccessString(MemberExpression exp, List _tables, List _selectColumnMap, Func getSelectGroupingMapString, SelectTableInfoType tbtype, bool isQuoteName) { + if (exp.Expression == null) { + switch (exp.Member.Name) { + case "Empty": return "''"; + } + return null; + } + var left = ExpressionLambdaToSql(exp.Expression, _tables, _selectColumnMap, getSelectGroupingMapString, tbtype, isQuoteName); + switch (exp.Member.Name) { + case "Length": return $"char_length({left})"; + } + return null; + } + internal override string ExpressionLambdaToSqlMemberAccessDateTime(MemberExpression exp, List _tables, List _selectColumnMap, Func getSelectGroupingMapString, SelectTableInfoType tbtype, bool isQuoteName) { + if (exp.Expression == null) { + switch (exp.Member.Name) { + case "Now": return "now()"; + case "UtcNow": return "utc_timestamp()"; + 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, _tables, _selectColumnMap, getSelectGroupingMapString, tbtype, isQuoteName); + 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; + } + internal override string ExpressionLambdaToSqlMemberAccessTimeSpan(MemberExpression exp, List _tables, List _selectColumnMap, Func getSelectGroupingMapString, SelectTableInfoType tbtype, bool isQuoteName) { + 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, _tables, _selectColumnMap, getSelectGroupingMapString, tbtype, isQuoteName); + 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; + } + + internal override string ExpressionLambdaToSqlCallString(MethodCallExpression exp, List _tables, List _selectColumnMap, Func getSelectGroupingMapString, SelectTableInfoType tbtype, bool isQuoteName) { + Func getExp = exparg => ExpressionLambdaToSql(exparg, _tables, _selectColumnMap, getSelectGroupingMapString, tbtype, isQuoteName); + if (exp.Object == null) { + switch (exp.Method.Name) { + case "IsNullOrEmpty": + var arg1 = getExp(exp.Arguments[0]); + return $"({arg1} is null or {arg1} = '')"; + } + } else { + var left = getExp(exp.Object); + switch (exp.Method.Name) { + case "StartsWith": + case "EndsWith": + case "Contains": + var args0Value = getExp(exp.Arguments[0]); + if (args0Value == "NULL") return $"({left}) IS NULL"; + if (exp.Method.Name == "StartsWith") return $"({left}) LIKE {(args0Value.EndsWith("'") ? args0Value.Insert(args0Value.Length - 1, "%") : $"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({left}, {indexOfFindStr}, {locateArgs1})-1)"; + } + return $"(locate({left}, {indexOfFindStr})-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])})"; + } + } + throw new Exception($"MySqlExpression 未现实函数表达式 {exp} 解析"); + } + internal override string ExpressionLambdaToSqlCallMath(MethodCallExpression exp, List _tables, List _selectColumnMap, Func getSelectGroupingMapString, SelectTableInfoType tbtype, bool isQuoteName) { + Func getExp = exparg => ExpressionLambdaToSql(exparg, _tables, _selectColumnMap, getSelectGroupingMapString, tbtype, isQuoteName); + 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)"; + } + throw new Exception($"MySqlExpression 未现实函数表达式 {exp} 解析"); + } + internal override string ExpressionLambdaToSqlCallDateTime(MethodCallExpression exp, List _tables, List _selectColumnMap, Func getSelectGroupingMapString, SelectTableInfoType tbtype, bool isQuoteName) { + Func getExp = exparg => ExpressionLambdaToSql(exparg, _tables, _selectColumnMap, getSelectGroupingMapString, tbtype, isQuoteName); + 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 $"cast({getExp(exp.Arguments[0])} as datetime)"; + case "ParseExact": + case "TryParse": + case "TryParseExact": return $"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": + if (exp.Arguments[0].Type.FullName == "System.DateTime" || exp.Arguments[0].Type.GenericTypeArguments.FirstOrDefault()?.FullName == "System.DateTime") + return $"timestampdiff(microsecond, {args1}, {left})"; + if (exp.Arguments[0].Type.FullName == "System.TimeSpan" || exp.Arguments[0].Type.GenericTypeArguments.FirstOrDefault()?.FullName == "System.TimeSpan") + return $"date_sub({left}, interval ({args1}) microsecond)"; + break; + case "Equals": return $"({left} = {getExp(exp.Arguments[0])})"; + case "CompareTo": return $"(({left}) - ({getExp(exp.Arguments[0])}))"; + case "ToString": return $"date_format({left}, '%Y-%m-%d %H:%i:%s.%f')"; + } + } + throw new Exception($"MySqlExpression 未现实函数表达式 {exp} 解析"); + } + internal override string ExpressionLambdaToSqlCallTimeSpan(MethodCallExpression exp, List _tables, List _selectColumnMap, Func getSelectGroupingMapString, SelectTableInfoType tbtype, bool isQuoteName) { + Func getExp = exparg => ExpressionLambdaToSql(exparg, _tables, _selectColumnMap, getSelectGroupingMapString, tbtype, isQuoteName); + 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} = {getExp(exp.Arguments[0])})"; + case "CompareTo": return $"({left}-({getExp(exp.Arguments[0])}))"; + case "ToString": return $"cast({left} as char)"; + } + } + throw new Exception($"MySqlExpression 未现实函数表达式 {exp} 解析"); + } + internal override string ExpressionLambdaToSqlCallConvert(MethodCallExpression exp, List _tables, List _selectColumnMap, Func getSelectGroupingMapString, SelectTableInfoType tbtype, bool isQuoteName) { + Func getExp = exparg => ExpressionLambdaToSql(exparg, _tables, _selectColumnMap, getSelectGroupingMapString, tbtype, isQuoteName); + 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 $"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)"; + } + } + throw new Exception($"MySqlExpression 未现实函数表达式 {exp} 解析"); + } + } +} diff --git a/FreeSql/Oracle/OracleProvider.cs b/FreeSql/Oracle/OracleProvider.cs new file mode 100644 index 00000000..7e3c8bd8 --- /dev/null +++ b/FreeSql/Oracle/OracleProvider.cs @@ -0,0 +1,49 @@ +using FreeSql.Internal; +using FreeSql.Internal.CommonProvider; +using FreeSql.Oracle.Curd; +using Microsoft.Extensions.Caching.Distributed; +using Microsoft.Extensions.Configuration; +using Microsoft.Extensions.Logging; +using System; +using System.Collections.Generic; +using System.Data.Common; + +namespace FreeSql.Oracle { + + class OracleProvider : IFreeSql { + + public ISelect Select() where T1 : class => new OracleSelect(this, this.InternalCommonUtils, this.InternalCommonExpression, null); + public ISelect Select(object dywhere) where T1 : class => new OracleSelect(this, this.InternalCommonUtils, this.InternalCommonExpression, dywhere); + public IInsert Insert() where T1 : class => new OracleInsert(this, this.InternalCommonUtils, this.InternalCommonExpression); + public IInsert Insert(T1 source) where T1 : class => this.Insert().AppendData(source); + public IInsert Insert(IEnumerable source) where T1 : class => this.Insert().AppendData(source); + public IUpdate Update() where T1 : class => new OracleUpdate(this, this.InternalCommonUtils, this.InternalCommonExpression, null); + public IUpdate Update(object dywhere) where T1 : class => new OracleUpdate(this, this.InternalCommonUtils, this.InternalCommonExpression, dywhere); + public IDelete Delete() where T1 : class => new OracleDelete(this, this.InternalCommonUtils, this.InternalCommonExpression, null); + public IDelete Delete(object dywhere) where T1 : class => new OracleDelete(this, this.InternalCommonUtils, this.InternalCommonExpression, dywhere); + + public IAdo Ado { get; } + public ICache Cache { get; } + public ICodeFirst CodeFirst { get; } + public IDbFirst DbFirst { get; } + public OracleProvider(IDistributedCache cache, ILogger log, string masterConnectionString, string[] slaveConnectionString) { + if (log == null) log = new LoggerFactory(new[] { new Microsoft.Extensions.Logging.Debug.DebugLoggerProvider() }).CreateLogger("FreeSql.Oracle"); + + this.InternalCommonUtils = new OracleUtils(this); + this.InternalCommonExpression = new OracleExpression(this.InternalCommonUtils); + + this.Cache = new CacheProvider(cache, log); + this.Ado = new OracleAdo(this.InternalCommonUtils, this.Cache, log, masterConnectionString, slaveConnectionString); + + this.DbFirst = new OracleDbFirst(this, this.InternalCommonUtils, this.InternalCommonExpression); + this.InternalCommonUtils.CodeFirst = this.CodeFirst = new OracleCodeFirst(this, this.InternalCommonUtils, this.InternalCommonExpression); + } + + internal CommonUtils InternalCommonUtils { get; } + internal CommonExpression InternalCommonExpression { get; } + + public void Transaction(Action handler) => Ado.Transaction(handler); + + public void Transaction(Action handler, TimeSpan timeout) => Ado.Transaction(handler, timeout); + } +} diff --git a/FreeSql/Oracle/OracleUtils.cs b/FreeSql/Oracle/OracleUtils.cs new file mode 100644 index 00000000..6e6a095c --- /dev/null +++ b/FreeSql/Oracle/OracleUtils.cs @@ -0,0 +1,47 @@ +using FreeSql.Internal; +using FreeSql.Internal.Model; +using Oracle.ManagedDataAccess.Client; +using System; +using System.Collections.Generic; +using System.Data.Common; + +namespace FreeSql.Oracle { + + class OracleUtils : CommonUtils { + IFreeSql _orm; + public OracleUtils(IFreeSql orm) { + _orm = orm; + } + + internal override DbParameter AppendParamter(List _params, string parameterName, Type type, object value) { + if (string.IsNullOrEmpty(parameterName)) parameterName = $"p_{_params?.Count}"; + else if (_orm.CodeFirst.IsSyncStructureToLower) parameterName = parameterName.ToLower(); + var ret = new OracleParameter { ParameterName = $"@{parameterName}", Value = value }; + var tp = _orm.CodeFirst.GetDbInfo(type)?.type; + if (tp != null) { + ret.OracleDbType = (OracleDbType)tp.Value; + } + _params?.Add(ret); + return ret; + } + + internal override DbParameter[] GetDbParamtersByObject(string sql, object obj) => + Utils.GetDbParamtersByObject(sql, obj, "@", (name, type, value) => { + var ret = new OracleParameter { ParameterName = $"@{name}", Value = value }; + var tp = _orm.CodeFirst.GetDbInfo(type)?.type; + if (tp != null) { + ret.OracleDbType = (OracleDbType)tp.Value; + } + return ret; + }); + + internal override string FormatSql(string sql, params object[] args) => sql?.FormatOracleSQL(args); + internal override string QuoteSqlName(string name) => $"\"{name.Trim('"').Replace(".", "\".\"")}\""; + internal override string QuoteParamterName(string name) => $"@{(_orm.CodeFirst.IsSyncStructureToLower ? name.ToLower() : name)}"; + internal override string IsNull(string sql, object value) => $"nvl({sql}, {value})"; + internal override string StringConcat(string left, string right, Type leftType, Type rightType) => $"{left} || {right}"; + + internal override string QuoteWriteParamter(Type type, string paramterName) => paramterName; + internal override string QuoteReadColumn(Type type, string columnName) => columnName; + } +} diff --git a/FreeSql/PostgreSQL/Curd/PostgreSQLInsert.cs b/FreeSql/PostgreSQL/Curd/PostgreSQLInsert.cs index 37089eee..4ce0d307 100644 --- a/FreeSql/PostgreSQL/Curd/PostgreSQLInsert.cs +++ b/FreeSql/PostgreSQL/Curd/PostgreSQLInsert.cs @@ -16,13 +16,23 @@ namespace FreeSql.PostgreSQL.Curd { var sql = this.ToSql(); if (string.IsNullOrEmpty(sql)) return 0; - return long.TryParse(string.Concat(_orm.Ado.ExecuteScalar(CommandType.Text, string.Concat(sql, " RETURNING ", _commonUtils.QuoteSqlName(_table.Columns.Where(a => a.Value.Attribute.IsIdentity).FirstOrDefault().Value.Attribute.Name)), _params)), out var trylng) ? trylng : 0; + var identCols = _table.Columns.Where(a => a.Value.Attribute.IsIdentity); + if (identCols.Any() == false) { + _orm.Ado.ExecuteNonQuery(CommandType.Text, sql, _params); + return 0; + } + return long.TryParse(string.Concat(_orm.Ado.ExecuteScalar(CommandType.Text, string.Concat(sql, " RETURNING ", _commonUtils.QuoteSqlName(identCols.First().Value.Attribute.Name)), _params)), out var trylng) ? trylng : 0; } async public override Task ExecuteIdentityAsync() { var sql = this.ToSql(); if (string.IsNullOrEmpty(sql)) return 0; - return long.TryParse(string.Concat(await _orm.Ado.ExecuteScalarAsync(CommandType.Text, string.Concat(sql, " RETURNING ", _commonUtils.QuoteSqlName(_table.Columns.Where(a => a.Value.Attribute.IsIdentity).FirstOrDefault().Value.Attribute.Name)), _params)), out var trylng) ? trylng : 0; + var identCols = _table.Columns.Where(a => a.Value.Attribute.IsIdentity); + if (identCols.Any() == false) { + await _orm.Ado.ExecuteNonQueryAsync(CommandType.Text, sql, _params); + return 0; + } + return long.TryParse(string.Concat(await _orm.Ado.ExecuteScalarAsync(CommandType.Text, string.Concat(sql, " RETURNING ", _commonUtils.QuoteSqlName(identCols.First().Value.Attribute.Name)), _params)), out var trylng) ? trylng : 0; } public override List ExecuteInserted() { diff --git a/FreeSql/PostgreSQL/PostgreSQLAdo/PostgreSQLAdo.cs b/FreeSql/PostgreSQL/PostgreSQLAdo/PostgreSQLAdo.cs index 96b0dfe8..411147a3 100644 --- a/FreeSql/PostgreSQL/PostgreSQLAdo/PostgreSQLAdo.cs +++ b/FreeSql/PostgreSQL/PostgreSQLAdo/PostgreSQLAdo.cs @@ -25,6 +25,7 @@ namespace FreeSql.PostgreSQL { } } } + static DateTime dt1970 = new DateTime(1970, 1, 1); public override object AddslashesProcessParam(object param) { bool isdic = false; diff --git a/FreeSql/PostgreSQL/PostgreSQLAdo/PostgreSQLConnectionPool.cs b/FreeSql/PostgreSQL/PostgreSQLAdo/PostgreSQLConnectionPool.cs index 7aca8408..badeaa43 100644 --- a/FreeSql/PostgreSQL/PostgreSQLAdo/PostgreSQLConnectionPool.cs +++ b/FreeSql/PostgreSQL/PostgreSQLAdo/PostgreSQLConnectionPool.cs @@ -136,7 +136,7 @@ namespace FreeSql.PostgreSQL { } } - public static class DbConnectionExtensions { + static class DbConnectionExtensions { public static bool Ping(this DbConnection that) { try { diff --git a/FreeSql/PostgreSQL/PostgreSQLAdo/PostgreSQLTypesExtensions.cs b/FreeSql/PostgreSQL/PostgreSQLAdo/PostgreSQLTypesExtensions.cs index 647a27ed..72f942fe 100644 --- a/FreeSql/PostgreSQL/PostgreSQLAdo/PostgreSQLTypesExtensions.cs +++ b/FreeSql/PostgreSQL/PostgreSQLAdo/PostgreSQLTypesExtensions.cs @@ -1,6 +1,7 @@ using Npgsql.LegacyPostgis; using NpgsqlTypes; using System; +using System.Collections; public static partial class PostgreSQLTypesExtensions { /// @@ -30,4 +31,35 @@ public static partial class PostgreSQLTypesExtensions { double radLng2 = (double)(point.X) * Math.PI / 180d; return 2 * Math.Asin(Math.Sqrt(Math.Pow(Math.Sin((radLat1 - radLat2) / 2), 2) + Math.Cos(radLat1) * Math.Cos(radLat2) * Math.Pow(Math.Sin((radLng1 - radLng2) / 2), 2))) * 6378137; } + + public static string To1010(this BitArray ba) { + char[] ret = new char[ba.Length]; + for (int a = 0; a < ba.Length; a++) ret[a] = ba[a] ? '1' : '0'; + return new string(ret); + } + + /// + /// 将 1010101010 这样的二进制字符串转换成 BitArray + /// + /// 1010101010 + /// + public static BitArray ToBitArray(this string _1010Str) { + if (_1010Str == null) return null; + BitArray ret = new BitArray(_1010Str.Length); + for (int a = 0; a < _1010Str.Length; a++) ret[a] = _1010Str[a] == '1'; + return ret; + } + + public static NpgsqlRange ToNpgsqlRange(this string that) { + var s = that; + if (string.IsNullOrEmpty(s) || s == "empty") return NpgsqlRange.Empty; + string s1 = s.Trim('(', ')', '[', ']'); + string[] ss = s1.Split(new char[] { ',' }, 2); + if (ss.Length != 2) return NpgsqlRange.Empty; + T t1 = default(T); + T t2 = default(T); + if (!string.IsNullOrEmpty(ss[0])) t1 = (T)Convert.ChangeType(ss[0], typeof(T)); + if (!string.IsNullOrEmpty(ss[1])) t2 = (T)Convert.ChangeType(ss[1], typeof(T)); + return new NpgsqlRange(t1, s[0] == '[', s[0] == '(', t2, s[s.Length - 1] == ']', s[s.Length - 1] == ')'); + } } \ No newline at end of file diff --git a/FreeSql/PostgreSQL/PostgreSQLCodeFirst.cs b/FreeSql/PostgreSQL/PostgreSQLCodeFirst.cs index 92bad45d..96a68414 100644 --- a/FreeSql/PostgreSQL/PostgreSQLCodeFirst.cs +++ b/FreeSql/PostgreSQL/PostgreSQLCodeFirst.cs @@ -132,14 +132,14 @@ namespace FreeSql.PostgreSQL { var tboldname = tb.DbOldName?.Split(new[] { '.' }, 2); //旧表名 if (tboldname?.Length == 1) tboldname = new[] { "public", tboldname[0] }; - if (string.Compare(tbname[0], "public", true) != 0 && _orm.Ado.ExecuteScalar(CommandType.Text, $"select 1 from pg_namespace where nspname='{tbname[0]}'") == null) //创建模式 + if (string.Compare(tbname[0], "public", true) != 0 && _orm.Ado.ExecuteScalar(CommandType.Text, " select 1 from pg_namespace where nspname={0}".FormatPostgreSQL(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 (_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) + 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; } @@ -171,7 +171,8 @@ namespace FreeSql.PostgreSQL { tboldname = null; //如果新表已经存在,不走改表名逻辑 //对比字段,只可以修改类型、增加字段、有限的修改字段名;保证安全不删除字段 - var sql = @"select + var sql = @" +select a.attname, t.typname, case when a.atttypmod > 0 and a.atttypmod < 32767 then a.atttypmod - 4 else a.attlen end len, @@ -194,7 +195,7 @@ where ns.nspname = {0} and c.relname = {1}".FormatPostgreSQL(tboldname ?? tbname var type = string.Concat(a[1]); var sqlType = string.Concat(a[3]); var max_length = long.Parse(string.Concat(a[2])); - switch (sqlType) { + 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; } @@ -288,7 +289,7 @@ where ns.nspname = {0} and c.relname = {1}".FormatPostgreSQL(tboldname ?? tbname 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"); + 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(); diff --git a/FreeSql/PostgreSQL/PostgreSQLDbFirst.cs b/FreeSql/PostgreSQL/PostgreSQLDbFirst.cs index d48cedb5..dfaf9e4b 100644 --- a/FreeSql/PostgreSQL/PostgreSQLDbFirst.cs +++ b/FreeSql/PostgreSQL/PostgreSQLDbFirst.cs @@ -1,10 +1,17 @@ using FreeSql.DatabaseModel; using FreeSql.Internal; -using MySql.Data.MySqlClient; +using Newtonsoft.Json.Linq; +using Npgsql.LegacyPostgis; +using NpgsqlTypes; +using SafeObjectPool; using System; +using System.Collections; using System.Collections.Generic; using System.Data; +using System.Data.Common; using System.Linq; +using System.Net; +using System.Net.NetworkInformation; using System.Text.RegularExpressions; namespace FreeSql.PostgreSQL { @@ -18,107 +25,168 @@ namespace FreeSql.PostgreSQL { _commonExpression = commonExpression; } - public int GetDbType(DbColumnInfo column) => (int)GetMySqlDbType(column); - MySqlDbType GetMySqlDbType(DbColumnInfo column) { - var is_unsigned = column.DbTypeTextFull.ToLower().EndsWith(" unsigned"); - switch (column.DbTypeText.ToLower()) { - case "bit": return MySqlDbType.Bit; + public int GetDbType(DbColumnInfo column) => (int)GetNpgsqlDbType(column); + NpgsqlDbType GetNpgsqlDbType(DbColumnInfo column) { + var dbtype = column.DbTypeText; + var isarray = dbtype.EndsWith("[]"); + if (isarray) dbtype = dbtype.Remove(dbtype.Length - 2); + NpgsqlDbType ret = NpgsqlDbType.Unknown; + switch (dbtype.ToLower().TrimStart('_')) { + case "int2": ret = NpgsqlDbType.Smallint;break; + case "int4": ret = NpgsqlDbType.Integer; break; + case "int8": ret = NpgsqlDbType.Bigint; break; + case "numeric": ret = NpgsqlDbType.Numeric; break; + case "float4": ret = NpgsqlDbType.Real; break; + case "float8": ret = NpgsqlDbType.Double; break; + case "money": ret = NpgsqlDbType.Money; break; - case "tinyint": return is_unsigned ? MySqlDbType.UByte : MySqlDbType.Byte; - case "smallint": return is_unsigned ? MySqlDbType.UInt16 : MySqlDbType.Int16; - case "mediumint": return is_unsigned ? MySqlDbType.UInt24 : MySqlDbType.Int24; - case "int": return is_unsigned ? MySqlDbType.UInt32 : MySqlDbType.Int32; - case "bigint": return is_unsigned ? MySqlDbType.UInt64 : MySqlDbType.Int64; + case "bpchar": ret = NpgsqlDbType.Char; break; + case "varchar": ret = NpgsqlDbType.Varchar; break; + case "text": ret = NpgsqlDbType.Text; break; - case "real": - case "double": return MySqlDbType.Double; - case "float": return MySqlDbType.Float; - case "numeric": - case "decimal": return MySqlDbType.Decimal; + case "timestamp": ret = NpgsqlDbType.Timestamp; break; + case "timestamptz": ret = NpgsqlDbType.TimestampTz; break; + case "date": ret = NpgsqlDbType.Date; break; + case "time": ret = NpgsqlDbType.Time; break; + case "timetz": ret = NpgsqlDbType.TimeTz; break; + case "interval": ret = NpgsqlDbType.Interval; break; - case "year": return MySqlDbType.Year; - case "time": return MySqlDbType.Time; - case "date": return MySqlDbType.Date; - case "timestamp": return MySqlDbType.Timestamp; - case "datetime": return MySqlDbType.DateTime; + case "bool": ret = NpgsqlDbType.Boolean; break; + case "bytea": ret = NpgsqlDbType.Bytea; break; + case "bit": ret = NpgsqlDbType.Bit; break; + case "varbit": ret = NpgsqlDbType.Varbit; break; - case "tinyblob": return MySqlDbType.TinyBlob; - case "blob": return MySqlDbType.Blob; - case "mediumblob": return MySqlDbType.MediumBlob; - case "longblob": return MySqlDbType.LongBlob; + case "point": ret = NpgsqlDbType.Point; break; + case "line": ret = NpgsqlDbType.Line; break; + case "lseg": ret = NpgsqlDbType.LSeg; break; + case "box": ret = NpgsqlDbType.Box; break; + case "path": ret = NpgsqlDbType.Path; break; + case "polygon": ret = NpgsqlDbType.Polygon; break; + case "circle": ret = NpgsqlDbType.Circle; break; - case "binary": return MySqlDbType.Binary; - case "varbinary": return MySqlDbType.VarBinary; + case "cidr": ret = NpgsqlDbType.Cidr; break; + case "inet": ret = NpgsqlDbType.Inet; break; + case "macaddr": ret = NpgsqlDbType.MacAddr; break; - case "tinytext": return MySqlDbType.TinyText; - case "text": return MySqlDbType.Text; - case "mediumtext": return MySqlDbType.MediumText; - case "longtext": return MySqlDbType.LongText; + case "json": ret = NpgsqlDbType.Json; break; + case "jsonb": ret = NpgsqlDbType.Jsonb; break; + case "uuid": ret = NpgsqlDbType.Uuid; break; - case "char": return MySqlDbType.String; - case "varchar": return MySqlDbType.VarChar; + case "int4range": ret = NpgsqlDbType.Range | NpgsqlDbType.Integer; break; + case "int8range": ret = NpgsqlDbType.Range | NpgsqlDbType.Bigint; break; + case "numrange": ret = NpgsqlDbType.Range | NpgsqlDbType.Numeric; break; + case "tsrange": ret = NpgsqlDbType.Range | NpgsqlDbType.Timestamp; break; + case "tstzrange": ret = NpgsqlDbType.Range | NpgsqlDbType.TimestampTz; break; + case "daterange": ret = NpgsqlDbType.Range | NpgsqlDbType.Date; break; - case "set": return MySqlDbType.Set; - case "enum": return MySqlDbType.Enum; - - case "point": return MySqlDbType.Geometry; - case "linestring": return MySqlDbType.Geometry; - case "polygon": return MySqlDbType.Geometry; - case "geometry": return MySqlDbType.Geometry; - case "multipoint": return MySqlDbType.Geometry; - case "multilinestring": return MySqlDbType.Geometry; - case "multipolygon": return MySqlDbType.Geometry; - case "geometrycollection": return MySqlDbType.Geometry; - default: return MySqlDbType.String; + case "hstore": ret = NpgsqlDbType.Hstore; break; + case "geometry": ret = NpgsqlDbType.Geometry; break; } + return isarray ? (ret | NpgsqlDbType.Array) : ret; } static readonly Dictionary _dicDbToCs = new Dictionary() { - { (int)MySqlDbType.Bit, ("(bool?)", "{0} == \"1\"", "{0} == true ? \"1\" : \"0\"", "bool?", typeof(bool), typeof(bool?), "{0}.Value", "GetBoolean") }, + { (int)NpgsqlDbType.Smallint, ("(short?)", "short.Parse({0})", "{0}.ToString()", "short?", typeof(short), typeof(short?), "{0}.Value", "GetInt16") }, + { (int)NpgsqlDbType.Integer, ("(int?)", "int.Parse({0})", "{0}.ToString()", "int?", typeof(int), typeof(int?), "{0}.Value", "GetInt32") }, + { (int)NpgsqlDbType.Bigint, ("(long?)", "long.Parse({0})", "{0}.ToString()", "long?", typeof(long), typeof(long?), "{0}.Value", "GetInt64") }, + { (int)NpgsqlDbType.Numeric, ("(decimal?)", "decimal.Parse({0})", "{0}.ToString()", "decimal?", typeof(decimal), typeof(decimal?), "{0}.Value", "GetDecimal") }, + { (int)NpgsqlDbType.Real, ("(float?)", "float.Parse({0})", "{0}.ToString()", "float?", typeof(float), typeof(float?), "{0}.Value", "GetFloat") }, + { (int)NpgsqlDbType.Double, ("(double?)", "double.Parse({0})", "{0}.ToString()", "double?", typeof(double), typeof(double?), "{0}.Value", "GetDouble") }, + { (int)NpgsqlDbType.Money, ("(decimal?)", "decimal.Parse({0})", "{0}.ToString()", "decimal?", typeof(decimal), typeof(decimal?), "{0}.Value", "GetDecimal") }, - { (int)MySqlDbType.Byte, ("(sbyte?)", "sbyte.Parse({0})", "{0}.ToString()", "sbyte?", typeof(sbyte), typeof(sbyte?), "{0}.Value", "GetByte") }, - { (int)MySqlDbType.Int16, ("(short?)", "short.Parse({0})", "{0}.ToString()", "short?", typeof(short), typeof(short?), "{0}.Value", "GetInt16") }, - { (int)MySqlDbType.Int24, ("(int?)", "int.Parse({0})", "{0}.ToString()", "int?", typeof(int), typeof(int?), "{0}.Value", "GetInt32") }, - { (int)MySqlDbType.Int32, ("(int?)", "int.Parse({0})", "{0}.ToString()", "int?", typeof(int), typeof(int?), "{0}.Value", "GetInt32") }, - { (int)MySqlDbType.Int64, ("(long?)", "long.Parse({0})", "{0}.ToString()", "long?", typeof(long), typeof(long?), "{0}.Value", "GetInt64") }, + { (int)NpgsqlDbType.Char, ("", "{0}.Replace(StringifySplit, \"|\")", "{0}.Replace(\"|\", StringifySplit)", "string", typeof(string), typeof(string), "{0}", "GetString") }, + { (int)NpgsqlDbType.Varchar, ("", "{0}.Replace(StringifySplit, \"|\")", "{0}.Replace(\"|\", StringifySplit)", "string", typeof(string), typeof(string), "{0}", "GetString") }, + { (int)NpgsqlDbType.Text, ("", "{0}.Replace(StringifySplit, \"|\")", "{0}.Replace(\"|\", StringifySplit)", "string", typeof(string), typeof(string), "{0}", "GetString") }, - { (int)MySqlDbType.UByte, ("(byte?)", "byte.Parse({0})", "{0}.ToString()", "byte?", typeof(byte), typeof(byte?), "{0}.Value", "GetByte") }, - { (int)MySqlDbType.UInt16, ("(ushort?)", "ushort.Parse({0})", "{0}.ToString()", "ushort?", typeof(ushort), typeof(ushort?), "{0}.Value", "GetInt16") }, - { (int)MySqlDbType.UInt24, ("(uint?)", "uint.Parse({0})", "{0}.ToString()", "uint?", typeof(uint), typeof(uint?), "{0}.Value", "GetInt32") }, - { (int)MySqlDbType.UInt32, ("(uint?)", "uint.Parse({0})", "{0}.ToString()", "uint?", typeof(uint), typeof(uint?), "{0}.Value", "GetInt32") }, - { (int)MySqlDbType.UInt64, ("(ulong?)", "ulong.Parse({0})", "{0}.ToString()", "ulong?", typeof(ulong), typeof(ulong?), "{0}.Value", "GetInt64") }, + { (int)NpgsqlDbType.Timestamp, ("(DateTime?)", "new DateTime(long.Parse({0}))", "{0}.Ticks.ToString()", "DateTime?", typeof(DateTime), typeof(DateTime?), "{0}.Value", "GetDateTime") }, + { (int)NpgsqlDbType.TimestampTz, ("(DateTime?)", "new DateTime(long.Parse({0}))", "{0}.Ticks.ToString()", "DateTime?", typeof(DateTime), typeof(DateTime?), "{0}.Value", "GetDateTime") }, + { (int)NpgsqlDbType.Date, ("(DateTime?)", "new DateTime(long.Parse({0}))", "{0}.Ticks.ToString()", "DateTime?", typeof(DateTime), typeof(DateTime?), "{0}.Value", "GetDateTime") }, + { (int)NpgsqlDbType.Time, ("(TimeSpan?)", "TimeSpan.Parse(double.Parse({0}))", "{0}.Ticks.ToString()", "TimeSpan?", typeof(TimeSpan), typeof(TimeSpan?), "{0}.Value", "GetValue") }, + { (int)NpgsqlDbType.TimeTz, ("(TimeSpan?)", "TimeSpan.Parse(double.Parse({0}))", "{0}.Ticks.ToString()", "TimeSpan?", typeof(TimeSpan), typeof(TimeSpan?), "{0}.Value", "GetValue") }, + { (int)NpgsqlDbType.Interval, ("(TimeSpan?)", "TimeSpan.Parse(double.Parse({0}))", "{0}.Ticks.ToString()", "TimeSpan?", typeof(TimeSpan), typeof(TimeSpan?), "{0}.Value", "GetValue") }, - { (int)MySqlDbType.Double, ("(double?)", "double.Parse({0})", "{0}.ToString()", "double?", typeof(double), typeof(double?), "{0}.Value", "GetDouble") }, - { (int)MySqlDbType.Float, ("(float?)", "float.Parse({0})", "{0}.ToString()", "float?", typeof(float), typeof(float?), "{0}.Value", "GetFloat") }, - { (int)MySqlDbType.Decimal, ("(decimal?)", "decimal.Parse({0})", "{0}.ToString()", "decimal?", typeof(decimal), typeof(decimal?), "{0}.Value", "GetDecimal") }, + { (int)NpgsqlDbType.Boolean, ("(bool?)", "{0} == \"1\"", "{0} == true ? \"1\" : \"0\"", "bool?", typeof(bool), typeof(bool?), "{0}.Value", "GetBoolean") }, + { (int)NpgsqlDbType.Bytea, ("(byte[])", "Convert.FromBase64String({0})", "Convert.ToBase64String({0})", "byte[]", typeof(byte[]), typeof(byte[]), "{0}", "GetValue") }, + { (int)NpgsqlDbType.Bit, ("(BitArray)", "{0}.ToBitArray()", "{0}.To1010()", "BitArray", typeof(BitArray), typeof(BitArray), "{0}", "GetValue") }, + { (int)NpgsqlDbType.Varbit, ("(BitArray)", "{0}.ToBitArray()", "{0}.To1010()", "BitArray", typeof(BitArray), typeof(BitArray), "{0}", "GetValue") }, - { (int)MySqlDbType.Year, ("(int?)", "int.Parse({0})", "{0}.ToString()", "int?", typeof(int), typeof(int?), "{0}.Value", "GetInt32") }, - { (int)MySqlDbType.Time, ("(TimeSpan?)", "TimeSpan.FromSeconds(double.Parse({0}))", "{0}.ToString()", "TimeSpan?", typeof(TimeSpan), typeof(TimeSpan?), "{0}.Value", "GetValue") }, - { (int)MySqlDbType.Date, ("(DateTime?)", "new DateTime(long.Parse({0}))", "{0}.ToString()", "DateTime?", typeof(DateTime), typeof(DateTime?), "{0}.Value", "GetDateTime") }, - { (int)MySqlDbType.Timestamp, ("(DateTime?)", "new DateTime(long.Parse({0}))", "{0}.TotalSeconds.ToString()", "DateTime?", typeof(DateTime), typeof(DateTime?), "{0}.Value", "GetDateTime") }, - { (int)MySqlDbType.DateTime, ("(DateTime?)", "new DateTime(long.Parse({0}))", "{0}.Ticks.ToString()", "DateTime?", typeof(DateTime), typeof(DateTime?), "{0}.Value", "GetDateTime") }, + { (int)NpgsqlDbType.Point, ("(NpgsqlPoint?)", "NpgsqlPoint.Parse({0})", "{0}.ToString()", "NpgsqlPoint", typeof(NpgsqlPoint), typeof(NpgsqlPoint?), "{0}", "GetValue") }, + { (int)NpgsqlDbType.Line, ("(NpgsqlLine?)", "NpgsqlLine.Parse({0})", "{0}.ToString()", "NpgsqlLine", typeof(NpgsqlLine), typeof(NpgsqlLine?), "{0}", "GetValue") }, + { (int)NpgsqlDbType.LSeg, ("(NpgsqlLSeg?)", "NpgsqlLSeg.Parse({0})", "{0}.ToString()", "NpgsqlLSeg", typeof(NpgsqlLSeg), typeof(NpgsqlLSeg?), "{0}", "GetValue") }, + { (int)NpgsqlDbType.Box, ("(NpgsqlBox?)", "NpgsqlBox.Parse({0})", "{0}.ToString()", "NpgsqlBox", typeof(NpgsqlBox), typeof(NpgsqlBox?), "{0}", "GetValue") }, + { (int)NpgsqlDbType.Path, ("(NpgsqlPath?)", "NpgsqlPath.Parse({0})", "{0}.ToString()", "NpgsqlPath", typeof(NpgsqlPath), typeof(NpgsqlPath?), "{0}", "GetValue") }, + { (int)NpgsqlDbType.Polygon, ("(NpgsqlPolygon?)", "NpgsqlPolygon.Parse({0})", "{0}.ToString()", "NpgsqlPolygon", typeof(NpgsqlPolygon), typeof(NpgsqlPolygon?), "{0}", "GetValue") }, + { (int)NpgsqlDbType.Circle, ("(NpgsqlCircle?)", "NpgsqlCircle.Parse({0})", "{0}.ToString()", "NpgsqlCircle", typeof(NpgsqlCircle), typeof(NpgsqlCircle?), "{0}", "GetValue") }, - { (int)MySqlDbType.TinyBlob, ("(byte[])", "Convert.FromBase64String({0})", "Convert.ToBase64String({0})", "byte[]", typeof(byte[]), typeof(byte[]), "{0}", "GetValue") }, - { (int)MySqlDbType.Blob, ("(byte[])", "Convert.FromBase64String({0})", "Convert.ToBase64String({0})", "byte[]", typeof(byte[]), typeof(byte[]), "{0}", "GetValue") }, - { (int)MySqlDbType.MediumBlob, ("(byte[])", "Convert.FromBase64String({0})", "Convert.ToBase64String({0})", "byte[]", typeof(byte[]), typeof(byte[]), "{0}", "GetValue") }, - { (int)MySqlDbType.LongBlob, ("(byte[])", "Convert.FromBase64String({0})", "Convert.ToBase64String({0})", "byte[]", typeof(byte[]), typeof(byte[]), "{0}", "GetValue") }, + { (int)NpgsqlDbType.Cidr, ("((IPAddress, int)?)", "(IPAddress, int)({0})", "{0}.ToString()", "(IPAddress, int)", typeof((IPAddress, int)), typeof((IPAddress, int)?), "{0}", "GetValue") }, + { (int)NpgsqlDbType.Inet, ("(IPAddress)", "IPAddress.Parse({0})", "{0}.ToString()", "IPAddress", typeof(IPAddress), typeof(IPAddress), "{0}", "GetValue") }, + { (int)NpgsqlDbType.MacAddr, ("(PhysicalAddress?)", "PhysicalAddress.Parse({0})", "{0}.ToString()", "PhysicalAddress", typeof(PhysicalAddress), typeof(PhysicalAddress), "{0}", "GetValue") }, - { (int)MySqlDbType.Binary, ("(byte[])", "Convert.FromBase64String({0})", "Convert.ToBase64String({0})", "byte[]", typeof(byte[]), typeof(byte[]), "{0}", "GetValue") }, - { (int)MySqlDbType.VarBinary, ("(byte[])", "Convert.FromBase64String({0})", "Convert.ToBase64String({0})", "byte[]", typeof(byte[]), typeof(byte[]), "{0}", "GetValue") }, + { (int)NpgsqlDbType.Json, ("(JToken)", "JToken.Parse({0})", "{0}.ToString()", "JToken", typeof(JToken), typeof(JToken), "{0}", "GetString") }, + { (int)NpgsqlDbType.Jsonb, ("(JToken)", "JToken.Parse({0})", "{0}.ToString()", "JToken", typeof(JToken), typeof(JToken), "{0}", "GetString") }, + { (int)NpgsqlDbType.Uuid, ("(Guid?)", "Guid.Parse({0})", "{0}.ToString()", "Guid", typeof(Guid), typeof(Guid?), "{0}", "GetString") }, - { (int)MySqlDbType.TinyText, ("", "{0}.Replace(StringifySplit, \"|\")", "{0}.Replace(\"|\", StringifySplit)", "string", typeof(string), typeof(string), "{0}", "GetString") }, - { (int)MySqlDbType.Text, ("", "{0}.Replace(StringifySplit, \"|\")", "{0}.Replace(\"|\", StringifySplit)", "string", typeof(string), typeof(string), "{0}", "GetString") }, - { (int)MySqlDbType.MediumText, ("", "{0}.Replace(StringifySplit, \"|\")", "{0}.Replace(\"|\", StringifySplit)", "string", typeof(string), typeof(string), "{0}", "GetString") }, - { (int)MySqlDbType.LongText, ("", "{0}.Replace(StringifySplit, \"|\")", "{0}.Replace(\"|\", StringifySplit)", "string", typeof(string), typeof(string), "{0}", "GetString") }, + { (int)(NpgsqlDbType.Range | NpgsqlDbType.Integer), ("(NpgsqlRange?)", "{0}.ToNpgsqlRange()", "{0}.ToString()", "NpgsqlRange", typeof(NpgsqlRange), typeof(NpgsqlRange?), "{0}", "GetString") }, + { (int)(NpgsqlDbType.Range | NpgsqlDbType.Bigint), ("(NpgsqlRange?)", "{0}.ToNpgsqlRange()", "{0}.ToString()", "NpgsqlRange", typeof(NpgsqlRange), typeof(NpgsqlRange?), "{0}", "GetString") }, + { (int)(NpgsqlDbType.Range | NpgsqlDbType.Numeric), ("(NpgsqlRange?)", "{0}.ToNpgsqlRange()", "{0}.ToString()", "NpgsqlRange", typeof(NpgsqlRange), typeof(NpgsqlRange?), "{0}", "GetString") }, + { (int)(NpgsqlDbType.Range | NpgsqlDbType.Timestamp), ("(NpgsqlRange?)", "{0}.ToNpgsqlRange()", "{0}.ToString()", "NpgsqlRange", typeof(NpgsqlRange), typeof(NpgsqlRange?), "{0}", "GetString") }, + { (int)(NpgsqlDbType.Range | NpgsqlDbType.TimestampTz), ("(NpgsqlRange?)", "{0}.ToNpgsqlRange()", "{0}.ToString()", "NpgsqlRange", typeof(NpgsqlRange), typeof(NpgsqlRange?), "{0}", "GetString") }, + { (int)(NpgsqlDbType.Range | NpgsqlDbType.Date), ("(NpgsqlRange?)", "{0}.ToNpgsqlRange()", "{0}.ToString()", "NpgsqlRange", typeof(NpgsqlRange), typeof(NpgsqlRange?), "{0}", "GetString") }, - { (int)MySqlDbType.String, ("", "{0}.Replace(StringifySplit, \"|\")", "{0}.Replace(\"|\", StringifySplit)", "string", typeof(string), typeof(string), "{0}", "GetString") }, - { (int)MySqlDbType.VarString, ("", "{0}.Replace(StringifySplit, \"|\")", "{0}.Replace(\"|\", StringifySplit)", "string", typeof(string), typeof(string), "{0}", "GetString") }, - { (int)MySqlDbType.VarChar, ("", "{0}.Replace(StringifySplit, \"|\")", "{0}.Replace(\"|\", StringifySplit)", "string", typeof(string), typeof(string), "{0}", "GetString") }, + { (int)NpgsqlDbType.Hstore, ("(Dictionary)", "JsonConvert.DeserializeObject>({0})", "JsonConvert.SerializeObject({0})", "Dictionary", typeof(Dictionary), typeof(Dictionary), "{0}", "GetValue") }, + { (int)NpgsqlDbType.Geometry, ("(PostgisGeometry)", "JsonConvert.DeserializeObject({0})", "JsonConvert.SerializeObject({0})", "PostgisGeometry", typeof(PostgisGeometry), typeof(PostgisGeometry), "{0}", "GetValue") }, - { (int)MySqlDbType.Set, ("(long?)", "long.Parse({0})", "{0}.ToInt64().ToString()", "Set", typeof(bool), typeof(Enum), "{0}", "GetInt64") }, - { (int)MySqlDbType.Enum, ("(long?)", "long.Parse({0})", "{0}.ToInt64().ToString()", "Enum", typeof(bool), typeof(Enum), "{0}", "GetInt64") }, + /*** array ***/ - { (int)MySqlDbType.Geometry, ("(MygisGeometry)", "MygisGeometry.Parse({0}.Replace(StringifySplit, \"|\"))", "{0}.AsText().Replace(\"|\", StringifySplit)", "MygisGeometry", typeof(MygisGeometry), typeof(MygisGeometry), "{0}", "GetString") }, + { (int)(NpgsqlDbType.Smallint | NpgsqlDbType.Array), ("(short[])", "JsonConvert.DeserializeObject({0})", "JsonConvert.SerializeObject({0})", "short[]", typeof(short[]), typeof(short[]), "{0}", "GetValue") }, + { (int)(NpgsqlDbType.Integer | NpgsqlDbType.Array), ("(int[])", "JsonConvert.DeserializeObject({0})", "JsonConvert.SerializeObject({0})", "int[]", typeof(int[]), typeof(int[]), "{0}", "GetValue") }, + { (int)(NpgsqlDbType.Bigint | NpgsqlDbType.Array), ("(long[])", "JsonConvert.DeserializeObject({0})", "JsonConvert.SerializeObject({0})", "long[]", typeof(long[]), typeof(long[]), "{0}", "GetValue") }, + { (int)(NpgsqlDbType.Numeric | NpgsqlDbType.Array), ("(decimal[])", "JsonConvert.DeserializeObject({0})", "JsonConvert.SerializeObject({0})", "decimal[]", typeof(decimal[]), typeof(decimal[]), "{0}", "GetValue") }, + { (int)(NpgsqlDbType.Real | NpgsqlDbType.Array), ("(float[])", "JsonConvert.DeserializeObject({0})", "JsonConvert.SerializeObject({0})", "float[]", typeof(float[]), typeof(float[]), "{0}", "GetValue") }, + { (int)(NpgsqlDbType.Double | NpgsqlDbType.Array), ("(double[])", "JsonConvert.DeserializeObject({0})", "JsonConvert.SerializeObject({0})", "double[]", typeof(double[]), typeof(double[]), "{0}", "GetValue") }, + { (int)(NpgsqlDbType.Money | NpgsqlDbType.Array), ("(decimal[])", "JsonConvert.DeserializeObject({0})", "JsonConvert.SerializeObject({0})", "decimal[]", typeof(decimal[]), typeof(decimal[]), "{0}", "GetValue") }, + + { (int)(NpgsqlDbType.Char | NpgsqlDbType.Array), ("(string[])", "JsonConvert.DeserializeObject({0})", "JsonConvert.SerializeObject({0})", "string[]", typeof(string[]), typeof(string[]), "{0}", "GetValue") }, + { (int)(NpgsqlDbType.Varchar | NpgsqlDbType.Array), ("(string[])", "JsonConvert.DeserializeObject({0})", "JsonConvert.SerializeObject({0})", "string[]", typeof(string[]), typeof(string[]), "{0}", "GetValue") }, + { (int)(NpgsqlDbType.Text | NpgsqlDbType.Array), ("(string[])", "JsonConvert.DeserializeObject({0})", "JsonConvert.SerializeObject({0})", "string[]", typeof(string[]), typeof(string[]), "{0}", "GetValue") }, + + { (int)(NpgsqlDbType.Timestamp | NpgsqlDbType.Array), ("(DateTime[])", "JsonConvert.DeserializeObject({0})", "JsonConvert.SerializeObject({0})", "DateTime[]", typeof(DateTime[]), typeof(DateTime[]), "{0}", "GetValue") }, + { (int)(NpgsqlDbType.TimestampTz | NpgsqlDbType.Array), ("(DateTime[])", "JsonConvert.DeserializeObject({0})", "JsonConvert.SerializeObject({0})", "DateTime[]", typeof(DateTime[]), typeof(DateTime[]), "{0}", "GetValue") }, + { (int)(NpgsqlDbType.Date | NpgsqlDbType.Array), ("(DateTime[])", "JsonConvert.DeserializeObject({0})", "JsonConvert.SerializeObject({0})", "DateTime[]", typeof(DateTime[]), typeof(DateTime[]), "{0}", "GetValue") }, + { (int)(NpgsqlDbType.Time | NpgsqlDbType.Array), ("(TimeSpan[])", "JsonConvert.DeserializeObject({0})", "JsonConvert.SerializeObject({0})", "TimeSpan[]", typeof(TimeSpan[]), typeof(TimeSpan[]), "{0}", "GetValue") }, + { (int)(NpgsqlDbType.TimeTz | NpgsqlDbType.Array), ("(TimeSpan[])", "JsonConvert.DeserializeObject({0})", "JsonConvert.SerializeObject({0})", "TimeSpan[]", typeof(TimeSpan[]), typeof(TimeSpan[]), "{0}", "GetValue") }, + { (int)(NpgsqlDbType.Interval | NpgsqlDbType.Array), ("(TimeSpan[])", "JsonConvert.DeserializeObject({0})", "JsonConvert.SerializeObject({0})", "TimeSpan[]", typeof(TimeSpan[]), typeof(TimeSpan[]), "{0}", "GetValue") }, + + { (int)(NpgsqlDbType.Boolean | NpgsqlDbType.Array), ("(bool[])", "JsonConvert.DeserializeObject({0})", "JsonConvert.SerializeObject({0})", "bool[]", typeof(bool[]), typeof(bool[]), "{0}", "GetValue") }, + { (int)(NpgsqlDbType.Bytea | NpgsqlDbType.Array), ("(byte[][])", "JsonConvert.DeserializeObject({0})", "JsonConvert.SerializeObject({0})", "byte[][]", typeof(byte[][]), typeof(byte[][]), "{0}", "GetValue") }, + { (int)(NpgsqlDbType.Bit | NpgsqlDbType.Array), ("(BitArray[])", "JsonConvert.DeserializeObject({0})", "JsonConvert.SerializeObject({0})", "BitArray[]", typeof(BitArray[]), typeof(BitArray[]), "{0}", "GetValue") }, + { (int)(NpgsqlDbType.Varbit | NpgsqlDbType.Array), ("(BitArray[])", "JsonConvert.DeserializeObject({0})", "JsonConvert.SerializeObject({0})", "BitArray[]", typeof(BitArray[]), typeof(BitArray[]), "{0}", "GetValue") }, + + { (int)(NpgsqlDbType.Point | NpgsqlDbType.Array), ("(NpgsqlPoint[])", "JsonConvert.DeserializeObject({0})", "JsonConvert.SerializeObject({0})", "NpgsqlPoint[]", typeof(NpgsqlPoint[]), typeof(NpgsqlPoint[]), "{0}", "GetValue") }, + { (int)(NpgsqlDbType.Line | NpgsqlDbType.Array), ("(NpgsqlLine[])", "JsonConvert.DeserializeObject({0})", "JsonConvert.SerializeObject({0})", "NpgsqlLine[]", typeof(NpgsqlLine[]), typeof(NpgsqlLine[]), "{0}", "GetValue") }, + { (int)(NpgsqlDbType.LSeg | NpgsqlDbType.Array), ("(NpgsqlLSeg[])", "JsonConvert.DeserializeObject({0})", "JsonConvert.SerializeObject({0})", "NpgsqlLSeg[]", typeof(NpgsqlLSeg[]), typeof(NpgsqlLSeg[]), "{0}", "GetValue") }, + { (int)(NpgsqlDbType.Box | NpgsqlDbType.Array), ("(NpgsqlBox[])", "JsonConvert.DeserializeObject({0})", "JsonConvert.SerializeObject({0})", "NpgsqlBox[]", typeof(NpgsqlBox[]), typeof(NpgsqlBox[]), "{0}", "GetValue") }, + { (int)(NpgsqlDbType.Path | NpgsqlDbType.Array), ("(NpgsqlPath[])", "JsonConvert.DeserializeObject({0})", "JsonConvert.SerializeObject({0})", "NpgsqlPath[]", typeof(NpgsqlPath[]), typeof(NpgsqlPath[]), "{0}", "GetValue") }, + { (int)(NpgsqlDbType.Polygon | NpgsqlDbType.Array), ("(NpgsqlPolygon[])", "JsonConvert.DeserializeObject({0})", "JsonConvert.SerializeObject({0})", "NpgsqlPolygon[]", typeof(NpgsqlPolygon[]), typeof(NpgsqlPolygon[]), "{0}", "GetValue") }, + { (int)(NpgsqlDbType.Circle | NpgsqlDbType.Array), ("(NpgsqlCircle[])", "JsonConvert.DeserializeObject({0})", "JsonConvert.SerializeObject({0})", "NpgsqlCircle[]", typeof(NpgsqlCircle[]), typeof(NpgsqlCircle[]), "{0}", "GetValue") }, + + { (int)(NpgsqlDbType.Cidr | NpgsqlDbType.Array), ("((IPAddress, int)[])", "JsonConvert.DeserializeObject<(IPAddress, int)[]>({0})", "JsonConvert.SerializeObject({0})", "(IPAddress, int)[]", typeof((IPAddress, int)[]), typeof((IPAddress, int)[]), "{0}", "GetValue") }, + { (int)(NpgsqlDbType.Inet | NpgsqlDbType.Array), ("(IPAddress[])", "JsonConvert.DeserializeObject({0})", "JsonConvert.SerializeObject({0})", "IPAddress[]", typeof(IPAddress[]), typeof(IPAddress[]), "{0}", "GetValue") }, + { (int)(NpgsqlDbType.MacAddr | NpgsqlDbType.Array), ("(PhysicalAddress[])", "JsonConvert.DeserializeObject({0})", "JsonConvert.SerializeObject({0})", "PhysicalAddress[]", typeof(PhysicalAddress[]), typeof(PhysicalAddress[]), "{0}", "GetValue") }, + + { (int)(NpgsqlDbType.Json | NpgsqlDbType.Array), ("(JToken[])", "JsonConvert.DeserializeObject({0})", "JsonConvert.SerializeObject({0})", "JToken[]", typeof(JToken[]), typeof(JToken[]), "{0}", "GetValue") }, + { (int)(NpgsqlDbType.Jsonb | NpgsqlDbType.Array), ("(JToken[])", "JsonConvert.DeserializeObject({0})", "JsonConvert.SerializeObject({0})", "JToken[]", typeof(JToken[]), typeof(JToken[]), "{0}", "GetValue") }, + { (int)(NpgsqlDbType.Uuid | NpgsqlDbType.Array), ("(Guid[])", "JsonConvert.DeserializeObject({0})", "JsonConvert.SerializeObject({0})", "Guid[]", typeof(Guid[]), typeof(Guid[]), "{0}", "GetValue") }, + + { (int)(NpgsqlDbType.Range | NpgsqlDbType.Integer | NpgsqlDbType.Array), ("(NpgsqlRange[])", "JsonConvert.DeserializeObject[]>({0})", "JsonConvert.SerializeObject({0})", "NpgsqlRange[]", typeof(NpgsqlRange[]), typeof(NpgsqlRange[]), "{0}", "GetValue") }, + { (int)(NpgsqlDbType.Range | NpgsqlDbType.Bigint | NpgsqlDbType.Array), ("(NpgsqlRange[])", "JsonConvert.DeserializeObject[]>({0})", "JsonConvert.SerializeObject({0})", "NpgsqlRange[]", typeof(NpgsqlRange[]), typeof(NpgsqlRange[]), "{0}", "GetValue") }, + { (int)(NpgsqlDbType.Range | NpgsqlDbType.Numeric | NpgsqlDbType.Array), ("(NpgsqlRange[])", "JsonConvert.DeserializeObject[]>({0})", "JsonConvert.SerializeObject({0})", "NpgsqlRange[]", typeof(NpgsqlRange[]), typeof(NpgsqlRange[]), "{0}", "GetValue") }, + { (int)(NpgsqlDbType.Range | NpgsqlDbType.Timestamp | NpgsqlDbType.Array), ("(NpgsqlRange[])", "JsonConvert.DeserializeObject[]>({0})", "JsonConvert.SerializeObject({0})", "NpgsqlRange[]", typeof(NpgsqlRange[]), typeof(NpgsqlRange[]), "{0}", "GetValue") }, + { (int)(NpgsqlDbType.Range | NpgsqlDbType.TimestampTz | NpgsqlDbType.Array), ("(NpgsqlRange[])", "JsonConvert.DeserializeObject[]>({0})", "JsonConvert.SerializeObject({0})", "NpgsqlRange[]", typeof(NpgsqlRange[]), typeof(NpgsqlRange[]), "{0}", "GetValue") }, + { (int)(NpgsqlDbType.Range | NpgsqlDbType.Date | NpgsqlDbType.Array), ("(NpgsqlRange[])", "JsonConvert.DeserializeObject[]>({0})", "JsonConvert.SerializeObject({0})", "NpgsqlRange[]", typeof(NpgsqlRange[]), typeof(NpgsqlRange[]), "{0}", "GetValue") }, + + { (int)(NpgsqlDbType.Hstore | NpgsqlDbType.Array), ("(Dictionary[])", "JsonConvert.DeserializeObject[]>({0})", "JsonConvert.SerializeObject({0})", "Dictionary[]", typeof(Dictionary[]), typeof(Dictionary[]), "{0}", "GetValue") }, + { (int)(NpgsqlDbType.Geometry | NpgsqlDbType.Array), ("(PostgisGeometry[])", "JsonConvert.DeserializeObject({0})", "JsonConvert.SerializeObject({0})", "PostgisGeometry[]", typeof(PostgisGeometry[]), typeof(PostgisGeometry[]), "{0}", "GetValue") }, }; public string GetCsConvert(DbColumnInfo column) => _dicDbToCs.TryGetValue(column.DbType, out var trydc) ? (column.IsNullable ? trydc.csConvert : trydc.csConvert.Replace("?", "")) : null; @@ -130,252 +198,313 @@ namespace FreeSql.PostgreSQL { public string GetDataReaderMethod(DbColumnInfo column) => _dicDbToCs.TryGetValue(column.DbType, out var trydc) ? trydc.dataReaderMethod : null; public List GetDatabases() { - var sql = @"select schema_name from information_schema.schemata where schema_name not in ('information_schema', 'mysql', 'performance_schema')"; + 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 List GetTablesByDatabase(params string[] database) { - var loc1 = new List(); - var loc2 = new Dictionary(); - var loc3 = new Dictionary>(); - - if (database == null || database.Any() == false) return loc1; - var databaseIn = string.Join(",", database.Select(a => "{0}".FormatMySql(a))); - var sql = string.Format(@"select -concat(a.table_schema, '.', a.table_name) 'id', -a.table_schema 'schema', -a.table_name 'table', -a.table_type 'type' -from information_schema.tables a -where a.table_schema in ({0})", databaseIn); - var ds = _orm.Ado.ExecuteArray(CommandType.Text, sql); - if (ds == null) return loc1; - - var loc6 = new List(); - var loc66 = new List(); - 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 type = string.Concat(row[3]) == "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, Type = type }); - loc3.Add(table_id, new Dictionary()); - switch (type) { - case DbTableType.TABLE: - case DbTableType.VIEW: - loc6.Add(table.Replace("'", "''")); - break; - case DbTableType.StoreProcedure: - loc66.Add(table.Replace("'", "''")); - break; - } + var olddatabase = ""; + using (var conn = _orm.Ado.MasterPool.Get(TimeSpan.FromSeconds(5))) { + olddatabase = conn.Value.Database; } - if (loc6.Count == 0) return loc1; - var loc8 = "'" + string.Join("','", loc6.ToArray()) + "'"; - var loc88 = "'" + string.Join("','", loc66.ToArray()) + "'"; + var dbs = database?.ToArray() ?? new[] { olddatabase }; + var tables = new List(); - sql = string.Format(@"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' -from information_schema.columns a -where a.table_schema in ({1}) and a.table_name in ({0}) -", loc8, databaseIn); - ds = _orm.Ado.ExecuteArray(CommandType.Text, sql); - if (ds == null) return loc1; + foreach (var db in dbs) { + if (string.IsNullOrEmpty(db) || string.Compare(db, olddatabase, true) != 0) continue; - 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]); - if (max_length == 0) max_length = -1; - if (database.Length == 1) { - table_id = table_id.Substring(table_id.IndexOf('.') + 1); + var loc1 = new List(); + var loc2 = new Dictionary(); + var loc3 = new Dictionary>(); + + var sql = $@" +select +b.nspname || '.' || a.tablename, +a.schemaname, +a.tablename , +'TABLE' +from pg_tables a +inner join pg_namespace b on b.nspname = a.schemaname +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, +'VIEW' +from pg_class a +inner join pg_namespace b on b.oid = a.relnamespace +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') +"; + var ds = _orm.Ado.ExecuteArray(CommandType.Text, sql); + if (ds == null) return loc1; + + var loc6 = new List(); + var loc66 = new List(); + foreach (object[] row in ds) { + var object_id = string.Concat(row[0]); + var owner = string.Concat(row[1]); + var table = string.Concat(row[2]); + Enum.TryParse(string.Concat(row[3]), out var type); + loc2.Add(object_id, new DbTableInfo { Id = object_id.ToString(), Schema = owner, Name = table, Type = type }); + loc3.Add(object_id, new Dictionary()); + switch (type) { + case DbTableType.VIEW: + case DbTableType.TABLE: + loc6.Add(object_id); + break; + case DbTableType.StoreProcedure: + loc66.Add(object_id); + break; + } } - 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], - Coment = comment - }); - loc3[table_id][column].DbType = this.GetDbType(loc3[table_id][column]); - loc3[table_id][column].CsType = this.GetCsTypeInfo(loc3[table_id][column]); - } + if (loc6.Count == 0) return loc1; + string loc8 = "'" + string.Join("','", loc6.ToArray()) + "'"; + string loc88 = "'" + string.Join("','", loc66.ToArray()) + "'"; - sql = string.Format(@"select -concat(a.constraint_schema, '.', a.table_name) 'table_id', -a.column_name, -concat(a.constraint_schema, '/', a.table_name, '/', a.constraint_name) 'index_id', -1 'IsUnique', -case when constraint_name = 'PRIMARY' then 1 else 0 end 'IsPrimaryKey', -0 'IsClustered', -0 'IsDesc' -from information_schema.key_column_usage a -where a.constraint_schema in ({1}) and a.table_name in ({0}) and isnull(position_in_unique_constraint) -", loc8, databaseIn); - ds = _orm.Ado.ExecuteArray(CommandType.Text, sql); - if (ds == null) return loc1; + sql = $@" +select +ns.nspname || '.' || c.relname as id, +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, +--case when e.adsrc = 'nextval(''' || case when ns.nspname = 'public' then '' else ns.nspname || '.' end || c.relname || '_' || a.attname || '_seq''::regclass)' then 1 else 0 end as is_identity, +d.description as comment, +a.attndims, +case when t.typelem = 0 then t.typtype else t2.typtype end, +ns2.nspname, +a.attnum +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 || '.' || c.relname in ({loc88})"; + ds = _orm.Ado.ExecuteArray(CommandType.Text, sql); + if (ds == null) return loc1; - var indexColumns = new Dictionary>>(); - var uniqueColumns = new Dictionary>>(); - 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"; - int is_desc = int.Parse(string.Concat(row[6])); - if (database.Length == 1) { - table_id = table_id.Substring(table_id.IndexOf('.') + 1); + 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(@"_seq'::regclass)"); + var comment = string.Concat(row[7]); + 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); + + 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], + Coment = comment + }); + loc3[object_id][column].DbType = this.GetDbType(loc3[object_id][column]); + loc3[object_id][column].CsType = this.GetCsTypeInfo(loc3[object_id][column]); } - 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> loc10 = null; - List loc11 = null; - if (!indexColumns.TryGetValue(table_id, out loc10)) - indexColumns.Add(table_id, loc10 = new Dictionary>()); - if (!loc10.TryGetValue(index_id, out loc11)) - loc10.Add(index_id, loc11 = new List()); - loc11.Add(loc9); - if (is_unique) { - if (!uniqueColumns.TryGetValue(table_id, out loc10)) - uniqueColumns.Add(table_id, loc10 = new Dictionary>()); + sql = $@" +select +ns.nspname || '.' || d.relname as table_id, +c.attname, +ns.nspname || '/' || d.relname || '/' || 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, +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 ns.nspname || '.' || d.relname in ({loc8}) +"; + ds = _orm.Ado.ExecuteArray(CommandType.Text, sql); + if (ds == null) return loc1; + + var indexColumns = new Dictionary>>(); + var uniqueColumns = new Dictionary>>(); + 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 = int.Parse(string.Concat(row[6])); + 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> loc10 = null; + List loc11 = null; + if (!indexColumns.TryGetValue(object_id, out loc10)) + indexColumns.Add(object_id, loc10 = new Dictionary>()); if (!loc10.TryGetValue(index_id, out loc11)) loc10.Add(index_id, loc11 = new List()); loc11.Add(loc9); - } - } - foreach (string table_id in indexColumns.Keys) { - foreach (var columns in indexColumns[table_id].Values) - loc2[table_id].Indexes.Add(columns); - } - foreach (string table_id in uniqueColumns.Keys) { - foreach (var columns in uniqueColumns[table_id].Values) { - columns.Sort((c1, c2) => c1.Name.CompareTo(c2.Name)); - loc2[table_id].Uniques.Add(columns); - } - } - - sql = string.Format(@"select -concat(a.constraint_schema, '.', a.table_name) 'table_id', -a.column_name, -concat(a.constraint_schema, '/', 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 a.constraint_schema in ({1}) and a.table_name in ({0}) and not isnull(position_in_unique_constraint) -", loc8, databaseIn); - ds = _orm.Ado.ExecuteArray(CommandType.Text, sql); - if (ds == null) return loc1; - - var fkColumns = new Dictionary>(); - 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 loc12 = null; - DbForeignInfo loc13 = null; - if (!fkColumns.TryGetValue(table_id, out loc12)) - fkColumns.Add(table_id, loc12 = new Dictionary()); - 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].Values) - loc2[table_id].Foreigns.Add(fk); - - 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.Uniques.Count > 0) { - foreach (var loc5 in loc4.Uniques[0]) { - loc5.IsPrimary = true; - loc4.Primarys.Add(loc5); + if (is_unique) { + if (!uniqueColumns.TryGetValue(object_id, out loc10)) + uniqueColumns.Add(object_id, loc10 = new Dictionary>()); + if (!loc10.TryGetValue(index_id, out loc11)) + loc10.Add(index_id, loc11 = new List()); + loc11.Add(loc9); } } - 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.Foreigns.Find(fk => fk.Columns.Find(c3 => c3.Name == c1.Name) != null) != null; - bool b2 = loc4.Foreigns.Find(fk => fk.Columns.Find(c3 => c3.Name == c2.Name) != null) != null; - compare = b2.CompareTo(b1); + foreach (var object_id in indexColumns.Keys) { + foreach (List columns in indexColumns[object_id].Values) + loc2[object_id].Indexes.Add(columns); + } + foreach (var object_id in uniqueColumns.Keys) { + foreach (var columns in uniqueColumns[object_id].Values) { + columns.Sort((c1, c2) => c1.Name.CompareTo(c2.Name)); + loc2[object_id].Uniques.Add(columns); } - if (compare == 0) compare = c1.Name.CompareTo(c2.Name); - return compare; + } + + 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.connamespace || '/' || 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 ns.nspname || '.' || b.relname in ({loc8}) +"; + ds = _orm.Ado.ExecuteArray(CommandType.Text, sql); + if (ds == null) return loc1; + + var fkColumns = new Dictionary>(); + 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 loc12 = null; + DbForeignInfo loc13 = null; + if (!fkColumns.TryGetValue(table_id, out loc12)) + fkColumns.Add(table_id, loc12 = new Dictionary()); + 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].Values) + loc2[table_id].Foreigns.Add(fk); + + 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.Uniques.Count > 0) { + foreach (var loc5 in loc4.Uniques[0]) { + loc5.IsPrimary = true; + loc4.Primarys.Add(loc5); + } + } + 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.Foreigns.Find(fk => fk.Columns.Find(c3 => c3.Name == c1.Name) != null) != null; + bool b2 = loc4.Foreigns.Find(fk => fk.Columns.Find(c3 => c3.Name == c2.Name) != null) != null; + 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; }); - 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; - }); - foreach (var loc4 in loc1) { - var dicUniques = new Dictionary>(); - if (loc4.Primarys.Count > 0) dicUniques.Add(string.Join(",", loc4.Primarys.Select(a => a.Name)), loc4.Primarys); - foreach (var loc5 in loc4.Uniques) { - var dickey = string.Join(",", loc5.Select(a => a.Name)); - if (dicUniques.ContainsKey(dickey)) continue; - dicUniques.Add(dickey, loc5); + foreach (var loc4 in loc1) { + var dicUniques = new Dictionary>(); + if (loc4.Primarys.Count > 0) dicUniques.Add(string.Join(",", loc4.Primarys.Select(a => a.Name)), loc4.Primarys); + foreach (var loc5 in loc4.Uniques) { + var dickey = string.Join(",", loc5.Select(a => a.Name)); + if (dicUniques.ContainsKey(dickey)) continue; + dicUniques.Add(dickey, loc5); + } + loc4.Uniques = dicUniques.Values.ToList(); } - loc4.Uniques = dicUniques.Values.ToList(); - } - loc2.Clear(); - loc3.Clear(); - return loc1; + loc2.Clear(); + loc3.Clear(); + tables.AddRange(loc1); + } + return tables; } public List GetEnumsByDatabase(params string[] database) { if (database == null || database.Length == 0) return new List(); - var drs = _orm.Ado.Query<(string name, string label)>(CommandType.Text, @"select + var drs = _orm.Ado.Query<(string name, string label)>(CommandType.Text, @" +select ns.nspname || '.' || a.typname, b.enumlabel from pg_type a diff --git a/FreeSql/SqlServer/SqlServerCodeFirst.cs b/FreeSql/SqlServer/SqlServerCodeFirst.cs index 58a76e48..da4cb616 100644 --- a/FreeSql/SqlServer/SqlServerCodeFirst.cs +++ b/FreeSql/SqlServer/SqlServerCodeFirst.cs @@ -77,7 +77,7 @@ namespace FreeSql.SqlServer { var conn = _orm.Ado.MasterPool.Get(TimeSpan.FromSeconds(5)); var database = conn.Value.Database; Func ExecuteScalar = (db, sql) => { - if (string.Compare(database, db) != 0) try { conn.Value.ChangeDatabase(db); } catch { } + if (string.Compare(database, db) != 0) conn.Value.ChangeDatabase(db); try { using (var cmd = conn.Value.CreateCommand()) { cmd.CommandText = sql; @@ -101,18 +101,18 @@ namespace FreeSql.SqlServer { if (tboldname?.Length == 1) tboldname = new[] { database, "dbo", tboldname[0] }; if (tboldname?.Length == 2) tboldname = new[] { database, tboldname[0], tboldname[1] }; - if (string.Compare(tbname[0], database, true) != 0 && ExecuteScalar(database, $"select 1 from sys.databases where name='{tbname[0]}'") == null) //创建数据库 + if (string.Compare(tbname[0], database, true) != 0 && ExecuteScalar(database, $" select 1 from sys.databases where name='{tbname[0]}'") == null) //创建数据库 ExecuteScalar(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 && ExecuteScalar(tbname[0], $"select 1 from sys.schemas where name='{tbname[1]}'") == null) //创建模式 + if (string.Compare(tbname[1], "dbo", true) != 0 && ExecuteScalar(tbname[0], $" select 1 from sys.schemas where name='{tbname[1]}'") == null) //创建模式 ExecuteScalar(tbname[0], $"create schema [{tbname[1]}] authorization [dbo]"); var sbalter = new StringBuilder(); var istmpatler = false; //创建临时表,导入数据,删除旧表,修改 - if (ExecuteScalar(tbname[0], $"select 1 from dbo.sysobjects where id = object_id(N'[{tbname[1]}].[{tbname[2]}]') and OBJECTPROPERTY(id, N'IsUserTable') = 1") == null) { //表不存在 + if (ExecuteScalar(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 && ExecuteScalar(database, $"select 1 from sys.databases where name='{tboldname[0]}'") == null || - string.Compare(tboldname[1], tbname[1], true) != 0 && ExecuteScalar(tboldname[0], $"select 1 from sys.schemas where name='{tboldname[1]}'") == null || - ExecuteScalar(tboldname[0], $"select 1 from dbo.sysobjects where id = object_id(N'[{tboldname[1]}].[{tboldname[2]}]') and OBJECTPROPERTY(id, N'IsUserTable') = 1") == null) + if (string.Compare(tboldname[0], tbname[0], true) != 0 && ExecuteScalar(database, $" select 1 from sys.databases where name='{tboldname[0]}'") == null || + string.Compare(tboldname[1], tbname[1], true) != 0 && ExecuteScalar(tboldname[0], $" select 1 from sys.schemas where name='{tboldname[1]}'") == null || + ExecuteScalar(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; } diff --git a/FreeSql/SqlServer/SqlServerDbFirst.cs b/FreeSql/SqlServer/SqlServerDbFirst.cs index 9b51886e..adff4fba 100644 --- a/FreeSql/SqlServer/SqlServerDbFirst.cs +++ b/FreeSql/SqlServer/SqlServerDbFirst.cs @@ -97,7 +97,7 @@ namespace FreeSql.SqlServer { public string GetDataReaderMethod(DbColumnInfo column) => _dicDbToCs.TryGetValue(column.DbType, out var trydc) ? trydc.dataReaderMethod : null; public List GetDatabases() { - var sql = @"select name from sys.databases where name not in ('master','tempdb','model','msdb')"; + 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(); } @@ -306,6 +306,7 @@ use {olddatabase}; } sql = $@" +use {db}; select b.object_id 'Object_id' ,c.name 'Column' diff --git a/FreeSql/SqlServer/SqlServerUtils.cs b/FreeSql/SqlServer/SqlServerUtils.cs index 655c4263..c14cc9e8 100644 --- a/FreeSql/SqlServer/SqlServerUtils.cs +++ b/FreeSql/SqlServer/SqlServerUtils.cs @@ -9,8 +9,8 @@ namespace FreeSql.SqlServer { class SqlServerUtils : CommonUtils { IFreeSql _orm; - public SqlServerUtils(IFreeSql mysql) { - _orm = mysql; + public SqlServerUtils(IFreeSql orm) { + _orm = orm; } internal override DbParameter AppendParamter(List _params, string parameterName, Type type, object value) {