mirror of
				https://github.com/nsnail/FreeSql.git
				synced 2025-11-04 17:20:49 +08:00 
			
		
		
		
	pgsql DbFirst 完成未测试;oracle 适配进行中
This commit is contained in:
		
							
								
								
									
										21
									
								
								FreeSql.Tests/PostgreSQL/PostgreSQLDbFirstTest.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										21
									
								
								FreeSql.Tests/PostgreSQL/PostgreSQLDbFirstTest.cs
									
									
									
									
									
										Normal file
									
								
							@@ -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]);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										54
									
								
								FreeSql/Extensions/FreeSqlGlobalExtensions.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										54
									
								
								FreeSql/Extensions/FreeSqlGlobalExtensions.cs
									
									
									
									
									
										Normal file
									
								
							@@ -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 {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/// <summary>
 | 
				
			||||||
 | 
						/// 测量两个经纬度的距离,返回单位:米
 | 
				
			||||||
 | 
						/// </summary>
 | 
				
			||||||
 | 
						/// <param name="that">经纬坐标1</param>
 | 
				
			||||||
 | 
						/// <param name="point">经纬坐标2</param>
 | 
				
			||||||
 | 
						/// <returns>返回距离(单位:米)</returns>
 | 
				
			||||||
 | 
						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<T>(this IDataReader dr, int index) {
 | 
				
			||||||
 | 
							string value = dr.GetString(index);
 | 
				
			||||||
 | 
							Type t = typeof(T);
 | 
				
			||||||
 | 
							foreach (var f in t.GetFields())
 | 
				
			||||||
 | 
								if (f.GetCustomAttribute<DescriptionAttribute>()?.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<DescriptionAttribute>();
 | 
				
			||||||
 | 
							return desc?.Description ?? name;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						public static long ToInt64(this Enum item) {
 | 
				
			||||||
 | 
							return Convert.ToInt64(item);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						public static IEnumerable<T> ToSet<T>(this long value) {
 | 
				
			||||||
 | 
							List<T> ret = new List<T>();
 | 
				
			||||||
 | 
							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;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
@@ -1,4 +1,4 @@
 | 
				
			|||||||
public static class StringExtensions {
 | 
					public static class FreeSqlStringExtensions {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/// <summary>
 | 
						/// <summary>
 | 
				
			||||||
	/// 特殊处理类似 string.Format 的使用方法,防止注入,以及 IS NULL 转换
 | 
						/// 特殊处理类似 string.Format 的使用方法,防止注入,以及 IS NULL 转换
 | 
				
			||||||
@@ -24,6 +24,14 @@
 | 
				
			|||||||
	/// <returns></returns>
 | 
						/// <returns></returns>
 | 
				
			||||||
	public static string FormatPostgreSQL(this string that, params object[] args) => _postgresqlAdo.Addslashes(that, args);
 | 
						public static string FormatPostgreSQL(this string that, params object[] args) => _postgresqlAdo.Addslashes(that, args);
 | 
				
			||||||
	static FreeSql.PostgreSQL.PostgreSQLAdo _postgresqlAdo = new FreeSql.PostgreSQL.PostgreSQLAdo();
 | 
						static FreeSql.PostgreSQL.PostgreSQLAdo _postgresqlAdo = new FreeSql.PostgreSQL.PostgreSQLAdo();
 | 
				
			||||||
 | 
						/// <summary>
 | 
				
			||||||
 | 
						/// 特殊处理类似 string.Format 的使用方法,防止注入,以及 IS NULL 转换
 | 
				
			||||||
 | 
						/// </summary>
 | 
				
			||||||
 | 
						/// <param name="that"></param>
 | 
				
			||||||
 | 
						/// <param name="args"></param>
 | 
				
			||||||
 | 
						/// <returns></returns>
 | 
				
			||||||
 | 
						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 {
 | 
					namespace System.Runtime.CompilerServices {
 | 
				
			||||||
@@ -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);
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		/// <summary>
 | 
					 | 
				
			||||||
		/// 将 1010101010 这样的二进制字符串转换成 BitArray
 | 
					 | 
				
			||||||
		/// </summary>
 | 
					 | 
				
			||||||
		/// <param name="_1010">1010101010</param>
 | 
					 | 
				
			||||||
		/// <returns></returns>
 | 
					 | 
				
			||||||
		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<T> ToNpgsqlRange<T>(this string that) {
 | 
					 | 
				
			||||||
			var s = that;
 | 
					 | 
				
			||||||
			if (string.IsNullOrEmpty(s) || s == "empty") return NpgsqlRange<T>.Empty;
 | 
					 | 
				
			||||||
			string s1 = s.Trim('(', ')', '[', ']');
 | 
					 | 
				
			||||||
			string[] ss = s1.Split(new char[] { ',' }, 2);
 | 
					 | 
				
			||||||
			if (ss.Length != 2) return NpgsqlRange<T>.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<T>(t1, s[0] == '[', s[0] == '(', t2, s[s.Length - 1] == ']', s[s.Length - 1] == ')');
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
@@ -20,6 +20,7 @@
 | 
				
			|||||||
    <PackageReference Include="Newtonsoft.Json" Version="12.0.1" />
 | 
					    <PackageReference Include="Newtonsoft.Json" Version="12.0.1" />
 | 
				
			||||||
    <PackageReference Include="Npgsql" Version="4.0.4" />
 | 
					    <PackageReference Include="Npgsql" Version="4.0.4" />
 | 
				
			||||||
    <PackageReference Include="Npgsql.LegacyPostgis" Version="4.0.4" />
 | 
					    <PackageReference Include="Npgsql.LegacyPostgis" Version="4.0.4" />
 | 
				
			||||||
 | 
					    <PackageReference Include="Oracle.ManagedDataAccess.Core" Version="2.18.3" />
 | 
				
			||||||
    <PackageReference Include="SafeObjectPool" Version="1.0.12" />
 | 
					    <PackageReference Include="SafeObjectPool" Version="1.0.12" />
 | 
				
			||||||
    <PackageReference Include="System.Data.SqlClient" Version="4.6.0" />
 | 
					    <PackageReference Include="System.Data.SqlClient" Version="4.6.0" />
 | 
				
			||||||
  </ItemGroup>
 | 
					  </ItemGroup>
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -92,6 +92,7 @@ namespace FreeSql {
 | 
				
			|||||||
				case DataType.MySql: ret = new MySql.MySqlProvider(_cache, _logger, _masterConnectionString, _slaveConnectionString); break;
 | 
									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.SqlServer: ret = new SqlServer.SqlServerProvider(_cache, _logger, _masterConnectionString, _slaveConnectionString); break;
 | 
				
			||||||
				case DataType.PostgreSQL: ret = new PostgreSQL.PostgreSQLProvider(_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) {
 | 
								if (ret != null) {
 | 
				
			||||||
				ret.CodeFirst.IsAutoSyncStructure = _isAutoSyncStructure;
 | 
									ret.CodeFirst.IsAutoSyncStructure = _isAutoSyncStructure;
 | 
				
			||||||
@@ -104,5 +105,5 @@ namespace FreeSql {
 | 
				
			|||||||
		}
 | 
							}
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	public enum DataType { MySql, SqlServer, PostgreSQL }
 | 
						public enum DataType { MySql, SqlServer, PostgreSQL, /*Oracle*/ }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -58,7 +58,7 @@ namespace FreeSql.Internal.CommonProvider {
 | 
				
			|||||||
			return this;
 | 
								return this;
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		public string ToSql() {
 | 
							public virtual string ToSql() {
 | 
				
			||||||
			if (_source == null || _source.Any() == false) return null;
 | 
								if (_source == null || _source.Any() == false) return null;
 | 
				
			||||||
			var sb = new StringBuilder();
 | 
								var sb = new StringBuilder();
 | 
				
			||||||
			sb.Append("INSERT INTO ").Append(_commonUtils.QuoteSqlName(_table.DbName)).Append("(");
 | 
								sb.Append("INSERT INTO ").Append(_commonUtils.QuoteSqlName(_table.DbName)).Append("(");
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -20,47 +20,4 @@ public static partial class MygisTypesExtensions {
 | 
				
			|||||||
		double radLng2 = (double)(point.X) * 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;
 | 
							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;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					 | 
				
			||||||
	/// <summary>
 | 
					 | 
				
			||||||
	/// 测量两个经纬度的距离,返回单位:米
 | 
					 | 
				
			||||||
	/// </summary>
 | 
					 | 
				
			||||||
	/// <param name="that">经纬坐标1</param>
 | 
					 | 
				
			||||||
	/// <param name="point">经纬坐标2</param>
 | 
					 | 
				
			||||||
	/// <returns>返回距离(单位:米)</returns>
 | 
					 | 
				
			||||||
	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<T>(this IDataReader dr, int index) {
 | 
					 | 
				
			||||||
		string value = dr.GetString(index);
 | 
					 | 
				
			||||||
		Type t = typeof(T);
 | 
					 | 
				
			||||||
		foreach (var f in t.GetFields())
 | 
					 | 
				
			||||||
			if (f.GetCustomAttribute<DescriptionAttribute>()?.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<DescriptionAttribute>();
 | 
					 | 
				
			||||||
		return desc?.Description ?? name;
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	public static long ToInt64(this Enum item) {
 | 
					 | 
				
			||||||
		return Convert.ToInt64(item);
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	public static IEnumerable<T> ToSet<T>(this long value) {
 | 
					 | 
				
			||||||
		List<T> ret = new List<T>();
 | 
					 | 
				
			||||||
		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;
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
@@ -85,7 +85,7 @@ namespace FreeSql.MySql {
 | 
				
			|||||||
			var conn = _orm.Ado.MasterPool.Get(TimeSpan.FromSeconds(5));
 | 
								var conn = _orm.Ado.MasterPool.Get(TimeSpan.FromSeconds(5));
 | 
				
			||||||
			var database = conn.Value.Database;
 | 
								var database = conn.Value.Database;
 | 
				
			||||||
			Func<string, string, object> ExecuteScalar = (db, sql) => {
 | 
								Func<string, string, object> 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 {
 | 
									try {
 | 
				
			||||||
					using (var cmd = conn.Value.CreateCommand()) {
 | 
										using (var cmd = conn.Value.CreateCommand()) {
 | 
				
			||||||
						cmd.CommandText = sql;
 | 
											cmd.CommandText = sql;
 | 
				
			||||||
@@ -107,16 +107,16 @@ namespace FreeSql.MySql {
 | 
				
			|||||||
					var tboldname = tb.DbOldName?.Split(new[] { '.' }, 2); //旧表名
 | 
										var tboldname = tb.DbOldName?.Split(new[] { '.' }, 2); //旧表名
 | 
				
			||||||
					if (tboldname?.Length == 1) tboldname = new[] { database, tboldname[0] };
 | 
										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");
 | 
											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 sbalter = new StringBuilder();
 | 
				
			||||||
					var istmpatler = false; //创建临时表,导入数据,删除旧表,修改
 | 
										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 (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 ||
 | 
												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)
 | 
													ExecuteScalar(tboldname[0], " SELECT 1 FROM information_schema.TABLES WHERE table_schema={0} and table_name={1}".FormatMySql(tboldname)) == null)
 | 
				
			||||||
								//数据库或模式或表不存在
 | 
													//数据库或表不存在
 | 
				
			||||||
								tboldname = null;
 | 
													tboldname = null;
 | 
				
			||||||
						}
 | 
											}
 | 
				
			||||||
						if (tboldname == null) {
 | 
											if (tboldname == null) {
 | 
				
			||||||
@@ -149,11 +149,8 @@ namespace FreeSql.MySql {
 | 
				
			|||||||
						tboldname = null; //如果新表已经存在,不走改表名逻辑
 | 
											tboldname = null; //如果新表已经存在,不走改表名逻辑
 | 
				
			||||||
 | 
					
 | 
				
			||||||
					//对比字段,只可以修改类型、增加字段、有限的修改字段名;保证安全不删除字段
 | 
										//对比字段,只可以修改类型、增加字段、有限的修改字段名;保证安全不删除字段
 | 
				
			||||||
					var addcols = new Dictionary<string, ColumnInfo>(StringComparer.CurrentCultureIgnoreCase);
 | 
										var sql = @"
 | 
				
			||||||
					foreach (var tbcol in tb.Columns) addcols.Add(tbcol.Value.Attribute.Name, tbcol.Value);
 | 
					select
 | 
				
			||||||
					var surplus = new Dictionary<string, bool>(StringComparer.CurrentCultureIgnoreCase);
 | 
					 | 
				
			||||||
					var dbcols = new List<DbColumnInfo>();
 | 
					 | 
				
			||||||
					var sql = @"select
 | 
					 | 
				
			||||||
a.column_name,
 | 
					a.column_name,
 | 
				
			||||||
a.column_type,
 | 
					a.column_type,
 | 
				
			||||||
case when a.is_nullable = 'YES' then 1 else 0 end 'is_nullable',
 | 
					case when a.is_nullable = 'YES' then 1 else 0 end 'is_nullable',
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -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.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.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.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(bool), 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") },
 | 
									{ (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 string GetDataReaderMethod(DbColumnInfo column) => _dicDbToCs.TryGetValue(column.DbType, out var trydc) ? trydc.dataReaderMethod : null;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		public List<string> GetDatabases() {
 | 
							public List<string> 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);
 | 
								var ds = _orm.Ado.ExecuteArray(CommandType.Text, sql);
 | 
				
			||||||
			return ds.Select(a => a.FirstOrDefault()?.ToString()).ToList();
 | 
								return ds.Select(a => a.FirstOrDefault()?.ToString()).ToList();
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
@@ -143,7 +143,8 @@ namespace FreeSql.MySql {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
			if (database == null || database.Any() == false) return loc1;
 | 
								if (database == null || database.Any() == false) return loc1;
 | 
				
			||||||
			var databaseIn = string.Join(",", database.Select(a => "{0}".FormatMySql(a)));
 | 
								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',
 | 
					concat(a.table_schema, '.', a.table_name) 'id',
 | 
				
			||||||
a.table_schema 'schema',
 | 
					a.table_schema 'schema',
 | 
				
			||||||
a.table_name 'table',
 | 
					a.table_name 'table',
 | 
				
			||||||
@@ -180,7 +181,8 @@ where a.table_schema in ({0})", databaseIn);
 | 
				
			|||||||
			var loc8 = "'" + string.Join("','", loc6.ToArray()) + "'";
 | 
								var loc8 = "'" + string.Join("','", loc6.ToArray()) + "'";
 | 
				
			||||||
			var loc88 = "'" + string.Join("','", loc66.ToArray()) + "'";
 | 
								var loc88 = "'" + string.Join("','", loc66.ToArray()) + "'";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
			sql = string.Format(@"select
 | 
								sql = string.Format(@"
 | 
				
			||||||
 | 
					select
 | 
				
			||||||
concat(a.table_schema, '.', a.table_name),
 | 
					concat(a.table_schema, '.', a.table_name),
 | 
				
			||||||
a.column_name,
 | 
					a.column_name,
 | 
				
			||||||
a.data_type,
 | 
					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]);
 | 
									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',
 | 
					concat(a.constraint_schema, '.', a.table_name) 'table_id',
 | 
				
			||||||
a.column_name,
 | 
					a.column_name,
 | 
				
			||||||
concat(a.constraint_schema, '/', a.table_name, '/', a.constraint_name) 'index_id',
 | 
					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',
 | 
					concat(a.constraint_schema, '.', a.table_name) 'table_id',
 | 
				
			||||||
a.column_name,
 | 
					a.column_name,
 | 
				
			||||||
concat(a.constraint_schema, '/', a.constraint_name) 'FKId',
 | 
					concat(a.constraint_schema, '/', a.constraint_name) 'FKId',
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -9,8 +9,8 @@ namespace FreeSql.MySql {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
	class MySqlUtils : CommonUtils {
 | 
						class MySqlUtils : CommonUtils {
 | 
				
			||||||
		IFreeSql _orm;
 | 
							IFreeSql _orm;
 | 
				
			||||||
		public MySqlUtils(IFreeSql mysql) {
 | 
							public MySqlUtils(IFreeSql orm) {
 | 
				
			||||||
			_orm = mysql;
 | 
								_orm = orm;
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		internal override DbParameter AppendParamter(List<DbParameter> _params, string parameterName, Type type, object value) {
 | 
							internal override DbParameter AppendParamter(List<DbParameter> _params, string parameterName, Type type, object value) {
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										45
									
								
								FreeSql/Oracle/Curd/OracleDelete.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										45
									
								
								FreeSql/Oracle/Curd/OracleDelete.cs
									
									
									
									
									
										Normal file
									
								
							@@ -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<T1> : Internal.CommonProvider.DeleteProvider<T1> where T1 : class {
 | 
				
			||||||
 | 
							public OracleDelete(IFreeSql orm, CommonUtils commonUtils, CommonExpression commonExpression, object dywhere)
 | 
				
			||||||
 | 
								: base(orm, commonUtils, commonExpression, dywhere) {
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							public override List<T1> ExecuteDeleted() {
 | 
				
			||||||
 | 
								var sql = this.ToSql();
 | 
				
			||||||
 | 
								if (string.IsNullOrEmpty(sql)) return new List<T1>();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								var sb = new StringBuilder();
 | 
				
			||||||
 | 
								sb.Append(sql).Append(" RETURNING ");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								var colidx = 0;
 | 
				
			||||||
 | 
								foreach (var col in _table.Columns.Values) {
 | 
				
			||||||
 | 
									if (colidx > 0) sb.Append(", ");
 | 
				
			||||||
 | 
									sb.Append(_commonUtils.QuoteReadColumn(col.CsType, _commonUtils.QuoteSqlName(col.Attribute.Name))).Append(" as ").Append(_commonUtils.QuoteSqlName(col.CsName));
 | 
				
			||||||
 | 
									++colidx;
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
								return _orm.Ado.Query<T1>(CommandType.Text, sb.ToString(), _params.ToArray());
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							async public override Task<List<T1>> ExecuteDeletedAsync() {
 | 
				
			||||||
 | 
								var sql = this.ToSql();
 | 
				
			||||||
 | 
								if (string.IsNullOrEmpty(sql)) return new List<T1>();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								var sb = new StringBuilder();
 | 
				
			||||||
 | 
								sb.Append(sql).Append(" RETURNING ");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								var colidx = 0;
 | 
				
			||||||
 | 
								foreach (var col in _table.Columns.Values) {
 | 
				
			||||||
 | 
									if (colidx > 0) sb.Append(", ");
 | 
				
			||||||
 | 
									sb.Append(_commonUtils.QuoteReadColumn(col.CsType, _commonUtils.QuoteSqlName(col.Attribute.Name))).Append(" as ").Append(_commonUtils.QuoteSqlName(col.CsName));
 | 
				
			||||||
 | 
									++colidx;
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
								return await _orm.Ado.QueryAsync<T1>(CommandType.Text, sb.ToString(), _params.ToArray());
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										105
									
								
								FreeSql/Oracle/Curd/OracleInsert.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										105
									
								
								FreeSql/Oracle/Curd/OracleInsert.cs
									
									
									
									
									
										Normal file
									
								
							@@ -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<T1> : Internal.CommonProvider.InsertProvider<T1> 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<long> 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<T1> ExecuteInserted() {
 | 
				
			||||||
 | 
								var sql = this.ToSql();
 | 
				
			||||||
 | 
								if (string.IsNullOrEmpty(sql)) return new List<T1>();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								var sb = new StringBuilder();
 | 
				
			||||||
 | 
								sb.Append(sql).Append(" RETURNING ");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								var colidx = 0;
 | 
				
			||||||
 | 
								foreach (var col in _table.Columns.Values) {
 | 
				
			||||||
 | 
									if (colidx > 0) sb.Append(", ");
 | 
				
			||||||
 | 
									sb.Append(_commonUtils.QuoteReadColumn(col.CsType, _commonUtils.QuoteSqlName(col.Attribute.Name))).Append(" as ").Append(_commonUtils.QuoteSqlName(col.CsName));
 | 
				
			||||||
 | 
									++colidx;
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
								return _orm.Ado.Query<T1>(CommandType.Text, sb.ToString(), _params);
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							async public override Task<List<T1>> ExecuteInsertedAsync() {
 | 
				
			||||||
 | 
								var sql = this.ToSql();
 | 
				
			||||||
 | 
								if (string.IsNullOrEmpty(sql)) return new List<T1>();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								var sb = new StringBuilder();
 | 
				
			||||||
 | 
								sb.Append(sql).Append(" RETURNING ");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								var colidx = 0;
 | 
				
			||||||
 | 
								foreach (var col in _table.Columns.Values) {
 | 
				
			||||||
 | 
									if (colidx > 0) sb.Append(", ");
 | 
				
			||||||
 | 
									sb.Append(_commonUtils.QuoteReadColumn(col.CsType, _commonUtils.QuoteSqlName(col.Attribute.Name))).Append(" as ").Append(_commonUtils.QuoteSqlName(col.CsName));
 | 
				
			||||||
 | 
									++colidx;
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
								return await _orm.Ado.QueryAsync<T1>(CommandType.Text, sb.ToString(), _params);
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										126
									
								
								FreeSql/Oracle/Curd/OracleSelect.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										126
									
								
								FreeSql/Oracle/Curd/OracleSelect.cs
									
									
									
									
									
										Normal file
									
								
							@@ -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<T1> : FreeSql.Internal.CommonProvider.Select1Provider<T1> 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<SelectTableInfo> _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<T1, T2, T3> From<T2, T3>(Expression<Func<ISelectFromExpression<T1>, T2, T3, ISelectFromExpression<T1>>> exp) { this.InternalFrom(exp?.Body); var ret = new OracleSelect<T1, T2, T3>(_orm, _commonUtils, _commonExpression, null); OracleSelect<T1>.CopyData(this, ret); return ret; }
 | 
				
			||||||
 | 
							public override ISelect<T1, T2, T3, T4> From<T2, T3, T4>(Expression<Func<ISelectFromExpression<T1>, T2, T3, T4, ISelectFromExpression<T1>>> exp) { this.InternalFrom(exp?.Body); var ret = new OracleSelect<T1, T2, T3, T4>(_orm, _commonUtils, _commonExpression, null); OracleSelect<T1>.CopyData(this, ret); return ret; }
 | 
				
			||||||
 | 
							public override ISelect<T1, T2, T3, T4, T5> From<T2, T3, T4, T5>(Expression<Func<ISelectFromExpression<T1>, T2, T3, T4, T5, ISelectFromExpression<T1>>> exp) { this.InternalFrom(exp?.Body); var ret = new OracleSelect<T1, T2, T3, T4, T5>(_orm, _commonUtils, _commonExpression, null); OracleSelect<T1>.CopyData(this, ret); return ret; }
 | 
				
			||||||
 | 
							public override ISelect<T1, T2, T3, T4, T5, T6> From<T2, T3, T4, T5, T6>(Expression<Func<ISelectFromExpression<T1>, T2, T3, T4, T5, T6, ISelectFromExpression<T1>>> exp) { this.InternalFrom(exp?.Body); var ret = new OracleSelect<T1, T2, T3, T4, T5, T6>(_orm, _commonUtils, _commonExpression, null); OracleSelect<T1>.CopyData(this, ret); return ret; }
 | 
				
			||||||
 | 
							public override ISelect<T1, T2, T3, T4, T5, T6, T7> From<T2, T3, T4, T5, T6, T7>(Expression<Func<ISelectFromExpression<T1>, T2, T3, T4, T5, T6, T7, ISelectFromExpression<T1>>> exp) { this.InternalFrom(exp?.Body); var ret = new OracleSelect<T1, T2, T3, T4, T5, T6, T7>(_orm, _commonUtils, _commonExpression, null); OracleSelect<T1>.CopyData(this, ret); return ret; }
 | 
				
			||||||
 | 
							public override ISelect<T1, T2, T3, T4, T5, T6, T7, T8> From<T2, T3, T4, T5, T6, T7, T8>(Expression<Func<ISelectFromExpression<T1>, T2, T3, T4, T5, T6, T7, T8, ISelectFromExpression<T1>>> exp) { this.InternalFrom(exp?.Body); var ret = new OracleSelect<T1, T2, T3, T4, T5, T6, T7, T8>(_orm, _commonUtils, _commonExpression, null); OracleSelect<T1>.CopyData(this, ret); return ret; }
 | 
				
			||||||
 | 
							public override ISelect<T1, T2, T3, T4, T5, T6, T7, T8, T9> From<T2, T3, T4, T5, T6, T7, T8, T9>(Expression<Func<ISelectFromExpression<T1>, T2, T3, T4, T5, T6, T7, T8, T9, ISelectFromExpression<T1>>> exp) { this.InternalFrom(exp?.Body); var ret = new OracleSelect<T1, T2, T3, T4, T5, T6, T7, T8, T9>(_orm, _commonUtils, _commonExpression, null); OracleSelect<T1>.CopyData(this, ret); return ret; }
 | 
				
			||||||
 | 
							public override ISelect<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10> From<T2, T3, T4, T5, T6, T7, T8, T9, T10>(Expression<Func<ISelectFromExpression<T1>, T2, T3, T4, T5, T6, T7, T8, T9, T10, ISelectFromExpression<T1>>> exp) { this.InternalFrom(exp?.Body); var ret = new OracleSelect<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10>(_orm, _commonUtils, _commonExpression, null); OracleSelect<T1>.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<T1, T2, T3> : FreeSql.Internal.CommonProvider.Select3Provider<T1, T2, T3> 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<T1>.ToSqlStatic(_commonUtils, _select, field ?? this.GetAllField().field, _join, _where, _groupby, _having, _orderby, _skip, _limit, _tables, _orm);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						class OracleSelect<T1, T2, T3, T4> : FreeSql.Internal.CommonProvider.Select4Provider<T1, T2, T3, T4> 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<T1>.ToSqlStatic(_commonUtils, _select, field ?? this.GetAllField().field, _join, _where, _groupby, _having, _orderby, _skip, _limit, _tables, _orm);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						class OracleSelect<T1, T2, T3, T4, T5> : FreeSql.Internal.CommonProvider.Select5Provider<T1, T2, T3, T4, T5> 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<T1>.ToSqlStatic(_commonUtils, _select, field ?? this.GetAllField().field, _join, _where, _groupby, _having, _orderby, _skip, _limit, _tables, _orm);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						class OracleSelect<T1, T2, T3, T4, T5, T6> : FreeSql.Internal.CommonProvider.Select6Provider<T1, T2, T3, T4, T5, T6> 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<T1>.ToSqlStatic(_commonUtils, _select, field ?? this.GetAllField().field, _join, _where, _groupby, _having, _orderby, _skip, _limit, _tables, _orm);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						class OracleSelect<T1, T2, T3, T4, T5, T6, T7> : FreeSql.Internal.CommonProvider.Select7Provider<T1, T2, T3, T4, T5, T6, T7> 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<T1>.ToSqlStatic(_commonUtils, _select, field ?? this.GetAllField().field, _join, _where, _groupby, _having, _orderby, _skip, _limit, _tables, _orm);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						class OracleSelect<T1, T2, T3, T4, T5, T6, T7, T8> : FreeSql.Internal.CommonProvider.Select8Provider<T1, T2, T3, T4, T5, T6, T7, T8> 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<T1>.ToSqlStatic(_commonUtils, _select, field ?? this.GetAllField().field, _join, _where, _groupby, _having, _orderby, _skip, _limit, _tables, _orm);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						class OracleSelect<T1, T2, T3, T4, T5, T6, T7, T8, T9> : FreeSql.Internal.CommonProvider.Select9Provider<T1, T2, T3, T4, T5, T6, T7, T8, T9> 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<T1>.ToSqlStatic(_commonUtils, _select, field ?? this.GetAllField().field, _join, _where, _groupby, _having, _orderby, _skip, _limit, _tables, _orm);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						class OracleSelect<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10> : FreeSql.Internal.CommonProvider.Select10Provider<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10> where 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<T1>.ToSqlStatic(_commonUtils, _select, field ?? this.GetAllField().field, _join, _where, _groupby, _having, _orderby, _skip, _limit, _tables, _orm);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										78
									
								
								FreeSql/Oracle/Curd/OracleUpdate.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										78
									
								
								FreeSql/Oracle/Curd/OracleUpdate.cs
									
									
									
									
									
										Normal file
									
								
							@@ -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<T1> : Internal.CommonProvider.UpdateProvider<T1> where T1 : class {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							public OracleUpdate(IFreeSql orm, CommonUtils commonUtils, CommonExpression commonExpression, object dywhere)
 | 
				
			||||||
 | 
								: base(orm, commonUtils, commonExpression, dywhere) {
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							public override List<T1> ExecuteUpdated() {
 | 
				
			||||||
 | 
								var sql = this.ToSql();
 | 
				
			||||||
 | 
								if (string.IsNullOrEmpty(sql)) return new List<T1>();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								var sb = new StringBuilder();
 | 
				
			||||||
 | 
								sb.Append(sql).Append(" RETURNING ");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								var colidx = 0;
 | 
				
			||||||
 | 
								foreach (var col in _table.Columns.Values) {
 | 
				
			||||||
 | 
									if (colidx > 0) sb.Append(", ");
 | 
				
			||||||
 | 
									sb.Append(_commonUtils.QuoteReadColumn(col.CsType, _commonUtils.QuoteSqlName(col.Attribute.Name))).Append(" as ").Append(_commonUtils.QuoteSqlName(col.CsName));
 | 
				
			||||||
 | 
									++colidx;
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
								return _orm.Ado.Query<T1>(CommandType.Text, sb.ToString(), _params.Concat(_paramsSource).ToArray());
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							async public override Task<List<T1>> ExecuteUpdatedAsync() {
 | 
				
			||||||
 | 
								var sql = this.ToSql();
 | 
				
			||||||
 | 
								if (string.IsNullOrEmpty(sql)) return new List<T1>();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								var sb = new StringBuilder();
 | 
				
			||||||
 | 
								sb.Append(sql).Append(" RETURNING ");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								var colidx = 0;
 | 
				
			||||||
 | 
								foreach (var col in _table.Columns.Values) {
 | 
				
			||||||
 | 
									if (colidx > 0) sb.Append(", ");
 | 
				
			||||||
 | 
									sb.Append(_commonUtils.QuoteReadColumn(col.CsType, _commonUtils.QuoteSqlName(col.Attribute.Name))).Append(" as ").Append(_commonUtils.QuoteSqlName(col.CsName));
 | 
				
			||||||
 | 
									++colidx;
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
								return await _orm.Ado.QueryAsync<T1>(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(")");
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										65
									
								
								FreeSql/Oracle/OracleAdo/OracleAdo.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										65
									
								
								FreeSql/Oracle/OracleAdo/OracleAdo.cs
									
									
									
									
									
										Normal file
									
								
							@@ -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<DbConnection> pool, Object<DbConnection> conn, Exception ex) {
 | 
				
			||||||
 | 
								(pool as OracleConnectionPool).Return(conn, ex);
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							protected override DbParameter[] GetDbParamtersByObject(string sql, object obj) => _util.GetDbParamtersByObject(sql, obj);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										153
									
								
								FreeSql/Oracle/OracleAdo/OracleConnectionPool.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										153
									
								
								FreeSql/Oracle/OracleAdo/OracleConnectionPool.cs
									
									
									
									
									
										Normal file
									
								
							@@ -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<DbConnection> {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							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<DbConnection> 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<DbConnection> {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							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<DbConnection>[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<DbConnection> 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<DbConnection> 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<DbConnection> 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<DbConnection> 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;
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										297
									
								
								FreeSql/Oracle/OracleCodeFirst.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										297
									
								
								FreeSql/Oracle/OracleCodeFirst.cs
									
									
									
									
									
										Normal file
									
								
							@@ -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<string, (OracleDbType type, string dbtype, string dbtypeFull, bool? isUnsigned, bool? isnullable, object defaultValue)> _dicCsToDb = new Dictionary<string, (OracleDbType type, string dbtype, string dbtypeFull, bool? isUnsigned, bool? isnullable, object defaultValue)>() {
 | 
				
			||||||
 | 
									{ 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<TEntity>() => 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<string, string, object> 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<string, ColumnInfo>(StringComparer.CurrentCultureIgnoreCase);
 | 
				
			||||||
 | 
										foreach (var tbcol in tb.Columns) addcols.Add(tbcol.Value.Attribute.Name, tbcol.Value);
 | 
				
			||||||
 | 
										var surplus = new Dictionary<string, bool>(StringComparer.CurrentCultureIgnoreCase);
 | 
				
			||||||
 | 
										var dbcols = new List<DbColumnInfo>();
 | 
				
			||||||
 | 
										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<string, bool> dicSyced = new ConcurrentDictionary<string, bool>();
 | 
				
			||||||
 | 
							public bool SyncStructure<TEntity>() => 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;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										385
									
								
								FreeSql/Oracle/OracleDbFirst.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										385
									
								
								FreeSql/Oracle/OracleDbFirst.cs
									
									
									
									
									
										Normal file
									
								
							@@ -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<int, (string csConvert, string csParse, string csStringify, string csType, Type csTypeInfo, Type csNullableTypeInfo, string csTypeValue, string dataReaderMethod)> _dicDbToCs = new Dictionary<int, (string csConvert, string csParse, string csStringify, string csType, Type csTypeInfo, Type csNullableTypeInfo, string csTypeValue, string dataReaderMethod)>() {
 | 
				
			||||||
 | 
									{ (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<string> 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<DbTableInfo> GetTablesByDatabase(params string[] database) {
 | 
				
			||||||
 | 
								var loc1 = new List<DbTableInfo>();
 | 
				
			||||||
 | 
								var loc2 = new Dictionary<string, DbTableInfo>();
 | 
				
			||||||
 | 
								var loc3 = new Dictionary<string, Dictionary<string, DbColumnInfo>>();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								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<string>();
 | 
				
			||||||
 | 
								var loc66 = new List<string>();
 | 
				
			||||||
 | 
								foreach (var row in ds) {
 | 
				
			||||||
 | 
									var table_id = string.Concat(row[0]);
 | 
				
			||||||
 | 
									var schema = string.Concat(row[1]);
 | 
				
			||||||
 | 
									var table = string.Concat(row[2]);
 | 
				
			||||||
 | 
									var 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<string, DbColumnInfo>());
 | 
				
			||||||
 | 
									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<string, Dictionary<string, List<DbColumnInfo>>>();
 | 
				
			||||||
 | 
								var uniqueColumns = new Dictionary<string, Dictionary<string, List<DbColumnInfo>>>();
 | 
				
			||||||
 | 
								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<string, List<DbColumnInfo>> loc10 = null;
 | 
				
			||||||
 | 
									List<DbColumnInfo> loc11 = null;
 | 
				
			||||||
 | 
									if (!indexColumns.TryGetValue(table_id, out loc10))
 | 
				
			||||||
 | 
										indexColumns.Add(table_id, loc10 = new Dictionary<string, List<DbColumnInfo>>());
 | 
				
			||||||
 | 
									if (!loc10.TryGetValue(index_id, out loc11))
 | 
				
			||||||
 | 
										loc10.Add(index_id, loc11 = new List<DbColumnInfo>());
 | 
				
			||||||
 | 
									loc11.Add(loc9);
 | 
				
			||||||
 | 
									if (is_unique) {
 | 
				
			||||||
 | 
										if (!uniqueColumns.TryGetValue(table_id, out loc10))
 | 
				
			||||||
 | 
											uniqueColumns.Add(table_id, loc10 = new Dictionary<string, List<DbColumnInfo>>());
 | 
				
			||||||
 | 
										if (!loc10.TryGetValue(index_id, out loc11))
 | 
				
			||||||
 | 
											loc10.Add(index_id, loc11 = new List<DbColumnInfo>());
 | 
				
			||||||
 | 
										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<string, Dictionary<string, DbForeignInfo>>();
 | 
				
			||||||
 | 
								foreach (var row in ds) {
 | 
				
			||||||
 | 
									string table_id = string.Concat(row[0]);
 | 
				
			||||||
 | 
									string column = string.Concat(row[1]);
 | 
				
			||||||
 | 
									string fk_id = string.Concat(row[2]);
 | 
				
			||||||
 | 
									string ref_table_id = string.Concat(row[3]);
 | 
				
			||||||
 | 
									bool is_foreign_key = string.Concat(row[4]) == "1";
 | 
				
			||||||
 | 
									string referenced_column = string.Concat(row[5]);
 | 
				
			||||||
 | 
									if (database.Length == 1) {
 | 
				
			||||||
 | 
										table_id = table_id.Substring(table_id.IndexOf('.') + 1);
 | 
				
			||||||
 | 
										ref_table_id = ref_table_id.Substring(ref_table_id.IndexOf('.') + 1);
 | 
				
			||||||
 | 
									}
 | 
				
			||||||
 | 
									if (loc3.ContainsKey(table_id) == false || loc3[table_id].ContainsKey(column) == false) continue;
 | 
				
			||||||
 | 
									var loc9 = loc3[table_id][column];
 | 
				
			||||||
 | 
									if (loc2.ContainsKey(ref_table_id) == false) continue;
 | 
				
			||||||
 | 
									var loc10 = loc2[ref_table_id];
 | 
				
			||||||
 | 
									var loc11 = loc3[ref_table_id][referenced_column];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
									Dictionary<string, DbForeignInfo> loc12 = null;
 | 
				
			||||||
 | 
									DbForeignInfo loc13 = null;
 | 
				
			||||||
 | 
									if (!fkColumns.TryGetValue(table_id, out loc12))
 | 
				
			||||||
 | 
										fkColumns.Add(table_id, loc12 = new Dictionary<string, DbForeignInfo>());
 | 
				
			||||||
 | 
									if (!loc12.TryGetValue(fk_id, out loc13))
 | 
				
			||||||
 | 
										loc12.Add(fk_id, loc13 = new DbForeignInfo { Table = loc2[table_id], ReferencedTable = loc10 });
 | 
				
			||||||
 | 
									loc13.Columns.Add(loc9);
 | 
				
			||||||
 | 
									loc13.ReferencedColumns.Add(loc11);
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
								foreach (var table_id in fkColumns.Keys)
 | 
				
			||||||
 | 
									foreach (var fk in fkColumns[table_id].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<string, List<DbColumnInfo>>();
 | 
				
			||||||
 | 
									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<DbEnumInfo> GetEnumsByDatabase(params string[] database) {
 | 
				
			||||||
 | 
								return new List<DbEnumInfo>();
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										315
									
								
								FreeSql/Oracle/OracleExpression.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										315
									
								
								FreeSql/Oracle/OracleExpression.cs
									
									
									
									
									
										Normal file
									
								
							@@ -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<SelectTableInfo> _tables, List<SelectColumnInfo> _selectColumnMap, Func<Expression[], string> getSelectGroupingMapString, SelectTableInfoType tbtype, bool isQuoteName) {
 | 
				
			||||||
 | 
								Func<Expression, string> 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<SelectTableInfo> _tables, List<SelectColumnInfo> _selectColumnMap, Func<Expression[], string> 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<SelectTableInfo> _tables, List<SelectColumnInfo> _selectColumnMap, Func<Expression[], string> 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<SelectTableInfo> _tables, List<SelectColumnInfo> _selectColumnMap, Func<Expression[], string> 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<SelectTableInfo> _tables, List<SelectColumnInfo> _selectColumnMap, Func<Expression[], string> getSelectGroupingMapString, SelectTableInfoType tbtype, bool isQuoteName) {
 | 
				
			||||||
 | 
								Func<Expression, string> 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<SelectTableInfo> _tables, List<SelectColumnInfo> _selectColumnMap, Func<Expression[], string> getSelectGroupingMapString, SelectTableInfoType tbtype, bool isQuoteName) {
 | 
				
			||||||
 | 
								Func<Expression, string> 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<SelectTableInfo> _tables, List<SelectColumnInfo> _selectColumnMap, Func<Expression[], string> getSelectGroupingMapString, SelectTableInfoType tbtype, bool isQuoteName) {
 | 
				
			||||||
 | 
								Func<Expression, string> 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<SelectTableInfo> _tables, List<SelectColumnInfo> _selectColumnMap, Func<Expression[], string> getSelectGroupingMapString, SelectTableInfoType tbtype, bool isQuoteName) {
 | 
				
			||||||
 | 
								Func<Expression, string> 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<SelectTableInfo> _tables, List<SelectColumnInfo> _selectColumnMap, Func<Expression[], string> getSelectGroupingMapString, SelectTableInfoType tbtype, bool isQuoteName) {
 | 
				
			||||||
 | 
								Func<Expression, string> 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} 解析");
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										49
									
								
								FreeSql/Oracle/OracleProvider.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										49
									
								
								FreeSql/Oracle/OracleProvider.cs
									
									
									
									
									
										Normal file
									
								
							@@ -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<T1> Select<T1>() where T1 : class => new OracleSelect<T1>(this, this.InternalCommonUtils, this.InternalCommonExpression, null);
 | 
				
			||||||
 | 
							public ISelect<T1> Select<T1>(object dywhere) where T1 : class => new OracleSelect<T1>(this, this.InternalCommonUtils, this.InternalCommonExpression, dywhere);
 | 
				
			||||||
 | 
							public IInsert<T1> Insert<T1>() where T1 : class => new OracleInsert<T1>(this, this.InternalCommonUtils, this.InternalCommonExpression);
 | 
				
			||||||
 | 
							public IInsert<T1> Insert<T1>(T1 source) where T1 : class => this.Insert<T1>().AppendData(source);
 | 
				
			||||||
 | 
							public IInsert<T1> Insert<T1>(IEnumerable<T1> source) where T1 : class => this.Insert<T1>().AppendData(source);
 | 
				
			||||||
 | 
							public IUpdate<T1> Update<T1>() where T1 : class => new OracleUpdate<T1>(this, this.InternalCommonUtils, this.InternalCommonExpression, null);
 | 
				
			||||||
 | 
							public IUpdate<T1> Update<T1>(object dywhere) where T1 : class => new OracleUpdate<T1>(this, this.InternalCommonUtils, this.InternalCommonExpression, dywhere);
 | 
				
			||||||
 | 
							public IDelete<T1> Delete<T1>() where T1 : class => new OracleDelete<T1>(this, this.InternalCommonUtils, this.InternalCommonExpression, null);
 | 
				
			||||||
 | 
							public IDelete<T1> Delete<T1>(object dywhere) where T1 : class => new OracleDelete<T1>(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);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										47
									
								
								FreeSql/Oracle/OracleUtils.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										47
									
								
								FreeSql/Oracle/OracleUtils.cs
									
									
									
									
									
										Normal file
									
								
							@@ -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<DbParameter> _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<OracleParameter>(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;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
@@ -16,13 +16,23 @@ namespace FreeSql.PostgreSQL.Curd {
 | 
				
			|||||||
			var sql = this.ToSql();
 | 
								var sql = this.ToSql();
 | 
				
			||||||
			if (string.IsNullOrEmpty(sql)) return 0;
 | 
								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<long> ExecuteIdentityAsync() {
 | 
							async public override Task<long> ExecuteIdentityAsync() {
 | 
				
			||||||
			var sql = this.ToSql();
 | 
								var sql = this.ToSql();
 | 
				
			||||||
			if (string.IsNullOrEmpty(sql)) return 0;
 | 
								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<T1> ExecuteInserted() {
 | 
							public override List<T1> ExecuteInserted() {
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -25,6 +25,7 @@ namespace FreeSql.PostgreSQL {
 | 
				
			|||||||
				}
 | 
									}
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		static DateTime dt1970 = new DateTime(1970, 1, 1);
 | 
							static DateTime dt1970 = new DateTime(1970, 1, 1);
 | 
				
			||||||
		public override object AddslashesProcessParam(object param) {
 | 
							public override object AddslashesProcessParam(object param) {
 | 
				
			||||||
			bool isdic = false;
 | 
								bool isdic = false;
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -136,7 +136,7 @@ namespace FreeSql.PostgreSQL {
 | 
				
			|||||||
		}
 | 
							}
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	public static class DbConnectionExtensions {
 | 
						static class DbConnectionExtensions {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		public static bool Ping(this DbConnection that) {
 | 
							public static bool Ping(this DbConnection that) {
 | 
				
			||||||
			try {
 | 
								try {
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,6 +1,7 @@
 | 
				
			|||||||
using Npgsql.LegacyPostgis;
 | 
					using Npgsql.LegacyPostgis;
 | 
				
			||||||
using NpgsqlTypes;
 | 
					using NpgsqlTypes;
 | 
				
			||||||
using System;
 | 
					using System;
 | 
				
			||||||
 | 
					using System.Collections;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
public static partial class PostgreSQLTypesExtensions {
 | 
					public static partial class PostgreSQLTypesExtensions {
 | 
				
			||||||
	/// <summary>
 | 
						/// <summary>
 | 
				
			||||||
@@ -30,4 +31,35 @@ public static partial class PostgreSQLTypesExtensions {
 | 
				
			|||||||
		double radLng2 = (double)(point.X) * 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;
 | 
							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);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/// <summary>
 | 
				
			||||||
 | 
						/// 将 1010101010 这样的二进制字符串转换成 BitArray
 | 
				
			||||||
 | 
						/// </summary>
 | 
				
			||||||
 | 
						/// <param name="_1010">1010101010</param>
 | 
				
			||||||
 | 
						/// <returns></returns>
 | 
				
			||||||
 | 
						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<T> ToNpgsqlRange<T>(this string that) {
 | 
				
			||||||
 | 
							var s = that;
 | 
				
			||||||
 | 
							if (string.IsNullOrEmpty(s) || s == "empty") return NpgsqlRange<T>.Empty;
 | 
				
			||||||
 | 
							string s1 = s.Trim('(', ')', '[', ']');
 | 
				
			||||||
 | 
							string[] ss = s1.Split(new char[] { ',' }, 2);
 | 
				
			||||||
 | 
							if (ss.Length != 2) return NpgsqlRange<T>.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<T>(t1, s[0] == '[', s[0] == '(', t2, s[s.Length - 1] == ']', s[s.Length - 1] == ')');
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
@@ -132,14 +132,14 @@ namespace FreeSql.PostgreSQL {
 | 
				
			|||||||
				var tboldname = tb.DbOldName?.Split(new[] { '.' }, 2); //旧表名
 | 
									var tboldname = tb.DbOldName?.Split(new[] { '.' }, 2); //旧表名
 | 
				
			||||||
				if (tboldname?.Length == 1) tboldname = new[] { "public", tboldname[0] };
 | 
									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");
 | 
										sb.Append("CREATE SCHEMA IF NOT EXISTS ").Append(tbname[0]).Append(";\r\n");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
				var sbalter = new StringBuilder();
 | 
									var sbalter = new StringBuilder();
 | 
				
			||||||
				var istmpatler = false; //创建临时表,导入数据,删除旧表,修改
 | 
									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 (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;
 | 
												tboldname = null;
 | 
				
			||||||
					}
 | 
										}
 | 
				
			||||||
@@ -171,7 +171,8 @@ namespace FreeSql.PostgreSQL {
 | 
				
			|||||||
					tboldname = null; //如果新表已经存在,不走改表名逻辑
 | 
										tboldname = null; //如果新表已经存在,不走改表名逻辑
 | 
				
			||||||
 | 
					
 | 
				
			||||||
				//对比字段,只可以修改类型、增加字段、有限的修改字段名;保证安全不删除字段
 | 
									//对比字段,只可以修改类型、增加字段、有限的修改字段名;保证安全不删除字段
 | 
				
			||||||
				var sql = @"select
 | 
									var sql = @"
 | 
				
			||||||
 | 
					select
 | 
				
			||||||
a.attname,
 | 
					a.attname,
 | 
				
			||||||
t.typname,
 | 
					t.typname,
 | 
				
			||||||
case when a.atttypmod > 0 and a.atttypmod < 32767 then a.atttypmod - 4 else a.attlen end len,
 | 
					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 type = string.Concat(a[1]);
 | 
				
			||||||
					var sqlType = string.Concat(a[3]);
 | 
										var sqlType = string.Concat(a[3]);
 | 
				
			||||||
					var max_length = long.Parse(string.Concat(a[2]));
 | 
										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;
 | 
											case "bool": case "name": case "bit": case "varbit": case "bpchar": case "varchar": case "bytea": case "text": case "uuid": break;
 | 
				
			||||||
						default: max_length *= 8; break;
 | 
											default: max_length *= 8; break;
 | 
				
			||||||
					}
 | 
										}
 | 
				
			||||||
@@ -288,7 +289,7 @@ where ns.nspname = {0} and c.relname = {1}".FormatPostgreSQL(tboldname ?? tbname
 | 
				
			|||||||
				if (seqcol.Item3) {
 | 
									if (seqcol.Item3) {
 | 
				
			||||||
					sb.Append("CREATE SEQUENCE ").Append(seqname).Append(";\r\n");
 | 
										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("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();
 | 
								return sb.Length == 0 ? null : sb.ToString();
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,10 +1,17 @@
 | 
				
			|||||||
using FreeSql.DatabaseModel;
 | 
					using FreeSql.DatabaseModel;
 | 
				
			||||||
using FreeSql.Internal;
 | 
					using FreeSql.Internal;
 | 
				
			||||||
using MySql.Data.MySqlClient;
 | 
					using Newtonsoft.Json.Linq;
 | 
				
			||||||
 | 
					using Npgsql.LegacyPostgis;
 | 
				
			||||||
 | 
					using NpgsqlTypes;
 | 
				
			||||||
 | 
					using SafeObjectPool;
 | 
				
			||||||
using System;
 | 
					using System;
 | 
				
			||||||
 | 
					using System.Collections;
 | 
				
			||||||
using System.Collections.Generic;
 | 
					using System.Collections.Generic;
 | 
				
			||||||
using System.Data;
 | 
					using System.Data;
 | 
				
			||||||
 | 
					using System.Data.Common;
 | 
				
			||||||
using System.Linq;
 | 
					using System.Linq;
 | 
				
			||||||
 | 
					using System.Net;
 | 
				
			||||||
 | 
					using System.Net.NetworkInformation;
 | 
				
			||||||
using System.Text.RegularExpressions;
 | 
					using System.Text.RegularExpressions;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
namespace FreeSql.PostgreSQL {
 | 
					namespace FreeSql.PostgreSQL {
 | 
				
			||||||
@@ -18,107 +25,168 @@ namespace FreeSql.PostgreSQL {
 | 
				
			|||||||
			_commonExpression = commonExpression;
 | 
								_commonExpression = commonExpression;
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		public int GetDbType(DbColumnInfo column) => (int)GetMySqlDbType(column);
 | 
							public int GetDbType(DbColumnInfo column) => (int)GetNpgsqlDbType(column);
 | 
				
			||||||
		MySqlDbType GetMySqlDbType(DbColumnInfo column) {
 | 
							NpgsqlDbType GetNpgsqlDbType(DbColumnInfo column) {
 | 
				
			||||||
			var is_unsigned = column.DbTypeTextFull.ToLower().EndsWith(" unsigned");
 | 
								var dbtype = column.DbTypeText;
 | 
				
			||||||
			switch (column.DbTypeText.ToLower()) {
 | 
								var isarray = dbtype.EndsWith("[]");
 | 
				
			||||||
				case "bit": return MySqlDbType.Bit;
 | 
								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 "bpchar": ret = NpgsqlDbType.Char; break;
 | 
				
			||||||
				case "smallint": return is_unsigned ? MySqlDbType.UInt16 : MySqlDbType.Int16;
 | 
									case "varchar": ret = NpgsqlDbType.Varchar; break;
 | 
				
			||||||
				case "mediumint": return is_unsigned ? MySqlDbType.UInt24 : MySqlDbType.Int24;
 | 
									case "text": ret = NpgsqlDbType.Text; break;
 | 
				
			||||||
				case "int": return is_unsigned ? MySqlDbType.UInt32 : MySqlDbType.Int32;
 | 
					 | 
				
			||||||
				case "bigint": return is_unsigned ? MySqlDbType.UInt64 : MySqlDbType.Int64;
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
				case "real":
 | 
									case "timestamp": ret = NpgsqlDbType.Timestamp; break;
 | 
				
			||||||
				case "double": return MySqlDbType.Double;
 | 
									case "timestamptz": ret = NpgsqlDbType.TimestampTz; break;
 | 
				
			||||||
				case "float": return MySqlDbType.Float;
 | 
									case "date": ret = NpgsqlDbType.Date; break;
 | 
				
			||||||
				case "numeric":
 | 
									case "time": ret = NpgsqlDbType.Time; break;
 | 
				
			||||||
				case "decimal": return MySqlDbType.Decimal;
 | 
									case "timetz": ret = NpgsqlDbType.TimeTz; break;
 | 
				
			||||||
 | 
									case "interval": ret = NpgsqlDbType.Interval; break;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
				case "year": return MySqlDbType.Year;
 | 
									case "bool": ret = NpgsqlDbType.Boolean; break;
 | 
				
			||||||
				case "time": return MySqlDbType.Time;
 | 
									case "bytea": ret = NpgsqlDbType.Bytea; break;
 | 
				
			||||||
				case "date": return MySqlDbType.Date;
 | 
									case "bit": ret = NpgsqlDbType.Bit; break;
 | 
				
			||||||
				case "timestamp": return MySqlDbType.Timestamp;
 | 
									case "varbit": ret = NpgsqlDbType.Varbit; break;
 | 
				
			||||||
				case "datetime": return MySqlDbType.DateTime;
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
				case "tinyblob": return MySqlDbType.TinyBlob;
 | 
									case "point": ret = NpgsqlDbType.Point; break;
 | 
				
			||||||
				case "blob": return MySqlDbType.Blob;
 | 
									case "line": ret = NpgsqlDbType.Line; break;
 | 
				
			||||||
				case "mediumblob": return MySqlDbType.MediumBlob;
 | 
									case "lseg": ret = NpgsqlDbType.LSeg; break;
 | 
				
			||||||
				case "longblob": return MySqlDbType.LongBlob;
 | 
									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 "cidr": ret = NpgsqlDbType.Cidr; break;
 | 
				
			||||||
				case "varbinary": return MySqlDbType.VarBinary;
 | 
									case "inet": ret = NpgsqlDbType.Inet; break;
 | 
				
			||||||
 | 
									case "macaddr": ret = NpgsqlDbType.MacAddr; break;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
				case "tinytext": return MySqlDbType.TinyText;
 | 
									case "json": ret = NpgsqlDbType.Json; break;
 | 
				
			||||||
				case "text": return MySqlDbType.Text;
 | 
									case "jsonb": ret = NpgsqlDbType.Jsonb; break;
 | 
				
			||||||
				case "mediumtext": return MySqlDbType.MediumText;
 | 
									case "uuid": ret = NpgsqlDbType.Uuid; break;
 | 
				
			||||||
				case "longtext": return MySqlDbType.LongText;
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
				case "char": return MySqlDbType.String;
 | 
									case "int4range": ret = NpgsqlDbType.Range | NpgsqlDbType.Integer; break;
 | 
				
			||||||
				case "varchar": return MySqlDbType.VarChar;
 | 
									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 "hstore": ret = NpgsqlDbType.Hstore; break;
 | 
				
			||||||
				case "enum": return MySqlDbType.Enum;
 | 
									case "geometry": ret = NpgsqlDbType.Geometry; break;
 | 
				
			||||||
 | 
					 | 
				
			||||||
				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;
 | 
					 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
 | 
								return isarray ? (ret | NpgsqlDbType.Array) : ret;
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		static readonly Dictionary<int, (string csConvert, string csParse, string csStringify, string csType, Type csTypeInfo, Type csNullableTypeInfo, string csTypeValue, string dataReaderMethod)> _dicDbToCs = new Dictionary<int, (string csConvert, string csParse, string csStringify, string csType, Type csTypeInfo, Type csNullableTypeInfo, string csTypeValue, string dataReaderMethod)>() {
 | 
							static readonly Dictionary<int, (string csConvert, string csParse, string csStringify, string csType, Type csTypeInfo, Type csNullableTypeInfo, string csTypeValue, string dataReaderMethod)> _dicDbToCs = new Dictionary<int, (string csConvert, string csParse, string csStringify, string csType, Type csTypeInfo, Type csNullableTypeInfo, string csTypeValue, string dataReaderMethod)>() {
 | 
				
			||||||
				{ (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)NpgsqlDbType.Char, ("", "{0}.Replace(StringifySplit, \"|\")", "{0}.Replace(\"|\", StringifySplit)", "string", typeof(string), typeof(string), "{0}", "GetString") },
 | 
				
			||||||
				{ (int)MySqlDbType.Int16, ("(short?)", "short.Parse({0})", "{0}.ToString()", "short?", typeof(short), typeof(short?), "{0}.Value", "GetInt16") },
 | 
									{ (int)NpgsqlDbType.Varchar, ("", "{0}.Replace(StringifySplit, \"|\")", "{0}.Replace(\"|\", StringifySplit)", "string", typeof(string), typeof(string), "{0}", "GetString") },
 | 
				
			||||||
				{ (int)MySqlDbType.Int24, ("(int?)", "int.Parse({0})", "{0}.ToString()", "int?", typeof(int), typeof(int?), "{0}.Value", "GetInt32") },
 | 
									{ (int)NpgsqlDbType.Text, ("", "{0}.Replace(StringifySplit, \"|\")", "{0}.Replace(\"|\", StringifySplit)", "string", typeof(string), typeof(string), "{0}", "GetString") },
 | 
				
			||||||
				{ (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)NpgsqlDbType.Timestamp,  ("(DateTime?)", "new DateTime(long.Parse({0}))", "{0}.Ticks.ToString()", "DateTime?", typeof(DateTime), typeof(DateTime?), "{0}.Value", "GetDateTime") },
 | 
				
			||||||
				{ (int)MySqlDbType.UInt16, ("(ushort?)", "ushort.Parse({0})", "{0}.ToString()", "ushort?", typeof(ushort), typeof(ushort?), "{0}.Value", "GetInt16") },
 | 
									{ (int)NpgsqlDbType.TimestampTz,  ("(DateTime?)", "new DateTime(long.Parse({0}))", "{0}.Ticks.ToString()", "DateTime?", typeof(DateTime), typeof(DateTime?), "{0}.Value", "GetDateTime") },
 | 
				
			||||||
				{ (int)MySqlDbType.UInt24, ("(uint?)", "uint.Parse({0})", "{0}.ToString()", "uint?", typeof(uint), typeof(uint?), "{0}.Value", "GetInt32") },
 | 
									{ (int)NpgsqlDbType.Date,  ("(DateTime?)", "new DateTime(long.Parse({0}))", "{0}.Ticks.ToString()", "DateTime?", typeof(DateTime), typeof(DateTime?), "{0}.Value", "GetDateTime") },
 | 
				
			||||||
				{ (int)MySqlDbType.UInt32, ("(uint?)", "uint.Parse({0})", "{0}.ToString()", "uint?", typeof(uint), typeof(uint?), "{0}.Value", "GetInt32") },
 | 
									{ (int)NpgsqlDbType.Time, ("(TimeSpan?)", "TimeSpan.Parse(double.Parse({0}))", "{0}.Ticks.ToString()", "TimeSpan?", typeof(TimeSpan), typeof(TimeSpan?), "{0}.Value", "GetValue") },
 | 
				
			||||||
				{ (int)MySqlDbType.UInt64, ("(ulong?)", "ulong.Parse({0})", "{0}.ToString()", "ulong?", typeof(ulong), typeof(ulong?), "{0}.Value", "GetInt64") },
 | 
									{ (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)NpgsqlDbType.Boolean, ("(bool?)", "{0} == \"1\"", "{0} == true ? \"1\" : \"0\"", "bool?", typeof(bool), typeof(bool?), "{0}.Value", "GetBoolean") },
 | 
				
			||||||
				{ (int)MySqlDbType.Float, ("(float?)", "float.Parse({0})", "{0}.ToString()", "float?", typeof(float), typeof(float?), "{0}.Value", "GetFloat") },
 | 
									{ (int)NpgsqlDbType.Bytea, ("(byte[])", "Convert.FromBase64String({0})", "Convert.ToBase64String({0})", "byte[]", typeof(byte[]), typeof(byte[]), "{0}", "GetValue") },
 | 
				
			||||||
				{ (int)MySqlDbType.Decimal, ("(decimal?)", "decimal.Parse({0})", "{0}.ToString()", "decimal?", typeof(decimal), typeof(decimal?), "{0}.Value", "GetDecimal") },
 | 
									{ (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)NpgsqlDbType.Point, ("(NpgsqlPoint?)", "NpgsqlPoint.Parse({0})", "{0}.ToString()", "NpgsqlPoint", typeof(NpgsqlPoint), typeof(NpgsqlPoint?), "{0}", "GetValue") },
 | 
				
			||||||
				{ (int)MySqlDbType.Time, ("(TimeSpan?)", "TimeSpan.FromSeconds(double.Parse({0}))", "{0}.ToString()", "TimeSpan?", typeof(TimeSpan), typeof(TimeSpan?), "{0}.Value", "GetValue") },
 | 
									{ (int)NpgsqlDbType.Line, ("(NpgsqlLine?)", "NpgsqlLine.Parse({0})", "{0}.ToString()", "NpgsqlLine", typeof(NpgsqlLine), typeof(NpgsqlLine?), "{0}", "GetValue") },
 | 
				
			||||||
				{ (int)MySqlDbType.Date, ("(DateTime?)", "new DateTime(long.Parse({0}))", "{0}.ToString()", "DateTime?", typeof(DateTime), typeof(DateTime?), "{0}.Value", "GetDateTime") },
 | 
									{ (int)NpgsqlDbType.LSeg, ("(NpgsqlLSeg?)", "NpgsqlLSeg.Parse({0})", "{0}.ToString()", "NpgsqlLSeg", typeof(NpgsqlLSeg), typeof(NpgsqlLSeg?), "{0}", "GetValue") },
 | 
				
			||||||
				{ (int)MySqlDbType.Timestamp, ("(DateTime?)", "new DateTime(long.Parse({0}))", "{0}.TotalSeconds.ToString()", "DateTime?", typeof(DateTime), typeof(DateTime?), "{0}.Value", "GetDateTime") },
 | 
									{ (int)NpgsqlDbType.Box, ("(NpgsqlBox?)", "NpgsqlBox.Parse({0})", "{0}.ToString()", "NpgsqlBox", typeof(NpgsqlBox), typeof(NpgsqlBox?), "{0}", "GetValue") },
 | 
				
			||||||
				{ (int)MySqlDbType.DateTime, ("(DateTime?)", "new DateTime(long.Parse({0}))", "{0}.Ticks.ToString()", "DateTime?", typeof(DateTime), typeof(DateTime?), "{0}.Value", "GetDateTime") },
 | 
									{ (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)NpgsqlDbType.Cidr, ("((IPAddress, int)?)", "(IPAddress, int)({0})", "{0}.ToString()", "(IPAddress, int)", typeof((IPAddress, int)), typeof((IPAddress, int)?), "{0}", "GetValue") },
 | 
				
			||||||
				{ (int)MySqlDbType.Blob, ("(byte[])", "Convert.FromBase64String({0})", "Convert.ToBase64String({0})", "byte[]", typeof(byte[]), typeof(byte[]), "{0}", "GetValue") },
 | 
									{ (int)NpgsqlDbType.Inet, ("(IPAddress)", "IPAddress.Parse({0})", "{0}.ToString()", "IPAddress", typeof(IPAddress), typeof(IPAddress), "{0}", "GetValue") },
 | 
				
			||||||
				{ (int)MySqlDbType.MediumBlob, ("(byte[])", "Convert.FromBase64String({0})", "Convert.ToBase64String({0})", "byte[]", typeof(byte[]), typeof(byte[]), "{0}", "GetValue") },
 | 
									{ (int)NpgsqlDbType.MacAddr, ("(PhysicalAddress?)", "PhysicalAddress.Parse({0})", "{0}.ToString()", "PhysicalAddress", typeof(PhysicalAddress), typeof(PhysicalAddress), "{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)NpgsqlDbType.Json, ("(JToken)", "JToken.Parse({0})", "{0}.ToString()", "JToken", typeof(JToken), typeof(JToken), "{0}", "GetString") },
 | 
				
			||||||
				{ (int)MySqlDbType.VarBinary, ("(byte[])", "Convert.FromBase64String({0})", "Convert.ToBase64String({0})", "byte[]", typeof(byte[]), typeof(byte[]), "{0}", "GetValue") },
 | 
									{ (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)(NpgsqlDbType.Range | NpgsqlDbType.Integer), ("(NpgsqlRange<int>?)", "{0}.ToNpgsqlRange<int>()", "{0}.ToString()", "NpgsqlRange<int>", typeof(NpgsqlRange<int>), typeof(NpgsqlRange<int>?), "{0}", "GetString") },
 | 
				
			||||||
				{ (int)MySqlDbType.Text, ("", "{0}.Replace(StringifySplit, \"|\")", "{0}.Replace(\"|\", StringifySplit)", "string", typeof(string), typeof(string), "{0}", "GetString") },
 | 
									{ (int)(NpgsqlDbType.Range | NpgsqlDbType.Bigint), ("(NpgsqlRange<long>?)", "{0}.ToNpgsqlRange<long>()", "{0}.ToString()", "NpgsqlRange<long>", typeof(NpgsqlRange<long>), typeof(NpgsqlRange<long>?), "{0}", "GetString") },
 | 
				
			||||||
				{ (int)MySqlDbType.MediumText, ("", "{0}.Replace(StringifySplit, \"|\")", "{0}.Replace(\"|\", StringifySplit)", "string", typeof(string), typeof(string), "{0}", "GetString") },
 | 
									{ (int)(NpgsqlDbType.Range | NpgsqlDbType.Numeric), ("(NpgsqlRange<decimal>?)", "{0}.ToNpgsqlRange<decimal>()", "{0}.ToString()", "NpgsqlRange<decimal>", typeof(NpgsqlRange<decimal>), typeof(NpgsqlRange<decimal>?), "{0}", "GetString") },
 | 
				
			||||||
				{ (int)MySqlDbType.LongText, ("", "{0}.Replace(StringifySplit, \"|\")", "{0}.Replace(\"|\", StringifySplit)", "string", typeof(string), typeof(string), "{0}", "GetString") },
 | 
									{ (int)(NpgsqlDbType.Range | NpgsqlDbType.Timestamp), ("(NpgsqlRange<DateTime>?)", "{0}.ToNpgsqlRange<DateTime>()", "{0}.ToString()", "NpgsqlRange<DateTime>", typeof(NpgsqlRange<DateTime>), typeof(NpgsqlRange<DateTime>?), "{0}", "GetString") },
 | 
				
			||||||
 | 
									{ (int)(NpgsqlDbType.Range | NpgsqlDbType.TimestampTz), ("(NpgsqlRange<DateTime>?)", "{0}.ToNpgsqlRange<DateTime>()", "{0}.ToString()", "NpgsqlRange<DateTime>", typeof(NpgsqlRange<DateTime>), typeof(NpgsqlRange<DateTime>?), "{0}", "GetString") },
 | 
				
			||||||
 | 
									{ (int)(NpgsqlDbType.Range | NpgsqlDbType.Date), ("(NpgsqlRange<DateTime>?)", "{0}.ToNpgsqlRange<DateTime>()", "{0}.ToString()", "NpgsqlRange<DateTime>", typeof(NpgsqlRange<DateTime>), typeof(NpgsqlRange<DateTime>?), "{0}", "GetString") },
 | 
				
			||||||
 | 
					
 | 
				
			||||||
				{ (int)MySqlDbType.String, ("", "{0}.Replace(StringifySplit, \"|\")", "{0}.Replace(\"|\", StringifySplit)", "string", typeof(string), typeof(string), "{0}", "GetString") },
 | 
									{ (int)NpgsqlDbType.Hstore, ("(Dictionary<string, string>)", "JsonConvert.DeserializeObject<Dictionary<string, string>>({0})", "JsonConvert.SerializeObject({0})", "Dictionary<string, string>", typeof(Dictionary<string, string>), typeof(Dictionary<string, string>), "{0}", "GetValue") },
 | 
				
			||||||
				{ (int)MySqlDbType.VarString, ("", "{0}.Replace(StringifySplit, \"|\")", "{0}.Replace(\"|\", StringifySplit)", "string", typeof(string), typeof(string), "{0}", "GetString") },
 | 
									{ (int)NpgsqlDbType.Geometry, ("(PostgisGeometry)", "JsonConvert.DeserializeObject<PostgisGeometry>({0})", "JsonConvert.SerializeObject({0})", "PostgisGeometry", typeof(PostgisGeometry), typeof(PostgisGeometry), "{0}", "GetValue") },
 | 
				
			||||||
				{ (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") },
 | 
									/*** array ***/
 | 
				
			||||||
				{ (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") },
 | 
									{ (int)(NpgsqlDbType.Smallint | NpgsqlDbType.Array), ("(short[])", "JsonConvert.DeserializeObject<short[]>({0})", "JsonConvert.SerializeObject({0})", "short[]", typeof(short[]), typeof(short[]), "{0}", "GetValue") },
 | 
				
			||||||
 | 
									{ (int)(NpgsqlDbType.Integer | NpgsqlDbType.Array), ("(int[])", "JsonConvert.DeserializeObject<int[]>({0})", "JsonConvert.SerializeObject({0})", "int[]", typeof(int[]), typeof(int[]), "{0}", "GetValue") },
 | 
				
			||||||
 | 
									{ (int)(NpgsqlDbType.Bigint | NpgsqlDbType.Array), ("(long[])", "JsonConvert.DeserializeObject<long[]>({0})", "JsonConvert.SerializeObject({0})", "long[]", typeof(long[]), typeof(long[]), "{0}", "GetValue") },
 | 
				
			||||||
 | 
									{ (int)(NpgsqlDbType.Numeric | NpgsqlDbType.Array), ("(decimal[])", "JsonConvert.DeserializeObject<decimal[]>({0})", "JsonConvert.SerializeObject({0})", "decimal[]", typeof(decimal[]), typeof(decimal[]), "{0}", "GetValue") },
 | 
				
			||||||
 | 
									{ (int)(NpgsqlDbType.Real | NpgsqlDbType.Array), ("(float[])", "JsonConvert.DeserializeObject<float[]>({0})", "JsonConvert.SerializeObject({0})", "float[]", typeof(float[]), typeof(float[]), "{0}", "GetValue") },
 | 
				
			||||||
 | 
									{ (int)(NpgsqlDbType.Double | NpgsqlDbType.Array), ("(double[])", "JsonConvert.DeserializeObject<double[]>({0})", "JsonConvert.SerializeObject({0})", "double[]", typeof(double[]), typeof(double[]), "{0}", "GetValue") },
 | 
				
			||||||
 | 
									{ (int)(NpgsqlDbType.Money | NpgsqlDbType.Array), ("(decimal[])", "JsonConvert.DeserializeObject<decimal[]>({0})", "JsonConvert.SerializeObject({0})", "decimal[]", typeof(decimal[]), typeof(decimal[]), "{0}", "GetValue") },
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
									{ (int)(NpgsqlDbType.Char | NpgsqlDbType.Array), ("(string[])", "JsonConvert.DeserializeObject<string[]>({0})", "JsonConvert.SerializeObject({0})", "string[]", typeof(string[]), typeof(string[]), "{0}", "GetValue") },
 | 
				
			||||||
 | 
									{ (int)(NpgsqlDbType.Varchar | NpgsqlDbType.Array), ("(string[])", "JsonConvert.DeserializeObject<string[]>({0})", "JsonConvert.SerializeObject({0})", "string[]", typeof(string[]), typeof(string[]), "{0}", "GetValue") },
 | 
				
			||||||
 | 
									{ (int)(NpgsqlDbType.Text | NpgsqlDbType.Array), ("(string[])", "JsonConvert.DeserializeObject<string[]>({0})", "JsonConvert.SerializeObject({0})", "string[]", typeof(string[]), typeof(string[]), "{0}", "GetValue") },
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
									{ (int)(NpgsqlDbType.Timestamp | NpgsqlDbType.Array), ("(DateTime[])", "JsonConvert.DeserializeObject<DateTime[]>({0})", "JsonConvert.SerializeObject({0})", "DateTime[]", typeof(DateTime[]), typeof(DateTime[]), "{0}", "GetValue") },
 | 
				
			||||||
 | 
									{ (int)(NpgsqlDbType.TimestampTz | NpgsqlDbType.Array), ("(DateTime[])", "JsonConvert.DeserializeObject<DateTime[]>({0})", "JsonConvert.SerializeObject({0})", "DateTime[]", typeof(DateTime[]), typeof(DateTime[]), "{0}", "GetValue") },
 | 
				
			||||||
 | 
									{ (int)(NpgsqlDbType.Date | NpgsqlDbType.Array), ("(DateTime[])", "JsonConvert.DeserializeObject<DateTime[]>({0})", "JsonConvert.SerializeObject({0})", "DateTime[]", typeof(DateTime[]), typeof(DateTime[]), "{0}", "GetValue") },
 | 
				
			||||||
 | 
									{ (int)(NpgsqlDbType.Time | NpgsqlDbType.Array), ("(TimeSpan[])", "JsonConvert.DeserializeObject<TimeSpan[]>({0})", "JsonConvert.SerializeObject({0})", "TimeSpan[]", typeof(TimeSpan[]), typeof(TimeSpan[]), "{0}", "GetValue") },
 | 
				
			||||||
 | 
									{ (int)(NpgsqlDbType.TimeTz | NpgsqlDbType.Array), ("(TimeSpan[])", "JsonConvert.DeserializeObject<TimeSpan[]>({0})", "JsonConvert.SerializeObject({0})", "TimeSpan[]", typeof(TimeSpan[]), typeof(TimeSpan[]), "{0}", "GetValue") },
 | 
				
			||||||
 | 
									{ (int)(NpgsqlDbType.Interval | NpgsqlDbType.Array), ("(TimeSpan[])", "JsonConvert.DeserializeObject<TimeSpan[]>({0})", "JsonConvert.SerializeObject({0})", "TimeSpan[]", typeof(TimeSpan[]), typeof(TimeSpan[]), "{0}", "GetValue") },
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
									{ (int)(NpgsqlDbType.Boolean | NpgsqlDbType.Array), ("(bool[])", "JsonConvert.DeserializeObject<bool[]>({0})", "JsonConvert.SerializeObject({0})", "bool[]", typeof(bool[]), typeof(bool[]), "{0}", "GetValue") },
 | 
				
			||||||
 | 
									{ (int)(NpgsqlDbType.Bytea | NpgsqlDbType.Array), ("(byte[][])", "JsonConvert.DeserializeObject<byte[][]>({0})", "JsonConvert.SerializeObject({0})", "byte[][]", typeof(byte[][]), typeof(byte[][]), "{0}", "GetValue") },
 | 
				
			||||||
 | 
									{ (int)(NpgsqlDbType.Bit | NpgsqlDbType.Array), ("(BitArray[])", "JsonConvert.DeserializeObject<BitArray[]>({0})", "JsonConvert.SerializeObject({0})", "BitArray[]", typeof(BitArray[]), typeof(BitArray[]), "{0}", "GetValue") },
 | 
				
			||||||
 | 
									{ (int)(NpgsqlDbType.Varbit | NpgsqlDbType.Array), ("(BitArray[])", "JsonConvert.DeserializeObject<BitArray[]>({0})", "JsonConvert.SerializeObject({0})", "BitArray[]", typeof(BitArray[]), typeof(BitArray[]), "{0}", "GetValue") },
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
									{ (int)(NpgsqlDbType.Point | NpgsqlDbType.Array), ("(NpgsqlPoint[])", "JsonConvert.DeserializeObject<NpgsqlPoint[]>({0})", "JsonConvert.SerializeObject({0})", "NpgsqlPoint[]", typeof(NpgsqlPoint[]), typeof(NpgsqlPoint[]), "{0}", "GetValue") },
 | 
				
			||||||
 | 
									{ (int)(NpgsqlDbType.Line | NpgsqlDbType.Array), ("(NpgsqlLine[])", "JsonConvert.DeserializeObject<BNpgsqlLineitArray[]>({0})", "JsonConvert.SerializeObject({0})", "NpgsqlLine[]", typeof(NpgsqlLine[]), typeof(NpgsqlLine[]), "{0}", "GetValue") },
 | 
				
			||||||
 | 
									{ (int)(NpgsqlDbType.LSeg | NpgsqlDbType.Array), ("(NpgsqlLSeg[])", "JsonConvert.DeserializeObject<NpgsqlLSeg[]>({0})", "JsonConvert.SerializeObject({0})", "NpgsqlLSeg[]", typeof(NpgsqlLSeg[]), typeof(NpgsqlLSeg[]), "{0}", "GetValue") },
 | 
				
			||||||
 | 
									{ (int)(NpgsqlDbType.Box | NpgsqlDbType.Array), ("(NpgsqlBox[])", "JsonConvert.DeserializeObject<NpgsqlBox[]>({0})", "JsonConvert.SerializeObject({0})", "NpgsqlBox[]", typeof(NpgsqlBox[]), typeof(NpgsqlBox[]), "{0}", "GetValue") },
 | 
				
			||||||
 | 
									{ (int)(NpgsqlDbType.Path | NpgsqlDbType.Array), ("(NpgsqlPath[])", "JsonConvert.DeserializeObject<NpgsqlPath[]>({0})", "JsonConvert.SerializeObject({0})", "NpgsqlPath[]", typeof(NpgsqlPath[]), typeof(NpgsqlPath[]), "{0}", "GetValue") },
 | 
				
			||||||
 | 
									{ (int)(NpgsqlDbType.Polygon | NpgsqlDbType.Array), ("(NpgsqlPolygon[])", "JsonConvert.DeserializeObject<NpgsqlPolygon[]>({0})", "JsonConvert.SerializeObject({0})", "NpgsqlPolygon[]", typeof(NpgsqlPolygon[]), typeof(NpgsqlPolygon[]), "{0}", "GetValue") },
 | 
				
			||||||
 | 
									{ (int)(NpgsqlDbType.Circle | NpgsqlDbType.Array), ("(NpgsqlCircle[])", "JsonConvert.DeserializeObject<NpgsqlCircle[]>({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<IPAddress[]>({0})", "JsonConvert.SerializeObject({0})", "IPAddress[]", typeof(IPAddress[]), typeof(IPAddress[]), "{0}", "GetValue") },
 | 
				
			||||||
 | 
									{ (int)(NpgsqlDbType.MacAddr | NpgsqlDbType.Array), ("(PhysicalAddress[])", "JsonConvert.DeserializeObject<PhysicalAddress[]>({0})", "JsonConvert.SerializeObject({0})", "PhysicalAddress[]", typeof(PhysicalAddress[]), typeof(PhysicalAddress[]), "{0}", "GetValue") },
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
									{ (int)(NpgsqlDbType.Json | NpgsqlDbType.Array), ("(JToken[])", "JsonConvert.DeserializeObject<JToken[]>({0})", "JsonConvert.SerializeObject({0})", "JToken[]", typeof(JToken[]), typeof(JToken[]), "{0}", "GetValue") },
 | 
				
			||||||
 | 
									{ (int)(NpgsqlDbType.Jsonb | NpgsqlDbType.Array), ("(JToken[])", "JsonConvert.DeserializeObject<JToken[]>({0})", "JsonConvert.SerializeObject({0})", "JToken[]", typeof(JToken[]), typeof(JToken[]), "{0}", "GetValue") },
 | 
				
			||||||
 | 
									{ (int)(NpgsqlDbType.Uuid | NpgsqlDbType.Array), ("(Guid[])", "JsonConvert.DeserializeObject<Guid[]>({0})", "JsonConvert.SerializeObject({0})", "Guid[]", typeof(Guid[]), typeof(Guid[]), "{0}", "GetValue") },
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
									{ (int)(NpgsqlDbType.Range | NpgsqlDbType.Integer | NpgsqlDbType.Array), ("(NpgsqlRange<int>[])", "JsonConvert.DeserializeObject<NpgsqlRange<int>[]>({0})", "JsonConvert.SerializeObject({0})", "NpgsqlRange<int>[]", typeof(NpgsqlRange<int>[]), typeof(NpgsqlRange<int>[]), "{0}", "GetValue") },
 | 
				
			||||||
 | 
									{ (int)(NpgsqlDbType.Range | NpgsqlDbType.Bigint | NpgsqlDbType.Array), ("(NpgsqlRange<long>[])", "JsonConvert.DeserializeObject<NpgsqlRange<long>[]>({0})", "JsonConvert.SerializeObject({0})", "NpgsqlRange<long>[]", typeof(NpgsqlRange<long>[]), typeof(NpgsqlRange<long>[]), "{0}", "GetValue") },
 | 
				
			||||||
 | 
									{ (int)(NpgsqlDbType.Range | NpgsqlDbType.Numeric | NpgsqlDbType.Array), ("(NpgsqlRange<decimal>[])", "JsonConvert.DeserializeObject<NpgsqlRange<decimal>[]>({0})", "JsonConvert.SerializeObject({0})", "NpgsqlRange<decimal>[]", typeof(NpgsqlRange<decimal>[]), typeof(NpgsqlRange<decimal>[]), "{0}", "GetValue") },
 | 
				
			||||||
 | 
									{ (int)(NpgsqlDbType.Range | NpgsqlDbType.Timestamp | NpgsqlDbType.Array), ("(NpgsqlRange<DateTime>[])", "JsonConvert.DeserializeObject<NpgsqlRange<DateTime>[]>({0})", "JsonConvert.SerializeObject({0})", "NpgsqlRange<DateTime>[]", typeof(NpgsqlRange<DateTime>[]), typeof(NpgsqlRange<DateTime>[]), "{0}", "GetValue") },
 | 
				
			||||||
 | 
									{ (int)(NpgsqlDbType.Range | NpgsqlDbType.TimestampTz | NpgsqlDbType.Array), ("(NpgsqlRange<DateTime>[])", "JsonConvert.DeserializeObject<NpgsqlRange<DateTime>[]>({0})", "JsonConvert.SerializeObject({0})", "NpgsqlRange<DateTime>[]", typeof(NpgsqlRange<DateTime>[]), typeof(NpgsqlRange<DateTime>[]), "{0}", "GetValue") },
 | 
				
			||||||
 | 
									{ (int)(NpgsqlDbType.Range | NpgsqlDbType.Date | NpgsqlDbType.Array), ("(NpgsqlRange<DateTime>[])", "JsonConvert.DeserializeObject<NpgsqlRange<DateTime>[]>({0})", "JsonConvert.SerializeObject({0})", "NpgsqlRange<DateTime>[]", typeof(NpgsqlRange<DateTime>[]), typeof(NpgsqlRange<DateTime>[]), "{0}", "GetValue") },
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
									{ (int)(NpgsqlDbType.Hstore | NpgsqlDbType.Array), ("(Dictionary<string, string>[])", "JsonConvert.DeserializeObject<Dictionary<string, string>[]>({0})", "JsonConvert.SerializeObject({0})", "Dictionary<string, string>[]", typeof(Dictionary<string, string>[]), typeof(Dictionary<string, string>[]), "{0}", "GetValue") },
 | 
				
			||||||
 | 
									{ (int)(NpgsqlDbType.Geometry | NpgsqlDbType.Array), ("(PostgisGeometry[])", "JsonConvert.DeserializeObject<PostgisGeometry[]>({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;
 | 
							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 string GetDataReaderMethod(DbColumnInfo column) => _dicDbToCs.TryGetValue(column.DbType, out var trydc) ? trydc.dataReaderMethod : null;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		public List<string> GetDatabases() {
 | 
							public List<string> 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);
 | 
								var ds = _orm.Ado.ExecuteArray(CommandType.Text, sql);
 | 
				
			||||||
			return ds.Select(a => a.FirstOrDefault()?.ToString()).ToList();
 | 
								return ds.Select(a => a.FirstOrDefault()?.ToString()).ToList();
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		public List<DbTableInfo> GetTablesByDatabase(params string[] database) {
 | 
							public List<DbTableInfo> GetTablesByDatabase(params string[] database) {
 | 
				
			||||||
			var loc1 = new List<DbTableInfo>();
 | 
								var olddatabase = "";
 | 
				
			||||||
			var loc2 = new Dictionary<string, DbTableInfo>();
 | 
								using (var conn = _orm.Ado.MasterPool.Get(TimeSpan.FromSeconds(5))) {
 | 
				
			||||||
			var loc3 = new Dictionary<string, Dictionary<string, DbColumnInfo>>();
 | 
									olddatabase = conn.Value.Database;
 | 
				
			||||||
 | 
					 | 
				
			||||||
			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<string>();
 | 
					 | 
				
			||||||
			var loc66 = new List<string>();
 | 
					 | 
				
			||||||
			foreach (var row in ds) {
 | 
					 | 
				
			||||||
				var table_id = string.Concat(row[0]);
 | 
					 | 
				
			||||||
				var schema = string.Concat(row[1]);
 | 
					 | 
				
			||||||
				var table = string.Concat(row[2]);
 | 
					 | 
				
			||||||
				var 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<string, DbColumnInfo>());
 | 
					 | 
				
			||||||
				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 dbs = database?.ToArray() ?? new[] { olddatabase };
 | 
				
			||||||
			var loc8 = "'" + string.Join("','", loc6.ToArray()) + "'";
 | 
								var tables = new List<DbTableInfo>();
 | 
				
			||||||
			var loc88 = "'" + string.Join("','", loc66.ToArray()) + "'";
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
			sql = string.Format(@"select
 | 
								foreach (var db in dbs) {
 | 
				
			||||||
concat(a.table_schema, '.', a.table_name),
 | 
									if (string.IsNullOrEmpty(db) || string.Compare(db, olddatabase, true) != 0) continue;
 | 
				
			||||||
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) {
 | 
									var loc1 = new List<DbTableInfo>();
 | 
				
			||||||
				string table_id = string.Concat(row[0]);
 | 
									var loc2 = new Dictionary<string, DbTableInfo>();
 | 
				
			||||||
				string column = string.Concat(row[1]);
 | 
									var loc3 = new Dictionary<string, Dictionary<string, DbColumnInfo>>();
 | 
				
			||||||
				string type = string.Concat(row[2]);
 | 
					
 | 
				
			||||||
				//long max_length = long.Parse(string.Concat(row[3]));
 | 
									var sql = $@"
 | 
				
			||||||
				string sqlType = string.Concat(row[4]);
 | 
					select
 | 
				
			||||||
				var m_len = Regex.Match(sqlType, @"\w+\((\d+)");
 | 
					b.nspname || '.' || a.tablename,
 | 
				
			||||||
				int max_length = m_len.Success ? int.Parse(m_len.Groups[1].Value) : -1;
 | 
					a.schemaname,
 | 
				
			||||||
				bool is_nullable = string.Concat(row[5]) == "1";
 | 
					a.tablename ,
 | 
				
			||||||
				bool is_identity = string.Concat(row[6]) == "1";
 | 
					'TABLE'
 | 
				
			||||||
				string comment = string.Concat(row[7]);
 | 
					from pg_tables a
 | 
				
			||||||
				if (max_length == 0) max_length = -1;
 | 
					inner join pg_namespace b on b.nspname = a.schemaname
 | 
				
			||||||
				if (database.Length == 1) {
 | 
					where a.schemaname not in ('pg_catalog', 'information_schema', 'topology')
 | 
				
			||||||
					table_id = table_id.Substring(table_id.IndexOf('.') + 1);
 | 
					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<string>();
 | 
				
			||||||
 | 
									var loc66 = new List<string>();
 | 
				
			||||||
 | 
									foreach (object[] row in ds) {
 | 
				
			||||||
 | 
										var object_id = string.Concat(row[0]);
 | 
				
			||||||
 | 
										var owner = string.Concat(row[1]);
 | 
				
			||||||
 | 
										var table = string.Concat(row[2]);
 | 
				
			||||||
 | 
										Enum.TryParse<DbTableType>(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<string, DbColumnInfo>());
 | 
				
			||||||
 | 
										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 {
 | 
									if (loc6.Count == 0) return loc1;
 | 
				
			||||||
					Name = column,
 | 
									string loc8 = "'" + string.Join("','", loc6.ToArray()) + "'";
 | 
				
			||||||
					MaxLength = max_length,
 | 
									string loc88 = "'" + string.Join("','", loc66.ToArray()) + "'";
 | 
				
			||||||
					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 
 | 
									sql = $@"
 | 
				
			||||||
concat(a.constraint_schema, '.', a.table_name) 'table_id',
 | 
					select
 | 
				
			||||||
a.column_name,
 | 
					ns.nspname || '.' || c.relname as id, 
 | 
				
			||||||
concat(a.constraint_schema, '/', a.table_name, '/', a.constraint_name) 'index_id',
 | 
					t.typname,
 | 
				
			||||||
1 'IsUnique',
 | 
					case when a.atttypmod > 0 and a.atttypmod < 32767 then a.atttypmod - 4 else a.attlen end len,
 | 
				
			||||||
case when constraint_name = 'PRIMARY' then 1 else 0 end 'IsPrimaryKey',
 | 
					case when t.typelem = 0 then t.typname else t2.typname end,
 | 
				
			||||||
0 'IsClustered',
 | 
					case when a.attnotnull then 0 else 1 end as is_nullable,
 | 
				
			||||||
0 'IsDesc'
 | 
					e.adsrc as is_identity,
 | 
				
			||||||
from information_schema.key_column_usage a
 | 
					--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,
 | 
				
			||||||
where a.constraint_schema in ({1}) and a.table_name in ({0}) and isnull(position_in_unique_constraint)
 | 
					d.description as comment,
 | 
				
			||||||
", loc8, databaseIn);
 | 
					a.attndims,
 | 
				
			||||||
			ds = _orm.Ado.ExecuteArray(CommandType.Text, sql);
 | 
					case when t.typelem = 0 then t.typtype else t2.typtype end,
 | 
				
			||||||
			if (ds == null) return loc1;
 | 
					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<string, Dictionary<string, List<DbColumnInfo>>>();
 | 
									foreach (object[] row in ds) {
 | 
				
			||||||
			var uniqueColumns = new Dictionary<string, Dictionary<string, List<DbColumnInfo>>>();
 | 
										var object_id = string.Concat(row[0]);
 | 
				
			||||||
			foreach (var row in ds) {
 | 
										var column = string.Concat(row[1]);
 | 
				
			||||||
				string table_id = string.Concat(row[0]);
 | 
										var type = string.Concat(row[2]);
 | 
				
			||||||
				string column = string.Concat(row[1]);
 | 
										var max_length = int.Parse(string.Concat(row[3]));
 | 
				
			||||||
				string index_id = string.Concat(row[2]);
 | 
										var sqlType = string.Concat(row[4]);
 | 
				
			||||||
				bool is_unique = string.Concat(row[3]) == "1";
 | 
										var is_nullable = string.Concat(row[5]) == "1";
 | 
				
			||||||
				bool is_primary_key = string.Concat(row[4]) == "1";
 | 
										var is_identity = string.Concat(row[6]).StartsWith(@"nextval('") && string.Concat(row[6]).EndsWith(@"_seq'::regclass)");
 | 
				
			||||||
				bool is_clustered = string.Concat(row[5]) == "1";
 | 
										var comment = string.Concat(row[7]);
 | 
				
			||||||
				int is_desc = int.Parse(string.Concat(row[6]));
 | 
										int attndims = int.Parse(string.Concat(row[8]));
 | 
				
			||||||
				if (database.Length == 1) {
 | 
										string typtype = string.Concat(row[9]);
 | 
				
			||||||
					table_id = table_id.Substring(table_id.IndexOf('.') + 1);
 | 
										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<string, List<DbColumnInfo>> loc10 = null;
 | 
									sql = $@"
 | 
				
			||||||
				List<DbColumnInfo> loc11 = null;
 | 
					select
 | 
				
			||||||
				if (!indexColumns.TryGetValue(table_id, out loc10))
 | 
					ns.nspname || '.' || d.relname as table_id, 
 | 
				
			||||||
					indexColumns.Add(table_id, loc10 = new Dictionary<string, List<DbColumnInfo>>());
 | 
					c.attname,
 | 
				
			||||||
				if (!loc10.TryGetValue(index_id, out loc11))
 | 
					ns.nspname || '/' || d.relname || '/' || b.relname as index_id,
 | 
				
			||||||
					loc10.Add(index_id, loc11 = new List<DbColumnInfo>());
 | 
					case when a.indisunique then 1 else 0 end IsUnique,
 | 
				
			||||||
				loc11.Add(loc9);
 | 
					case when a.indisprimary then 1 else 0 end IsPrimary,
 | 
				
			||||||
				if (is_unique) {
 | 
					case when a.indisclustered then 0 else 1 end IsClustered,
 | 
				
			||||||
					if (!uniqueColumns.TryGetValue(table_id, out loc10))
 | 
					0 IsDesc,
 | 
				
			||||||
						uniqueColumns.Add(table_id, loc10 = new Dictionary<string, List<DbColumnInfo>>());
 | 
					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<string, Dictionary<string, List<DbColumnInfo>>>();
 | 
				
			||||||
 | 
									var uniqueColumns = new Dictionary<string, Dictionary<string, List<DbColumnInfo>>>();
 | 
				
			||||||
 | 
									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<string, List<DbColumnInfo>> loc10 = null;
 | 
				
			||||||
 | 
										List<DbColumnInfo> loc11 = null;
 | 
				
			||||||
 | 
										if (!indexColumns.TryGetValue(object_id, out loc10))
 | 
				
			||||||
 | 
											indexColumns.Add(object_id, loc10 = new Dictionary<string, List<DbColumnInfo>>());
 | 
				
			||||||
					if (!loc10.TryGetValue(index_id, out loc11))
 | 
										if (!loc10.TryGetValue(index_id, out loc11))
 | 
				
			||||||
						loc10.Add(index_id, loc11 = new List<DbColumnInfo>());
 | 
											loc10.Add(index_id, loc11 = new List<DbColumnInfo>());
 | 
				
			||||||
					loc11.Add(loc9);
 | 
										loc11.Add(loc9);
 | 
				
			||||||
				}
 | 
										if (is_unique) {
 | 
				
			||||||
			}
 | 
											if (!uniqueColumns.TryGetValue(object_id, out loc10))
 | 
				
			||||||
			foreach (string table_id in indexColumns.Keys) {
 | 
												uniqueColumns.Add(object_id, loc10 = new Dictionary<string, List<DbColumnInfo>>());
 | 
				
			||||||
				foreach (var columns in indexColumns[table_id].Values)
 | 
											if (!loc10.TryGetValue(index_id, out loc11))
 | 
				
			||||||
					loc2[table_id].Indexes.Add(columns);
 | 
												loc10.Add(index_id, loc11 = new List<DbColumnInfo>());
 | 
				
			||||||
			}
 | 
											loc11.Add(loc9);
 | 
				
			||||||
			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<string, Dictionary<string, DbForeignInfo>>();
 | 
					 | 
				
			||||||
			foreach (var row in ds) {
 | 
					 | 
				
			||||||
				string table_id = string.Concat(row[0]);
 | 
					 | 
				
			||||||
				string column = string.Concat(row[1]);
 | 
					 | 
				
			||||||
				string fk_id = string.Concat(row[2]);
 | 
					 | 
				
			||||||
				string ref_table_id = string.Concat(row[3]);
 | 
					 | 
				
			||||||
				bool is_foreign_key = string.Concat(row[4]) == "1";
 | 
					 | 
				
			||||||
				string referenced_column = string.Concat(row[5]);
 | 
					 | 
				
			||||||
				if (database.Length == 1) {
 | 
					 | 
				
			||||||
					table_id = table_id.Substring(table_id.IndexOf('.') + 1);
 | 
					 | 
				
			||||||
					ref_table_id = ref_table_id.Substring(ref_table_id.IndexOf('.') + 1);
 | 
					 | 
				
			||||||
				}
 | 
					 | 
				
			||||||
				if (loc3.ContainsKey(table_id) == false || loc3[table_id].ContainsKey(column) == false) continue;
 | 
					 | 
				
			||||||
				var loc9 = loc3[table_id][column];
 | 
					 | 
				
			||||||
				if (loc2.ContainsKey(ref_table_id) == false) continue;
 | 
					 | 
				
			||||||
				var loc10 = loc2[ref_table_id];
 | 
					 | 
				
			||||||
				var loc11 = loc3[ref_table_id][referenced_column];
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
				Dictionary<string, DbForeignInfo> loc12 = null;
 | 
					 | 
				
			||||||
				DbForeignInfo loc13 = null;
 | 
					 | 
				
			||||||
				if (!fkColumns.TryGetValue(table_id, out loc12))
 | 
					 | 
				
			||||||
					fkColumns.Add(table_id, loc12 = new Dictionary<string, DbForeignInfo>());
 | 
					 | 
				
			||||||
				if (!loc12.TryGetValue(fk_id, out loc13))
 | 
					 | 
				
			||||||
					loc12.Add(fk_id, loc13 = new DbForeignInfo { Table = loc2[table_id], ReferencedTable = loc10 });
 | 
					 | 
				
			||||||
				loc13.Columns.Add(loc9);
 | 
					 | 
				
			||||||
				loc13.ReferencedColumns.Add(loc11);
 | 
					 | 
				
			||||||
			}
 | 
					 | 
				
			||||||
			foreach (var table_id in fkColumns.Keys)
 | 
					 | 
				
			||||||
				foreach (var fk in fkColumns[table_id].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));
 | 
									foreach (var object_id in indexColumns.Keys) {
 | 
				
			||||||
				loc4.Columns.Sort((c1, c2) => {
 | 
										foreach (List<DbColumnInfo> columns in indexColumns[object_id].Values)
 | 
				
			||||||
					int compare = c2.IsPrimary.CompareTo(c1.IsPrimary);
 | 
											loc2[object_id].Indexes.Add(columns);
 | 
				
			||||||
					if (compare == 0) {
 | 
									}
 | 
				
			||||||
						bool b1 = loc4.Foreigns.Find(fk => fk.Columns.Find(c3 => c3.Name == c1.Name) != null) != null;
 | 
									foreach (var object_id in uniqueColumns.Keys) {
 | 
				
			||||||
						bool b2 = loc4.Foreigns.Find(fk => fk.Columns.Find(c3 => c3.Name == c2.Name) != null) != null;
 | 
										foreach (var columns in uniqueColumns[object_id].Values) {
 | 
				
			||||||
						compare = b2.CompareTo(b1);
 | 
											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<string, Dictionary<string, DbForeignInfo>>();
 | 
				
			||||||
 | 
									foreach (object[] row in ds) {
 | 
				
			||||||
 | 
										var table_id = string.Concat(row[0]);
 | 
				
			||||||
 | 
										var column = row[1] as string[];
 | 
				
			||||||
 | 
										var fk_id = string.Concat(row[2]);
 | 
				
			||||||
 | 
										var ref_table_id = string.Concat(row[3]);
 | 
				
			||||||
 | 
										var is_foreign_key = string.Concat(row[4]) == "1";
 | 
				
			||||||
 | 
										var referenced_column = row[5] as string[];
 | 
				
			||||||
 | 
										var referenced_db = string.Concat(row[6]);
 | 
				
			||||||
 | 
										var referenced_table = string.Concat(row[7]);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
										if (loc2.ContainsKey(ref_table_id) == false) continue;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
										Dictionary<string, DbForeignInfo> loc12 = null;
 | 
				
			||||||
 | 
										DbForeignInfo loc13 = null;
 | 
				
			||||||
 | 
										if (!fkColumns.TryGetValue(table_id, out loc12))
 | 
				
			||||||
 | 
											fkColumns.Add(table_id, loc12 = new Dictionary<string, DbForeignInfo>());
 | 
				
			||||||
 | 
										if (!loc12.TryGetValue(fk_id, out loc13))
 | 
				
			||||||
 | 
											loc12.Add(fk_id, loc13 = new DbForeignInfo { Table = loc2[table_id], ReferencedTable = loc2[ref_table_id] });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
										for (int a = 0; a < column.Length; a++) {
 | 
				
			||||||
 | 
											loc13.Columns.Add(loc3[table_id][column[a]]);
 | 
				
			||||||
 | 
											loc13.ReferencedColumns.Add(loc3[ref_table_id][referenced_column[a]]);
 | 
				
			||||||
 | 
										}
 | 
				
			||||||
 | 
									}
 | 
				
			||||||
 | 
									foreach (var table_id in fkColumns.Keys)
 | 
				
			||||||
 | 
										foreach (var fk in fkColumns[table_id].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);
 | 
									foreach (var loc4 in loc1) {
 | 
				
			||||||
			}
 | 
										var dicUniques = new Dictionary<string, List<DbColumnInfo>>();
 | 
				
			||||||
			loc1.Sort((t1, t2) => {
 | 
										if (loc4.Primarys.Count > 0) dicUniques.Add(string.Join(",", loc4.Primarys.Select(a => a.Name)), loc4.Primarys);
 | 
				
			||||||
				var ret = t1.Schema.CompareTo(t2.Schema);
 | 
										foreach (var loc5 in loc4.Uniques) {
 | 
				
			||||||
				if (ret == 0) ret = t1.Name.CompareTo(t2.Name);
 | 
											var dickey = string.Join(",", loc5.Select(a => a.Name));
 | 
				
			||||||
				return ret;
 | 
											if (dicUniques.ContainsKey(dickey)) continue;
 | 
				
			||||||
			});
 | 
											dicUniques.Add(dickey, loc5);
 | 
				
			||||||
			foreach (var loc4 in loc1) {
 | 
										}
 | 
				
			||||||
				var dicUniques = new Dictionary<string, List<DbColumnInfo>>();
 | 
										loc4.Uniques = dicUniques.Values.ToList();
 | 
				
			||||||
				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();
 | 
									loc2.Clear();
 | 
				
			||||||
			loc3.Clear();
 | 
									loc3.Clear();
 | 
				
			||||||
			return loc1;
 | 
									tables.AddRange(loc1);
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
								return tables;
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		public List<DbEnumInfo> GetEnumsByDatabase(params string[] database) {
 | 
							public List<DbEnumInfo> GetEnumsByDatabase(params string[] database) {
 | 
				
			||||||
			if (database == null || database.Length == 0) return new List<DbEnumInfo>();
 | 
								if (database == null || database.Length == 0) return new List<DbEnumInfo>();
 | 
				
			||||||
			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,
 | 
					ns.nspname || '.' || a.typname,
 | 
				
			||||||
b.enumlabel
 | 
					b.enumlabel
 | 
				
			||||||
from pg_type a
 | 
					from pg_type a
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -77,7 +77,7 @@ namespace FreeSql.SqlServer {
 | 
				
			|||||||
			var conn = _orm.Ado.MasterPool.Get(TimeSpan.FromSeconds(5));
 | 
								var conn = _orm.Ado.MasterPool.Get(TimeSpan.FromSeconds(5));
 | 
				
			||||||
			var database = conn.Value.Database;
 | 
								var database = conn.Value.Database;
 | 
				
			||||||
			Func<string, string, object> ExecuteScalar = (db, sql) => {
 | 
								Func<string, string, object> 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 {
 | 
									try {
 | 
				
			||||||
					using (var cmd = conn.Value.CreateCommand()) {
 | 
										using (var cmd = conn.Value.CreateCommand()) {
 | 
				
			||||||
						cmd.CommandText = sql;
 | 
											cmd.CommandText = sql;
 | 
				
			||||||
@@ -101,18 +101,18 @@ namespace FreeSql.SqlServer {
 | 
				
			|||||||
					if (tboldname?.Length == 1) tboldname = new[] { database, "dbo", tboldname[0] };
 | 
										if (tboldname?.Length == 1) tboldname = new[] { database, "dbo", tboldname[0] };
 | 
				
			||||||
					if (tboldname?.Length == 2) tboldname = new[] { database, tboldname[0], tboldname[1] };
 | 
										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]}];");
 | 
											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]");
 | 
											ExecuteScalar(tbname[0], $"create schema [{tbname[1]}] authorization [dbo]");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
					var sbalter = new StringBuilder();
 | 
										var sbalter = new StringBuilder();
 | 
				
			||||||
					var istmpatler = false; //创建临时表,导入数据,删除旧表,修改
 | 
										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 (tboldname != null) {
 | 
				
			||||||
							if (string.Compare(tboldname[0], tbname[0], true) != 0 && ExecuteScalar(database, $"select 1 from sys.databases where name='{tboldname[0]}'") == 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 ||
 | 
													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)
 | 
													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;
 | 
													tboldname = null;
 | 
				
			||||||
						}
 | 
											}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -97,7 +97,7 @@ namespace FreeSql.SqlServer {
 | 
				
			|||||||
		public string GetDataReaderMethod(DbColumnInfo column) => _dicDbToCs.TryGetValue(column.DbType, out var trydc) ? trydc.dataReaderMethod : null;
 | 
							public string GetDataReaderMethod(DbColumnInfo column) => _dicDbToCs.TryGetValue(column.DbType, out var trydc) ? trydc.dataReaderMethod : null;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		public List<string> GetDatabases() {
 | 
							public List<string> 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);
 | 
								var ds = _orm.Ado.ExecuteArray(CommandType.Text, sql);
 | 
				
			||||||
			return ds.Select(a => a.FirstOrDefault()?.ToString()).ToList();
 | 
								return ds.Select(a => a.FirstOrDefault()?.ToString()).ToList();
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
@@ -306,6 +306,7 @@ use {olddatabase};
 | 
				
			|||||||
				}
 | 
									}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
				sql = $@"
 | 
									sql = $@"
 | 
				
			||||||
 | 
					use {db};
 | 
				
			||||||
select 
 | 
					select 
 | 
				
			||||||
 b.object_id 'Object_id'
 | 
					 b.object_id 'Object_id'
 | 
				
			||||||
,c.name 'Column'
 | 
					,c.name 'Column'
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -9,8 +9,8 @@ namespace FreeSql.SqlServer {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
	class SqlServerUtils : CommonUtils {
 | 
						class SqlServerUtils : CommonUtils {
 | 
				
			||||||
		IFreeSql _orm;
 | 
							IFreeSql _orm;
 | 
				
			||||||
		public SqlServerUtils(IFreeSql mysql) {
 | 
							public SqlServerUtils(IFreeSql orm) {
 | 
				
			||||||
			_orm = mysql;
 | 
								_orm = orm;
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		internal override DbParameter AppendParamter(List<DbParameter> _params, string parameterName, Type type, object value) {
 | 
							internal override DbParameter AppendParamter(List<DbParameter> _params, string parameterName, Type type, object value) {
 | 
				
			||||||
 
 | 
				
			|||||||
		Reference in New Issue
	
	Block a user