mirror of
				https://github.com/nsnail/FreeSql.git
				synced 2025-11-04 09:15:27 +08:00 
			
		
		
		
	- 调整 移除对 System.ValueType 的依赖,减少版本冲突问题;(目前 FreeSql.dll 无任何公用库依赖)
This commit is contained in:
		@@ -73,14 +73,14 @@ public class RazorModel {
 | 
				
			|||||||
		if (col.CsType != null)
 | 
							if (col.CsType != null)
 | 
				
			||||||
		{
 | 
							{
 | 
				
			||||||
			var dbinfo = fsql.CodeFirst.GetDbInfo(col.CsType);
 | 
								var dbinfo = fsql.CodeFirst.GetDbInfo(col.CsType);
 | 
				
			||||||
			if (dbinfo != null && dbinfo.Value.dbtypeFull.Replace("NOT NULL", "").Trim() != col.DbTypeTextFull)
 | 
								if (dbinfo != null && dbinfo.dbtypeFull.Replace("NOT NULL", "").Trim() != col.DbTypeTextFull)
 | 
				
			||||||
				sb.Add("DbType = \"" + col.DbTypeTextFull + "\"");
 | 
									sb.Add("DbType = \"" + col.DbTypeTextFull + "\"");
 | 
				
			||||||
			if (col.IsPrimary)
 | 
								if (col.IsPrimary)
 | 
				
			||||||
				sb.Add("IsPrimary = true");
 | 
									sb.Add("IsPrimary = true");
 | 
				
			||||||
			if (col.IsIdentity)
 | 
								if (col.IsIdentity)
 | 
				
			||||||
				sb.Add("IsIdentity = true");
 | 
									sb.Add("IsIdentity = true");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
			if (dbinfo != null && dbinfo.Value.isnullable != col.IsNullable)
 | 
								if (dbinfo != null && dbinfo.isnullable != col.IsNullable)
 | 
				
			||||||
			{
 | 
								{
 | 
				
			||||||
				if (col.IsNullable && fsql.DbFirst.GetCsType(col).Contains("?") == false && col.CsType.IsValueType)
 | 
									if (col.IsNullable && fsql.DbFirst.GetCsType(col).Contains("?") == false && col.CsType.IsValueType)
 | 
				
			||||||
					sb.Add("IsNullable = true");
 | 
										sb.Add("IsNullable = true");
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,7 +1,7 @@
 | 
				
			|||||||
<Project Sdk="Microsoft.NET.Sdk">
 | 
					<Project Sdk="Microsoft.NET.Sdk">
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  <PropertyGroup>
 | 
					  <PropertyGroup>
 | 
				
			||||||
    <TargetFrameworks>netstandard2.0;netcoreapp31;netcoreapp22;netcoreapp21;net45;net40</TargetFrameworks>
 | 
					    <TargetFrameworks>netstandard2.0;netcoreapp31;netcoreapp30;netcoreapp22;netcoreapp21;net45;net40</TargetFrameworks>
 | 
				
			||||||
    <Version>1.3.0-preview4</Version>
 | 
					    <Version>1.3.0-preview4</Version>
 | 
				
			||||||
    <GeneratePackageOnBuild>true</GeneratePackageOnBuild>
 | 
					    <GeneratePackageOnBuild>true</GeneratePackageOnBuild>
 | 
				
			||||||
    <Authors>YeXiangQin</Authors>
 | 
					    <Authors>YeXiangQin</Authors>
 | 
				
			||||||
@@ -32,13 +32,16 @@
 | 
				
			|||||||
  <PropertyGroup Condition="'$(TargetFramework)' == 'net40'">
 | 
					  <PropertyGroup Condition="'$(TargetFramework)' == 'net40'">
 | 
				
			||||||
    <DefineConstants>net40</DefineConstants>
 | 
					    <DefineConstants>net40</DefineConstants>
 | 
				
			||||||
  </PropertyGroup>
 | 
					  </PropertyGroup>
 | 
				
			||||||
  <PropertyGroup Condition="'$(TargetFramework)' == 'netcoreapp31' or '$(TargetFramework)' == 'netcoreapp22' or '$(TargetFramework)' == 'netcoreapp21'">
 | 
					  <PropertyGroup Condition="'$(TargetFramework)' == 'netcoreapp31' or '$(TargetFramework)' == 'netcoreapp30' or '$(TargetFramework)' == 'netcoreapp22' or '$(TargetFramework)' == 'netcoreapp21'">
 | 
				
			||||||
    <DefineConstants>netcoreapp</DefineConstants>
 | 
					    <DefineConstants>netcoreapp</DefineConstants>
 | 
				
			||||||
  </PropertyGroup>
 | 
					  </PropertyGroup>
 | 
				
			||||||
  
 | 
					  
 | 
				
			||||||
  <ItemGroup Condition="'$(TargetFramework)' == 'netcoreapp31'">
 | 
					  <ItemGroup Condition="'$(TargetFramework)' == 'netcoreapp31'">
 | 
				
			||||||
    <PackageReference Include="Microsoft.Extensions.DependencyInjection" Version="3.1.1" />
 | 
					    <PackageReference Include="Microsoft.Extensions.DependencyInjection" Version="3.1.1" />
 | 
				
			||||||
  </ItemGroup>
 | 
					  </ItemGroup>
 | 
				
			||||||
 | 
					  <ItemGroup Condition="'$(TargetFramework)' == 'netcoreapp30'">
 | 
				
			||||||
 | 
					    <PackageReference Include="Microsoft.Extensions.DependencyInjection" Version="3.0.3" />
 | 
				
			||||||
 | 
					  </ItemGroup>
 | 
				
			||||||
  <ItemGroup Condition="'$(TargetFramework)' == 'netcoreapp22'">
 | 
					  <ItemGroup Condition="'$(TargetFramework)' == 'netcoreapp22'">
 | 
				
			||||||
    <PackageReference Include="Microsoft.Extensions.DependencyInjection" Version="2.2.0" />
 | 
					    <PackageReference Include="Microsoft.Extensions.DependencyInjection" Version="2.2.0" />
 | 
				
			||||||
  </ItemGroup>
 | 
					  </ItemGroup>
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -153,8 +153,19 @@ namespace FreeSql
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
    public class FluentDataFilter : IDisposable
 | 
					    public class FluentDataFilter : IDisposable
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
 | 
					        internal class FilterInfo
 | 
				
			||||||
        internal List<(Type type, string name, LambdaExpression exp)> _filters = new List<(Type type, string name, LambdaExpression exp)>();
 | 
					        {
 | 
				
			||||||
 | 
					            public Type type { get; }
 | 
				
			||||||
 | 
					            public string name { get; }
 | 
				
			||||||
 | 
					            public LambdaExpression exp { get; }
 | 
				
			||||||
 | 
					            public FilterInfo(Type type, string name, LambdaExpression exp)
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					                this.type = type;
 | 
				
			||||||
 | 
					                this.name = name;
 | 
				
			||||||
 | 
					                this.exp = exp;
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        internal List<FilterInfo> _filters = new List<FilterInfo>();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        public FluentDataFilter Apply<TEntity>(string filterName, Expression<Func<TEntity, bool>> filterAndValidateExp) where TEntity : class
 | 
					        public FluentDataFilter Apply<TEntity>(string filterName, Expression<Func<TEntity, bool>> filterAndValidateExp) where TEntity : class
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
@@ -162,7 +173,7 @@ namespace FreeSql
 | 
				
			|||||||
                throw new ArgumentNullException(nameof(filterName));
 | 
					                throw new ArgumentNullException(nameof(filterName));
 | 
				
			||||||
            if (filterAndValidateExp == null) return this;
 | 
					            if (filterAndValidateExp == null) return this;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            _filters.Add((typeof(TEntity), filterName, filterAndValidateExp));
 | 
					            _filters.Add(new FilterInfo(typeof(TEntity), filterName, filterAndValidateExp));
 | 
				
			||||||
            return this;
 | 
					            return this;
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,7 +1,7 @@
 | 
				
			|||||||
<Project Sdk="Microsoft.NET.Sdk">
 | 
					<Project Sdk="Microsoft.NET.Sdk">
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  <PropertyGroup>
 | 
					  <PropertyGroup>
 | 
				
			||||||
    <TargetFrameworks>netstandard2.0;netcoreapp31;netcoreapp22;netcoreapp21;net45;net40</TargetFrameworks>
 | 
					    <TargetFrameworks>netstandard2.0;netcoreapp31;netcoreapp30;netcoreapp22;netcoreapp21;net45;net40</TargetFrameworks>
 | 
				
			||||||
    <Version>1.3.0-preview4</Version>
 | 
					    <Version>1.3.0-preview4</Version>
 | 
				
			||||||
    <Authors>YeXiangQin</Authors>
 | 
					    <Authors>YeXiangQin</Authors>
 | 
				
			||||||
    <Description>FreeSql Implementation of General Repository, Support MySql/SqlServer/PostgreSQL/Oracle/Sqlite/达梦/Access, and read/write separation、and split table.</Description>
 | 
					    <Description>FreeSql Implementation of General Repository, Support MySql/SqlServer/PostgreSQL/Oracle/Sqlite/达梦/Access, and read/write separation、and split table.</Description>
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -13,6 +13,18 @@ namespace FreeSql.DatabaseModel
 | 
				
			|||||||
        /// <summary>
 | 
					        /// <summary>
 | 
				
			||||||
        /// 枚举项
 | 
					        /// 枚举项
 | 
				
			||||||
        /// </summary>
 | 
					        /// </summary>
 | 
				
			||||||
        public List<(string label, string value)> Labels { get; set; }
 | 
					        public List<LabelInfo> Labels { get; set; }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        public class LabelInfo
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            public string label { get; }
 | 
				
			||||||
 | 
					            public string value { get; }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            public LabelInfo(string label, string value)
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					                this.label = label;
 | 
				
			||||||
 | 
					                this.value = value;
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -51,6 +51,7 @@ public static class FreeSqlGlobalExpressionCall
 | 
				
			|||||||
        return false;
 | 
					        return false;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#if netcoreapp
 | 
				
			||||||
    /// <summary>
 | 
					    /// <summary>
 | 
				
			||||||
    /// C#:从元组集合中查找 exp1, exp2 是否存在<para></para>
 | 
					    /// C#:从元组集合中查找 exp1, exp2 是否存在<para></para>
 | 
				
			||||||
    /// SQL: <para></para>
 | 
					    /// SQL: <para></para>
 | 
				
			||||||
@@ -127,4 +128,5 @@ public static class FreeSqlGlobalExpressionCall
 | 
				
			|||||||
        expContext.Value.Result = sb.ToString();
 | 
					        expContext.Value.Result = sb.ToString();
 | 
				
			||||||
        return true;
 | 
					        return true;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
@@ -1,7 +1,7 @@
 | 
				
			|||||||
<Project Sdk="Microsoft.NET.Sdk">
 | 
					<Project Sdk="Microsoft.NET.Sdk">
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	<PropertyGroup>
 | 
						<PropertyGroup>
 | 
				
			||||||
		<TargetFrameworks>netstandard2.0;net45;net40</TargetFrameworks>
 | 
							<TargetFrameworks>netstandard2.0;netcoreapp31;netcoreapp30;netcoreapp22;netcoreapp21;net45;net40</TargetFrameworks>
 | 
				
			||||||
		<Version>1.3.0-preview4</Version>
 | 
							<Version>1.3.0-preview4</Version>
 | 
				
			||||||
		<GeneratePackageOnBuild>true</GeneratePackageOnBuild>
 | 
							<GeneratePackageOnBuild>true</GeneratePackageOnBuild>
 | 
				
			||||||
		<Authors>YeXiangQin</Authors>
 | 
							<Authors>YeXiangQin</Authors>
 | 
				
			||||||
@@ -32,9 +32,11 @@
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
	<ItemGroup>
 | 
						<ItemGroup>
 | 
				
			||||||
	  <PackageReference Include="SafeObjectPool" Version="2.3.1" />
 | 
						  <PackageReference Include="SafeObjectPool" Version="2.3.1" />
 | 
				
			||||||
	  <PackageReference Include="System.ValueTuple" Version="4.5.0" />
 | 
					 | 
				
			||||||
	</ItemGroup>
 | 
						</ItemGroup>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  <PropertyGroup Condition="'$(TargetFramework)' == 'netcoreapp31' or '$(TargetFramework)' == 'netcoreapp30' or '$(TargetFramework)' == 'netcoreapp22' or '$(TargetFramework)' == 'netcoreapp21'">
 | 
				
			||||||
 | 
					    <DefineConstants>netcoreapp</DefineConstants>
 | 
				
			||||||
 | 
					  </PropertyGroup>
 | 
				
			||||||
  <PropertyGroup Condition="'$(TargetFramework)' == 'net40'">
 | 
					  <PropertyGroup Condition="'$(TargetFramework)' == 'net40'">
 | 
				
			||||||
    <DefineConstants>net40</DefineConstants>
 | 
					    <DefineConstants>net40</DefineConstants>
 | 
				
			||||||
  </PropertyGroup>
 | 
					  </PropertyGroup>
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -2260,137 +2260,6 @@
 | 
				
			|||||||
            <param name="parms"></param>
 | 
					            <param name="parms"></param>
 | 
				
			||||||
            <returns></returns>
 | 
					            <returns></returns>
 | 
				
			||||||
        </member>
 | 
					        </member>
 | 
				
			||||||
        <member name="M:FreeSql.IAdo.ExecuteReaderAsync(System.Func{System.Data.Common.DbDataReader,System.Threading.Tasks.Task},System.Data.CommandType,System.String,System.Data.Common.DbParameter[])">
 | 
					 | 
				
			||||||
            <summary>
 | 
					 | 
				
			||||||
            查询,若使用读写分离,查询【从库】条件cmdText.StartsWith("SELECT "),否则查询【主库】
 | 
					 | 
				
			||||||
            </summary>
 | 
					 | 
				
			||||||
            <param name="readerHander"></param>
 | 
					 | 
				
			||||||
            <param name="cmdType"></param>
 | 
					 | 
				
			||||||
            <param name="cmdText"></param>
 | 
					 | 
				
			||||||
            <param name="cmdParms"></param>
 | 
					 | 
				
			||||||
        </member>
 | 
					 | 
				
			||||||
        <member name="M:FreeSql.IAdo.ExecuteReaderAsync(System.Func{System.Data.Common.DbDataReader,System.Threading.Tasks.Task},System.String,System.Object)">
 | 
					 | 
				
			||||||
            <summary>
 | 
					 | 
				
			||||||
            查询,ExecuteReaderAsync(dr => {}, "select * from user where age > ?age", new { age = 25 })
 | 
					 | 
				
			||||||
            </summary>
 | 
					 | 
				
			||||||
            <param name="cmdText"></param>
 | 
					 | 
				
			||||||
            <param name="parms"></param>
 | 
					 | 
				
			||||||
        </member>
 | 
					 | 
				
			||||||
        <member name="M:FreeSql.IAdo.ExecuteArrayAsync(System.Data.CommandType,System.String,System.Data.Common.DbParameter[])">
 | 
					 | 
				
			||||||
            <summary>
 | 
					 | 
				
			||||||
            查询
 | 
					 | 
				
			||||||
            </summary>
 | 
					 | 
				
			||||||
            <param name="cmdText"></param>
 | 
					 | 
				
			||||||
            <param name="cmdParms"></param>
 | 
					 | 
				
			||||||
        </member>
 | 
					 | 
				
			||||||
        <member name="M:FreeSql.IAdo.ExecuteArrayAsync(System.String,System.Object)">
 | 
					 | 
				
			||||||
            <summary>
 | 
					 | 
				
			||||||
            查询,ExecuteArrayAsync("select * from user where age > ?age", new { age = 25 })
 | 
					 | 
				
			||||||
            </summary>
 | 
					 | 
				
			||||||
            <param name="cmdText"></param>
 | 
					 | 
				
			||||||
            <param name="parms"></param>
 | 
					 | 
				
			||||||
            <returns></returns>
 | 
					 | 
				
			||||||
        </member>
 | 
					 | 
				
			||||||
        <member name="M:FreeSql.IAdo.ExecuteDataSetAsync(System.Data.CommandType,System.String,System.Data.Common.DbParameter[])">
 | 
					 | 
				
			||||||
            <summary>
 | 
					 | 
				
			||||||
            查询
 | 
					 | 
				
			||||||
            </summary>
 | 
					 | 
				
			||||||
            <param name="cmdText"></param>
 | 
					 | 
				
			||||||
            <param name="cmdParms"></param>
 | 
					 | 
				
			||||||
        </member>
 | 
					 | 
				
			||||||
        <member name="M:FreeSql.IAdo.ExecuteDataSetAsync(System.String,System.Object)">
 | 
					 | 
				
			||||||
            <summary>
 | 
					 | 
				
			||||||
            查询,ExecuteDataSetAsync("select * from user where age > ?age; select 2", new { age = 25 })
 | 
					 | 
				
			||||||
            </summary>
 | 
					 | 
				
			||||||
            <param name="cmdText"></param>
 | 
					 | 
				
			||||||
            <param name="parms"></param>
 | 
					 | 
				
			||||||
            <returns></returns>
 | 
					 | 
				
			||||||
        </member>
 | 
					 | 
				
			||||||
        <member name="M:FreeSql.IAdo.ExecuteDataTableAsync(System.Data.CommandType,System.String,System.Data.Common.DbParameter[])">
 | 
					 | 
				
			||||||
            <summary>
 | 
					 | 
				
			||||||
            查询
 | 
					 | 
				
			||||||
            </summary>
 | 
					 | 
				
			||||||
            <param name="cmdText"></param>
 | 
					 | 
				
			||||||
            <param name="cmdParms"></param>
 | 
					 | 
				
			||||||
        </member>
 | 
					 | 
				
			||||||
        <member name="M:FreeSql.IAdo.ExecuteDataTableAsync(System.String,System.Object)">
 | 
					 | 
				
			||||||
            <summary>
 | 
					 | 
				
			||||||
            查询,ExecuteDataTableAsync("select * from user where age > ?age", new { age = 25 })
 | 
					 | 
				
			||||||
            </summary>
 | 
					 | 
				
			||||||
            <param name="cmdText"></param>
 | 
					 | 
				
			||||||
            <param name="parms"></param>
 | 
					 | 
				
			||||||
            <returns></returns>
 | 
					 | 
				
			||||||
        </member>
 | 
					 | 
				
			||||||
        <member name="M:FreeSql.IAdo.ExecuteNonQueryAsync(System.Data.CommandType,System.String,System.Data.Common.DbParameter[])">
 | 
					 | 
				
			||||||
            <summary>
 | 
					 | 
				
			||||||
            在【主库】执行
 | 
					 | 
				
			||||||
            </summary>
 | 
					 | 
				
			||||||
            <param name="cmdType"></param>
 | 
					 | 
				
			||||||
            <param name="cmdText"></param>
 | 
					 | 
				
			||||||
            <param name="cmdParms"></param>
 | 
					 | 
				
			||||||
        </member>
 | 
					 | 
				
			||||||
        <member name="M:FreeSql.IAdo.ExecuteNonQueryAsync(System.String,System.Object)">
 | 
					 | 
				
			||||||
            <summary>
 | 
					 | 
				
			||||||
            在【主库】执行,ExecuteNonQueryAsync("delete from user where age > ?age", new { age = 25 })
 | 
					 | 
				
			||||||
            </summary>
 | 
					 | 
				
			||||||
            <param name="cmdText"></param>
 | 
					 | 
				
			||||||
            <param name="parms"></param>
 | 
					 | 
				
			||||||
            <returns></returns>
 | 
					 | 
				
			||||||
        </member>
 | 
					 | 
				
			||||||
        <member name="M:FreeSql.IAdo.ExecuteScalarAsync(System.Data.CommandType,System.String,System.Data.Common.DbParameter[])">
 | 
					 | 
				
			||||||
            <summary>
 | 
					 | 
				
			||||||
            在【主库】执行
 | 
					 | 
				
			||||||
            </summary>
 | 
					 | 
				
			||||||
            <param name="cmdType"></param>
 | 
					 | 
				
			||||||
            <param name="cmdText"></param>
 | 
					 | 
				
			||||||
            <param name="cmdParms"></param>
 | 
					 | 
				
			||||||
        </member>
 | 
					 | 
				
			||||||
        <member name="M:FreeSql.IAdo.ExecuteScalarAsync(System.String,System.Object)">
 | 
					 | 
				
			||||||
            <summary>
 | 
					 | 
				
			||||||
            在【主库】执行,ExecuteScalarAsync("select 1 from user where age > ?age", new { age = 25 })
 | 
					 | 
				
			||||||
            </summary>
 | 
					 | 
				
			||||||
            <param name="cmdText"></param>
 | 
					 | 
				
			||||||
            <param name="parms"></param>
 | 
					 | 
				
			||||||
            <returns></returns>
 | 
					 | 
				
			||||||
        </member>
 | 
					 | 
				
			||||||
        <member name="M:FreeSql.IAdo.QueryAsync``1(System.Data.CommandType,System.String,System.Data.Common.DbParameter[])">
 | 
					 | 
				
			||||||
            <summary>
 | 
					 | 
				
			||||||
            执行SQL返回对象集合,QueryAsync<User>("select * from user where age > ?age", new SqlParameter { ParameterName = "age", Value = 25 })
 | 
					 | 
				
			||||||
            </summary>
 | 
					 | 
				
			||||||
            <typeparam name="T"></typeparam>
 | 
					 | 
				
			||||||
            <param name="cmdType"></param>
 | 
					 | 
				
			||||||
            <param name="cmdText"></param>
 | 
					 | 
				
			||||||
            <param name="cmdParms"></param>
 | 
					 | 
				
			||||||
            <returns></returns>
 | 
					 | 
				
			||||||
        </member>
 | 
					 | 
				
			||||||
        <member name="M:FreeSql.IAdo.QueryAsync``1(System.String,System.Object)">
 | 
					 | 
				
			||||||
            <summary>
 | 
					 | 
				
			||||||
            执行SQL返回对象集合,QueryAsync<User>("select * from user where age > ?age", new { age = 25 })
 | 
					 | 
				
			||||||
            </summary>
 | 
					 | 
				
			||||||
            <typeparam name="T"></typeparam>
 | 
					 | 
				
			||||||
            <param name="cmdText"></param>
 | 
					 | 
				
			||||||
            <param name="parms"></param>
 | 
					 | 
				
			||||||
            <returns></returns>
 | 
					 | 
				
			||||||
        </member>
 | 
					 | 
				
			||||||
        <member name="M:FreeSql.IAdo.QueryAsync``2(System.Data.CommandType,System.String,System.Data.Common.DbParameter[])">
 | 
					 | 
				
			||||||
            <summary>
 | 
					 | 
				
			||||||
            执行SQL返回对象集合,Query<User>("select * from user where age > ?age; select * from address", new SqlParameter { ParameterName = "age", Value = 25 })
 | 
					 | 
				
			||||||
            </summary>
 | 
					 | 
				
			||||||
            <typeparam name="T1"></typeparam>
 | 
					 | 
				
			||||||
            <param name="cmdType"></param>
 | 
					 | 
				
			||||||
            <param name="cmdText"></param>
 | 
					 | 
				
			||||||
            <param name="cmdParms"></param>
 | 
					 | 
				
			||||||
            <returns></returns>
 | 
					 | 
				
			||||||
        </member>
 | 
					 | 
				
			||||||
        <member name="M:FreeSql.IAdo.QueryAsync``2(System.String,System.Object)">
 | 
					 | 
				
			||||||
            <summary>
 | 
					 | 
				
			||||||
            执行SQL返回对象集合,Query<User>("select * from user where age > ?age; select * from address", new { age = 25 })
 | 
					 | 
				
			||||||
            </summary>
 | 
					 | 
				
			||||||
            <typeparam name="T1"></typeparam>
 | 
					 | 
				
			||||||
            <param name="cmdText"></param>
 | 
					 | 
				
			||||||
            <param name="parms"></param>
 | 
					 | 
				
			||||||
            <returns></returns>
 | 
					 | 
				
			||||||
        </member>
 | 
					 | 
				
			||||||
        <member name="E:FreeSql.IAop.ParseExpression">
 | 
					        <member name="E:FreeSql.IAop.ParseExpression">
 | 
				
			||||||
            <summary>
 | 
					            <summary>
 | 
				
			||||||
            可自定义解析表达式
 | 
					            可自定义解析表达式
 | 
				
			||||||
@@ -2945,40 +2814,6 @@
 | 
				
			|||||||
            <param name="end"></param>
 | 
					            <param name="end"></param>
 | 
				
			||||||
            <returns></returns>
 | 
					            <returns></returns>
 | 
				
			||||||
        </member>
 | 
					        </member>
 | 
				
			||||||
        <member name="M:FreeSqlGlobalExpressionCall.Contains``2(System.Collections.Generic.IEnumerable{System.ValueTuple{``0,``1}},``0,``1)">
 | 
					 | 
				
			||||||
            <summary>
 | 
					 | 
				
			||||||
            C#:从元组集合中查找 exp1, exp2 是否存在<para></para>
 | 
					 | 
				
			||||||
            SQL: <para></para>
 | 
					 | 
				
			||||||
            exp1 = that[0].Item1 and exp2 = that[0].Item2 OR <para></para>
 | 
					 | 
				
			||||||
            exp1 = that[1].Item1 and exp2 = that[1].Item2 OR <para></para>
 | 
					 | 
				
			||||||
            ... <para></para>
 | 
					 | 
				
			||||||
            注意:当 that 为 null 或 empty 时,返回 1=0
 | 
					 | 
				
			||||||
            </summary>
 | 
					 | 
				
			||||||
            <typeparam name="T1"></typeparam>
 | 
					 | 
				
			||||||
            <typeparam name="T2"></typeparam>
 | 
					 | 
				
			||||||
            <param name="that"></param>
 | 
					 | 
				
			||||||
            <param name="exp1"></param>
 | 
					 | 
				
			||||||
            <param name="exp2"></param>
 | 
					 | 
				
			||||||
            <returns></returns>
 | 
					 | 
				
			||||||
        </member>
 | 
					 | 
				
			||||||
        <member name="M:FreeSqlGlobalExpressionCall.Contains``3(System.Collections.Generic.IEnumerable{System.ValueTuple{``0,``1,``2}},``0,``1,``2)">
 | 
					 | 
				
			||||||
            <summary>
 | 
					 | 
				
			||||||
            C#:从元组集合中查找 exp1, exp2, exp2 是否存在<para></para>
 | 
					 | 
				
			||||||
            SQL: <para></para>
 | 
					 | 
				
			||||||
            exp1 = that[0].Item1 and exp2 = that[0].Item2 and exp3 = that[0].Item3 OR <para></para>
 | 
					 | 
				
			||||||
            exp1 = that[1].Item1 and exp2 = that[1].Item2 and exp3 = that[1].Item3 OR <para></para>
 | 
					 | 
				
			||||||
            ... <para></para>
 | 
					 | 
				
			||||||
            注意:当 that 为 null 或 empty 时,返回 1=0
 | 
					 | 
				
			||||||
            </summary>
 | 
					 | 
				
			||||||
            <typeparam name="T1"></typeparam>
 | 
					 | 
				
			||||||
            <typeparam name="T2"></typeparam>
 | 
					 | 
				
			||||||
            <typeparam name="T3"></typeparam>
 | 
					 | 
				
			||||||
            <param name="that"></param>
 | 
					 | 
				
			||||||
            <param name="exp1"></param>
 | 
					 | 
				
			||||||
            <param name="exp2"></param>
 | 
					 | 
				
			||||||
            <param name="exp3"></param>
 | 
					 | 
				
			||||||
            <returns></returns>
 | 
					 | 
				
			||||||
        </member>
 | 
					 | 
				
			||||||
        <member name="M:FreeSqlGlobalExtensions.Distance(System.Drawing.Point,System.Drawing.Point)">
 | 
					        <member name="M:FreeSqlGlobalExtensions.Distance(System.Drawing.Point,System.Drawing.Point)">
 | 
				
			||||||
            <summary>
 | 
					            <summary>
 | 
				
			||||||
            测量两个经纬度的距离,返回单位:米
 | 
					            测量两个经纬度的距离,返回单位:米
 | 
				
			||||||
@@ -3243,3 +3078,188 @@
 | 
				
			|||||||
        </member>
 | 
					        </member>
 | 
				
			||||||
    </members>
 | 
					    </members>
 | 
				
			||||||
</doc>
 | 
					</doc>
 | 
				
			||||||
 | 
					.IncludeMany(a => a.Tags.Take(5))<para></para>
 | 
				
			||||||
 | 
					            可以 .Select 设置只查询部分字段,如: (a => new TNavigate { Title = a.Title }) 
 | 
				
			||||||
 | 
					            </param>
 | 
				
			||||||
 | 
					            <param name="then">即能 ThenInclude,还可以二次过滤(这个 EFCore 做不到?)</param>
 | 
				
			||||||
 | 
					            <returns></returns>
 | 
				
			||||||
 | 
					        </member>
 | 
				
			||||||
 | 
					        <member name="M:System.Linq.Expressions.LambadaExpressionExtensions.And``1(System.Linq.Expressions.Expression{System.Func{``0,System.Boolean}},System.Linq.Expressions.Expression{System.Func{``0,System.Boolean}})">
 | 
				
			||||||
 | 
					            <summary>
 | 
				
			||||||
 | 
					            使用 and 拼接两个 lambda 表达式
 | 
				
			||||||
 | 
					            </summary>
 | 
				
			||||||
 | 
					            <returns></returns>
 | 
				
			||||||
 | 
					        </member>
 | 
				
			||||||
 | 
					        <member name="M:System.Linq.Expressions.LambadaExpressionExtensions.And``1(System.Linq.Expressions.Expression{System.Func{``0,System.Boolean}},System.Boolean,System.Linq.Expressions.Expression{System.Func{``0,System.Boolean}})">
 | 
				
			||||||
 | 
					            <summary>
 | 
				
			||||||
 | 
					            使用 and 拼接两个 lambda 表达式
 | 
				
			||||||
 | 
					            </summary>
 | 
				
			||||||
 | 
					            <typeparam name="T"></typeparam>
 | 
				
			||||||
 | 
					            <param name="exp1"></param>
 | 
				
			||||||
 | 
					            <param name="condition">true 时生效</param>
 | 
				
			||||||
 | 
					            <param name="exp2"></param>
 | 
				
			||||||
 | 
					            <returns></returns>
 | 
				
			||||||
 | 
					        </member>
 | 
				
			||||||
 | 
					        <member name="M:System.Linq.Expressions.LambadaExpressionExtensions.Or``1(System.Linq.Expressions.Expression{System.Func{``0,System.Boolean}},System.Linq.Expressions.Expression{System.Func{``0,System.Boolean}})">
 | 
				
			||||||
 | 
					            <summary>
 | 
				
			||||||
 | 
					            使用 or 拼接两个 lambda 表达式
 | 
				
			||||||
 | 
					            </summary>
 | 
				
			||||||
 | 
					            <returns></returns>
 | 
				
			||||||
 | 
					        </member>
 | 
				
			||||||
 | 
					        <member name="M:System.Linq.Expressions.LambadaExpressionExtensions.Or``1(System.Linq.Expressions.Expression{System.Func{``0,System.Boolean}},System.Boolean,System.Linq.Expressions.Expression{System.Func{``0,System.Boolean}})">
 | 
				
			||||||
 | 
					            <summary>
 | 
				
			||||||
 | 
					            使用 or 拼接两个 lambda 表达式
 | 
				
			||||||
 | 
					            </summary>
 | 
				
			||||||
 | 
					            <typeparam name="T"></typeparam>
 | 
				
			||||||
 | 
					            <param name="exp1"></param>
 | 
				
			||||||
 | 
					            <param name="condition">true 时生效</param>
 | 
				
			||||||
 | 
					            <param name="exp2"></param>
 | 
				
			||||||
 | 
					            <returns></returns>
 | 
				
			||||||
 | 
					        </member>
 | 
				
			||||||
 | 
					        <member name="M:System.Linq.Expressions.LambadaExpressionExtensions.Not``1(System.Linq.Expressions.Expression{System.Func{``0,System.Boolean}},System.Boolean)">
 | 
				
			||||||
 | 
					            <summary>
 | 
				
			||||||
 | 
					            将 lambda 表达式取反
 | 
				
			||||||
 | 
					            </summary>
 | 
				
			||||||
 | 
					            <typeparam name="T"></typeparam>
 | 
				
			||||||
 | 
					            <param name="exp"></param>
 | 
				
			||||||
 | 
					            <param name="condition">true 时生效</param>
 | 
				
			||||||
 | 
					            <returns></returns>
 | 
				
			||||||
 | 
					        </member>
 | 
				
			||||||
 | 
					        <member name="M:FreeUtil.NewMongodbId">
 | 
				
			||||||
 | 
					            <summary>
 | 
				
			||||||
 | 
					            生成类似Mongodb的ObjectId有序、不重复Guid
 | 
				
			||||||
 | 
					            </summary>
 | 
				
			||||||
 | 
					            <returns></returns>
 | 
				
			||||||
 | 
					        </member>
 | 
				
			||||||
 | 
					        <member name="M:IFreeSql.Insert``1">
 | 
				
			||||||
 | 
					            <summary>
 | 
				
			||||||
 | 
					            插入数据
 | 
				
			||||||
 | 
					            </summary>
 | 
				
			||||||
 | 
					            <typeparam name="T1"></typeparam>
 | 
				
			||||||
 | 
					            <returns></returns>
 | 
				
			||||||
 | 
					        </member>
 | 
				
			||||||
 | 
					        <member name="M:IFreeSql.Insert``1(``0)">
 | 
				
			||||||
 | 
					            <summary>
 | 
				
			||||||
 | 
					            插入数据,传入实体
 | 
				
			||||||
 | 
					            </summary>
 | 
				
			||||||
 | 
					            <typeparam name="T1"></typeparam>
 | 
				
			||||||
 | 
					            <param name="source"></param>
 | 
				
			||||||
 | 
					            <returns></returns>
 | 
				
			||||||
 | 
					        </member>
 | 
				
			||||||
 | 
					        <member name="M:IFreeSql.Insert``1(``0[])">
 | 
				
			||||||
 | 
					            <summary>
 | 
				
			||||||
 | 
					            插入数据,传入实体数组
 | 
				
			||||||
 | 
					            </summary>
 | 
				
			||||||
 | 
					            <typeparam name="T1"></typeparam>
 | 
				
			||||||
 | 
					            <param name="source"></param>
 | 
				
			||||||
 | 
					            <returns></returns>
 | 
				
			||||||
 | 
					        </member>
 | 
				
			||||||
 | 
					        <member name="M:IFreeSql.Insert``1(System.Collections.Generic.List{``0})">
 | 
				
			||||||
 | 
					            <summary>
 | 
				
			||||||
 | 
					            插入数据,传入实体集合
 | 
				
			||||||
 | 
					            </summary>
 | 
				
			||||||
 | 
					            <typeparam name="T1"></typeparam>
 | 
				
			||||||
 | 
					            <param name="source"></param>
 | 
				
			||||||
 | 
					            <returns></returns>
 | 
				
			||||||
 | 
					        </member>
 | 
				
			||||||
 | 
					        <member name="M:IFreeSql.Insert``1(System.Collections.Generic.IEnumerable{``0})">
 | 
				
			||||||
 | 
					            <summary>
 | 
				
			||||||
 | 
					            插入数据,传入实体集合
 | 
				
			||||||
 | 
					            </summary>
 | 
				
			||||||
 | 
					            <typeparam name="T1"></typeparam>
 | 
				
			||||||
 | 
					            <param name="source"></param>
 | 
				
			||||||
 | 
					            <returns></returns>
 | 
				
			||||||
 | 
					        </member>
 | 
				
			||||||
 | 
					        <member name="M:IFreeSql.Update``1">
 | 
				
			||||||
 | 
					            <summary>
 | 
				
			||||||
 | 
					            修改数据
 | 
				
			||||||
 | 
					            </summary>
 | 
				
			||||||
 | 
					            <typeparam name="T1"></typeparam>
 | 
				
			||||||
 | 
					            <returns></returns>
 | 
				
			||||||
 | 
					        </member>
 | 
				
			||||||
 | 
					        <member name="M:IFreeSql.Update``1(System.Object)">
 | 
				
			||||||
 | 
					            <summary>
 | 
				
			||||||
 | 
					            修改数据,传入动态对象如:主键值 | new[]{主键值1,主键值2} | TEntity1 | new[]{TEntity1,TEntity2} | new{id=1}
 | 
				
			||||||
 | 
					            </summary>
 | 
				
			||||||
 | 
					            <typeparam name="T1"></typeparam>
 | 
				
			||||||
 | 
					            <param name="dywhere">主键值、主键值集合、实体、实体集合、匿名对象、匿名对象集合</param>
 | 
				
			||||||
 | 
					            <returns></returns>
 | 
				
			||||||
 | 
					        </member>
 | 
				
			||||||
 | 
					        <member name="M:IFreeSql.Select``1">
 | 
				
			||||||
 | 
					            <summary>
 | 
				
			||||||
 | 
					            查询数据
 | 
				
			||||||
 | 
					            </summary>
 | 
				
			||||||
 | 
					            <typeparam name="T1"></typeparam>
 | 
				
			||||||
 | 
					            <returns></returns>
 | 
				
			||||||
 | 
					        </member>
 | 
				
			||||||
 | 
					        <member name="M:IFreeSql.Select``1(System.Object)">
 | 
				
			||||||
 | 
					            <summary>
 | 
				
			||||||
 | 
					            查询数据,传入动态对象如:主键值 | new[]{主键值1,主键值2} | TEntity1 | new[]{TEntity1,TEntity2} | new{id=1}
 | 
				
			||||||
 | 
					            </summary>
 | 
				
			||||||
 | 
					            <typeparam name="T1"></typeparam>
 | 
				
			||||||
 | 
					            <param name="dywhere">主键值、主键值集合、实体、实体集合、匿名对象、匿名对象集合</param>
 | 
				
			||||||
 | 
					            <returns></returns>
 | 
				
			||||||
 | 
					        </member>
 | 
				
			||||||
 | 
					        <member name="M:IFreeSql.Delete``1">
 | 
				
			||||||
 | 
					            <summary>
 | 
				
			||||||
 | 
					            删除数据
 | 
				
			||||||
 | 
					            </summary>
 | 
				
			||||||
 | 
					            <typeparam name="T1"></typeparam>
 | 
				
			||||||
 | 
					            <returns></returns>
 | 
				
			||||||
 | 
					        </member>
 | 
				
			||||||
 | 
					        <member name="M:IFreeSql.Delete``1(System.Object)">
 | 
				
			||||||
 | 
					            <summary>
 | 
				
			||||||
 | 
					            删除数据,传入动态对象如:主键值 | new[]{主键值1,主键值2} | TEntity1 | new[]{TEntity1,TEntity2} | new{id=1}
 | 
				
			||||||
 | 
					            </summary>
 | 
				
			||||||
 | 
					            <typeparam name="T1"></typeparam>
 | 
				
			||||||
 | 
					            <param name="dywhere">主键值、主键值集合、实体、实体集合、匿名对象、匿名对象集合</param>
 | 
				
			||||||
 | 
					            <returns></returns>
 | 
				
			||||||
 | 
					        </member>
 | 
				
			||||||
 | 
					        <member name="M:IFreeSql.Transaction(System.Action)">
 | 
				
			||||||
 | 
					            <summary>
 | 
				
			||||||
 | 
					            开启事务(不支持异步),60秒未执行完成(可能)被其他线程事务自动提交
 | 
				
			||||||
 | 
					            </summary>
 | 
				
			||||||
 | 
					            <param name="handler">事务体 () => {}</param>
 | 
				
			||||||
 | 
					        </member>
 | 
				
			||||||
 | 
					        <member name="M:IFreeSql.Transaction(System.TimeSpan,System.Action)">
 | 
				
			||||||
 | 
					            <summary>
 | 
				
			||||||
 | 
					            开启事务(不支持异步)
 | 
				
			||||||
 | 
					            </summary>
 | 
				
			||||||
 | 
					            <param name="timeout">超时,未执行完成(可能)被其他线程事务自动提交</param>
 | 
				
			||||||
 | 
					            <param name="handler">事务体 () => {}</param>
 | 
				
			||||||
 | 
					        </member>
 | 
				
			||||||
 | 
					        <member name="M:IFreeSql.Transaction(System.Data.IsolationLevel,System.TimeSpan,System.Action)">
 | 
				
			||||||
 | 
					            <summary>
 | 
				
			||||||
 | 
					            开启事务(不支持异步)
 | 
				
			||||||
 | 
					            </summary>
 | 
				
			||||||
 | 
					            <param name="isolationLevel"></param>
 | 
				
			||||||
 | 
					            <param name="handler">事务体 () => {}</param>
 | 
				
			||||||
 | 
					            <param name="timeout">超时,未执行完成(可能)被其他线程事务自动提交</param>
 | 
				
			||||||
 | 
					        </member>
 | 
				
			||||||
 | 
					        <member name="P:IFreeSql.Ado">
 | 
				
			||||||
 | 
					            <summary>
 | 
				
			||||||
 | 
					            数据库访问对象
 | 
				
			||||||
 | 
					            </summary>
 | 
				
			||||||
 | 
					        </member>
 | 
				
			||||||
 | 
					        <member name="P:IFreeSql.Aop">
 | 
				
			||||||
 | 
					            <summary>
 | 
				
			||||||
 | 
					            所有拦截方法都在这里
 | 
				
			||||||
 | 
					            </summary>
 | 
				
			||||||
 | 
					        </member>
 | 
				
			||||||
 | 
					        <member name="P:IFreeSql.CodeFirst">
 | 
				
			||||||
 | 
					            <summary>
 | 
				
			||||||
 | 
					            CodeFirst 模式开发相关方法
 | 
				
			||||||
 | 
					            </summary>
 | 
				
			||||||
 | 
					        </member>
 | 
				
			||||||
 | 
					        <member name="P:IFreeSql.DbFirst">
 | 
				
			||||||
 | 
					            <summary>
 | 
				
			||||||
 | 
					            DbFirst 模式开发相关方法
 | 
				
			||||||
 | 
					            </summary>
 | 
				
			||||||
 | 
					        </member>
 | 
				
			||||||
 | 
					        <member name="P:IFreeSql.GlobalFilter">
 | 
				
			||||||
 | 
					            <summary>
 | 
				
			||||||
 | 
					            全局过滤设置,可默认附加为 Select/Update/Delete 条件
 | 
				
			||||||
 | 
					            </summary>
 | 
				
			||||||
 | 
					        </member>
 | 
				
			||||||
 | 
					    </members>
 | 
				
			||||||
 | 
					</doc>
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,4 +1,5 @@
 | 
				
			|||||||
using System;
 | 
					using FreeSql.Internal.Model;
 | 
				
			||||||
 | 
					using System;
 | 
				
			||||||
using System.Collections.Generic;
 | 
					using System.Collections.Generic;
 | 
				
			||||||
using System.Data;
 | 
					using System.Data;
 | 
				
			||||||
using System.Linq.Expressions;
 | 
					using System.Linq.Expressions;
 | 
				
			||||||
@@ -50,7 +51,7 @@ namespace FreeSql
 | 
				
			|||||||
        ISelect<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10> Where(Expression<Func<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, bool>> exp);
 | 
					        ISelect<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10> Where(Expression<Func<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, bool>> exp);
 | 
				
			||||||
        ISelect<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10> WhereIf(bool condition, Expression<Func<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, bool>> exp);
 | 
					        ISelect<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10> WhereIf(bool condition, Expression<Func<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, bool>> exp);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        ISelectGrouping<TKey, (T1, T2, T3, T4, T5, T6, T7, T8, T9, T10)> GroupBy<TKey>(Expression<Func<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, TKey>> exp);
 | 
					        ISelectGrouping<TKey, NaviteTuple<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10>> GroupBy<TKey>(Expression<Func<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, TKey>> exp);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        ISelect<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10> OrderBy<TMember>(Expression<Func<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, TMember>> column);
 | 
					        ISelect<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10> OrderBy<TMember>(Expression<Func<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, TMember>> column);
 | 
				
			||||||
        ISelect<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10> OrderByDescending<TMember>(Expression<Func<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, TMember>> column);
 | 
					        ISelect<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10> OrderByDescending<TMember>(Expression<Func<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, TMember>> column);
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,4 +1,5 @@
 | 
				
			|||||||
using System;
 | 
					using FreeSql.Internal.Model;
 | 
				
			||||||
 | 
					using System;
 | 
				
			||||||
using System.Collections.Generic;
 | 
					using System.Collections.Generic;
 | 
				
			||||||
using System.Data;
 | 
					using System.Data;
 | 
				
			||||||
using System.Linq.Expressions;
 | 
					using System.Linq.Expressions;
 | 
				
			||||||
@@ -50,7 +51,7 @@ namespace FreeSql
 | 
				
			|||||||
        ISelect<T1, T2> Where(Expression<Func<T1, T2, bool>> exp);
 | 
					        ISelect<T1, T2> Where(Expression<Func<T1, T2, bool>> exp);
 | 
				
			||||||
        ISelect<T1, T2> WhereIf(bool condition, Expression<Func<T1, T2, bool>> exp);
 | 
					        ISelect<T1, T2> WhereIf(bool condition, Expression<Func<T1, T2, bool>> exp);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        ISelectGrouping<TKey, (T1, T2)> GroupBy<TKey>(Expression<Func<T1, T2, TKey>> exp);
 | 
					        ISelectGrouping<TKey, NaviteTuple<T1, T2>> GroupBy<TKey>(Expression<Func<T1, T2, TKey>> exp);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        ISelect<T1, T2> OrderBy<TMember>(Expression<Func<T1, T2, TMember>> column);
 | 
					        ISelect<T1, T2> OrderBy<TMember>(Expression<Func<T1, T2, TMember>> column);
 | 
				
			||||||
        ISelect<T1, T2> OrderByDescending<TMember>(Expression<Func<T1, T2, TMember>> column);
 | 
					        ISelect<T1, T2> OrderByDescending<TMember>(Expression<Func<T1, T2, TMember>> column);
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,4 +1,5 @@
 | 
				
			|||||||
using System;
 | 
					using FreeSql.Internal.Model;
 | 
				
			||||||
 | 
					using System;
 | 
				
			||||||
using System.Collections.Generic;
 | 
					using System.Collections.Generic;
 | 
				
			||||||
using System.Data;
 | 
					using System.Data;
 | 
				
			||||||
using System.Linq.Expressions;
 | 
					using System.Linq.Expressions;
 | 
				
			||||||
@@ -50,7 +51,7 @@ namespace FreeSql
 | 
				
			|||||||
        ISelect<T1, T2, T3> Where(Expression<Func<T1, T2, T3, bool>> exp);
 | 
					        ISelect<T1, T2, T3> Where(Expression<Func<T1, T2, T3, bool>> exp);
 | 
				
			||||||
        ISelect<T1, T2, T3> WhereIf(bool condition, Expression<Func<T1, T2, T3, bool>> exp);
 | 
					        ISelect<T1, T2, T3> WhereIf(bool condition, Expression<Func<T1, T2, T3, bool>> exp);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        ISelectGrouping<TKey, (T1, T2, T3)> GroupBy<TKey>(Expression<Func<T1, T2, T3, TKey>> exp);
 | 
					        ISelectGrouping<TKey, NaviteTuple<T1, T2, T3>> GroupBy<TKey>(Expression<Func<T1, T2, T3, TKey>> exp);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        ISelect<T1, T2, T3> OrderBy<TMember>(Expression<Func<T1, T2, T3, TMember>> column);
 | 
					        ISelect<T1, T2, T3> OrderBy<TMember>(Expression<Func<T1, T2, T3, TMember>> column);
 | 
				
			||||||
        ISelect<T1, T2, T3> OrderByDescending<TMember>(Expression<Func<T1, T2, T3, TMember>> column);
 | 
					        ISelect<T1, T2, T3> OrderByDescending<TMember>(Expression<Func<T1, T2, T3, TMember>> column);
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,4 +1,5 @@
 | 
				
			|||||||
using System;
 | 
					using FreeSql.Internal.Model;
 | 
				
			||||||
 | 
					using System;
 | 
				
			||||||
using System.Collections.Generic;
 | 
					using System.Collections.Generic;
 | 
				
			||||||
using System.Data;
 | 
					using System.Data;
 | 
				
			||||||
using System.Linq.Expressions;
 | 
					using System.Linq.Expressions;
 | 
				
			||||||
@@ -50,7 +51,7 @@ namespace FreeSql
 | 
				
			|||||||
        ISelect<T1, T2, T3, T4> Where(Expression<Func<T1, T2, T3, T4, bool>> exp);
 | 
					        ISelect<T1, T2, T3, T4> Where(Expression<Func<T1, T2, T3, T4, bool>> exp);
 | 
				
			||||||
        ISelect<T1, T2, T3, T4> WhereIf(bool condition, Expression<Func<T1, T2, T3, T4, bool>> exp);
 | 
					        ISelect<T1, T2, T3, T4> WhereIf(bool condition, Expression<Func<T1, T2, T3, T4, bool>> exp);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        ISelectGrouping<TKey, (T1, T2, T3, T4)> GroupBy<TKey>(Expression<Func<T1, T2, T3, T4, TKey>> exp);
 | 
					        ISelectGrouping<TKey, NaviteTuple<T1, T2, T3, T4>> GroupBy<TKey>(Expression<Func<T1, T2, T3, T4, TKey>> exp);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        ISelect<T1, T2, T3, T4> OrderBy<TMember>(Expression<Func<T1, T2, T3, T4, TMember>> column);
 | 
					        ISelect<T1, T2, T3, T4> OrderBy<TMember>(Expression<Func<T1, T2, T3, T4, TMember>> column);
 | 
				
			||||||
        ISelect<T1, T2, T3, T4> OrderByDescending<TMember>(Expression<Func<T1, T2, T3, T4, TMember>> column);
 | 
					        ISelect<T1, T2, T3, T4> OrderByDescending<TMember>(Expression<Func<T1, T2, T3, T4, TMember>> column);
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,4 +1,5 @@
 | 
				
			|||||||
using System;
 | 
					using FreeSql.Internal.Model;
 | 
				
			||||||
 | 
					using System;
 | 
				
			||||||
using System.Collections.Generic;
 | 
					using System.Collections.Generic;
 | 
				
			||||||
using System.Data;
 | 
					using System.Data;
 | 
				
			||||||
using System.Linq.Expressions;
 | 
					using System.Linq.Expressions;
 | 
				
			||||||
@@ -50,7 +51,7 @@ namespace FreeSql
 | 
				
			|||||||
        ISelect<T1, T2, T3, T4, T5> Where(Expression<Func<T1, T2, T3, T4, T5, bool>> exp);
 | 
					        ISelect<T1, T2, T3, T4, T5> Where(Expression<Func<T1, T2, T3, T4, T5, bool>> exp);
 | 
				
			||||||
        ISelect<T1, T2, T3, T4, T5> WhereIf(bool condition, Expression<Func<T1, T2, T3, T4, T5, bool>> exp);
 | 
					        ISelect<T1, T2, T3, T4, T5> WhereIf(bool condition, Expression<Func<T1, T2, T3, T4, T5, bool>> exp);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        ISelectGrouping<TKey, (T1, T2, T3, T4, T5)> GroupBy<TKey>(Expression<Func<T1, T2, T3, T4, T5, TKey>> exp);
 | 
					        ISelectGrouping<TKey, NaviteTuple<T1, T2, T3, T4, T5>> GroupBy<TKey>(Expression<Func<T1, T2, T3, T4, T5, TKey>> exp);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        ISelect<T1, T2, T3, T4, T5> OrderBy<TMember>(Expression<Func<T1, T2, T3, T4, T5, TMember>> column);
 | 
					        ISelect<T1, T2, T3, T4, T5> OrderBy<TMember>(Expression<Func<T1, T2, T3, T4, T5, TMember>> column);
 | 
				
			||||||
        ISelect<T1, T2, T3, T4, T5> OrderByDescending<TMember>(Expression<Func<T1, T2, T3, T4, T5, TMember>> column);
 | 
					        ISelect<T1, T2, T3, T4, T5> OrderByDescending<TMember>(Expression<Func<T1, T2, T3, T4, T5, TMember>> column);
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,4 +1,5 @@
 | 
				
			|||||||
using System;
 | 
					using FreeSql.Internal.Model;
 | 
				
			||||||
 | 
					using System;
 | 
				
			||||||
using System.Collections.Generic;
 | 
					using System.Collections.Generic;
 | 
				
			||||||
using System.Data;
 | 
					using System.Data;
 | 
				
			||||||
using System.Linq.Expressions;
 | 
					using System.Linq.Expressions;
 | 
				
			||||||
@@ -50,7 +51,7 @@ namespace FreeSql
 | 
				
			|||||||
        ISelect<T1, T2, T3, T4, T5, T6> Where(Expression<Func<T1, T2, T3, T4, T5, T6, bool>> exp);
 | 
					        ISelect<T1, T2, T3, T4, T5, T6> Where(Expression<Func<T1, T2, T3, T4, T5, T6, bool>> exp);
 | 
				
			||||||
        ISelect<T1, T2, T3, T4, T5, T6> WhereIf(bool condition, Expression<Func<T1, T2, T3, T4, T5, T6, bool>> exp);
 | 
					        ISelect<T1, T2, T3, T4, T5, T6> WhereIf(bool condition, Expression<Func<T1, T2, T3, T4, T5, T6, bool>> exp);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        ISelectGrouping<TKey, (T1, T2, T3, T4, T5, T6)> GroupBy<TKey>(Expression<Func<T1, T2, T3, T4, T5, T6, TKey>> exp);
 | 
					        ISelectGrouping<TKey, NaviteTuple<T1, T2, T3, T4, T5, T6>> GroupBy<TKey>(Expression<Func<T1, T2, T3, T4, T5, T6, TKey>> exp);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        ISelect<T1, T2, T3, T4, T5, T6> OrderBy<TMember>(Expression<Func<T1, T2, T3, T4, T5, T6, TMember>> column);
 | 
					        ISelect<T1, T2, T3, T4, T5, T6> OrderBy<TMember>(Expression<Func<T1, T2, T3, T4, T5, T6, TMember>> column);
 | 
				
			||||||
        ISelect<T1, T2, T3, T4, T5, T6> OrderByDescending<TMember>(Expression<Func<T1, T2, T3, T4, T5, T6, TMember>> column);
 | 
					        ISelect<T1, T2, T3, T4, T5, T6> OrderByDescending<TMember>(Expression<Func<T1, T2, T3, T4, T5, T6, TMember>> column);
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,4 +1,5 @@
 | 
				
			|||||||
using System;
 | 
					using FreeSql.Internal.Model;
 | 
				
			||||||
 | 
					using System;
 | 
				
			||||||
using System.Collections.Generic;
 | 
					using System.Collections.Generic;
 | 
				
			||||||
using System.Data;
 | 
					using System.Data;
 | 
				
			||||||
using System.Linq.Expressions;
 | 
					using System.Linq.Expressions;
 | 
				
			||||||
@@ -50,7 +51,7 @@ namespace FreeSql
 | 
				
			|||||||
        ISelect<T1, T2, T3, T4, T5, T6, T7> Where(Expression<Func<T1, T2, T3, T4, T5, T6, T7, bool>> exp);
 | 
					        ISelect<T1, T2, T3, T4, T5, T6, T7> Where(Expression<Func<T1, T2, T3, T4, T5, T6, T7, bool>> exp);
 | 
				
			||||||
        ISelect<T1, T2, T3, T4, T5, T6, T7> WhereIf(bool condition, Expression<Func<T1, T2, T3, T4, T5, T6, T7, bool>> exp);
 | 
					        ISelect<T1, T2, T3, T4, T5, T6, T7> WhereIf(bool condition, Expression<Func<T1, T2, T3, T4, T5, T6, T7, bool>> exp);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        ISelectGrouping<TKey, (T1, T2, T3, T4, T5, T6, T7)> GroupBy<TKey>(Expression<Func<T1, T2, T3, T4, T5, T6, T7, TKey>> exp);
 | 
					        ISelectGrouping<TKey, NaviteTuple<T1, T2, T3, T4, T5, T6, T7>> GroupBy<TKey>(Expression<Func<T1, T2, T3, T4, T5, T6, T7, TKey>> exp);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        ISelect<T1, T2, T3, T4, T5, T6, T7> OrderBy<TMember>(Expression<Func<T1, T2, T3, T4, T5, T6, T7, TMember>> column);
 | 
					        ISelect<T1, T2, T3, T4, T5, T6, T7> OrderBy<TMember>(Expression<Func<T1, T2, T3, T4, T5, T6, T7, TMember>> column);
 | 
				
			||||||
        ISelect<T1, T2, T3, T4, T5, T6, T7> OrderByDescending<TMember>(Expression<Func<T1, T2, T3, T4, T5, T6, T7, TMember>> column);
 | 
					        ISelect<T1, T2, T3, T4, T5, T6, T7> OrderByDescending<TMember>(Expression<Func<T1, T2, T3, T4, T5, T6, T7, TMember>> column);
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,4 +1,5 @@
 | 
				
			|||||||
using System;
 | 
					using FreeSql.Internal.Model;
 | 
				
			||||||
 | 
					using System;
 | 
				
			||||||
using System.Collections.Generic;
 | 
					using System.Collections.Generic;
 | 
				
			||||||
using System.Data;
 | 
					using System.Data;
 | 
				
			||||||
using System.Linq.Expressions;
 | 
					using System.Linq.Expressions;
 | 
				
			||||||
@@ -50,7 +51,7 @@ namespace FreeSql
 | 
				
			|||||||
        ISelect<T1, T2, T3, T4, T5, T6, T7, T8> Where(Expression<Func<T1, T2, T3, T4, T5, T6, T7, T8, bool>> exp);
 | 
					        ISelect<T1, T2, T3, T4, T5, T6, T7, T8> Where(Expression<Func<T1, T2, T3, T4, T5, T6, T7, T8, bool>> exp);
 | 
				
			||||||
        ISelect<T1, T2, T3, T4, T5, T6, T7, T8> WhereIf(bool condition, Expression<Func<T1, T2, T3, T4, T5, T6, T7, T8, bool>> exp);
 | 
					        ISelect<T1, T2, T3, T4, T5, T6, T7, T8> WhereIf(bool condition, Expression<Func<T1, T2, T3, T4, T5, T6, T7, T8, bool>> exp);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        ISelectGrouping<TKey, (T1, T2, T3, T4, T5, T6, T7, T8)> GroupBy<TKey>(Expression<Func<T1, T2, T3, T4, T5, T6, T7, T8, TKey>> exp);
 | 
					        ISelectGrouping<TKey, NaviteTuple<T1, T2, T3, T4, T5, T6, T7, T8>> GroupBy<TKey>(Expression<Func<T1, T2, T3, T4, T5, T6, T7, T8, TKey>> exp);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        ISelect<T1, T2, T3, T4, T5, T6, T7, T8> OrderBy<TMember>(Expression<Func<T1, T2, T3, T4, T5, T6, T7, T8, TMember>> column);
 | 
					        ISelect<T1, T2, T3, T4, T5, T6, T7, T8> OrderBy<TMember>(Expression<Func<T1, T2, T3, T4, T5, T6, T7, T8, TMember>> column);
 | 
				
			||||||
        ISelect<T1, T2, T3, T4, T5, T6, T7, T8> OrderByDescending<TMember>(Expression<Func<T1, T2, T3, T4, T5, T6, T7, T8, TMember>> column);
 | 
					        ISelect<T1, T2, T3, T4, T5, T6, T7, T8> OrderByDescending<TMember>(Expression<Func<T1, T2, T3, T4, T5, T6, T7, T8, TMember>> column);
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,4 +1,5 @@
 | 
				
			|||||||
using System;
 | 
					using FreeSql.Internal.Model;
 | 
				
			||||||
 | 
					using System;
 | 
				
			||||||
using System.Collections.Generic;
 | 
					using System.Collections.Generic;
 | 
				
			||||||
using System.Data;
 | 
					using System.Data;
 | 
				
			||||||
using System.Linq.Expressions;
 | 
					using System.Linq.Expressions;
 | 
				
			||||||
@@ -50,7 +51,7 @@ namespace FreeSql
 | 
				
			|||||||
        ISelect<T1, T2, T3, T4, T5, T6, T7, T8, T9> Where(Expression<Func<T1, T2, T3, T4, T5, T6, T7, T8, T9, bool>> exp);
 | 
					        ISelect<T1, T2, T3, T4, T5, T6, T7, T8, T9> Where(Expression<Func<T1, T2, T3, T4, T5, T6, T7, T8, T9, bool>> exp);
 | 
				
			||||||
        ISelect<T1, T2, T3, T4, T5, T6, T7, T8, T9> WhereIf(bool condition, Expression<Func<T1, T2, T3, T4, T5, T6, T7, T8, T9, bool>> exp);
 | 
					        ISelect<T1, T2, T3, T4, T5, T6, T7, T8, T9> WhereIf(bool condition, Expression<Func<T1, T2, T3, T4, T5, T6, T7, T8, T9, bool>> exp);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        ISelectGrouping<TKey, (T1, T2, T3, T4, T5, T6, T7, T8, T9)> GroupBy<TKey>(Expression<Func<T1, T2, T3, T4, T5, T6, T7, T8, T9, TKey>> exp);
 | 
					        ISelectGrouping<TKey, NaviteTuple<T1, T2, T3, T4, T5, T6, T7, T8, T9>> GroupBy<TKey>(Expression<Func<T1, T2, T3, T4, T5, T6, T7, T8, T9, TKey>> exp);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        ISelect<T1, T2, T3, T4, T5, T6, T7, T8, T9> OrderBy<TMember>(Expression<Func<T1, T2, T3, T4, T5, T6, T7, T8, T9, TMember>> column);
 | 
					        ISelect<T1, T2, T3, T4, T5, T6, T7, T8, T9> OrderBy<TMember>(Expression<Func<T1, T2, T3, T4, T5, T6, T7, T8, T9, TMember>> column);
 | 
				
			||||||
        ISelect<T1, T2, T3, T4, T5, T6, T7, T8, T9> OrderByDescending<TMember>(Expression<Func<T1, T2, T3, T4, T5, T6, T7, T8, T9, TMember>> column);
 | 
					        ISelect<T1, T2, T3, T4, T5, T6, T7, T8, T9> OrderByDescending<TMember>(Expression<Func<T1, T2, T3, T4, T5, T6, T7, T8, T9, TMember>> column);
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,4 +1,5 @@
 | 
				
			|||||||
using FreeSql.DatabaseModel;
 | 
					using FreeSql.DatabaseModel;
 | 
				
			||||||
 | 
					using FreeSql.Internal.Model;
 | 
				
			||||||
using SafeObjectPool;
 | 
					using SafeObjectPool;
 | 
				
			||||||
using System;
 | 
					using System;
 | 
				
			||||||
using System.Collections.Generic;
 | 
					using System.Collections.Generic;
 | 
				
			||||||
@@ -185,9 +186,9 @@ namespace FreeSql
 | 
				
			|||||||
        /// <param name="cmdText"></param>
 | 
					        /// <param name="cmdText"></param>
 | 
				
			||||||
        /// <param name="cmdParms"></param>
 | 
					        /// <param name="cmdParms"></param>
 | 
				
			||||||
        /// <returns></returns>
 | 
					        /// <returns></returns>
 | 
				
			||||||
        (List<T1>, List<T2>) Query<T1, T2>(CommandType cmdType, string cmdText, params DbParameter[] cmdParms);
 | 
					        NaviteTuple<List<T1>, List<T2>> Query<T1, T2>(CommandType cmdType, string cmdText, params DbParameter[] cmdParms);
 | 
				
			||||||
        (List<T1>, List<T2>) Query<T1, T2>(DbTransaction transaction, CommandType cmdType, string cmdText, params DbParameter[] cmdParms);
 | 
					        NaviteTuple<List<T1>, List<T2>> Query<T1, T2>(DbTransaction transaction, CommandType cmdType, string cmdText, params DbParameter[] cmdParms);
 | 
				
			||||||
        (List<T1>, List<T2>) Query<T1, T2>(DbConnection connection, DbTransaction transaction, CommandType cmdType, string cmdText, params DbParameter[] cmdParms);
 | 
					        NaviteTuple<List<T1>, List<T2>> Query<T1, T2>(DbConnection connection, DbTransaction transaction, CommandType cmdType, string cmdText, params DbParameter[] cmdParms);
 | 
				
			||||||
        /// <summary>
 | 
					        /// <summary>
 | 
				
			||||||
        /// 执行SQL返回对象集合,Query<User>("select * from user where age > ?age; select * from address", new { age = 25 })
 | 
					        /// 执行SQL返回对象集合,Query<User>("select * from user where age > ?age; select * from address", new { age = 25 })
 | 
				
			||||||
        /// </summary>
 | 
					        /// </summary>
 | 
				
			||||||
@@ -195,28 +196,28 @@ namespace FreeSql
 | 
				
			|||||||
        /// <param name="cmdText"></param>
 | 
					        /// <param name="cmdText"></param>
 | 
				
			||||||
        /// <param name="parms"></param>
 | 
					        /// <param name="parms"></param>
 | 
				
			||||||
        /// <returns></returns>
 | 
					        /// <returns></returns>
 | 
				
			||||||
        (List<T1>, List<T2>) Query<T1, T2>(string cmdText, object parms = null);
 | 
					        NaviteTuple<List<T1>, List<T2>> Query<T1, T2>(string cmdText, object parms = null);
 | 
				
			||||||
        (List<T1>, List<T2>) Query<T1, T2>(DbTransaction transaction, string cmdText, object parms = null);
 | 
					        NaviteTuple<List<T1>, List<T2>> Query<T1, T2>(DbTransaction transaction, string cmdText, object parms = null);
 | 
				
			||||||
        (List<T1>, List<T2>) Query<T1, T2>(DbConnection connection, DbTransaction transaction, string cmdText, object parms = null);
 | 
					        NaviteTuple<List<T1>, List<T2>> Query<T1, T2>(DbConnection connection, DbTransaction transaction, string cmdText, object parms = null);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        (List<T1>, List<T2>, List<T3>) Query<T1, T2, T3>(CommandType cmdType, string cmdText, params DbParameter[] cmdParms);
 | 
					        NaviteTuple<List<T1>, List<T2>, List<T3>> Query<T1, T2, T3>(CommandType cmdType, string cmdText, params DbParameter[] cmdParms);
 | 
				
			||||||
        (List<T1>, List<T2>, List<T3>) Query<T1, T2, T3>(DbTransaction transaction, CommandType cmdType, string cmdText, params DbParameter[] cmdParms);
 | 
					        NaviteTuple<List<T1>, List<T2>, List<T3>> Query<T1, T2, T3>(DbTransaction transaction, CommandType cmdType, string cmdText, params DbParameter[] cmdParms);
 | 
				
			||||||
        (List<T1>, List<T2>, List<T3>) Query<T1, T2, T3>(DbConnection connection, DbTransaction transaction, CommandType cmdType, string cmdText, params DbParameter[] cmdParms);
 | 
					        NaviteTuple<List<T1>, List<T2>, List<T3>> Query<T1, T2, T3>(DbConnection connection, DbTransaction transaction, CommandType cmdType, string cmdText, params DbParameter[] cmdParms);
 | 
				
			||||||
        (List<T1>, List<T2>, List<T3>) Query<T1, T2, T3>(string cmdText, object parms = null);
 | 
					        NaviteTuple<List<T1>, List<T2>, List<T3>> Query<T1, T2, T3>(string cmdText, object parms = null);
 | 
				
			||||||
        (List<T1>, List<T2>, List<T3>) Query<T1, T2, T3>(DbTransaction transaction, string cmdText, object parms = null);
 | 
					        NaviteTuple<List<T1>, List<T2>, List<T3>> Query<T1, T2, T3>(DbTransaction transaction, string cmdText, object parms = null);
 | 
				
			||||||
        (List<T1>, List<T2>, List<T3>) Query<T1, T2, T3>(DbConnection connection, DbTransaction transaction, string cmdText, object parms = null);
 | 
					        NaviteTuple<List<T1>, List<T2>, List<T3>> Query<T1, T2, T3>(DbConnection connection, DbTransaction transaction, string cmdText, object parms = null);
 | 
				
			||||||
        (List<T1>, List<T2>, List<T3>, List<T4>) Query<T1, T2, T3, T4>(CommandType cmdType, string cmdText, params DbParameter[] cmdParms);
 | 
					        NaviteTuple<List<T1>, List<T2>, List<T3>, List<T4>> Query<T1, T2, T3, T4>(CommandType cmdType, string cmdText, params DbParameter[] cmdParms);
 | 
				
			||||||
        (List<T1>, List<T2>, List<T3>, List<T4>) Query<T1, T2, T3, T4>(DbTransaction transaction, CommandType cmdType, string cmdText, params DbParameter[] cmdParms);
 | 
					        NaviteTuple<List<T1>, List<T2>, List<T3>, List<T4>> Query<T1, T2, T3, T4>(DbTransaction transaction, CommandType cmdType, string cmdText, params DbParameter[] cmdParms);
 | 
				
			||||||
        (List<T1>, List<T2>, List<T3>, List<T4>) Query<T1, T2, T3, T4>(DbConnection connection, DbTransaction transaction, CommandType cmdType, string cmdText, params DbParameter[] cmdParms);
 | 
					        NaviteTuple<List<T1>, List<T2>, List<T3>, List<T4>> Query<T1, T2, T3, T4>(DbConnection connection, DbTransaction transaction, CommandType cmdType, string cmdText, params DbParameter[] cmdParms);
 | 
				
			||||||
        (List<T1>, List<T2>, List<T3>, List<T4>) Query<T1, T2, T3, T4>(string cmdText, object parms = null);
 | 
					        NaviteTuple<List<T1>, List<T2>, List<T3>, List<T4>> Query<T1, T2, T3, T4>(string cmdText, object parms = null);
 | 
				
			||||||
        (List<T1>, List<T2>, List<T3>, List<T4>) Query<T1, T2, T3, T4>(DbTransaction transaction, string cmdText, object parms = null);
 | 
					        NaviteTuple<List<T1>, List<T2>, List<T3>, List<T4>> Query<T1, T2, T3, T4>(DbTransaction transaction, string cmdText, object parms = null);
 | 
				
			||||||
        (List<T1>, List<T2>, List<T3>, List<T4>) Query<T1, T2, T3, T4>(DbConnection connection, DbTransaction transaction, string cmdText, object parms = null);
 | 
					        NaviteTuple<List<T1>, List<T2>, List<T3>, List<T4>> Query<T1, T2, T3, T4>(DbConnection connection, DbTransaction transaction, string cmdText, object parms = null);
 | 
				
			||||||
        (List<T1>, List<T2>, List<T3>, List<T4>, List<T5>) Query<T1, T2, T3, T4, T5>(CommandType cmdType, string cmdText, params DbParameter[] cmdParms);
 | 
					        NaviteTuple<List<T1>, List<T2>, List<T3>, List<T4>, List<T5>> Query<T1, T2, T3, T4, T5>(CommandType cmdType, string cmdText, params DbParameter[] cmdParms);
 | 
				
			||||||
        (List<T1>, List<T2>, List<T3>, List<T4>, List<T5>) Query<T1, T2, T3, T4, T5>(DbTransaction transaction, CommandType cmdType, string cmdText, params DbParameter[] cmdParms);
 | 
					        NaviteTuple<List<T1>, List<T2>, List<T3>, List<T4>, List<T5>> Query<T1, T2, T3, T4, T5>(DbTransaction transaction, CommandType cmdType, string cmdText, params DbParameter[] cmdParms);
 | 
				
			||||||
        (List<T1>, List<T2>, List<T3>, List<T4>, List<T5>) Query<T1, T2, T3, T4, T5>(DbConnection connection, DbTransaction transaction, CommandType cmdType, string cmdText, params DbParameter[] cmdParms);
 | 
					        NaviteTuple<List<T1>, List<T2>, List<T3>, List<T4>, List<T5>> Query<T1, T2, T3, T4, T5>(DbConnection connection, DbTransaction transaction, CommandType cmdType, string cmdText, params DbParameter[] cmdParms);
 | 
				
			||||||
        (List<T1>, List<T2>, List<T3>, List<T4>, List<T5>) Query<T1, T2, T3, T4, T5>(string cmdText, object parms = null);
 | 
					        NaviteTuple<List<T1>, List<T2>, List<T3>, List<T4>, List<T5>> Query<T1, T2, T3, T4, T5>(string cmdText, object parms = null);
 | 
				
			||||||
        (List<T1>, List<T2>, List<T3>, List<T4>, List<T5>) Query<T1, T2, T3, T4, T5>(DbTransaction transaction, string cmdText, object parms = null);
 | 
					        NaviteTuple<List<T1>, List<T2>, List<T3>, List<T4>, List<T5>> Query<T1, T2, T3, T4, T5>(DbTransaction transaction, string cmdText, object parms = null);
 | 
				
			||||||
        (List<T1>, List<T2>, List<T3>, List<T4>, List<T5>) Query<T1, T2, T3, T4, T5>(DbConnection connection, DbTransaction transaction, string cmdText, object parms = null);
 | 
					        NaviteTuple<List<T1>, List<T2>, List<T3>, List<T4>, List<T5>> Query<T1, T2, T3, T4, T5>(DbConnection connection, DbTransaction transaction, string cmdText, object parms = null);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#if net40
 | 
					#if net40
 | 
				
			||||||
#else
 | 
					#else
 | 
				
			||||||
@@ -357,9 +358,9 @@ namespace FreeSql
 | 
				
			|||||||
        /// <param name="cmdText"></param>
 | 
					        /// <param name="cmdText"></param>
 | 
				
			||||||
        /// <param name="cmdParms"></param>
 | 
					        /// <param name="cmdParms"></param>
 | 
				
			||||||
        /// <returns></returns>
 | 
					        /// <returns></returns>
 | 
				
			||||||
        Task<(List<T1>, List<T2>)> QueryAsync<T1, T2>(CommandType cmdType, string cmdText, params DbParameter[] cmdParms);
 | 
					        Task<NaviteTuple<List<T1>, List<T2>>> QueryAsync<T1, T2>(CommandType cmdType, string cmdText, params DbParameter[] cmdParms);
 | 
				
			||||||
        Task<(List<T1>, List<T2>)> QueryAsync<T1, T2>(DbTransaction transaction, CommandType cmdType, string cmdText, params DbParameter[] cmdParms);
 | 
					        Task<NaviteTuple<List<T1>, List<T2>>> QueryAsync<T1, T2>(DbTransaction transaction, CommandType cmdType, string cmdText, params DbParameter[] cmdParms);
 | 
				
			||||||
        Task<(List<T1>, List<T2>)> QueryAsync<T1, T2>(DbConnection connection, DbTransaction transaction, CommandType cmdType, string cmdText, params DbParameter[] cmdParms);
 | 
					        Task<NaviteTuple<List<T1>, List<T2>>> QueryAsync<T1, T2>(DbConnection connection, DbTransaction transaction, CommandType cmdType, string cmdText, params DbParameter[] cmdParms);
 | 
				
			||||||
        /// <summary>
 | 
					        /// <summary>
 | 
				
			||||||
        /// 执行SQL返回对象集合,Query<User>("select * from user where age > ?age; select * from address", new { age = 25 })
 | 
					        /// 执行SQL返回对象集合,Query<User>("select * from user where age > ?age; select * from address", new { age = 25 })
 | 
				
			||||||
        /// </summary>
 | 
					        /// </summary>
 | 
				
			||||||
@@ -367,28 +368,28 @@ namespace FreeSql
 | 
				
			|||||||
        /// <param name="cmdText"></param>
 | 
					        /// <param name="cmdText"></param>
 | 
				
			||||||
        /// <param name="parms"></param>
 | 
					        /// <param name="parms"></param>
 | 
				
			||||||
        /// <returns></returns>
 | 
					        /// <returns></returns>
 | 
				
			||||||
        Task<(List<T1>, List<T2>)> QueryAsync<T1, T2>(string cmdText, object parms = null);
 | 
					        Task<NaviteTuple<List<T1>, List<T2>>> QueryAsync<T1, T2>(string cmdText, object parms = null);
 | 
				
			||||||
        Task<(List<T1>, List<T2>)> QueryAsync<T1, T2>(DbTransaction transaction, string cmdText, object parms = null);
 | 
					        Task<NaviteTuple<List<T1>, List<T2>>> QueryAsync<T1, T2>(DbTransaction transaction, string cmdText, object parms = null);
 | 
				
			||||||
        Task<(List<T1>, List<T2>)> QueryAsync<T1, T2>(DbConnection connection, DbTransaction transaction, string cmdText, object parms = null);
 | 
					        Task<NaviteTuple<List<T1>, List<T2>>> QueryAsync<T1, T2>(DbConnection connection, DbTransaction transaction, string cmdText, object parms = null);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        Task<(List<T1>, List<T2>, List<T3>)> QueryAsync<T1, T2, T3>(CommandType cmdType, string cmdText, params DbParameter[] cmdParms);
 | 
					        Task<NaviteTuple<List<T1>, List<T2>, List<T3>>> QueryAsync<T1, T2, T3>(CommandType cmdType, string cmdText, params DbParameter[] cmdParms);
 | 
				
			||||||
        Task<(List<T1>, List<T2>, List<T3>)> QueryAsync<T1, T2, T3>(DbTransaction transaction, CommandType cmdType, string cmdText, params DbParameter[] cmdParms);
 | 
					        Task<NaviteTuple<List<T1>, List<T2>, List<T3>>> QueryAsync<T1, T2, T3>(DbTransaction transaction, CommandType cmdType, string cmdText, params DbParameter[] cmdParms);
 | 
				
			||||||
        Task<(List<T1>, List<T2>, List<T3>)> QueryAsync<T1, T2, T3>(DbConnection connection, DbTransaction transaction, CommandType cmdType, string cmdText, params DbParameter[] cmdParms);
 | 
					        Task<NaviteTuple<List<T1>, List<T2>, List<T3>>> QueryAsync<T1, T2, T3>(DbConnection connection, DbTransaction transaction, CommandType cmdType, string cmdText, params DbParameter[] cmdParms);
 | 
				
			||||||
        Task<(List<T1>, List<T2>, List<T3>)> QueryAsync<T1, T2, T3>(string cmdText, object parms = null);
 | 
					        Task<NaviteTuple<List<T1>, List<T2>, List<T3>>> QueryAsync<T1, T2, T3>(string cmdText, object parms = null);
 | 
				
			||||||
        Task<(List<T1>, List<T2>, List<T3>)> QueryAsync<T1, T2, T3>(DbTransaction transaction, string cmdText, object parms = null);
 | 
					        Task<NaviteTuple<List<T1>, List<T2>, List<T3>>> QueryAsync<T1, T2, T3>(DbTransaction transaction, string cmdText, object parms = null);
 | 
				
			||||||
        Task<(List<T1>, List<T2>, List<T3>)> QueryAsync<T1, T2, T3>(DbConnection connection, DbTransaction transaction, string cmdText, object parms = null);
 | 
					        Task<NaviteTuple<List<T1>, List<T2>, List<T3>>> QueryAsync<T1, T2, T3>(DbConnection connection, DbTransaction transaction, string cmdText, object parms = null);
 | 
				
			||||||
        Task<(List<T1>, List<T2>, List<T3>, List<T4>)> QueryAsync<T1, T2, T3, T4>(CommandType cmdType, string cmdText, params DbParameter[] cmdParms);
 | 
					        Task<NaviteTuple<List<T1>, List<T2>, List<T3>, List<T4>>> QueryAsync<T1, T2, T3, T4>(CommandType cmdType, string cmdText, params DbParameter[] cmdParms);
 | 
				
			||||||
        Task<(List<T1>, List<T2>, List<T3>, List<T4>)> QueryAsync<T1, T2, T3, T4>(DbTransaction transaction, CommandType cmdType, string cmdText, params DbParameter[] cmdParms);
 | 
					        Task<NaviteTuple<List<T1>, List<T2>, List<T3>, List<T4>>> QueryAsync<T1, T2, T3, T4>(DbTransaction transaction, CommandType cmdType, string cmdText, params DbParameter[] cmdParms);
 | 
				
			||||||
        Task<(List<T1>, List<T2>, List<T3>, List<T4>)> QueryAsync<T1, T2, T3, T4>(DbConnection connection, DbTransaction transaction, CommandType cmdType, string cmdText, params DbParameter[] cmdParms);
 | 
					        Task<NaviteTuple<List<T1>, List<T2>, List<T3>, List<T4>>> QueryAsync<T1, T2, T3, T4>(DbConnection connection, DbTransaction transaction, CommandType cmdType, string cmdText, params DbParameter[] cmdParms);
 | 
				
			||||||
        Task<(List<T1>, List<T2>, List<T3>, List<T4>)> QueryAsync<T1, T2, T3, T4>(string cmdText, object parms = null);
 | 
					        Task<NaviteTuple<List<T1>, List<T2>, List<T3>, List<T4>>> QueryAsync<T1, T2, T3, T4>(string cmdText, object parms = null);
 | 
				
			||||||
        Task<(List<T1>, List<T2>, List<T3>, List<T4>)> QueryAsync<T1, T2, T3, T4>(DbTransaction transaction, string cmdText, object parms = null);
 | 
					        Task<NaviteTuple<List<T1>, List<T2>, List<T3>, List<T4>>> QueryAsync<T1, T2, T3, T4>(DbTransaction transaction, string cmdText, object parms = null);
 | 
				
			||||||
        Task<(List<T1>, List<T2>, List<T3>, List<T4>)> QueryAsync<T1, T2, T3, T4>(DbConnection connection, DbTransaction transaction, string cmdText, object parms = null);
 | 
					        Task<NaviteTuple<List<T1>, List<T2>, List<T3>, List<T4>>> QueryAsync<T1, T2, T3, T4>(DbConnection connection, DbTransaction transaction, string cmdText, object parms = null);
 | 
				
			||||||
        Task<(List<T1>, List<T2>, List<T3>, List<T4>, List<T5>)> QueryAsync<T1, T2, T3, T4, T5>(CommandType cmdType, string cmdText, params DbParameter[] cmdParms);
 | 
					        Task<NaviteTuple<List<T1>, List<T2>, List<T3>, List<T4>, List<T5>>> QueryAsync<T1, T2, T3, T4, T5>(CommandType cmdType, string cmdText, params DbParameter[] cmdParms);
 | 
				
			||||||
        Task<(List<T1>, List<T2>, List<T3>, List<T4>, List<T5>)> QueryAsync<T1, T2, T3, T4, T5>(DbTransaction transaction, CommandType cmdType, string cmdText, params DbParameter[] cmdParms);
 | 
					        Task<NaviteTuple<List<T1>, List<T2>, List<T3>, List<T4>, List<T5>>> QueryAsync<T1, T2, T3, T4, T5>(DbTransaction transaction, CommandType cmdType, string cmdText, params DbParameter[] cmdParms);
 | 
				
			||||||
        Task<(List<T1>, List<T2>, List<T3>, List<T4>, List<T5>)> QueryAsync<T1, T2, T3, T4, T5>(DbConnection connection, DbTransaction transaction, CommandType cmdType, string cmdText, params DbParameter[] cmdParms);
 | 
					        Task<NaviteTuple<List<T1>, List<T2>, List<T3>, List<T4>, List<T5>>> QueryAsync<T1, T2, T3, T4, T5>(DbConnection connection, DbTransaction transaction, CommandType cmdType, string cmdText, params DbParameter[] cmdParms);
 | 
				
			||||||
        Task<(List<T1>, List<T2>, List<T3>, List<T4>, List<T5>)> QueryAsync<T1, T2, T3, T4, T5>(string cmdText, object parms = null);
 | 
					        Task<NaviteTuple<List<T1>, List<T2>, List<T3>, List<T4>, List<T5>>> QueryAsync<T1, T2, T3, T4, T5>(string cmdText, object parms = null);
 | 
				
			||||||
        Task<(List<T1>, List<T2>, List<T3>, List<T4>, List<T5>)> QueryAsync<T1, T2, T3, T4, T5>(DbTransaction transaction, string cmdText, object parms = null);
 | 
					        Task<NaviteTuple<List<T1>, List<T2>, List<T3>, List<T4>, List<T5>>> QueryAsync<T1, T2, T3, T4, T5>(DbTransaction transaction, string cmdText, object parms = null);
 | 
				
			||||||
        Task<(List<T1>, List<T2>, List<T3>, List<T4>, List<T5>)> QueryAsync<T1, T2, T3, T4, T5>(DbConnection connection, DbTransaction transaction, string cmdText, object parms = null);
 | 
					        Task<NaviteTuple<List<T1>, List<T2>, List<T3>, List<T4>, List<T5>>> QueryAsync<T1, T2, T3, T4, T5>(DbConnection connection, DbTransaction transaction, string cmdText, object parms = null);
 | 
				
			||||||
        #endregion
 | 
					        #endregion
 | 
				
			||||||
#endif
 | 
					#endif
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -87,7 +87,7 @@ namespace FreeSql
 | 
				
			|||||||
        /// </summary>
 | 
					        /// </summary>
 | 
				
			||||||
        /// <param name="type"></param>
 | 
					        /// <param name="type"></param>
 | 
				
			||||||
        /// <returns></returns>
 | 
					        /// <returns></returns>
 | 
				
			||||||
        (int type, string dbtype, string dbtypeFull, bool? isnullable, object defaultValue)? GetDbInfo(Type type);
 | 
					        DbInfoResult GetDbInfo(Type type);
 | 
				
			||||||
        /// <summary>
 | 
					        /// <summary>
 | 
				
			||||||
        /// 在外部配置实体的特性
 | 
					        /// 在外部配置实体的特性
 | 
				
			||||||
        /// </summary>
 | 
					        /// </summary>
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -8,6 +8,7 @@ using System.Diagnostics;
 | 
				
			|||||||
using System.Linq;
 | 
					using System.Linq;
 | 
				
			||||||
using System.Text;
 | 
					using System.Text;
 | 
				
			||||||
using System.Reflection;
 | 
					using System.Reflection;
 | 
				
			||||||
 | 
					using FreeSql.Internal.Model;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
namespace FreeSql.Internal.CommonProvider
 | 
					namespace FreeSql.Internal.CommonProvider
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
@@ -33,7 +34,7 @@ namespace FreeSql.Internal.CommonProvider
 | 
				
			|||||||
            this.DataType = dataType;
 | 
					            this.DataType = dataType;
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        void LoggerException(IObjectPool<DbConnection> pool, (Aop.CommandBeforeEventArgs before, DbCommand cmd, bool isclose) pc, Exception ex, DateTime dt, StringBuilder logtxt, bool isThrowException = true)
 | 
					        void LoggerException(IObjectPool<DbConnection> pool, PrepareCommandResult pc, Exception ex, DateTime dt, StringBuilder logtxt, bool isThrowException = true)
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
            var cmd = pc.cmd;
 | 
					            var cmd = pc.cmd;
 | 
				
			||||||
            if (pc.isclose) pc.cmd.Connection.Close();
 | 
					            if (pc.isclose) pc.cmd.Connection.Close();
 | 
				
			||||||
@@ -121,14 +122,14 @@ namespace FreeSql.Internal.CommonProvider
 | 
				
			|||||||
            return ret;
 | 
					            return ret;
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
        #region query multi
 | 
					        #region query multi
 | 
				
			||||||
        public (List<T1>, List<T2>) Query<T1, T2>(string cmdText, object parms = null) => Query<T1, T2>(null, null, CommandType.Text, cmdText, GetDbParamtersByObject(cmdText, parms));
 | 
					        public NaviteTuple<List<T1>, List<T2>> Query<T1, T2>(string cmdText, object parms = null) => Query<T1, T2>(null, null, CommandType.Text, cmdText, GetDbParamtersByObject(cmdText, parms));
 | 
				
			||||||
        public (List<T1>, List<T2>) Query<T1, T2>(DbTransaction transaction, string cmdText, object parms = null) => Query<T1, T2>(null, transaction, CommandType.Text, cmdText, GetDbParamtersByObject(cmdText, parms));
 | 
					        public NaviteTuple<List<T1>, List<T2>> Query<T1, T2>(DbTransaction transaction, string cmdText, object parms = null) => Query<T1, T2>(null, transaction, CommandType.Text, cmdText, GetDbParamtersByObject(cmdText, parms));
 | 
				
			||||||
        public (List<T1>, List<T2>) Query<T1, T2>(DbConnection connection, DbTransaction transaction, string cmdText, object parms = null) => Query<T1, T2>(connection, transaction, CommandType.Text, cmdText, GetDbParamtersByObject(cmdText, parms));
 | 
					        public NaviteTuple<List<T1>, List<T2>> Query<T1, T2>(DbConnection connection, DbTransaction transaction, string cmdText, object parms = null) => Query<T1, T2>(connection, transaction, CommandType.Text, cmdText, GetDbParamtersByObject(cmdText, parms));
 | 
				
			||||||
        public (List<T1>, List<T2>) Query<T1, T2>(CommandType cmdType, string cmdText, params DbParameter[] cmdParms) => Query<T1, T2>(null, null, cmdType, cmdText, cmdParms);
 | 
					        public NaviteTuple<List<T1>, List<T2>> Query<T1, T2>(CommandType cmdType, string cmdText, params DbParameter[] cmdParms) => Query<T1, T2>(null, null, cmdType, cmdText, cmdParms);
 | 
				
			||||||
        public (List<T1>, List<T2>) Query<T1, T2>(DbTransaction transaction, CommandType cmdType, string cmdText, params DbParameter[] cmdParms) => Query<T1, T2>(null, transaction, cmdType, cmdText, cmdParms);
 | 
					        public NaviteTuple<List<T1>, List<T2>> Query<T1, T2>(DbTransaction transaction, CommandType cmdType, string cmdText, params DbParameter[] cmdParms) => Query<T1, T2>(null, transaction, cmdType, cmdText, cmdParms);
 | 
				
			||||||
        public (List<T1>, List<T2>) Query<T1, T2>(DbConnection connection, DbTransaction transaction, CommandType cmdType, string cmdText, params DbParameter[] cmdParms)
 | 
					        public NaviteTuple<List<T1>, List<T2>> Query<T1, T2>(DbConnection connection, DbTransaction transaction, CommandType cmdType, string cmdText, params DbParameter[] cmdParms)
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
            if (string.IsNullOrEmpty(cmdText)) return (new List<T1>(), new List<T2>());
 | 
					            if (string.IsNullOrEmpty(cmdText)) return NaviteTuple.Create(new List<T1>(), new List<T2>());
 | 
				
			||||||
            var ret1 = new List<T1>();
 | 
					            var ret1 = new List<T1>();
 | 
				
			||||||
            var type1 = typeof(T1);
 | 
					            var type1 = typeof(T1);
 | 
				
			||||||
            string flag1 = null;
 | 
					            string flag1 = null;
 | 
				
			||||||
@@ -180,17 +181,17 @@ namespace FreeSql.Internal.CommonProvider
 | 
				
			|||||||
                        break;
 | 
					                        break;
 | 
				
			||||||
                }
 | 
					                }
 | 
				
			||||||
            }, cmdType, cmdText, cmdParms);
 | 
					            }, cmdType, cmdText, cmdParms);
 | 
				
			||||||
            return (ret1, ret2);
 | 
					            return NaviteTuple.Create(ret1, ret2);
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        public (List<T1>, List<T2>, List<T3>) Query<T1, T2, T3>(string cmdText, object parms = null) => Query<T1, T2, T3>(null, null, CommandType.Text, cmdText, GetDbParamtersByObject(cmdText, parms));
 | 
					        public NaviteTuple<List<T1>, List<T2>, List<T3>> Query<T1, T2, T3>(string cmdText, object parms = null) => Query<T1, T2, T3>(null, null, CommandType.Text, cmdText, GetDbParamtersByObject(cmdText, parms));
 | 
				
			||||||
        public (List<T1>, List<T2>, List<T3>) Query<T1, T2, T3>(DbTransaction transaction, string cmdText, object parms = null) => Query<T1, T2, T3>(null, transaction, CommandType.Text, cmdText, GetDbParamtersByObject(cmdText, parms));
 | 
					        public NaviteTuple<List<T1>, List<T2>, List<T3>> Query<T1, T2, T3>(DbTransaction transaction, string cmdText, object parms = null) => Query<T1, T2, T3>(null, transaction, CommandType.Text, cmdText, GetDbParamtersByObject(cmdText, parms));
 | 
				
			||||||
        public (List<T1>, List<T2>, List<T3>) Query<T1, T2, T3>(DbConnection connection, DbTransaction transaction, string cmdText, object parms = null) => Query<T1, T2, T3>(connection, transaction, CommandType.Text, cmdText, GetDbParamtersByObject(cmdText, parms));
 | 
					        public NaviteTuple<List<T1>, List<T2>, List<T3>> Query<T1, T2, T3>(DbConnection connection, DbTransaction transaction, string cmdText, object parms = null) => Query<T1, T2, T3>(connection, transaction, CommandType.Text, cmdText, GetDbParamtersByObject(cmdText, parms));
 | 
				
			||||||
        public (List<T1>, List<T2>, List<T3>) Query<T1, T2, T3>(CommandType cmdType, string cmdText, params DbParameter[] cmdParms) => Query<T1, T2, T3>(null, null, cmdType, cmdText, cmdParms);
 | 
					        public NaviteTuple<List<T1>, List<T2>, List<T3>> Query<T1, T2, T3>(CommandType cmdType, string cmdText, params DbParameter[] cmdParms) => Query<T1, T2, T3>(null, null, cmdType, cmdText, cmdParms);
 | 
				
			||||||
        public (List<T1>, List<T2>, List<T3>) Query<T1, T2, T3>(DbTransaction transaction, CommandType cmdType, string cmdText, params DbParameter[] cmdParms) => Query<T1, T2, T3>(null, transaction, cmdType, cmdText, cmdParms);
 | 
					        public NaviteTuple<List<T1>, List<T2>, List<T3>> Query<T1, T2, T3>(DbTransaction transaction, CommandType cmdType, string cmdText, params DbParameter[] cmdParms) => Query<T1, T2, T3>(null, transaction, cmdType, cmdText, cmdParms);
 | 
				
			||||||
        public (List<T1>, List<T2>, List<T3>) Query<T1, T2, T3>(DbConnection connection, DbTransaction transaction, CommandType cmdType, string cmdText, params DbParameter[] cmdParms)
 | 
					        public NaviteTuple<List<T1>, List<T2>, List<T3>> Query<T1, T2, T3>(DbConnection connection, DbTransaction transaction, CommandType cmdType, string cmdText, params DbParameter[] cmdParms)
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
            if (string.IsNullOrEmpty(cmdText)) return (new List<T1>(), new List<T2>(), new List<T3>());
 | 
					            if (string.IsNullOrEmpty(cmdText)) return NaviteTuple.Create(new List<T1>(), new List<T2>(), new List<T3>());
 | 
				
			||||||
            var ret1 = new List<T1>();
 | 
					            var ret1 = new List<T1>();
 | 
				
			||||||
            var type1 = typeof(T1);
 | 
					            var type1 = typeof(T1);
 | 
				
			||||||
            string flag1 = null;
 | 
					            string flag1 = null;
 | 
				
			||||||
@@ -265,17 +266,17 @@ namespace FreeSql.Internal.CommonProvider
 | 
				
			|||||||
                        break;
 | 
					                        break;
 | 
				
			||||||
                }
 | 
					                }
 | 
				
			||||||
            }, cmdType, cmdText, cmdParms);
 | 
					            }, cmdType, cmdText, cmdParms);
 | 
				
			||||||
            return (ret1, ret2, ret3);
 | 
					            return NaviteTuple.Create(ret1, ret2, ret3);
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        public (List<T1>, List<T2>, List<T3>, List<T4>) Query<T1, T2, T3, T4>(string cmdText, object parms = null) => Query<T1, T2, T3, T4>(null, null, CommandType.Text, cmdText, GetDbParamtersByObject(cmdText, parms));
 | 
					        public NaviteTuple<List<T1>, List<T2>, List<T3>, List<T4>> Query<T1, T2, T3, T4>(string cmdText, object parms = null) => Query<T1, T2, T3, T4>(null, null, CommandType.Text, cmdText, GetDbParamtersByObject(cmdText, parms));
 | 
				
			||||||
        public (List<T1>, List<T2>, List<T3>, List<T4>) Query<T1, T2, T3, T4>(DbTransaction transaction, string cmdText, object parms = null) => Query<T1, T2, T3, T4>(null, transaction, CommandType.Text, cmdText, GetDbParamtersByObject(cmdText, parms));
 | 
					        public NaviteTuple<List<T1>, List<T2>, List<T3>, List<T4>> Query<T1, T2, T3, T4>(DbTransaction transaction, string cmdText, object parms = null) => Query<T1, T2, T3, T4>(null, transaction, CommandType.Text, cmdText, GetDbParamtersByObject(cmdText, parms));
 | 
				
			||||||
        public (List<T1>, List<T2>, List<T3>, List<T4>) Query<T1, T2, T3, T4>(DbConnection connection, DbTransaction transaction, string cmdText, object parms = null) => Query<T1, T2, T3, T4>(connection, transaction, CommandType.Text, cmdText, GetDbParamtersByObject(cmdText, parms));
 | 
					        public NaviteTuple<List<T1>, List<T2>, List<T3>, List<T4>> Query<T1, T2, T3, T4>(DbConnection connection, DbTransaction transaction, string cmdText, object parms = null) => Query<T1, T2, T3, T4>(connection, transaction, CommandType.Text, cmdText, GetDbParamtersByObject(cmdText, parms));
 | 
				
			||||||
        public (List<T1>, List<T2>, List<T3>, List<T4>) Query<T1, T2, T3, T4>(CommandType cmdType, string cmdText, params DbParameter[] cmdParms) => Query<T1, T2, T3, T4>(null, null, cmdType, cmdText, cmdParms);
 | 
					        public NaviteTuple<List<T1>, List<T2>, List<T3>, List<T4>> Query<T1, T2, T3, T4>(CommandType cmdType, string cmdText, params DbParameter[] cmdParms) => Query<T1, T2, T3, T4>(null, null, cmdType, cmdText, cmdParms);
 | 
				
			||||||
        public (List<T1>, List<T2>, List<T3>, List<T4>) Query<T1, T2, T3, T4>(DbTransaction transaction, CommandType cmdType, string cmdText, params DbParameter[] cmdParms) => Query<T1, T2, T3, T4>(null, transaction, cmdType, cmdText, cmdParms);
 | 
					        public NaviteTuple<List<T1>, List<T2>, List<T3>, List<T4>> Query<T1, T2, T3, T4>(DbTransaction transaction, CommandType cmdType, string cmdText, params DbParameter[] cmdParms) => Query<T1, T2, T3, T4>(null, transaction, cmdType, cmdText, cmdParms);
 | 
				
			||||||
        public (List<T1>, List<T2>, List<T3>, List<T4>) Query<T1, T2, T3, T4>(DbConnection connection, DbTransaction transaction, CommandType cmdType, string cmdText, params DbParameter[] cmdParms)
 | 
					        public NaviteTuple<List<T1>, List<T2>, List<T3>, List<T4>> Query<T1, T2, T3, T4>(DbConnection connection, DbTransaction transaction, CommandType cmdType, string cmdText, params DbParameter[] cmdParms)
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
            if (string.IsNullOrEmpty(cmdText)) return (new List<T1>(), new List<T2>(), new List<T3>(), new List<T4>());
 | 
					            if (string.IsNullOrEmpty(cmdText)) return NaviteTuple.Create(new List<T1>(), new List<T2>(), new List<T3>(), new List<T4>());
 | 
				
			||||||
            var ret1 = new List<T1>();
 | 
					            var ret1 = new List<T1>();
 | 
				
			||||||
            var type1 = typeof(T1);
 | 
					            var type1 = typeof(T1);
 | 
				
			||||||
            string flag1 = null;
 | 
					            string flag1 = null;
 | 
				
			||||||
@@ -373,17 +374,17 @@ namespace FreeSql.Internal.CommonProvider
 | 
				
			|||||||
                        break;
 | 
					                        break;
 | 
				
			||||||
                }
 | 
					                }
 | 
				
			||||||
            }, cmdType, cmdText, cmdParms);
 | 
					            }, cmdType, cmdText, cmdParms);
 | 
				
			||||||
            return (ret1, ret2, ret3, ret4);
 | 
					            return NaviteTuple.Create(ret1, ret2, ret3, ret4);
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        public (List<T1>, List<T2>, List<T3>, List<T4>, List<T5>) Query<T1, T2, T3, T4, T5>(string cmdText, object parms = null) => Query<T1, T2, T3, T4, T5>(null, null, CommandType.Text, cmdText, GetDbParamtersByObject(cmdText, parms));
 | 
					        public NaviteTuple<List<T1>, List<T2>, List<T3>, List<T4>, List<T5>> Query<T1, T2, T3, T4, T5>(string cmdText, object parms = null) => Query<T1, T2, T3, T4, T5>(null, null, CommandType.Text, cmdText, GetDbParamtersByObject(cmdText, parms));
 | 
				
			||||||
        public (List<T1>, List<T2>, List<T3>, List<T4>, List<T5>) Query<T1, T2, T3, T4, T5>(DbTransaction transaction, string cmdText, object parms = null) => Query<T1, T2, T3, T4, T5>(null, transaction, CommandType.Text, cmdText, GetDbParamtersByObject(cmdText, parms));
 | 
					        public NaviteTuple<List<T1>, List<T2>, List<T3>, List<T4>, List<T5>> Query<T1, T2, T3, T4, T5>(DbTransaction transaction, string cmdText, object parms = null) => Query<T1, T2, T3, T4, T5>(null, transaction, CommandType.Text, cmdText, GetDbParamtersByObject(cmdText, parms));
 | 
				
			||||||
        public (List<T1>, List<T2>, List<T3>, List<T4>, List<T5>) Query<T1, T2, T3, T4, T5>(DbConnection connection, DbTransaction transaction, string cmdText, object parms = null) => Query<T1, T2, T3, T4, T5>(connection, transaction, CommandType.Text, cmdText, GetDbParamtersByObject(cmdText, parms));
 | 
					        public NaviteTuple<List<T1>, List<T2>, List<T3>, List<T4>, List<T5>> Query<T1, T2, T3, T4, T5>(DbConnection connection, DbTransaction transaction, string cmdText, object parms = null) => Query<T1, T2, T3, T4, T5>(connection, transaction, CommandType.Text, cmdText, GetDbParamtersByObject(cmdText, parms));
 | 
				
			||||||
        public (List<T1>, List<T2>, List<T3>, List<T4>, List<T5>) Query<T1, T2, T3, T4, T5>(CommandType cmdType, string cmdText, params DbParameter[] cmdParms) => Query<T1, T2, T3, T4, T5>(null, null, cmdType, cmdText, cmdParms);
 | 
					        public NaviteTuple<List<T1>, List<T2>, List<T3>, List<T4>, List<T5>> Query<T1, T2, T3, T4, T5>(CommandType cmdType, string cmdText, params DbParameter[] cmdParms) => Query<T1, T2, T3, T4, T5>(null, null, cmdType, cmdText, cmdParms);
 | 
				
			||||||
        public (List<T1>, List<T2>, List<T3>, List<T4>, List<T5>) Query<T1, T2, T3, T4, T5>(DbTransaction transaction, CommandType cmdType, string cmdText, params DbParameter[] cmdParms) => Query<T1, T2, T3, T4, T5>(null, transaction, cmdType, cmdText, cmdParms);
 | 
					        public NaviteTuple<List<T1>, List<T2>, List<T3>, List<T4>, List<T5>> Query<T1, T2, T3, T4, T5>(DbTransaction transaction, CommandType cmdType, string cmdText, params DbParameter[] cmdParms) => Query<T1, T2, T3, T4, T5>(null, transaction, cmdType, cmdText, cmdParms);
 | 
				
			||||||
        public (List<T1>, List<T2>, List<T3>, List<T4>, List<T5>) Query<T1, T2, T3, T4, T5>(DbConnection connection, DbTransaction transaction, CommandType cmdType, string cmdText, params DbParameter[] cmdParms)
 | 
					        public NaviteTuple<List<T1>, List<T2>, List<T3>, List<T4>, List<T5>> Query<T1, T2, T3, T4, T5>(DbConnection connection, DbTransaction transaction, CommandType cmdType, string cmdText, params DbParameter[] cmdParms)
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
            if (string.IsNullOrEmpty(cmdText)) return (new List<T1>(), new List<T2>(), new List<T3>(), new List<T4>(), new List<T5>());
 | 
					            if (string.IsNullOrEmpty(cmdText)) return NaviteTuple.Create(new List<T1>(), new List<T2>(), new List<T3>(), new List<T4>(), new List<T5>());
 | 
				
			||||||
            var ret1 = new List<T1>();
 | 
					            var ret1 = new List<T1>();
 | 
				
			||||||
            var type1 = typeof(T1);
 | 
					            var type1 = typeof(T1);
 | 
				
			||||||
            string flag1 = null;
 | 
					            string flag1 = null;
 | 
				
			||||||
@@ -504,7 +505,7 @@ namespace FreeSql.Internal.CommonProvider
 | 
				
			|||||||
                        break;
 | 
					                        break;
 | 
				
			||||||
                }
 | 
					                }
 | 
				
			||||||
            }, cmdType, cmdText, cmdParms);
 | 
					            }, cmdType, cmdText, cmdParms);
 | 
				
			||||||
            return (ret1, ret2, ret3, ret4, ret5);
 | 
					            return NaviteTuple.Create(ret1, ret2, ret3, ret4, ret5);
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
        #endregion
 | 
					        #endregion
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -771,7 +772,19 @@ namespace FreeSql.Internal.CommonProvider
 | 
				
			|||||||
            return val;
 | 
					            return val;
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        (Aop.CommandBeforeEventArgs before, DbCommand cmd, bool isclose) PrepareCommand(DbConnection connection, DbTransaction transaction, CommandType cmdType, string cmdText, DbParameter[] cmdParms, StringBuilder logtxt)
 | 
					        class PrepareCommandResult
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            public Aop.CommandBeforeEventArgs before { get; }
 | 
				
			||||||
 | 
					            public DbCommand cmd { get; }
 | 
				
			||||||
 | 
					            public bool isclose { get; }
 | 
				
			||||||
 | 
					            public PrepareCommandResult(Aop.CommandBeforeEventArgs before, DbCommand cmd, bool isclose)
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					                this.before = before;
 | 
				
			||||||
 | 
					                this.cmd = cmd;
 | 
				
			||||||
 | 
					                this.isclose = isclose;
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        PrepareCommandResult PrepareCommand(DbConnection connection, DbTransaction transaction, CommandType cmdType, string cmdText, DbParameter[] cmdParms, StringBuilder logtxt)
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
            var dt = DateTime.Now;
 | 
					            var dt = DateTime.Now;
 | 
				
			||||||
            DbCommand cmd = CreateCommand();
 | 
					            DbCommand cmd = CreateCommand();
 | 
				
			||||||
@@ -818,7 +831,7 @@ namespace FreeSql.Internal.CommonProvider
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
            var before = new Aop.CommandBeforeEventArgs(cmd);
 | 
					            var before = new Aop.CommandBeforeEventArgs(cmd);
 | 
				
			||||||
            _util?._orm?.Aop.CommandBeforeHandler?.Invoke(_util._orm, before);
 | 
					            _util?._orm?.Aop.CommandBeforeHandler?.Invoke(_util._orm, before);
 | 
				
			||||||
            return (before, cmd, isclose);
 | 
					            return new PrepareCommandResult(before, cmd, isclose);
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,4 +1,5 @@
 | 
				
			|||||||
using SafeObjectPool;
 | 
					using FreeSql.Internal.Model;
 | 
				
			||||||
 | 
					using SafeObjectPool;
 | 
				
			||||||
using System;
 | 
					using System;
 | 
				
			||||||
using System.Collections.Generic;
 | 
					using System.Collections.Generic;
 | 
				
			||||||
using System.Data;
 | 
					using System.Data;
 | 
				
			||||||
@@ -48,14 +49,14 @@ namespace FreeSql.Internal.CommonProvider
 | 
				
			|||||||
            return ret;
 | 
					            return ret;
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
        #region QueryAsync multi
 | 
					        #region QueryAsync multi
 | 
				
			||||||
        public Task<(List<T1>, List<T2>)> QueryAsync<T1, T2>(string cmdText, object parms = null) => QueryAsync<T1, T2>(null, null, CommandType.Text, cmdText, GetDbParamtersByObject(cmdText, parms));
 | 
					        public Task<NaviteTuple<List<T1>, List<T2>>> QueryAsync<T1, T2>(string cmdText, object parms = null) => QueryAsync<T1, T2>(null, null, CommandType.Text, cmdText, GetDbParamtersByObject(cmdText, parms));
 | 
				
			||||||
        public Task<(List<T1>, List<T2>)> QueryAsync<T1, T2>(DbTransaction transaction, string cmdText, object parms = null) => QueryAsync<T1, T2>(null, transaction, CommandType.Text, cmdText, GetDbParamtersByObject(cmdText, parms));
 | 
					        public Task<NaviteTuple<List<T1>, List<T2>>> QueryAsync<T1, T2>(DbTransaction transaction, string cmdText, object parms = null) => QueryAsync<T1, T2>(null, transaction, CommandType.Text, cmdText, GetDbParamtersByObject(cmdText, parms));
 | 
				
			||||||
        public Task<(List<T1>, List<T2>)> QueryAsync<T1, T2>(DbConnection connection, DbTransaction transaction, string cmdText, object parms = null) => QueryAsync<T1, T2>(connection, transaction, CommandType.Text, cmdText, GetDbParamtersByObject(cmdText, parms));
 | 
					        public Task<NaviteTuple<List<T1>, List<T2>>> QueryAsync<T1, T2>(DbConnection connection, DbTransaction transaction, string cmdText, object parms = null) => QueryAsync<T1, T2>(connection, transaction, CommandType.Text, cmdText, GetDbParamtersByObject(cmdText, parms));
 | 
				
			||||||
        public Task<(List<T1>, List<T2>)> QueryAsync<T1, T2>(CommandType cmdType, string cmdText, params DbParameter[] cmdParms) => QueryAsync<T1, T2>(null, null, cmdType, cmdText, cmdParms);
 | 
					        public Task<NaviteTuple<List<T1>, List<T2>>> QueryAsync<T1, T2>(CommandType cmdType, string cmdText, params DbParameter[] cmdParms) => QueryAsync<T1, T2>(null, null, cmdType, cmdText, cmdParms);
 | 
				
			||||||
        public Task<(List<T1>, List<T2>)> QueryAsync<T1, T2>(DbTransaction transaction, CommandType cmdType, string cmdText, params DbParameter[] cmdParms) => QueryAsync<T1, T2>(null, transaction, cmdType, cmdText, cmdParms);
 | 
					        public Task<NaviteTuple<List<T1>, List<T2>>> QueryAsync<T1, T2>(DbTransaction transaction, CommandType cmdType, string cmdText, params DbParameter[] cmdParms) => QueryAsync<T1, T2>(null, transaction, cmdType, cmdText, cmdParms);
 | 
				
			||||||
        async public Task<(List<T1>, List<T2>)> QueryAsync<T1, T2>(DbConnection connection, DbTransaction transaction, CommandType cmdType, string cmdText, params DbParameter[] cmdParms)
 | 
					        async public Task<NaviteTuple<List<T1>, List<T2>>> QueryAsync<T1, T2>(DbConnection connection, DbTransaction transaction, CommandType cmdType, string cmdText, params DbParameter[] cmdParms)
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
            if (string.IsNullOrEmpty(cmdText)) return (new List<T1>(), new List<T2>());
 | 
					            if (string.IsNullOrEmpty(cmdText)) return NaviteTuple.Create(new List<T1>(), new List<T2>());
 | 
				
			||||||
            var ret1 = new List<T1>();
 | 
					            var ret1 = new List<T1>();
 | 
				
			||||||
            var type1 = typeof(T1);
 | 
					            var type1 = typeof(T1);
 | 
				
			||||||
            string flag1 = null;
 | 
					            string flag1 = null;
 | 
				
			||||||
@@ -108,17 +109,17 @@ namespace FreeSql.Internal.CommonProvider
 | 
				
			|||||||
                }
 | 
					                }
 | 
				
			||||||
                return Task.FromResult(false);
 | 
					                return Task.FromResult(false);
 | 
				
			||||||
            }, cmdType, cmdText, cmdParms);
 | 
					            }, cmdType, cmdText, cmdParms);
 | 
				
			||||||
            return (ret1, ret2);
 | 
					            return NaviteTuple.Create(ret1, ret2);
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        public Task<(List<T1>, List<T2>, List<T3>)> QueryAsync<T1, T2, T3>(string cmdText, object parms = null) => QueryAsync<T1, T2, T3>(null, null, CommandType.Text, cmdText, GetDbParamtersByObject(cmdText, parms));
 | 
					        public Task<NaviteTuple<List<T1>, List<T2>, List<T3>>> QueryAsync<T1, T2, T3>(string cmdText, object parms = null) => QueryAsync<T1, T2, T3>(null, null, CommandType.Text, cmdText, GetDbParamtersByObject(cmdText, parms));
 | 
				
			||||||
        public Task<(List<T1>, List<T2>, List<T3>)> QueryAsync<T1, T2, T3>(DbTransaction transaction, string cmdText, object parms = null) => QueryAsync<T1, T2, T3>(null, transaction, CommandType.Text, cmdText, GetDbParamtersByObject(cmdText, parms));
 | 
					        public Task<NaviteTuple<List<T1>, List<T2>, List<T3>>> QueryAsync<T1, T2, T3>(DbTransaction transaction, string cmdText, object parms = null) => QueryAsync<T1, T2, T3>(null, transaction, CommandType.Text, cmdText, GetDbParamtersByObject(cmdText, parms));
 | 
				
			||||||
        public Task<(List<T1>, List<T2>, List<T3>)> QueryAsync<T1, T2, T3>(DbConnection connection, DbTransaction transaction, string cmdText, object parms = null) => QueryAsync<T1, T2, T3>(connection, transaction, CommandType.Text, cmdText, GetDbParamtersByObject(cmdText, parms));
 | 
					        public Task<NaviteTuple<List<T1>, List<T2>, List<T3>>> QueryAsync<T1, T2, T3>(DbConnection connection, DbTransaction transaction, string cmdText, object parms = null) => QueryAsync<T1, T2, T3>(connection, transaction, CommandType.Text, cmdText, GetDbParamtersByObject(cmdText, parms));
 | 
				
			||||||
        public Task<(List<T1>, List<T2>, List<T3>)> QueryAsync<T1, T2, T3>(CommandType cmdType, string cmdText, params DbParameter[] cmdParms) => QueryAsync<T1, T2, T3>(null, null, cmdType, cmdText, cmdParms);
 | 
					        public Task<NaviteTuple<List<T1>, List<T2>, List<T3>>> QueryAsync<T1, T2, T3>(CommandType cmdType, string cmdText, params DbParameter[] cmdParms) => QueryAsync<T1, T2, T3>(null, null, cmdType, cmdText, cmdParms);
 | 
				
			||||||
        public Task<(List<T1>, List<T2>, List<T3>)> QueryAsync<T1, T2, T3>(DbTransaction transaction, CommandType cmdType, string cmdText, params DbParameter[] cmdParms) => QueryAsync<T1, T2, T3>(null, transaction, cmdType, cmdText, cmdParms);
 | 
					        public Task<NaviteTuple<List<T1>, List<T2>, List<T3>>> QueryAsync<T1, T2, T3>(DbTransaction transaction, CommandType cmdType, string cmdText, params DbParameter[] cmdParms) => QueryAsync<T1, T2, T3>(null, transaction, cmdType, cmdText, cmdParms);
 | 
				
			||||||
        async public Task<(List<T1>, List<T2>, List<T3>)> QueryAsync<T1, T2, T3>(DbConnection connection, DbTransaction transaction, CommandType cmdType, string cmdText, params DbParameter[] cmdParms)
 | 
					        async public Task<NaviteTuple<List<T1>, List<T2>, List<T3>>> QueryAsync<T1, T2, T3>(DbConnection connection, DbTransaction transaction, CommandType cmdType, string cmdText, params DbParameter[] cmdParms)
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
            if (string.IsNullOrEmpty(cmdText)) return (new List<T1>(), new List<T2>(), new List<T3>());
 | 
					            if (string.IsNullOrEmpty(cmdText)) return NaviteTuple.Create(new List<T1>(), new List<T2>(), new List<T3>());
 | 
				
			||||||
            var ret1 = new List<T1>();
 | 
					            var ret1 = new List<T1>();
 | 
				
			||||||
            var type1 = typeof(T1);
 | 
					            var type1 = typeof(T1);
 | 
				
			||||||
            string flag1 = null;
 | 
					            string flag1 = null;
 | 
				
			||||||
@@ -194,17 +195,17 @@ namespace FreeSql.Internal.CommonProvider
 | 
				
			|||||||
                }
 | 
					                }
 | 
				
			||||||
                return Task.FromResult(false);
 | 
					                return Task.FromResult(false);
 | 
				
			||||||
            }, cmdType, cmdText, cmdParms);
 | 
					            }, cmdType, cmdText, cmdParms);
 | 
				
			||||||
            return (ret1, ret2, ret3);
 | 
					            return NaviteTuple.Create(ret1, ret2, ret3);
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        public Task<(List<T1>, List<T2>, List<T3>, List<T4>)> QueryAsync<T1, T2, T3, T4>(string cmdText, object parms = null) => QueryAsync<T1, T2, T3, T4>(null, null, CommandType.Text, cmdText, GetDbParamtersByObject(cmdText, parms));
 | 
					        public Task<NaviteTuple<List<T1>, List<T2>, List<T3>, List<T4>>> QueryAsync<T1, T2, T3, T4>(string cmdText, object parms = null) => QueryAsync<T1, T2, T3, T4>(null, null, CommandType.Text, cmdText, GetDbParamtersByObject(cmdText, parms));
 | 
				
			||||||
        public Task<(List<T1>, List<T2>, List<T3>, List<T4>)> QueryAsync<T1, T2, T3, T4>(DbTransaction transaction, string cmdText, object parms = null) => QueryAsync<T1, T2, T3, T4>(null, transaction, CommandType.Text, cmdText, GetDbParamtersByObject(cmdText, parms));
 | 
					        public Task<NaviteTuple<List<T1>, List<T2>, List<T3>, List<T4>>> QueryAsync<T1, T2, T3, T4>(DbTransaction transaction, string cmdText, object parms = null) => QueryAsync<T1, T2, T3, T4>(null, transaction, CommandType.Text, cmdText, GetDbParamtersByObject(cmdText, parms));
 | 
				
			||||||
        public Task<(List<T1>, List<T2>, List<T3>, List<T4>)> QueryAsync<T1, T2, T3, T4>(DbConnection connection, DbTransaction transaction, string cmdText, object parms = null) => QueryAsync<T1, T2, T3, T4>(connection, transaction, CommandType.Text, cmdText, GetDbParamtersByObject(cmdText, parms));
 | 
					        public Task<NaviteTuple<List<T1>, List<T2>, List<T3>, List<T4>>> QueryAsync<T1, T2, T3, T4>(DbConnection connection, DbTransaction transaction, string cmdText, object parms = null) => QueryAsync<T1, T2, T3, T4>(connection, transaction, CommandType.Text, cmdText, GetDbParamtersByObject(cmdText, parms));
 | 
				
			||||||
        public Task<(List<T1>, List<T2>, List<T3>, List<T4>)> QueryAsync<T1, T2, T3, T4>(CommandType cmdType, string cmdText, params DbParameter[] cmdParms) => QueryAsync<T1, T2, T3, T4>(null, null, cmdType, cmdText, cmdParms);
 | 
					        public Task<NaviteTuple<List<T1>, List<T2>, List<T3>, List<T4>>> QueryAsync<T1, T2, T3, T4>(CommandType cmdType, string cmdText, params DbParameter[] cmdParms) => QueryAsync<T1, T2, T3, T4>(null, null, cmdType, cmdText, cmdParms);
 | 
				
			||||||
        public Task<(List<T1>, List<T2>, List<T3>, List<T4>)> QueryAsync<T1, T2, T3, T4>(DbTransaction transaction, CommandType cmdType, string cmdText, params DbParameter[] cmdParms) => QueryAsync<T1, T2, T3, T4>(null, transaction, cmdType, cmdText, cmdParms);
 | 
					        public Task<NaviteTuple<List<T1>, List<T2>, List<T3>, List<T4>>> QueryAsync<T1, T2, T3, T4>(DbTransaction transaction, CommandType cmdType, string cmdText, params DbParameter[] cmdParms) => QueryAsync<T1, T2, T3, T4>(null, transaction, cmdType, cmdText, cmdParms);
 | 
				
			||||||
        async public Task<(List<T1>, List<T2>, List<T3>, List<T4>)> QueryAsync<T1, T2, T3, T4>(DbConnection connection, DbTransaction transaction, CommandType cmdType, string cmdText, params DbParameter[] cmdParms)
 | 
					        async public Task<NaviteTuple<List<T1>, List<T2>, List<T3>, List<T4>>> QueryAsync<T1, T2, T3, T4>(DbConnection connection, DbTransaction transaction, CommandType cmdType, string cmdText, params DbParameter[] cmdParms)
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
            if (string.IsNullOrEmpty(cmdText)) return (new List<T1>(), new List<T2>(), new List<T3>(), new List<T4>());
 | 
					            if (string.IsNullOrEmpty(cmdText)) return NaviteTuple.Create(new List<T1>(), new List<T2>(), new List<T3>(), new List<T4>());
 | 
				
			||||||
            var ret1 = new List<T1>();
 | 
					            var ret1 = new List<T1>();
 | 
				
			||||||
            var type1 = typeof(T1);
 | 
					            var type1 = typeof(T1);
 | 
				
			||||||
            string flag1 = null;
 | 
					            string flag1 = null;
 | 
				
			||||||
@@ -303,17 +304,17 @@ namespace FreeSql.Internal.CommonProvider
 | 
				
			|||||||
                }
 | 
					                }
 | 
				
			||||||
                return Task.FromResult(false);
 | 
					                return Task.FromResult(false);
 | 
				
			||||||
            }, cmdType, cmdText, cmdParms);
 | 
					            }, cmdType, cmdText, cmdParms);
 | 
				
			||||||
            return (ret1, ret2, ret3, ret4);
 | 
					            return NaviteTuple.Create(ret1, ret2, ret3, ret4);
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        public Task<(List<T1>, List<T2>, List<T3>, List<T4>, List<T5>)> QueryAsync<T1, T2, T3, T4, T5>(string cmdText, object parms = null) => QueryAsync<T1, T2, T3, T4, T5>(null, null, CommandType.Text, cmdText, GetDbParamtersByObject(cmdText, parms));
 | 
					        public Task<NaviteTuple<List<T1>, List<T2>, List<T3>, List<T4>, List<T5>>> QueryAsync<T1, T2, T3, T4, T5>(string cmdText, object parms = null) => QueryAsync<T1, T2, T3, T4, T5>(null, null, CommandType.Text, cmdText, GetDbParamtersByObject(cmdText, parms));
 | 
				
			||||||
        public Task<(List<T1>, List<T2>, List<T3>, List<T4>, List<T5>)> QueryAsync<T1, T2, T3, T4, T5>(DbTransaction transaction, string cmdText, object parms = null) => QueryAsync<T1, T2, T3, T4, T5>(null, transaction, CommandType.Text, cmdText, GetDbParamtersByObject(cmdText, parms));
 | 
					        public Task<NaviteTuple<List<T1>, List<T2>, List<T3>, List<T4>, List<T5>>> QueryAsync<T1, T2, T3, T4, T5>(DbTransaction transaction, string cmdText, object parms = null) => QueryAsync<T1, T2, T3, T4, T5>(null, transaction, CommandType.Text, cmdText, GetDbParamtersByObject(cmdText, parms));
 | 
				
			||||||
        public Task<(List<T1>, List<T2>, List<T3>, List<T4>, List<T5>)> QueryAsync<T1, T2, T3, T4, T5>(DbConnection connection, DbTransaction transaction, string cmdText, object parms = null) => QueryAsync<T1, T2, T3, T4, T5>(connection, transaction, CommandType.Text, cmdText, GetDbParamtersByObject(cmdText, parms));
 | 
					        public Task<NaviteTuple<List<T1>, List<T2>, List<T3>, List<T4>, List<T5>>> QueryAsync<T1, T2, T3, T4, T5>(DbConnection connection, DbTransaction transaction, string cmdText, object parms = null) => QueryAsync<T1, T2, T3, T4, T5>(connection, transaction, CommandType.Text, cmdText, GetDbParamtersByObject(cmdText, parms));
 | 
				
			||||||
        public Task<(List<T1>, List<T2>, List<T3>, List<T4>, List<T5>)> QueryAsync<T1, T2, T3, T4, T5>(CommandType cmdType, string cmdText, params DbParameter[] cmdParms) => QueryAsync<T1, T2, T3, T4, T5>(null, null, cmdType, cmdText, cmdParms);
 | 
					        public Task<NaviteTuple<List<T1>, List<T2>, List<T3>, List<T4>, List<T5>>> QueryAsync<T1, T2, T3, T4, T5>(CommandType cmdType, string cmdText, params DbParameter[] cmdParms) => QueryAsync<T1, T2, T3, T4, T5>(null, null, cmdType, cmdText, cmdParms);
 | 
				
			||||||
        public Task<(List<T1>, List<T2>, List<T3>, List<T4>, List<T5>)> QueryAsync<T1, T2, T3, T4, T5>(DbTransaction transaction, CommandType cmdType, string cmdText, params DbParameter[] cmdParms) => QueryAsync<T1, T2, T3, T4, T5>(null, transaction, cmdType, cmdText, cmdParms);
 | 
					        public Task<NaviteTuple<List<T1>, List<T2>, List<T3>, List<T4>, List<T5>>> QueryAsync<T1, T2, T3, T4, T5>(DbTransaction transaction, CommandType cmdType, string cmdText, params DbParameter[] cmdParms) => QueryAsync<T1, T2, T3, T4, T5>(null, transaction, cmdType, cmdText, cmdParms);
 | 
				
			||||||
        async public Task<(List<T1>, List<T2>, List<T3>, List<T4>, List<T5>)> QueryAsync<T1, T2, T3, T4, T5>(DbConnection connection, DbTransaction transaction, CommandType cmdType, string cmdText, params DbParameter[] cmdParms)
 | 
					        async public Task<NaviteTuple<List<T1>, List<T2>, List<T3>, List<T4>, List<T5>>> QueryAsync<T1, T2, T3, T4, T5>(DbConnection connection, DbTransaction transaction, CommandType cmdType, string cmdText, params DbParameter[] cmdParms)
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
            if (string.IsNullOrEmpty(cmdText)) return (new List<T1>(), new List<T2>(), new List<T3>(), new List<T4>(), new List<T5>());
 | 
					            if (string.IsNullOrEmpty(cmdText)) return NaviteTuple.Create(new List<T1>(), new List<T2>(), new List<T3>(), new List<T4>(), new List<T5>());
 | 
				
			||||||
            var ret1 = new List<T1>();
 | 
					            var ret1 = new List<T1>();
 | 
				
			||||||
            var type1 = typeof(T1);
 | 
					            var type1 = typeof(T1);
 | 
				
			||||||
            string flag1 = null;
 | 
					            string flag1 = null;
 | 
				
			||||||
@@ -435,7 +436,7 @@ namespace FreeSql.Internal.CommonProvider
 | 
				
			|||||||
                }
 | 
					                }
 | 
				
			||||||
                return Task.FromResult(false);
 | 
					                return Task.FromResult(false);
 | 
				
			||||||
            }, cmdType, cmdText, cmdParms);
 | 
					            }, cmdType, cmdText, cmdParms);
 | 
				
			||||||
            return (ret1, ret2, ret3, ret4, ret5);
 | 
					            return NaviteTuple.Create(ret1, ret2, ret3, ret4, ret5);
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
        #endregion
 | 
					        #endregion
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -700,7 +701,7 @@ namespace FreeSql.Internal.CommonProvider
 | 
				
			|||||||
            return val;
 | 
					            return val;
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        async Task<(Aop.CommandBeforeEventArgs before, DbCommand cmd, bool isclose)> PrepareCommandAsync(DbConnection connection, DbTransaction transaction, CommandType cmdType, string cmdText, DbParameter[] cmdParms, StringBuilder logtxt)
 | 
					        async Task<PrepareCommandResult> PrepareCommandAsync(DbConnection connection, DbTransaction transaction, CommandType cmdType, string cmdText, DbParameter[] cmdParms, StringBuilder logtxt)
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
            DateTime dt = DateTime.Now;
 | 
					            DateTime dt = DateTime.Now;
 | 
				
			||||||
            DbCommand cmd = CreateCommand();
 | 
					            DbCommand cmd = CreateCommand();
 | 
				
			||||||
@@ -744,7 +745,7 @@ namespace FreeSql.Internal.CommonProvider
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
            var before = new Aop.CommandBeforeEventArgs(cmd);
 | 
					            var before = new Aop.CommandBeforeEventArgs(cmd);
 | 
				
			||||||
            _util?._orm?.Aop.CommandBeforeHandler?.Invoke(_util._orm, before);
 | 
					            _util?._orm?.Aop.CommandBeforeHandler?.Invoke(_util._orm, before);
 | 
				
			||||||
            return (before, cmd, isclose);
 | 
					            return new PrepareCommandResult(before, cmd, isclose);
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -35,7 +35,7 @@ namespace FreeSql.Internal.CommonProvider
 | 
				
			|||||||
        public virtual bool IsGenerateCommandParameterWithLambda { get; set; } = false;
 | 
					        public virtual bool IsGenerateCommandParameterWithLambda { get; set; } = false;
 | 
				
			||||||
        public bool IsLazyLoading { get; set; } = false;
 | 
					        public bool IsLazyLoading { get; set; } = false;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        public abstract (int type, string dbtype, string dbtypeFull, bool? isnullable, object defaultValue)? GetDbInfo(Type type);
 | 
					        public abstract DbInfoResult GetDbInfo(Type type);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        public ICodeFirst ConfigEntity<T>(Action<TableFluent<T>> entity) => _commonUtils.ConfigEntity(entity);
 | 
					        public ICodeFirst ConfigEntity<T>(Action<TableFluent<T>> entity) => _commonUtils.ConfigEntity(entity);
 | 
				
			||||||
        public ICodeFirst ConfigEntity(Type type, Action<TableFluent> entity) => _commonUtils.ConfigEntity(type, entity);
 | 
					        public ICodeFirst ConfigEntity(Type type, Action<TableFluent> entity) => _commonUtils.ConfigEntity(type, entity);
 | 
				
			||||||
@@ -50,12 +50,22 @@ namespace FreeSql.Internal.CommonProvider
 | 
				
			|||||||
            return tableName;
 | 
					            return tableName;
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
        public string GetComparisonDDLStatements<TEntity>() =>
 | 
					        public string GetComparisonDDLStatements<TEntity>() =>
 | 
				
			||||||
            this.GetComparisonDDLStatements((typeof(TEntity), ""));
 | 
					            this.GetComparisonDDLStatements(new TypeAndName(typeof(TEntity), ""));
 | 
				
			||||||
        public string GetComparisonDDLStatements(params Type[] entityTypes) => entityTypes == null ? null : 
 | 
					        public string GetComparisonDDLStatements(params Type[] entityTypes) => entityTypes == null ? null : 
 | 
				
			||||||
            this.GetComparisonDDLStatements(entityTypes.Distinct().Select(a => (a, "")).ToArray());
 | 
					            this.GetComparisonDDLStatements(entityTypes.Distinct().Select(a => new TypeAndName(a, "")).ToArray());
 | 
				
			||||||
        public string GetComparisonDDLStatements(Type entityType, string tableName) =>
 | 
					        public string GetComparisonDDLStatements(Type entityType, string tableName) =>
 | 
				
			||||||
           this.GetComparisonDDLStatements((entityType, GetTableNameLowerOrUpper(tableName)));
 | 
					           this.GetComparisonDDLStatements(new TypeAndName(entityType, GetTableNameLowerOrUpper(tableName)));
 | 
				
			||||||
        protected abstract string GetComparisonDDLStatements(params (Type entityType, string tableName)[] objects);
 | 
					        protected abstract string GetComparisonDDLStatements(params TypeAndName[] objects);
 | 
				
			||||||
 | 
					        public class TypeAndName
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            public Type entityType { get; }
 | 
				
			||||||
 | 
					            public string tableName { get; }
 | 
				
			||||||
 | 
					            public TypeAndName(Type entityType, string tableName)
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					                this.entityType = entityType;
 | 
				
			||||||
 | 
					                this.tableName = tableName;
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        static object syncStructureLock = new object();
 | 
					        static object syncStructureLock = new object();
 | 
				
			||||||
        object _dicSycedLock = new object();
 | 
					        object _dicSycedLock = new object();
 | 
				
			||||||
@@ -72,16 +82,16 @@ namespace FreeSql.Internal.CommonProvider
 | 
				
			|||||||
            _dicSycedGetOrAdd(entityType).TryAdd(GetTableNameLowerOrUpper(tableName), true);
 | 
					            _dicSycedGetOrAdd(entityType).TryAdd(GetTableNameLowerOrUpper(tableName), true);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        public bool SyncStructure<TEntity>() =>
 | 
					        public bool SyncStructure<TEntity>() =>
 | 
				
			||||||
            this.SyncStructure((typeof(TEntity), ""));
 | 
					            this.SyncStructure(new TypeAndName(typeof(TEntity), ""));
 | 
				
			||||||
        public bool SyncStructure(params Type[] entityTypes) => entityTypes == null ? false :
 | 
					        public bool SyncStructure(params Type[] entityTypes) => entityTypes == null ? false :
 | 
				
			||||||
            this.SyncStructure(entityTypes.Distinct().Select(a => (a, "")).ToArray());
 | 
					            this.SyncStructure(entityTypes.Distinct().Select(a => new TypeAndName(a, "")).ToArray());
 | 
				
			||||||
        public bool SyncStructure(Type entityType, string tableName) =>
 | 
					        public bool SyncStructure(Type entityType, string tableName) =>
 | 
				
			||||||
           this.SyncStructure((entityType, GetTableNameLowerOrUpper(tableName)));
 | 
					           this.SyncStructure(new TypeAndName(entityType, GetTableNameLowerOrUpper(tableName)));
 | 
				
			||||||
        protected bool SyncStructure(params (Type entityType, string tableName)[] objects)
 | 
					        protected bool SyncStructure(params TypeAndName[] objects)
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
            if (objects == null) return false;
 | 
					            if (objects == null) return false;
 | 
				
			||||||
            (Type entityType, string tableName)[] syncObjects = objects.Where(a => _dicSycedGetOrAdd(a.entityType).ContainsKey(GetTableNameLowerOrUpper(a.tableName)) == false && GetTableByEntity(a.entityType)?.DisableSyncStructure == false)
 | 
					            var syncObjects = objects.Where(a => _dicSycedGetOrAdd(a.entityType).ContainsKey(GetTableNameLowerOrUpper(a.tableName)) == false && GetTableByEntity(a.entityType)?.DisableSyncStructure == false)
 | 
				
			||||||
                .Select(a => (a.entityType, GetTableNameLowerOrUpper(a.tableName))).ToArray();
 | 
					                .Select(a => new TypeAndName(a.entityType, GetTableNameLowerOrUpper(a.tableName))).ToArray();
 | 
				
			||||||
            if (syncObjects.Any() == false) return false;
 | 
					            if (syncObjects.Any() == false) return false;
 | 
				
			||||||
            var before = new Aop.SyncStructureBeforeEventArgs(syncObjects.Select(a => a.entityType).ToArray());
 | 
					            var before = new Aop.SyncStructureBeforeEventArgs(syncObjects.Select(a => a.entityType).ToArray());
 | 
				
			||||||
            _orm.Aop.SyncStructureBeforeHandler?.Invoke(this, before);
 | 
					            _orm.Aop.SyncStructureBeforeHandler?.Invoke(this, before);
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -349,7 +349,7 @@ namespace FreeSql.Internal.CommonProvider
 | 
				
			|||||||
            }
 | 
					            }
 | 
				
			||||||
            return ret;
 | 
					            return ret;
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
        internal List<T1> ToListAfPrivate(string sql, GetAllFieldExpressionTreeInfo af, (string field, ReadAnonymousTypeInfo read, List<object> retlist)[] otherData)
 | 
					        internal List<T1> ToListAfPrivate(string sql, GetAllFieldExpressionTreeInfo af, ReadAnonymousTypeOtherInfo[] otherData)
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
            var dbParms = _params.ToArray();
 | 
					            var dbParms = _params.ToArray();
 | 
				
			||||||
            var before = new Aop.CurdBeforeEventArgs(_tables[0].Table.Type, _tables[0].Table, Aop.CurdType.Select, sql, dbParms);
 | 
					            var before = new Aop.CurdBeforeEventArgs(_tables[0].Table.Type, _tables[0].Table, Aop.CurdType.Select, sql, dbParms);
 | 
				
			||||||
@@ -383,7 +383,7 @@ namespace FreeSql.Internal.CommonProvider
 | 
				
			|||||||
            _trackToList?.Invoke(ret);
 | 
					            _trackToList?.Invoke(ret);
 | 
				
			||||||
            return ret;
 | 
					            return ret;
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
        internal List<T1> ToListPrivate(GetAllFieldExpressionTreeInfo af, (string field, ReadAnonymousTypeInfo read, List<object> retlist)[] otherData)
 | 
					        internal List<T1> ToListPrivate(GetAllFieldExpressionTreeInfo af, ReadAnonymousTypeOtherInfo[] otherData)
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
            string sql = null;
 | 
					            string sql = null;
 | 
				
			||||||
            if (otherData?.Length > 0)
 | 
					            if (otherData?.Length > 0)
 | 
				
			||||||
@@ -399,7 +399,7 @@ namespace FreeSql.Internal.CommonProvider
 | 
				
			|||||||
            return ToListAfPrivate(sql, af, otherData);
 | 
					            return ToListAfPrivate(sql, af, otherData);
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
        #region ToChunk
 | 
					        #region ToChunk
 | 
				
			||||||
        internal void ToListAfChunkPrivate(int chunkSize, Action<List<T1>> chunkDone, string sql, GetAllFieldExpressionTreeInfo af, (string field, ReadAnonymousTypeInfo read, List<object> retlist)[] otherData)
 | 
					        internal void ToListAfChunkPrivate(int chunkSize, Action<List<T1>> chunkDone, string sql, GetAllFieldExpressionTreeInfo af, ReadAnonymousTypeOtherInfo[] otherData)
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
            var dbParms = _params.ToArray();
 | 
					            var dbParms = _params.ToArray();
 | 
				
			||||||
            var before = new Aop.CurdBeforeEventArgs(_tables[0].Table.Type, _tables[0].Table, Aop.CurdType.Select, sql, dbParms);
 | 
					            var before = new Aop.CurdBeforeEventArgs(_tables[0].Table.Type, _tables[0].Table, Aop.CurdType.Select, sql, dbParms);
 | 
				
			||||||
@@ -453,7 +453,7 @@ namespace FreeSql.Internal.CommonProvider
 | 
				
			|||||||
                chunkDone(ret);
 | 
					                chunkDone(ret);
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
        internal void ToListChunkPrivate(int chunkSize, Action<List<T1>> chunkDone, GetAllFieldExpressionTreeInfo af, (string field, ReadAnonymousTypeInfo read, List<object> retlist)[] otherData)
 | 
					        internal void ToListChunkPrivate(int chunkSize, Action<List<T1>> chunkDone, GetAllFieldExpressionTreeInfo af, ReadAnonymousTypeOtherInfo[] otherData)
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
            string sql = null;
 | 
					            string sql = null;
 | 
				
			||||||
            if (otherData?.Length > 0)
 | 
					            if (otherData?.Length > 0)
 | 
				
			||||||
@@ -487,7 +487,7 @@ namespace FreeSql.Internal.CommonProvider
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
        public T1 First() => this.ToOne();
 | 
					        public T1 First() => this.ToOne();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        internal List<TReturn> ToListMrPrivate<TReturn>(string sql, (ReadAnonymousTypeInfo map, string field) af, (string field, ReadAnonymousTypeInfo read, List<object> retlist)[] otherData)
 | 
					        internal List<TReturn> ToListMrPrivate<TReturn>(string sql, ReadAnonymousTypeAfInfo af, ReadAnonymousTypeOtherInfo[] otherData)
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
            var type = typeof(TReturn);
 | 
					            var type = typeof(TReturn);
 | 
				
			||||||
            var dbParms = _params.ToArray();
 | 
					            var dbParms = _params.ToArray();
 | 
				
			||||||
@@ -521,7 +521,7 @@ namespace FreeSql.Internal.CommonProvider
 | 
				
			|||||||
            _trackToList?.Invoke(ret);
 | 
					            _trackToList?.Invoke(ret);
 | 
				
			||||||
            return ret;
 | 
					            return ret;
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
        internal List<TReturn> ToListMapReaderPrivate<TReturn>((ReadAnonymousTypeInfo map, string field) af, (string field, ReadAnonymousTypeInfo read, List<object> retlist)[] otherData)
 | 
					        internal List<TReturn> ToListMapReaderPrivate<TReturn>(ReadAnonymousTypeAfInfo af, ReadAnonymousTypeOtherInfo[] otherData)
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
            string sql = null;
 | 
					            string sql = null;
 | 
				
			||||||
            if (otherData?.Length > 0)
 | 
					            if (otherData?.Length > 0)
 | 
				
			||||||
@@ -536,15 +536,15 @@ namespace FreeSql.Internal.CommonProvider
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
            return ToListMrPrivate<TReturn>(sql, af, otherData);
 | 
					            return ToListMrPrivate<TReturn>(sql, af, otherData);
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
        protected List<TReturn> ToListMapReader<TReturn>((ReadAnonymousTypeInfo map, string field) af) => ToListMapReaderPrivate<TReturn>(af, null);
 | 
					        protected List<TReturn> ToListMapReader<TReturn>(ReadAnonymousTypeAfInfo af) => ToListMapReaderPrivate<TReturn>(af, null);
 | 
				
			||||||
        protected (ReadAnonymousTypeInfo map, string field) GetExpressionField(Expression newexp, FieldAliasOptions fieldAlias = FieldAliasOptions.AsIndex)
 | 
					        protected ReadAnonymousTypeAfInfo GetExpressionField(Expression newexp, FieldAliasOptions fieldAlias = FieldAliasOptions.AsIndex)
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
            var map = new ReadAnonymousTypeInfo();
 | 
					            var map = new ReadAnonymousTypeInfo();
 | 
				
			||||||
            var field = new StringBuilder();
 | 
					            var field = new StringBuilder();
 | 
				
			||||||
            var index = fieldAlias == FieldAliasOptions.AsProperty ? CommonExpression.ReadAnonymousFieldAsCsName : 0;
 | 
					            var index = fieldAlias == FieldAliasOptions.AsProperty ? CommonExpression.ReadAnonymousFieldAsCsName : 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            _commonExpression.ReadAnonymousField(_tables, field, map, ref index, newexp, null, _whereCascadeExpression, true);
 | 
					            _commonExpression.ReadAnonymousField(_tables, field, map, ref index, newexp, null, _whereCascadeExpression, true);
 | 
				
			||||||
            return (map, field.Length > 0 ? field.Remove(0, 2).ToString() : null);
 | 
					            return new ReadAnonymousTypeAfInfo(map, field.Length > 0 ? field.Remove(0, 2).ToString() : null);
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
        static ConcurrentDictionary<string, GetAllFieldExpressionTreeInfo> _dicGetAllFieldExpressionTree = new ConcurrentDictionary<string, GetAllFieldExpressionTreeInfo>();
 | 
					        static ConcurrentDictionary<string, GetAllFieldExpressionTreeInfo> _dicGetAllFieldExpressionTree = new ConcurrentDictionary<string, GetAllFieldExpressionTreeInfo>();
 | 
				
			||||||
        public class GetAllFieldExpressionTreeInfo
 | 
					        public class GetAllFieldExpressionTreeInfo
 | 
				
			||||||
@@ -830,7 +830,7 @@ namespace FreeSql.Internal.CommonProvider
 | 
				
			|||||||
                };
 | 
					                };
 | 
				
			||||||
            });
 | 
					            });
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
        protected (ReadAnonymousTypeInfo map, string field) GetAllFieldReflection()
 | 
					        protected ReadAnonymousTypeAfInfo GetAllFieldReflection()
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
            var tb1 = _tables.First().Table;
 | 
					            var tb1 = _tables.First().Table;
 | 
				
			||||||
            var type = tb1.TypeLazy ?? tb1.Type;
 | 
					            var type = tb1.TypeLazy ?? tb1.Type;
 | 
				
			||||||
@@ -879,7 +879,7 @@ namespace FreeSql.Internal.CommonProvider
 | 
				
			|||||||
                }
 | 
					                }
 | 
				
			||||||
                map.Childs.Add(child);
 | 
					                map.Childs.Add(child);
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
            return (map, field.ToString());
 | 
					            return new ReadAnonymousTypeAfInfo(map, field.ToString());
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        string GetToDeleteWhere(string alias)
 | 
					        string GetToDeleteWhere(string alias)
 | 
				
			||||||
@@ -1109,7 +1109,7 @@ namespace FreeSql.Internal.CommonProvider
 | 
				
			|||||||
            var index = 0;
 | 
					            var index = 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            _commonExpression.ReadAnonymousField(_tables, field, map, ref index, select, null, _whereCascadeExpression, true);
 | 
					            _commonExpression.ReadAnonymousField(_tables, field, map, ref index, select, null, _whereCascadeExpression, true);
 | 
				
			||||||
            return this.ToListMapReader<TReturn>((map, field.Length > 0 ? field.Remove(0, 2).ToString() : null)).FirstOrDefault();
 | 
					            return this.ToListMapReader<TReturn>(new ReadAnonymousTypeAfInfo(map, field.Length > 0 ? field.Remove(0, 2).ToString() : null)).FirstOrDefault();
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        protected TSelect InternalWhere(Expression exp) => exp == null ? this as TSelect : this.Where(_commonExpression.ExpressionWhereLambda(_tables, exp, null, _whereCascadeExpression, _params));
 | 
					        protected TSelect InternalWhere(Expression exp) => exp == null ? this as TSelect : this.Where(_commonExpression.ExpressionWhereLambda(_tables, exp, null, _whereCascadeExpression, _params));
 | 
				
			||||||
@@ -1194,7 +1194,7 @@ namespace FreeSql.Internal.CommonProvider
 | 
				
			|||||||
            return ret;
 | 
					            return ret;
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        async internal Task<List<T1>> ToListAfPrivateAsync(string sql, GetAllFieldExpressionTreeInfo af, (string field, ReadAnonymousTypeInfo read, List<object> retlist)[] otherData)
 | 
					        async internal Task<List<T1>> ToListAfPrivateAsync(string sql, GetAllFieldExpressionTreeInfo af, ReadAnonymousTypeOtherInfo[] otherData)
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
            var dbParms = _params.ToArray();
 | 
					            var dbParms = _params.ToArray();
 | 
				
			||||||
            var before = new Aop.CurdBeforeEventArgs(_tables[0].Table.Type, _tables[0].Table, Aop.CurdType.Select, sql, dbParms);
 | 
					            var before = new Aop.CurdBeforeEventArgs(_tables[0].Table.Type, _tables[0].Table, Aop.CurdType.Select, sql, dbParms);
 | 
				
			||||||
@@ -1230,7 +1230,7 @@ namespace FreeSql.Internal.CommonProvider
 | 
				
			|||||||
            return ret;
 | 
					            return ret;
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        internal Task<List<T1>> ToListPrivateAsync(GetAllFieldExpressionTreeInfo af, (string field, ReadAnonymousTypeInfo read, List<object> retlist)[] otherData)
 | 
					        internal Task<List<T1>> ToListPrivateAsync(GetAllFieldExpressionTreeInfo af, ReadAnonymousTypeOtherInfo[] otherData)
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
            string sql = null;
 | 
					            string sql = null;
 | 
				
			||||||
            if (otherData?.Length > 0)
 | 
					            if (otherData?.Length > 0)
 | 
				
			||||||
@@ -1260,7 +1260,7 @@ namespace FreeSql.Internal.CommonProvider
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
        public Task<T1> FirstAsync() => this.ToOneAsync();
 | 
					        public Task<T1> FirstAsync() => this.ToOneAsync();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        async internal Task<List<TReturn>> ToListMrPrivateAsync<TReturn>(string sql, (ReadAnonymousTypeInfo map, string field) af, (string field, ReadAnonymousTypeInfo read, List<object> retlist)[] otherData)
 | 
					        async internal Task<List<TReturn>> ToListMrPrivateAsync<TReturn>(string sql, ReadAnonymousTypeAfInfo af, ReadAnonymousTypeOtherInfo[] otherData)
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
            var type = typeof(TReturn);
 | 
					            var type = typeof(TReturn);
 | 
				
			||||||
            var dbParms = _params.ToArray();
 | 
					            var dbParms = _params.ToArray();
 | 
				
			||||||
@@ -1295,7 +1295,7 @@ namespace FreeSql.Internal.CommonProvider
 | 
				
			|||||||
            _trackToList?.Invoke(ret);
 | 
					            _trackToList?.Invoke(ret);
 | 
				
			||||||
            return ret;
 | 
					            return ret;
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
        internal Task<List<TReturn>> ToListMapReaderPrivateAsync<TReturn>((ReadAnonymousTypeInfo map, string field) af, (string field, ReadAnonymousTypeInfo read, List<object> retlist)[] otherData)
 | 
					        internal Task<List<TReturn>> ToListMapReaderPrivateAsync<TReturn>(ReadAnonymousTypeAfInfo af, ReadAnonymousTypeOtherInfo[] otherData)
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
            string sql = null;
 | 
					            string sql = null;
 | 
				
			||||||
            if (otherData?.Length > 0)
 | 
					            if (otherData?.Length > 0)
 | 
				
			||||||
@@ -1310,7 +1310,7 @@ namespace FreeSql.Internal.CommonProvider
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
            return ToListMrPrivateAsync<TReturn>(sql, af, otherData);
 | 
					            return ToListMrPrivateAsync<TReturn>(sql, af, otherData);
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
        protected Task<List<TReturn>> ToListMapReaderAsync<TReturn>((ReadAnonymousTypeInfo map, string field) af) => ToListMapReaderPrivateAsync<TReturn>(af, null);
 | 
					        protected Task<List<TReturn>> ToListMapReaderAsync<TReturn>(ReadAnonymousTypeAfInfo af) => ToListMapReaderPrivateAsync<TReturn>(af, null);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        async protected Task<double> InternalAvgAsync(Expression exp)
 | 
					        async protected Task<double> InternalAvgAsync(Expression exp)
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
@@ -1355,7 +1355,7 @@ namespace FreeSql.Internal.CommonProvider
 | 
				
			|||||||
            var index = 0;
 | 
					            var index = 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            _commonExpression.ReadAnonymousField(_tables, field, map, ref index, select, null, _whereCascadeExpression, true);
 | 
					            _commonExpression.ReadAnonymousField(_tables, field, map, ref index, select, null, _whereCascadeExpression, true);
 | 
				
			||||||
            return (await this.ToListMapReaderAsync<TReturn>((map, field.Length > 0 ? field.Remove(0, 2).ToString() : null))).FirstOrDefault();
 | 
					            return (await this.ToListMapReaderAsync<TReturn>(new ReadAnonymousTypeAfInfo(map, field.Length > 0 ? field.Remove(0, 2).ToString() : null))).FirstOrDefault();
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
#endif
 | 
					#endif
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -43,11 +43,11 @@ namespace FreeSql.Internal.CommonProvider
 | 
				
			|||||||
            return this.InternalAvg(column?.Body);
 | 
					            return this.InternalAvg(column?.Body);
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        ISelectGrouping<TKey, (T1, T2, T3, T4, T5, T6, T7, T8, T9, T10)> ISelect<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10>.GroupBy<TKey>(Expression<Func<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, TKey>> exp)
 | 
					        ISelectGrouping<TKey, NaviteTuple<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10>> ISelect<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10>.GroupBy<TKey>(Expression<Func<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, TKey>> exp)
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
            if (exp == null) return this.InternalGroupBy<TKey, (T1, T2, T3, T4, T5, T6, T7, T8, T9, T10)>(exp?.Body);
 | 
					            if (exp == null) return this.InternalGroupBy<TKey, NaviteTuple<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10>>(exp?.Body);
 | 
				
			||||||
            for (var a = 0; a < exp.Parameters.Count; a++) _tables[a].Parameter = exp.Parameters[a];
 | 
					            for (var a = 0; a < exp.Parameters.Count; a++) _tables[a].Parameter = exp.Parameters[a];
 | 
				
			||||||
            return this.InternalGroupBy<TKey, (T1, T2, T3, T4, T5, T6, T7, T8, T9, T10)>(exp?.Body);
 | 
					            return this.InternalGroupBy<TKey, NaviteTuple<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10>>(exp?.Body);
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        TMember ISelect<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10>.Max<TMember>(Expression<Func<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, TMember>> column)
 | 
					        TMember ISelect<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10>.Max<TMember>(Expression<Func<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, TMember>> column)
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -368,7 +368,7 @@ namespace FreeSql.Internal.CommonProvider
 | 
				
			|||||||
            return this;
 | 
					            return this;
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        static (ParameterExpression param, List<MemberExpression> members) GetExpressionStack(Expression exp)
 | 
					        static NaviteTuple<ParameterExpression, List<MemberExpression>> GetExpressionStack(Expression exp)
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
            Expression tmpExp = exp;
 | 
					            Expression tmpExp = exp;
 | 
				
			||||||
            ParameterExpression param = null;
 | 
					            ParameterExpression param = null;
 | 
				
			||||||
@@ -392,7 +392,7 @@ namespace FreeSql.Internal.CommonProvider
 | 
				
			|||||||
                }
 | 
					                }
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
            if (param == null) throw new Exception($"表达式错误,它的顶级对象不是 ParameterExpression:{exp}");
 | 
					            if (param == null) throw new Exception($"表达式错误,它的顶级对象不是 ParameterExpression:{exp}");
 | 
				
			||||||
            return (param, members);
 | 
					            return NaviteTuple.Create(param, members);
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
        static MethodInfo GetEntityValueWithPropertyNameMethod = typeof(EntityUtilExtensions).GetMethod("GetEntityValueWithPropertyName");
 | 
					        static MethodInfo GetEntityValueWithPropertyNameMethod = typeof(EntityUtilExtensions).GetMethod("GetEntityValueWithPropertyName");
 | 
				
			||||||
        static ConcurrentDictionary<Type, ConcurrentDictionary<string, MethodInfo>> _dicTypeMethod = new ConcurrentDictionary<Type, ConcurrentDictionary<string, MethodInfo>>();
 | 
					        static ConcurrentDictionary<Type, ConcurrentDictionary<string, MethodInfo>> _dicTypeMethod = new ConcurrentDictionary<Type, ConcurrentDictionary<string, MethodInfo>>();
 | 
				
			||||||
@@ -429,7 +429,9 @@ namespace FreeSql.Internal.CommonProvider
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
            if (expBody.NodeType != ExpressionType.MemberAccess) throw throwNavigateSelector;
 | 
					            if (expBody.NodeType != ExpressionType.MemberAccess) throw throwNavigateSelector;
 | 
				
			||||||
            var collMem = expBody as MemberExpression;
 | 
					            var collMem = expBody as MemberExpression;
 | 
				
			||||||
            var (membersParam, members) = GetExpressionStack(collMem.Expression);
 | 
					            var ges = GetExpressionStack(collMem.Expression);
 | 
				
			||||||
 | 
					            var membersParam = ges.Item1;
 | 
				
			||||||
 | 
					            var members = ges.Item2;
 | 
				
			||||||
            var tb = _commonUtils.GetTableByEntity(collMem.Expression.Type);
 | 
					            var tb = _commonUtils.GetTableByEntity(collMem.Expression.Type);
 | 
				
			||||||
            if (tb == null) throw throwNavigateSelector;
 | 
					            if (tb == null) throw throwNavigateSelector;
 | 
				
			||||||
            var collMemElementType = (collMem.Type.IsGenericType ? collMem.Type.GetGenericArguments().FirstOrDefault() : collMem.Type.GetElementType());
 | 
					            var collMemElementType = (collMem.Type.IsGenericType ? collMem.Type.GetGenericArguments().FirstOrDefault() : collMem.Type.GetElementType());
 | 
				
			||||||
@@ -484,7 +486,9 @@ namespace FreeSql.Internal.CommonProvider
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
                                if (leftP1MemberExp.Expression == whereExpArgLamb.Parameters[0])
 | 
					                                if (leftP1MemberExp.Expression == whereExpArgLamb.Parameters[0])
 | 
				
			||||||
                                {
 | 
					                                {
 | 
				
			||||||
                                    var (rightMembersParam, rightMembers) = GetExpressionStack(rightP1MemberExp.Expression);
 | 
					                                    var rightGes = GetExpressionStack(rightP1MemberExp.Expression);
 | 
				
			||||||
 | 
					                                    var rightMembersParam = rightGes.Item1;
 | 
				
			||||||
 | 
					                                    var rightMembers = rightGes.Item2;
 | 
				
			||||||
                                    if (rightMembersParam != membersParam) throw throwNavigateSelector;
 | 
					                                    if (rightMembersParam != membersParam) throw throwNavigateSelector;
 | 
				
			||||||
                                    var isCollMemEquals = rightMembers.Count == members.Count;
 | 
					                                    var isCollMemEquals = rightMembers.Count == members.Count;
 | 
				
			||||||
                                    if (isCollMemEquals)
 | 
					                                    if (isCollMemEquals)
 | 
				
			||||||
@@ -513,7 +517,9 @@ namespace FreeSql.Internal.CommonProvider
 | 
				
			|||||||
                                }
 | 
					                                }
 | 
				
			||||||
                                if (rightP1MemberExp.Expression == whereExpArgLamb.Parameters[0])
 | 
					                                if (rightP1MemberExp.Expression == whereExpArgLamb.Parameters[0])
 | 
				
			||||||
                                {
 | 
					                                {
 | 
				
			||||||
                                    var (leftMembersParam, leftMembers) = GetExpressionStack(leftP1MemberExp.Expression);
 | 
					                                    var leftGes = GetExpressionStack(leftP1MemberExp.Expression);
 | 
				
			||||||
 | 
					                                    var leftMembersParam = leftGes.Item1;
 | 
				
			||||||
 | 
					                                    var leftMembers = leftGes.Item2;
 | 
				
			||||||
                                    if (leftMembersParam != membersParam) throw throwNavigateSelector;
 | 
					                                    if (leftMembersParam != membersParam) throw throwNavigateSelector;
 | 
				
			||||||
                                    var isCollMemEquals = leftMembers.Count == members.Count;
 | 
					                                    var isCollMemEquals = leftMembers.Count == members.Count;
 | 
				
			||||||
                                    if (isCollMemEquals)
 | 
					                                    if (isCollMemEquals)
 | 
				
			||||||
@@ -715,7 +721,7 @@ namespace FreeSql.Internal.CommonProvider
 | 
				
			|||||||
                            if (takeNumber > 0)
 | 
					                            if (takeNumber > 0)
 | 
				
			||||||
                            {
 | 
					                            {
 | 
				
			||||||
                                Select0Provider<ISelect<TNavigate>, TNavigate>.GetAllFieldExpressionTreeInfo af = null;
 | 
					                                Select0Provider<ISelect<TNavigate>, TNavigate>.GetAllFieldExpressionTreeInfo af = null;
 | 
				
			||||||
                                (ReadAnonymousTypeInfo map, string field) mf = default;
 | 
					                                ReadAnonymousTypeAfInfo mf = default;
 | 
				
			||||||
                                if (selectExp == null) af = subSelect.GetAllFieldExpressionTreeLevelAll();
 | 
					                                if (selectExp == null) af = subSelect.GetAllFieldExpressionTreeLevelAll();
 | 
				
			||||||
                                else mf = subSelect.GetExpressionField(selectExp);
 | 
					                                else mf = subSelect.GetExpressionField(selectExp);
 | 
				
			||||||
                                var sbSql = new StringBuilder();
 | 
					                                var sbSql = new StringBuilder();
 | 
				
			||||||
@@ -890,10 +896,10 @@ namespace FreeSql.Internal.CommonProvider
 | 
				
			|||||||
                            sbJoin.Clear();
 | 
					                            sbJoin.Clear();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                            Select0Provider<ISelect<TNavigate>, TNavigate>.GetAllFieldExpressionTreeInfo af = null;
 | 
					                            Select0Provider<ISelect<TNavigate>, TNavigate>.GetAllFieldExpressionTreeInfo af = null;
 | 
				
			||||||
                            (ReadAnonymousTypeInfo map, string field) mf = default;
 | 
					                            ReadAnonymousTypeAfInfo mf = default;
 | 
				
			||||||
                            if (selectExp == null) af = subSelect.GetAllFieldExpressionTreeLevelAll();
 | 
					                            if (selectExp == null) af = subSelect.GetAllFieldExpressionTreeLevelAll();
 | 
				
			||||||
                            else mf = subSelect.GetExpressionField(selectExp);
 | 
					                            else mf = subSelect.GetExpressionField(selectExp);
 | 
				
			||||||
                            (string field, ReadAnonymousTypeInfo read)? otherData = null;
 | 
					                            ReadAnonymousTypeAfInfo otherData = null;
 | 
				
			||||||
                            var sbSql = new StringBuilder();
 | 
					                            var sbSql = new StringBuilder();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                            if (_selectExpression == null)
 | 
					                            if (_selectExpression == null)
 | 
				
			||||||
@@ -918,7 +924,7 @@ namespace FreeSql.Internal.CommonProvider
 | 
				
			|||||||
                                    read.Childs.Add(child);
 | 
					                                    read.Childs.Add(child);
 | 
				
			||||||
                                    field.Append(", ").Append(_commonUtils.QuoteReadColumn(child.CsType, child.MapType, child.DbField));
 | 
					                                    field.Append(", ").Append(_commonUtils.QuoteReadColumn(child.CsType, child.MapType, child.DbField));
 | 
				
			||||||
                                }
 | 
					                                }
 | 
				
			||||||
                                otherData = (field.ToString(), read);
 | 
					                                otherData = new ReadAnonymousTypeAfInfo(read, field.ToString());
 | 
				
			||||||
                            }
 | 
					                            }
 | 
				
			||||||
                            Func<Dictionary<string, bool>> getWhereDic = () =>
 | 
					                            Func<Dictionary<string, bool>> getWhereDic = () =>
 | 
				
			||||||
                            {
 | 
					                            {
 | 
				
			||||||
@@ -978,14 +984,14 @@ namespace FreeSql.Internal.CommonProvider
 | 
				
			|||||||
                            {
 | 
					                            {
 | 
				
			||||||
#if net40
 | 
					#if net40
 | 
				
			||||||
#else
 | 
					#else
 | 
				
			||||||
                                if (selectExp == null) subList = await subSelect.ToListAfPrivateAsync(sbSql.ToString(), af, otherData == null ? null : new[] { (otherData.Value.field, otherData.Value.read, midList) });
 | 
					                                if (selectExp == null) subList = await subSelect.ToListAfPrivateAsync(sbSql.ToString(), af, otherData == null ? null : new[] { new ReadAnonymousTypeOtherInfo(otherData.field, otherData.map, midList) });
 | 
				
			||||||
                                else subList = await subSelect.ToListMrPrivateAsync<TNavigate>(sbSql.ToString(), mf, otherData == null ? null : new[] { (otherData.Value.field, otherData.Value.read, midList) });
 | 
					                                else subList = await subSelect.ToListMrPrivateAsync<TNavigate>(sbSql.ToString(), mf, otherData == null ? null : new[] { new ReadAnonymousTypeOtherInfo(otherData.field, otherData.map, midList) });
 | 
				
			||||||
#endif
 | 
					#endif
 | 
				
			||||||
                            }
 | 
					                            }
 | 
				
			||||||
                            else
 | 
					                            else
 | 
				
			||||||
                            {
 | 
					                            {
 | 
				
			||||||
                                if (selectExp == null) subList = subSelect.ToListAfPrivate(sbSql.ToString(), af, otherData == null ? null : new[] { (otherData.Value.field, otherData.Value.read, midList) });
 | 
					                                if (selectExp == null) subList = subSelect.ToListAfPrivate(sbSql.ToString(), af, otherData == null ? null : new[] { new ReadAnonymousTypeOtherInfo(otherData.field, otherData.map, midList) });
 | 
				
			||||||
                                else subList = subSelect.ToListMrPrivate<TNavigate>(sbSql.ToString(), mf, otherData == null ? null : new[] { (otherData.Value.field, otherData.Value.read, midList) });
 | 
					                                else subList = subSelect.ToListMrPrivate<TNavigate>(sbSql.ToString(), mf, otherData == null ? null : new[] { new ReadAnonymousTypeOtherInfo(otherData.field, otherData.map, midList) });
 | 
				
			||||||
                            }
 | 
					                            }
 | 
				
			||||||
                            if (subList.Any() == false)
 | 
					                            if (subList.Any() == false)
 | 
				
			||||||
                            {
 | 
					                            {
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -27,11 +27,11 @@ namespace FreeSql.Internal.CommonProvider
 | 
				
			|||||||
            return this.InternalAvg(column?.Body);
 | 
					            return this.InternalAvg(column?.Body);
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        ISelectGrouping<TKey, (T1, T2)> ISelect<T1, T2>.GroupBy<TKey>(Expression<Func<T1, T2, TKey>> exp)
 | 
					        ISelectGrouping<TKey, NaviteTuple<T1, T2>> ISelect<T1, T2>.GroupBy<TKey>(Expression<Func<T1, T2, TKey>> exp)
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
            if (exp == null) return this.InternalGroupBy<TKey, (T1, T2)>(exp?.Body);
 | 
					            if (exp == null) return this.InternalGroupBy<TKey, NaviteTuple<T1, T2>>(exp?.Body);
 | 
				
			||||||
            for (var a = 0; a < exp.Parameters.Count; a++) _tables[a].Parameter = exp.Parameters[a];
 | 
					            for (var a = 0; a < exp.Parameters.Count; a++) _tables[a].Parameter = exp.Parameters[a];
 | 
				
			||||||
            return this.InternalGroupBy<TKey, (T1, T2)>(exp?.Body);
 | 
					            return this.InternalGroupBy<TKey, NaviteTuple<T1, T2>>(exp?.Body);
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        TMember ISelect<T1, T2>.Max<TMember>(Expression<Func<T1, T2, TMember>> column)
 | 
					        TMember ISelect<T1, T2>.Max<TMember>(Expression<Func<T1, T2, TMember>> column)
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -29,11 +29,11 @@ namespace FreeSql.Internal.CommonProvider
 | 
				
			|||||||
            return this.InternalAvg(column?.Body);
 | 
					            return this.InternalAvg(column?.Body);
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        ISelectGrouping<TKey, (T1, T2, T3)> ISelect<T1, T2, T3>.GroupBy<TKey>(Expression<Func<T1, T2, T3, TKey>> exp)
 | 
					        ISelectGrouping<TKey, NaviteTuple<T1, T2, T3>> ISelect<T1, T2, T3>.GroupBy<TKey>(Expression<Func<T1, T2, T3, TKey>> exp)
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
            if (exp == null) return this.InternalGroupBy<TKey, (T1, T2, T3)>(exp?.Body);
 | 
					            if (exp == null) return this.InternalGroupBy<TKey, NaviteTuple<T1, T2, T3>>(exp?.Body);
 | 
				
			||||||
            for (var a = 0; a < exp.Parameters.Count; a++) _tables[a].Parameter = exp.Parameters[a];
 | 
					            for (var a = 0; a < exp.Parameters.Count; a++) _tables[a].Parameter = exp.Parameters[a];
 | 
				
			||||||
            return this.InternalGroupBy<TKey, (T1, T2, T3)>(exp?.Body);
 | 
					            return this.InternalGroupBy<TKey, NaviteTuple<T1, T2, T3>>(exp?.Body);
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        TMember ISelect<T1, T2, T3>.Max<TMember>(Expression<Func<T1, T2, T3, TMember>> column)
 | 
					        TMember ISelect<T1, T2, T3>.Max<TMember>(Expression<Func<T1, T2, T3, TMember>> column)
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -31,11 +31,11 @@ namespace FreeSql.Internal.CommonProvider
 | 
				
			|||||||
            return this.InternalAvg(column?.Body);
 | 
					            return this.InternalAvg(column?.Body);
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        ISelectGrouping<TKey, (T1, T2, T3, T4)> ISelect<T1, T2, T3, T4>.GroupBy<TKey>(Expression<Func<T1, T2, T3, T4, TKey>> exp)
 | 
					        ISelectGrouping<TKey, NaviteTuple<T1, T2, T3, T4>> ISelect<T1, T2, T3, T4>.GroupBy<TKey>(Expression<Func<T1, T2, T3, T4, TKey>> exp)
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
            if (exp == null) return this.InternalGroupBy<TKey, (T1, T2, T3, T4)>(exp?.Body);
 | 
					            if (exp == null) return this.InternalGroupBy<TKey, NaviteTuple<T1, T2, T3, T4>>(exp?.Body);
 | 
				
			||||||
            for (var a = 0; a < exp.Parameters.Count; a++) _tables[a].Parameter = exp.Parameters[a];
 | 
					            for (var a = 0; a < exp.Parameters.Count; a++) _tables[a].Parameter = exp.Parameters[a];
 | 
				
			||||||
            return this.InternalGroupBy<TKey, (T1, T2, T3, T4)>(exp?.Body);
 | 
					            return this.InternalGroupBy<TKey, NaviteTuple<T1, T2, T3, T4>>(exp?.Body);
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        TMember ISelect<T1, T2, T3, T4>.Max<TMember>(Expression<Func<T1, T2, T3, T4, TMember>> column)
 | 
					        TMember ISelect<T1, T2, T3, T4>.Max<TMember>(Expression<Func<T1, T2, T3, T4, TMember>> column)
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -33,11 +33,11 @@ namespace FreeSql.Internal.CommonProvider
 | 
				
			|||||||
            return this.InternalAvg(column?.Body);
 | 
					            return this.InternalAvg(column?.Body);
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        ISelectGrouping<TKey, (T1, T2, T3, T4, T5)> ISelect<T1, T2, T3, T4, T5>.GroupBy<TKey>(Expression<Func<T1, T2, T3, T4, T5, TKey>> exp)
 | 
					        ISelectGrouping<TKey, NaviteTuple<T1, T2, T3, T4, T5>> ISelect<T1, T2, T3, T4, T5>.GroupBy<TKey>(Expression<Func<T1, T2, T3, T4, T5, TKey>> exp)
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
            if (exp == null) return this.InternalGroupBy<TKey, (T1, T2, T3, T4, T5)>(exp?.Body);
 | 
					            if (exp == null) return this.InternalGroupBy<TKey, NaviteTuple<T1, T2, T3, T4, T5>>(exp?.Body);
 | 
				
			||||||
            for (var a = 0; a < exp.Parameters.Count; a++) _tables[a].Parameter = exp.Parameters[a];
 | 
					            for (var a = 0; a < exp.Parameters.Count; a++) _tables[a].Parameter = exp.Parameters[a];
 | 
				
			||||||
            return this.InternalGroupBy<TKey, (T1, T2, T3, T4, T5)>(exp?.Body);
 | 
					            return this.InternalGroupBy<TKey, NaviteTuple<T1, T2, T3, T4, T5>>(exp?.Body);
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        TMember ISelect<T1, T2, T3, T4, T5>.Max<TMember>(Expression<Func<T1, T2, T3, T4, T5, TMember>> column)
 | 
					        TMember ISelect<T1, T2, T3, T4, T5>.Max<TMember>(Expression<Func<T1, T2, T3, T4, T5, TMember>> column)
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -35,11 +35,11 @@ namespace FreeSql.Internal.CommonProvider
 | 
				
			|||||||
            return this.InternalAvg(column?.Body);
 | 
					            return this.InternalAvg(column?.Body);
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        ISelectGrouping<TKey, (T1, T2, T3, T4, T5, T6)> ISelect<T1, T2, T3, T4, T5, T6>.GroupBy<TKey>(Expression<Func<T1, T2, T3, T4, T5, T6, TKey>> exp)
 | 
					        ISelectGrouping<TKey, NaviteTuple<T1, T2, T3, T4, T5, T6>> ISelect<T1, T2, T3, T4, T5, T6>.GroupBy<TKey>(Expression<Func<T1, T2, T3, T4, T5, T6, TKey>> exp)
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
            if (exp == null) return this.InternalGroupBy<TKey, (T1, T2, T3, T4, T5, T6)>(exp?.Body);
 | 
					            if (exp == null) return this.InternalGroupBy<TKey, NaviteTuple<T1, T2, T3, T4, T5, T6>>(exp?.Body);
 | 
				
			||||||
            for (var a = 0; a < exp.Parameters.Count; a++) _tables[a].Parameter = exp.Parameters[a];
 | 
					            for (var a = 0; a < exp.Parameters.Count; a++) _tables[a].Parameter = exp.Parameters[a];
 | 
				
			||||||
            return this.InternalGroupBy<TKey, (T1, T2, T3, T4, T5, T6)>(exp?.Body);
 | 
					            return this.InternalGroupBy<TKey, NaviteTuple<T1, T2, T3, T4, T5, T6>>(exp?.Body);
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        TMember ISelect<T1, T2, T3, T4, T5, T6>.Max<TMember>(Expression<Func<T1, T2, T3, T4, T5, T6, TMember>> column)
 | 
					        TMember ISelect<T1, T2, T3, T4, T5, T6>.Max<TMember>(Expression<Func<T1, T2, T3, T4, T5, T6, TMember>> column)
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -37,11 +37,11 @@ namespace FreeSql.Internal.CommonProvider
 | 
				
			|||||||
            return this.InternalAvg(column?.Body);
 | 
					            return this.InternalAvg(column?.Body);
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        ISelectGrouping<TKey, (T1, T2, T3, T4, T5, T6, T7)> ISelect<T1, T2, T3, T4, T5, T6, T7>.GroupBy<TKey>(Expression<Func<T1, T2, T3, T4, T5, T6, T7, TKey>> exp)
 | 
					        ISelectGrouping<TKey, NaviteTuple<T1, T2, T3, T4, T5, T6, T7>> ISelect<T1, T2, T3, T4, T5, T6, T7>.GroupBy<TKey>(Expression<Func<T1, T2, T3, T4, T5, T6, T7, TKey>> exp)
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
            if (exp == null) return this.InternalGroupBy<TKey, (T1, T2, T3, T4, T5, T6, T7)>(exp?.Body);
 | 
					            if (exp == null) return this.InternalGroupBy<TKey, NaviteTuple<T1, T2, T3, T4, T5, T6, T7>>(exp?.Body);
 | 
				
			||||||
            for (var a = 0; a < exp.Parameters.Count; a++) _tables[a].Parameter = exp.Parameters[a];
 | 
					            for (var a = 0; a < exp.Parameters.Count; a++) _tables[a].Parameter = exp.Parameters[a];
 | 
				
			||||||
            return this.InternalGroupBy<TKey, (T1, T2, T3, T4, T5, T6, T7)>(exp?.Body);
 | 
					            return this.InternalGroupBy<TKey, NaviteTuple<T1, T2, T3, T4, T5, T6, T7>>(exp?.Body);
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        TMember ISelect<T1, T2, T3, T4, T5, T6, T7>.Max<TMember>(Expression<Func<T1, T2, T3, T4, T5, T6, T7, TMember>> column)
 | 
					        TMember ISelect<T1, T2, T3, T4, T5, T6, T7>.Max<TMember>(Expression<Func<T1, T2, T3, T4, T5, T6, T7, TMember>> column)
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -39,11 +39,11 @@ namespace FreeSql.Internal.CommonProvider
 | 
				
			|||||||
            return this.InternalAvg(column?.Body);
 | 
					            return this.InternalAvg(column?.Body);
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        ISelectGrouping<TKey, (T1, T2, T3, T4, T5, T6, T7, T8)> ISelect<T1, T2, T3, T4, T5, T6, T7, T8>.GroupBy<TKey>(Expression<Func<T1, T2, T3, T4, T5, T6, T7, T8, TKey>> exp)
 | 
					        ISelectGrouping<TKey, NaviteTuple<T1, T2, T3, T4, T5, T6, T7, T8>> ISelect<T1, T2, T3, T4, T5, T6, T7, T8>.GroupBy<TKey>(Expression<Func<T1, T2, T3, T4, T5, T6, T7, T8, TKey>> exp)
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
            if (exp == null) return this.InternalGroupBy<TKey, (T1, T2, T3, T4, T5, T6, T7, T8)>(exp?.Body);
 | 
					            if (exp == null) return this.InternalGroupBy<TKey, NaviteTuple<T1, T2, T3, T4, T5, T6, T7, T8>>(exp?.Body);
 | 
				
			||||||
            for (var a = 0; a < exp.Parameters.Count; a++) _tables[a].Parameter = exp.Parameters[a];
 | 
					            for (var a = 0; a < exp.Parameters.Count; a++) _tables[a].Parameter = exp.Parameters[a];
 | 
				
			||||||
            return this.InternalGroupBy<TKey, (T1, T2, T3, T4, T5, T6, T7, T8)>(exp?.Body);
 | 
					            return this.InternalGroupBy<TKey, NaviteTuple<T1, T2, T3, T4, T5, T6, T7, T8>>(exp?.Body);
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        TMember ISelect<T1, T2, T3, T4, T5, T6, T7, T8>.Max<TMember>(Expression<Func<T1, T2, T3, T4, T5, T6, T7, T8, TMember>> column)
 | 
					        TMember ISelect<T1, T2, T3, T4, T5, T6, T7, T8>.Max<TMember>(Expression<Func<T1, T2, T3, T4, T5, T6, T7, T8, TMember>> column)
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -41,11 +41,11 @@ namespace FreeSql.Internal.CommonProvider
 | 
				
			|||||||
            return this.InternalAvg(column?.Body);
 | 
					            return this.InternalAvg(column?.Body);
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        ISelectGrouping<TKey, (T1, T2, T3, T4, T5, T6, T7, T8, T9)> ISelect<T1, T2, T3, T4, T5, T6, T7, T8, T9>.GroupBy<TKey>(Expression<Func<T1, T2, T3, T4, T5, T6, T7, T8, T9, TKey>> exp)
 | 
					        ISelectGrouping<TKey, NaviteTuple<T1, T2, T3, T4, T5, T6, T7, T8, T9>> ISelect<T1, T2, T3, T4, T5, T6, T7, T8, T9>.GroupBy<TKey>(Expression<Func<T1, T2, T3, T4, T5, T6, T7, T8, T9, TKey>> exp)
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
            if (exp == null) return this.InternalGroupBy<TKey, (T1, T2, T3, T4, T5, T6, T7, T8, T9)>(exp?.Body);
 | 
					            if (exp == null) return this.InternalGroupBy<TKey, NaviteTuple<T1, T2, T3, T4, T5, T6, T7, T8, T9>>(exp?.Body);
 | 
				
			||||||
            for (var a = 0; a < exp.Parameters.Count; a++) _tables[a].Parameter = exp.Parameters[a];
 | 
					            for (var a = 0; a < exp.Parameters.Count; a++) _tables[a].Parameter = exp.Parameters[a];
 | 
				
			||||||
            return this.InternalGroupBy<TKey, (T1, T2, T3, T4, T5, T6, T7, T8, T9)>(exp?.Body);
 | 
					            return this.InternalGroupBy<TKey, NaviteTuple<T1, T2, T3, T4, T5, T6, T7, T8, T9>>(exp?.Body);
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        TMember ISelect<T1, T2, T3, T4, T5, T6, T7, T8, T9>.Max<TMember>(Expression<Func<T1, T2, T3, T4, T5, T6, T7, T8, T9, TMember>> column)
 | 
					        TMember ISelect<T1, T2, T3, T4, T5, T6, T7, T8, T9>.Max<TMember>(Expression<Func<T1, T2, T3, T4, T5, T6, T7, T8, T9, TMember>> column)
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -117,7 +117,7 @@ namespace FreeSql.Internal.CommonProvider
 | 
				
			|||||||
            if (map.Childs.Any() == false && map.MapType == null) map.MapType = typeof(TReturn);
 | 
					            if (map.Childs.Any() == false && map.MapType == null) map.MapType = typeof(TReturn);
 | 
				
			||||||
            var method = _select.GetType().GetMethod("ToListMapReader", BindingFlags.Instance | BindingFlags.NonPublic);
 | 
					            var method = _select.GetType().GetMethod("ToListMapReader", BindingFlags.Instance | BindingFlags.NonPublic);
 | 
				
			||||||
            method = method.MakeGenericMethod(typeof(TReturn));
 | 
					            method = method.MakeGenericMethod(typeof(TReturn));
 | 
				
			||||||
            return method.Invoke(_select, new object[] { (map, field.Length > 0 ? field.Remove(0, 2).ToString() : null) }) as List<TReturn>;
 | 
					            return method.Invoke(_select, new object[] { new ReadAnonymousTypeAfInfo(map, field.Length > 0 ? field.Remove(0, 2).ToString() : null) }) as List<TReturn>;
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
        
 | 
					        
 | 
				
			||||||
        public List<TReturn> Select<TReturn>(Expression<Func<ISelectGroupingAggregate<TKey, TValue>, TReturn>> select) => ToList(select);
 | 
					        public List<TReturn> Select<TReturn>(Expression<Func<ISelectGroupingAggregate<TKey, TValue>, TReturn>> select) => ToList(select);
 | 
				
			||||||
@@ -185,7 +185,7 @@ namespace FreeSql.Internal.CommonProvider
 | 
				
			|||||||
            if (map.Childs.Any() == false && map.MapType == null) map.MapType = typeof(TReturn);
 | 
					            if (map.Childs.Any() == false && map.MapType == null) map.MapType = typeof(TReturn);
 | 
				
			||||||
            var method = _select.GetType().GetMethod("ToListMapReaderAsync", BindingFlags.Instance | BindingFlags.NonPublic);
 | 
					            var method = _select.GetType().GetMethod("ToListMapReaderAsync", BindingFlags.Instance | BindingFlags.NonPublic);
 | 
				
			||||||
            method = method.MakeGenericMethod(typeof(TReturn));
 | 
					            method = method.MakeGenericMethod(typeof(TReturn));
 | 
				
			||||||
            return method.Invoke(_select, new object[] { (map, field.Length > 0 ? field.Remove(0, 2).ToString() : null) }) as Task<List<TReturn>>;
 | 
					            return method.Invoke(_select, new object[] { new ReadAnonymousTypeAfInfo(map, field.Length > 0 ? field.Remove(0, 2).ToString() : null) }) as Task<List<TReturn>>;
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
#endif
 | 
					#endif
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										71
									
								
								FreeSql/Internal/Model/DbToCs.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										71
									
								
								FreeSql/Internal/Model/DbToCs.cs
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,71 @@
 | 
				
			|||||||
 | 
					using System;
 | 
				
			||||||
 | 
					using System.Collections.Generic;
 | 
				
			||||||
 | 
					using System.Text;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					namespace FreeSql.Internal.Model
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    public class DbToCs
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        public string csConvert { get; }
 | 
				
			||||||
 | 
					        public string csParse { get; }
 | 
				
			||||||
 | 
					        public string csStringify { get; }
 | 
				
			||||||
 | 
					        public string csType { get; }
 | 
				
			||||||
 | 
					        public Type csTypeInfo { get; }
 | 
				
			||||||
 | 
					        public Type csNullableTypeInfo { get; }
 | 
				
			||||||
 | 
					        public string csTypeValue { get; }
 | 
				
			||||||
 | 
					        public string dataReaderMethod { get; }
 | 
				
			||||||
 | 
					        public DbToCs(string csConvert, string csParse, string csStringify, string csType, Type csTypeInfo, Type csNullableTypeInfo, string csTypeValue, string dataReaderMethod)
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            this.csConvert = csConvert;
 | 
				
			||||||
 | 
					            this.csParse = csParse;
 | 
				
			||||||
 | 
					            this.csStringify = csStringify;
 | 
				
			||||||
 | 
					            this.csType = csType;
 | 
				
			||||||
 | 
					            this.csTypeInfo = csTypeInfo;
 | 
				
			||||||
 | 
					            this.csNullableTypeInfo = csNullableTypeInfo;
 | 
				
			||||||
 | 
					            this.csTypeValue = csTypeValue;
 | 
				
			||||||
 | 
					            this.dataReaderMethod = dataReaderMethod;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    public static class CsToDb
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        public static CsToDb<T> New<T>(T type, string dbtype, string dbtypeFull, bool? isUnsigned, bool? isnullable, object defaultValue) =>
 | 
				
			||||||
 | 
					            new CsToDb<T>(type, dbtype, dbtypeFull, isUnsigned, isnullable, defaultValue);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    public class CsToDb<T>
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        public T type { get; }
 | 
				
			||||||
 | 
					        public string dbtype { get; }
 | 
				
			||||||
 | 
					        public string dbtypeFull { get; }
 | 
				
			||||||
 | 
					        public bool? isUnsigned { get; }
 | 
				
			||||||
 | 
					        public bool? isnullable { get; }
 | 
				
			||||||
 | 
					        public object defaultValue { get; }
 | 
				
			||||||
 | 
					        public CsToDb(T type, string dbtype, string dbtypeFull, bool? isUnsigned, bool? isnullable, object defaultValue)
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            this.type = type;
 | 
				
			||||||
 | 
					            this.dbtype = dbtype;
 | 
				
			||||||
 | 
					            this.dbtypeFull = dbtypeFull;
 | 
				
			||||||
 | 
					            this.isUnsigned = isUnsigned;
 | 
				
			||||||
 | 
					            this.isnullable = isnullable;
 | 
				
			||||||
 | 
					            this.defaultValue = defaultValue;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    public class DbInfoResult
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        public int type { get; }
 | 
				
			||||||
 | 
					        public string dbtype { get; }
 | 
				
			||||||
 | 
					        public string dbtypeFull { get; }
 | 
				
			||||||
 | 
					        public bool? isnullable { get; }
 | 
				
			||||||
 | 
					        public object defaultValue { get; }
 | 
				
			||||||
 | 
					        public DbInfoResult(int type, string dbtype, string dbtypeFull, bool? isnullable, object defaultValue)
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            this.type = type;
 | 
				
			||||||
 | 
					            this.dbtype = dbtype;
 | 
				
			||||||
 | 
					            this.dbtypeFull = dbtypeFull;
 | 
				
			||||||
 | 
					            this.isnullable = isnullable;
 | 
				
			||||||
 | 
					            this.defaultValue = defaultValue;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										182
									
								
								FreeSql/Internal/Model/NaviteTuple.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										182
									
								
								FreeSql/Internal/Model/NaviteTuple.cs
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,182 @@
 | 
				
			|||||||
 | 
					using System;
 | 
				
			||||||
 | 
					using System.Collections.Generic;
 | 
				
			||||||
 | 
					using System.Text;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					namespace FreeSql.Internal.Model
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    public static class NaviteTuple
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        public static NaviteTuple<T1, T2> Create<T1, T2>(T1 item1, T2 item2) => new NaviteTuple<T1, T2>(item1, item2);
 | 
				
			||||||
 | 
					        public static NaviteTuple<T1, T2, T3> Create<T1, T2, T3>(T1 item1, T2 item2, T3 item3) => new NaviteTuple<T1, T2, T3>(item1, item2, item3);
 | 
				
			||||||
 | 
					        public static NaviteTuple<T1, T2, T3, T4> Create<T1, T2, T3, T4>(T1 item1, T2 item2, T3 item3, T4 item4) => new NaviteTuple<T1, T2, T3, T4>(item1, item2, item3, item4);
 | 
				
			||||||
 | 
					        public static NaviteTuple<T1, T2, T3, T4, T5> Create<T1, T2, T3, T4, T5>(T1 item1, T2 item2, T3 item3, T4 item4, T5 item5) => new NaviteTuple<T1, T2, T3, T4, T5>(item1, item2, item3, item4, item5);
 | 
				
			||||||
 | 
					        public static NaviteTuple<T1, T2, T3, T4, T5, T6> Create<T1, T2, T3, T4, T5, T6>(T1 item1, T2 item2, T3 item3, T4 item4, T5 item5, T6 item6) => new NaviteTuple<T1, T2, T3, T4, T5, T6>(item1, item2, item3, item4, item5, item6);
 | 
				
			||||||
 | 
					        public static NaviteTuple<T1, T2, T3, T4, T5, T6, T7> Create<T1, T2, T3, T4, T5, T6, T7>(T1 item1, T2 item2, T3 item3, T4 item4, T5 item5, T6 item6, T7 item7) => new NaviteTuple<T1, T2, T3, T4, T5, T6, T7>(item1, item2, item3, item4, item5, item6, item7);
 | 
				
			||||||
 | 
					        public static NaviteTuple<T1, T2, T3, T4, T5, T6, T7, T8> Create<T1, T2, T3, T4, T5, T6, T7, T8>(T1 item1, T2 item2, T3 item3, T4 item4, T5 item5, T6 item6, T7 item7, T8 item8) => new NaviteTuple<T1, T2, T3, T4, T5, T6, T7, T8>(item1, item2, item3, item4, item5, item6, item7, item8);
 | 
				
			||||||
 | 
					        public static NaviteTuple<T1, T2, T3, T4, T5, T6, T7, T8, T9> Create<T1, T2, T3, T4, T5, T6, T7, T8, T9>(T1 item1, T2 item2, T3 item3, T4 item4, T5 item5, T6 item6, T7 item7, T8 item8, T9 item9) => new NaviteTuple<T1, T2, T3, T4, T5, T6, T7, T8, T9>(item1, item2, item3, item4, item5, item6, item7, item8, item9);
 | 
				
			||||||
 | 
					        public static NaviteTuple<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10> Create<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10>(T1 item1, T2 item2, T3 item3, T4 item4, T5 item5, T6 item6, T7 item7, T8 item8, T9 item9, T10 item10) => new NaviteTuple<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10>(item1, item2, item3, item4, item5, item6, item7, item8, item9, item10);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    public class NaviteTuple<T1, T2>
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        public T1 Item1 { get; }
 | 
				
			||||||
 | 
					        public T2 Item2 { get; }
 | 
				
			||||||
 | 
					        public NaviteTuple(T1 item1, T2 item2)
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            Item1 = item1;
 | 
				
			||||||
 | 
					            Item2 = item2;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    public class NaviteTuple<T1, T2, T3>
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        public T1 Item1 { get; }
 | 
				
			||||||
 | 
					        public T2 Item2 { get; }
 | 
				
			||||||
 | 
					        public T3 Item3 { get; }
 | 
				
			||||||
 | 
					        public NaviteTuple(T1 item1, T2 item2, T3 item3)
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            Item1 = item1;
 | 
				
			||||||
 | 
					            Item2 = item2;
 | 
				
			||||||
 | 
					            Item3 = item3;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    public class NaviteTuple<T1, T2, T3, T4>
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        public T1 Item1 { get; }
 | 
				
			||||||
 | 
					        public T2 Item2 { get; }
 | 
				
			||||||
 | 
					        public T3 Item3 { get; }
 | 
				
			||||||
 | 
					        public T4 Item4 { get; }
 | 
				
			||||||
 | 
					        public NaviteTuple(T1 item1, T2 item2, T3 item3, T4 item4)
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            Item1 = item1;
 | 
				
			||||||
 | 
					            Item2 = item2;
 | 
				
			||||||
 | 
					            Item3 = item3;
 | 
				
			||||||
 | 
					            Item4 = item4;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    public class NaviteTuple<T1, T2, T3, T4, T5>
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        public T1 Item1 { get; }
 | 
				
			||||||
 | 
					        public T2 Item2 { get; }
 | 
				
			||||||
 | 
					        public T3 Item3 { get; }
 | 
				
			||||||
 | 
					        public T4 Item4 { get; }
 | 
				
			||||||
 | 
					        public T5 Item5 { get; }
 | 
				
			||||||
 | 
					        public NaviteTuple(T1 item1, T2 item2, T3 item3, T4 item4, T5 item5)
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            Item1 = item1;
 | 
				
			||||||
 | 
					            Item2 = item2;
 | 
				
			||||||
 | 
					            Item3 = item3;
 | 
				
			||||||
 | 
					            Item4 = item4;
 | 
				
			||||||
 | 
					            Item5 = item5;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    public class NaviteTuple<T1, T2, T3, T4, T5, T6>
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        public T1 Item1 { get; }
 | 
				
			||||||
 | 
					        public T2 Item2 { get; }
 | 
				
			||||||
 | 
					        public T3 Item3 { get; }
 | 
				
			||||||
 | 
					        public T4 Item4 { get; }
 | 
				
			||||||
 | 
					        public T5 Item5 { get; }
 | 
				
			||||||
 | 
					        public T6 Item6 { get; }
 | 
				
			||||||
 | 
					        public NaviteTuple(T1 item1, T2 item2, T3 item3, T4 item4, T5 item5, T6 item6)
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            Item1 = item1;
 | 
				
			||||||
 | 
					            Item2 = item2;
 | 
				
			||||||
 | 
					            Item3 = item3;
 | 
				
			||||||
 | 
					            Item4 = item4;
 | 
				
			||||||
 | 
					            Item5 = item5;
 | 
				
			||||||
 | 
					            Item6 = item6;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    public class NaviteTuple<T1, T2, T3, T4, T5, T6, T7>
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        public T1 Item1 { get; }
 | 
				
			||||||
 | 
					        public T2 Item2 { get; }
 | 
				
			||||||
 | 
					        public T3 Item3 { get; }
 | 
				
			||||||
 | 
					        public T4 Item4 { get; }
 | 
				
			||||||
 | 
					        public T5 Item5 { get; }
 | 
				
			||||||
 | 
					        public T6 Item6 { get; }
 | 
				
			||||||
 | 
					        public T7 Item7 { get; }
 | 
				
			||||||
 | 
					        public NaviteTuple(T1 item1, T2 item2, T3 item3, T4 item4, T5 item5, T6 item6, T7 item7)
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            Item1 = item1;
 | 
				
			||||||
 | 
					            Item2 = item2;
 | 
				
			||||||
 | 
					            Item3 = item3;
 | 
				
			||||||
 | 
					            Item4 = item4;
 | 
				
			||||||
 | 
					            Item5 = item5;
 | 
				
			||||||
 | 
					            Item6 = item6;
 | 
				
			||||||
 | 
					            Item7 = item7;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    public class NaviteTuple<T1, T2, T3, T4, T5, T6, T7, T8>
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        public T1 Item1 { get; }
 | 
				
			||||||
 | 
					        public T2 Item2 { get; }
 | 
				
			||||||
 | 
					        public T3 Item3 { get; }
 | 
				
			||||||
 | 
					        public T4 Item4 { get; }
 | 
				
			||||||
 | 
					        public T5 Item5 { get; }
 | 
				
			||||||
 | 
					        public T6 Item6 { get; }
 | 
				
			||||||
 | 
					        public T7 Item7 { get; }
 | 
				
			||||||
 | 
					        public T8 Item8 { get; }
 | 
				
			||||||
 | 
					        public NaviteTuple(T1 item1, T2 item2, T3 item3, T4 item4, T5 item5, T6 item6, T7 item7, T8 item8)
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            Item1 = item1;
 | 
				
			||||||
 | 
					            Item2 = item2;
 | 
				
			||||||
 | 
					            Item3 = item3;
 | 
				
			||||||
 | 
					            Item4 = item4;
 | 
				
			||||||
 | 
					            Item5 = item5;
 | 
				
			||||||
 | 
					            Item6 = item6;
 | 
				
			||||||
 | 
					            Item7 = item7;
 | 
				
			||||||
 | 
					            Item8 = item8;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    public class NaviteTuple<T1, T2, T3, T4, T5, T6, T7, T8, T9>
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        public T1 Item1 { get; }
 | 
				
			||||||
 | 
					        public T2 Item2 { get; }
 | 
				
			||||||
 | 
					        public T3 Item3 { get; }
 | 
				
			||||||
 | 
					        public T4 Item4 { get; }
 | 
				
			||||||
 | 
					        public T5 Item5 { get; }
 | 
				
			||||||
 | 
					        public T6 Item6 { get; }
 | 
				
			||||||
 | 
					        public T7 Item7 { get; }
 | 
				
			||||||
 | 
					        public T8 Item8 { get; }
 | 
				
			||||||
 | 
					        public T9 Item9 { get; }
 | 
				
			||||||
 | 
					        public NaviteTuple(T1 item1, T2 item2, T3 item3, T4 item4, T5 item5, T6 item6, T7 item7, T8 item8, T9 item9)
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            Item1 = item1;
 | 
				
			||||||
 | 
					            Item2 = item2;
 | 
				
			||||||
 | 
					            Item3 = item3;
 | 
				
			||||||
 | 
					            Item4 = item4;
 | 
				
			||||||
 | 
					            Item5 = item5;
 | 
				
			||||||
 | 
					            Item6 = item6;
 | 
				
			||||||
 | 
					            Item7 = item7;
 | 
				
			||||||
 | 
					            Item8 = item8;
 | 
				
			||||||
 | 
					            Item9 = item9;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    public class NaviteTuple<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10>
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        public T1 Item1 { get; }
 | 
				
			||||||
 | 
					        public T2 Item2 { get; }
 | 
				
			||||||
 | 
					        public T3 Item3 { get; }
 | 
				
			||||||
 | 
					        public T4 Item4 { get; }
 | 
				
			||||||
 | 
					        public T5 Item5 { get; }
 | 
				
			||||||
 | 
					        public T6 Item6 { get; }
 | 
				
			||||||
 | 
					        public T7 Item7 { get; }
 | 
				
			||||||
 | 
					        public T8 Item8 { get; }
 | 
				
			||||||
 | 
					        public T9 Item9 { get; }
 | 
				
			||||||
 | 
					        public T10 Item10 { get; }
 | 
				
			||||||
 | 
					        public NaviteTuple(T1 item1, T2 item2, T3 item3, T4 item4, T5 item5, T6 item6, T7 item7, T8 item8, T9 item9, T10 item10)
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            Item1 = item1;
 | 
				
			||||||
 | 
					            Item2 = item2;
 | 
				
			||||||
 | 
					            Item3 = item3;
 | 
				
			||||||
 | 
					            Item4 = item4;
 | 
				
			||||||
 | 
					            Item5 = item5;
 | 
				
			||||||
 | 
					            Item6 = item6;
 | 
				
			||||||
 | 
					            Item7 = item7;
 | 
				
			||||||
 | 
					            Item8 = item8;
 | 
				
			||||||
 | 
					            Item9 = item9;
 | 
				
			||||||
 | 
					            Item10 = item10;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
@@ -18,4 +18,25 @@ namespace FreeSql.Internal.Model
 | 
				
			|||||||
        public bool IsEntity { get; set; }
 | 
					        public bool IsEntity { get; set; }
 | 
				
			||||||
        public bool IsDefaultCtor { get; set; }
 | 
					        public bool IsDefaultCtor { get; set; }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					    public class ReadAnonymousTypeAfInfo
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        public ReadAnonymousTypeInfo map { get; }
 | 
				
			||||||
 | 
					        public string field { get; }
 | 
				
			||||||
 | 
					        public ReadAnonymousTypeAfInfo(ReadAnonymousTypeInfo map, string field)
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            this.map = map;
 | 
				
			||||||
 | 
					            this.field = field;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    public class ReadAnonymousTypeOtherInfo {
 | 
				
			||||||
 | 
					        public string field { get; }
 | 
				
			||||||
 | 
					        public ReadAnonymousTypeInfo read { get; }
 | 
				
			||||||
 | 
					        public List<object> retlist { get; }
 | 
				
			||||||
 | 
					        public ReadAnonymousTypeOtherInfo(string field, ReadAnonymousTypeInfo read, List<object> retlist)
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            this.field = field;
 | 
				
			||||||
 | 
					            this.read = read;
 | 
				
			||||||
 | 
					            this.retlist = retlist;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -66,7 +66,7 @@ namespace FreeSql.Internal
 | 
				
			|||||||
                trytb.DbOldName = trytb.DbOldName?.ToUpper();
 | 
					                trytb.DbOldName = trytb.DbOldName?.ToUpper();
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
            if (tbattr != null) trytb.DisableSyncStructure = tbattr.DisableSyncStructure;
 | 
					            if (tbattr != null) trytb.DisableSyncStructure = tbattr.DisableSyncStructure;
 | 
				
			||||||
            var propsLazy = new List<(PropertyInfo, bool, bool)>();
 | 
					            var propsLazy = new List<NaviteTuple<PropertyInfo, bool, bool>>();
 | 
				
			||||||
            var propsNavObjs = new List<PropertyInfo>();
 | 
					            var propsNavObjs = new List<PropertyInfo>();
 | 
				
			||||||
            var propsComment = CommonUtils.GetProperyCommentBySummary(entity);
 | 
					            var propsComment = CommonUtils.GetProperyCommentBySummary(entity);
 | 
				
			||||||
            var columnsList = new List<ColumnInfo>();
 | 
					            var columnsList = new List<ColumnInfo>();
 | 
				
			||||||
@@ -87,7 +87,7 @@ namespace FreeSql.Internal
 | 
				
			|||||||
                        var getIsVirtual = p.GetGetMethod()?.IsVirtual;// trytb.Type.GetMethod($"get_{p.Name}")?.IsVirtual;
 | 
					                        var getIsVirtual = p.GetGetMethod()?.IsVirtual;// trytb.Type.GetMethod($"get_{p.Name}")?.IsVirtual;
 | 
				
			||||||
                        var setIsVirtual = setMethod?.IsVirtual;
 | 
					                        var setIsVirtual = setMethod?.IsVirtual;
 | 
				
			||||||
                        if (getIsVirtual == true || setIsVirtual == true)
 | 
					                        if (getIsVirtual == true || setIsVirtual == true)
 | 
				
			||||||
                            propsLazy.Add((p, getIsVirtual == true, setIsVirtual == true));
 | 
					                            propsLazy.Add(NaviteTuple.Create(p, getIsVirtual == true, setIsVirtual == true));
 | 
				
			||||||
                    }
 | 
					                    }
 | 
				
			||||||
                    propsNavObjs.Add(p);
 | 
					                    propsNavObjs.Add(p);
 | 
				
			||||||
                    continue;
 | 
					                    continue;
 | 
				
			||||||
@@ -97,8 +97,8 @@ namespace FreeSql.Internal
 | 
				
			|||||||
                    colattr = new ColumnAttribute
 | 
					                    colattr = new ColumnAttribute
 | 
				
			||||||
                    {
 | 
					                    {
 | 
				
			||||||
                        Name = p.Name,
 | 
					                        Name = p.Name,
 | 
				
			||||||
                        DbType = tp.Value.dbtypeFull,
 | 
					                        DbType = tp.dbtypeFull,
 | 
				
			||||||
                        IsNullable = tp.Value.isnullable ?? true,
 | 
					                        IsNullable = tp.isnullable ?? true,
 | 
				
			||||||
                        MapType = p.PropertyType
 | 
					                        MapType = p.PropertyType
 | 
				
			||||||
                    };
 | 
					                    };
 | 
				
			||||||
                if (colattr._IsNullable == null) colattr._IsNullable = tp?.isnullable;
 | 
					                if (colattr._IsNullable == null) colattr._IsNullable = tp?.isnullable;
 | 
				
			||||||
@@ -111,7 +111,7 @@ namespace FreeSql.Internal
 | 
				
			|||||||
                else
 | 
					                else
 | 
				
			||||||
                    colattr.DbType = colattr.DbType.ToUpper();
 | 
					                    colattr.DbType = colattr.DbType.ToUpper();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                if (colattr._IsNullable == null && tp != null && tp.Value.isnullable == null) colattr.IsNullable = tp.Value.dbtypeFull.Contains("NOT NULL") == false;
 | 
					                if (colattr._IsNullable == null && tp != null && tp.isnullable == null) colattr.IsNullable = tp.dbtypeFull.Contains("NOT NULL") == false;
 | 
				
			||||||
                if (colattr.DbType?.Contains("NOT NULL") == true) colattr.IsNullable = false;
 | 
					                if (colattr.DbType?.Contains("NOT NULL") == true) colattr.IsNullable = false;
 | 
				
			||||||
                if (string.IsNullOrEmpty(colattr.Name)) colattr.Name = p.Name;
 | 
					                if (string.IsNullOrEmpty(colattr.Name)) colattr.Name = p.Name;
 | 
				
			||||||
                if (common.CodeFirst.IsSyncStructureToLower) colattr.Name = colattr.Name.ToLower();
 | 
					                if (common.CodeFirst.IsSyncStructureToLower) colattr.Name = colattr.Name.ToLower();
 | 
				
			||||||
@@ -419,7 +419,7 @@ namespace FreeSql.Internal
 | 
				
			|||||||
            foreach (var pnv in propsNavObjs)
 | 
					            foreach (var pnv in propsNavObjs)
 | 
				
			||||||
            {
 | 
					            {
 | 
				
			||||||
                var vp = propsLazy.Where(a => a.Item1 == pnv).FirstOrDefault();
 | 
					                var vp = propsLazy.Where(a => a.Item1 == pnv).FirstOrDefault();
 | 
				
			||||||
                var isLazy = vp.Item1 != null && !string.IsNullOrEmpty(trytbTypeLazyName);
 | 
					                var isLazy = vp != null && vp.Item1 != null && !string.IsNullOrEmpty(trytbTypeLazyName);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                AddTableRef(common, trytb, pnv, isLazy, vp, cscode);
 | 
					                AddTableRef(common, trytb, pnv, isLazy, vp, cscode);
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
@@ -445,7 +445,7 @@ namespace FreeSql.Internal
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
            return tbc.TryGetValue(entity, out var trytb2) ? trytb2 : trytb;
 | 
					            return tbc.TryGetValue(entity, out var trytb2) ? trytb2 : trytb;
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
        public static void AddTableRef(CommonUtils common, TableInfo trytb, PropertyInfo pnv, bool isLazy, (PropertyInfo, bool, bool)? vp, StringBuilder cscode)
 | 
					        public static void AddTableRef(CommonUtils common, TableInfo trytb, PropertyInfo pnv, bool isLazy, NaviteTuple<PropertyInfo, bool, bool> vp, StringBuilder cscode)
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
            var trytbTypeName = trytb.Type.IsNested ? $"{trytb.Type.DeclaringType.Namespace?.NotNullAndConcat(".")}{trytb.Type.DeclaringType.Name}.{trytb.Type.Name}" : $"{trytb.Type.Namespace?.NotNullAndConcat(".")}{trytb.Type.Name}";
 | 
					            var trytbTypeName = trytb.Type.IsNested ? $"{trytb.Type.DeclaringType.Namespace?.NotNullAndConcat(".")}{trytb.Type.DeclaringType.Name}.{trytb.Type.Name}" : $"{trytb.Type.Namespace?.NotNullAndConcat(".")}{trytb.Type.Name}";
 | 
				
			||||||
            var propTypeName = pnv.PropertyType.IsGenericType ?
 | 
					            var propTypeName = pnv.PropertyType.IsGenericType ?
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -17,35 +17,35 @@ namespace FreeSql.MsAccess
 | 
				
			|||||||
        public MsAccessCodeFirst(IFreeSql orm, CommonUtils commonUtils, CommonExpression commonExpression) : base(orm, commonUtils, commonExpression) { }
 | 
					        public MsAccessCodeFirst(IFreeSql orm, CommonUtils commonUtils, CommonExpression commonExpression) : base(orm, commonUtils, commonExpression) { }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        static object _dicCsToDbLock = new object();
 | 
					        static object _dicCsToDbLock = new object();
 | 
				
			||||||
        static Dictionary<string, (OleDbType type, string dbtype, string dbtypeFull, bool? isUnsigned, bool? isnullable, object defaultValue)> _dicCsToDb = new Dictionary<string, (OleDbType type, string dbtype, string dbtypeFull, bool? isUnsigned, bool? isnullable, object defaultValue)>() {
 | 
					        static Dictionary<string, CsToDb<OleDbType>> _dicCsToDb = new Dictionary<string, CsToDb<OleDbType>>() {
 | 
				
			||||||
                { typeof(bool).FullName,  (OleDbType.Boolean, "bit","bit NOT NULL", null, false, false) },{ typeof(bool?).FullName,  (OleDbType.Boolean, "bit","bit", null, true, null) },
 | 
					                { typeof(bool).FullName,  CsToDb.New(OleDbType.Boolean, "bit","bit NOT NULL", null, false, false) },{ typeof(bool?).FullName,  CsToDb.New(OleDbType.Boolean, "bit","bit", null, true, null) },
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                { typeof(sbyte).FullName,  (OleDbType.TinyInt, "decimal", "decimal(3,0) NOT NULL", false, false, 0) },{ typeof(sbyte?).FullName,  (OleDbType.TinyInt, "decimal", "decimal(3,0)", false, true, null) },
 | 
					                { typeof(sbyte).FullName,  CsToDb.New(OleDbType.TinyInt, "decimal", "decimal(3,0) NOT NULL", false, false, 0) },{ typeof(sbyte?).FullName, CsToDb.New(OleDbType.TinyInt, "decimal", "decimal(3,0)", false, true, null) },
 | 
				
			||||||
                { typeof(short).FullName,  (OleDbType.SmallInt, "decimal","decimal(6,0) NOT NULL", false, false, 0) },{ typeof(short?).FullName,  (OleDbType.SmallInt, "decimal", "decimal(6,0)", false, true, null) },
 | 
					                { typeof(short).FullName,  CsToDb.New(OleDbType.SmallInt, "decimal","decimal(6,0) NOT NULL", false, false, 0) },{ typeof(short?).FullName, CsToDb.New(OleDbType.SmallInt, "decimal", "decimal(6,0)", false, true, null) },
 | 
				
			||||||
                { typeof(int).FullName,  (OleDbType.Integer, "decimal", "decimal(11,0) NOT NULL", false, false, 0) },{ typeof(int?).FullName,  (OleDbType.Integer, "decimal", "decimal(11,0)", false, true, null) },
 | 
					                { typeof(int).FullName,  CsToDb.New(OleDbType.Integer, "decimal", "decimal(11,0) NOT NULL", false, false, 0) },{ typeof(int?).FullName, CsToDb.New(OleDbType.Integer, "decimal", "decimal(11,0)", false, true, null) },
 | 
				
			||||||
                { typeof(long).FullName,  (OleDbType.BigInt, "decimal","decimal(20,0) NOT NULL", false, false, 0) },{ typeof(long?).FullName,  (OleDbType.BigInt, "decimal","decimal(20,0)", false, true, null) },
 | 
					                { typeof(long).FullName,  CsToDb.New(OleDbType.BigInt, "decimal","decimal(20,0) NOT NULL", false, false, 0) },{ typeof(long?).FullName, CsToDb.New(OleDbType.BigInt, "decimal","decimal(20,0)", false, true, null) },
 | 
				
			||||||
                // access int long 类型是留给自动增长用的,所以这里全映射为 decimal
 | 
					                // access int long 类型是留给自动增长用的,所以这里全映射为 decimal
 | 
				
			||||||
                { typeof(byte).FullName,  (OleDbType.UnsignedTinyInt, "decimal","decimal(3,0) NOT NULL", true, false, 0) },{ typeof(byte?).FullName,  (OleDbType.UnsignedTinyInt, "decimal","decimal(3,0)", true, true, null) },
 | 
					                { typeof(byte).FullName,  CsToDb.New(OleDbType.UnsignedTinyInt, "decimal","decimal(3,0) NOT NULL", true, false, 0) },{ typeof(byte?).FullName, CsToDb.New(OleDbType.UnsignedTinyInt, "decimal","decimal(3,0)", true, true, null) },
 | 
				
			||||||
                { typeof(ushort).FullName,  (OleDbType.UnsignedSmallInt, "decimal","decimal(5,0) NOT NULL", true, false, 0) },{ typeof(ushort?).FullName,  (OleDbType.UnsignedSmallInt, "decimal", "decimal(5,0)", true, true, null) },
 | 
					                { typeof(ushort).FullName,  CsToDb.New(OleDbType.UnsignedSmallInt, "decimal","decimal(5,0) NOT NULL", true, false, 0) },{ typeof(ushort?).FullName, CsToDb.New(OleDbType.UnsignedSmallInt, "decimal", "decimal(5,0)", true, true, null) },
 | 
				
			||||||
                { typeof(uint).FullName,  (OleDbType.UnsignedInt, "decimal", "decimal(10,0) NOT NULL", true, false, 0) },{ typeof(uint?).FullName,  (OleDbType.UnsignedInt, "decimal", "decimal(10,0)", true, true, null) },
 | 
					                { typeof(uint).FullName,  CsToDb.New(OleDbType.UnsignedInt, "decimal", "decimal(10,0) NOT NULL", true, false, 0) },{ typeof(uint?).FullName, CsToDb.New(OleDbType.UnsignedInt, "decimal", "decimal(10,0)", true, true, null) },
 | 
				
			||||||
                { typeof(ulong).FullName,  (OleDbType.UnsignedBigInt, "decimal", "decimal(20,0) NOT NULL", true, false, 0) },{ typeof(ulong?).FullName,  (OleDbType.UnsignedBigInt, "decimal", "decimal(20,0)", true, true, null) },
 | 
					                { typeof(ulong).FullName, CsToDb.New (OleDbType.UnsignedBigInt, "decimal", "decimal(20,0) NOT NULL", true, false, 0) },{ typeof(ulong?).FullName, CsToDb.New(OleDbType.UnsignedBigInt, "decimal", "decimal(20,0)", true, true, null) },
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                { typeof(double).FullName,  (OleDbType.Double, "double", "double NOT NULL", false, false, 0) },{ typeof(double?).FullName,  (OleDbType.Double, "double", "double", false, true, null) },
 | 
					                { typeof(double).FullName,  CsToDb.New(OleDbType.Double, "double", "double NOT NULL", false, false, 0) },{ typeof(double?).FullName, CsToDb.New(OleDbType.Double, "double", "double", false, true, null) },
 | 
				
			||||||
                { typeof(float).FullName,  (OleDbType.Currency, "single","single NOT NULL", false, false, 0) },{ typeof(float?).FullName,  (OleDbType.Currency, "single","single", false, true, null) },
 | 
					                { typeof(float).FullName, CsToDb.New(OleDbType.Currency, "single","single NOT NULL", false, false, 0) },{ typeof(float?).FullName, CsToDb.New(OleDbType.Currency, "single","single", false, true, null) },
 | 
				
			||||||
                { typeof(decimal).FullName,  (OleDbType.Decimal, "decimal", "decimal(10,2) NOT NULL", false, false, 0) },{ typeof(decimal?).FullName,  (OleDbType.Decimal, "decimal", "decimal(10,2)", false, true, null) },
 | 
					                { typeof(decimal).FullName, CsToDb.New(OleDbType.Decimal, "decimal", "decimal(10,2) NOT NULL", false, false, 0) },{ typeof(decimal?).FullName, CsToDb.New(OleDbType.Decimal, "decimal", "decimal(10,2)", false, true, null) },
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                { typeof(TimeSpan).FullName,  (OleDbType.DBTime, "datetime","datetime NOT NULL", false, false, 0) },{ typeof(TimeSpan?).FullName,  (OleDbType.DBTime, "datetime", "datetime",false, true, null) },
 | 
					                { typeof(TimeSpan).FullName, CsToDb.New(OleDbType.DBTime, "datetime","datetime NOT NULL", false, false, 0) },{ typeof(TimeSpan?).FullName, CsToDb.New(OleDbType.DBTime, "datetime", "datetime",false, true, null) },
 | 
				
			||||||
                { typeof(DateTime).FullName,  (OleDbType.DBTimeStamp, "datetime", "datetime NOT NULL", false, false, new DateTime(1970,1,1)) },{ typeof(DateTime?).FullName,  (OleDbType.DBTimeStamp, "datetime", "datetime", false, true, null) },
 | 
					                { typeof(DateTime).FullName, CsToDb.New(OleDbType.DBTimeStamp, "datetime", "datetime NOT NULL", false, false, new DateTime(1970,1,1)) },{ typeof(DateTime?).FullName, CsToDb.New(OleDbType.DBTimeStamp, "datetime", "datetime", false, true, null) },
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                { typeof(byte[]).FullName,  (OleDbType.VarBinary, "varbinary", "varbinary(255)", false, null, new byte[0]) },
 | 
					                { typeof(byte[]).FullName, CsToDb.New(OleDbType.VarBinary, "varbinary", "varbinary(255)", false, null, new byte[0]) },
 | 
				
			||||||
                { typeof(string).FullName,  (OleDbType.VarChar, "varchar", "varchar(255)", false, null, "") },
 | 
					                { typeof(string).FullName, CsToDb.New(OleDbType.VarChar, "varchar", "varchar(255)", false, null, "") },
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                { typeof(Guid).FullName,  (OleDbType.Guid, "varchar", "varchar(36) NOT NULL", false, false, Guid.Empty) },{ typeof(Guid?).FullName,  (OleDbType.Guid, "varchar", "varchar(36)", false, true, null) },
 | 
					                { typeof(Guid).FullName, CsToDb.New(OleDbType.Guid, "varchar", "varchar(36) NOT NULL", false, false, Guid.Empty) },{ typeof(Guid?).FullName, CsToDb.New(OleDbType.Guid, "varchar", "varchar(36)", false, true, null) },
 | 
				
			||||||
            };
 | 
					            };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        public override (int type, string dbtype, string dbtypeFull, bool? isnullable, object defaultValue)? GetDbInfo(Type type)
 | 
					        public override DbInfoResult 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 (_dicCsToDb.TryGetValue(type.FullName, out var trydc)) return new DbInfoResult((int)trydc.type, trydc.dbtype, trydc.dbtypeFull, trydc.isnullable, trydc.defaultValue);
 | 
				
			||||||
            if (type.IsArray) return null;
 | 
					            if (type.IsArray) return null;
 | 
				
			||||||
            var enumType = type.IsEnum ? type : null;
 | 
					            var enumType = type.IsEnum ? type : null;
 | 
				
			||||||
            if (enumType == null && type.IsNullableType())
 | 
					            if (enumType == null && type.IsNullableType())
 | 
				
			||||||
@@ -56,8 +56,8 @@ namespace FreeSql.MsAccess
 | 
				
			|||||||
            if (enumType != null)
 | 
					            if (enumType != null)
 | 
				
			||||||
            {
 | 
					            {
 | 
				
			||||||
                var newItem = enumType.GetCustomAttributes(typeof(FlagsAttribute), false).Any() ?
 | 
					                var newItem = enumType.GetCustomAttributes(typeof(FlagsAttribute), false).Any() ?
 | 
				
			||||||
                    (OleDbType.BigInt, "decimal", $"decimal(20,0){(type.IsEnum ? " NOT NULL" : "")}", false, type.IsEnum ? false : true, Enum.GetValues(enumType).GetValue(0)) :
 | 
					                    CsToDb.New(OleDbType.BigInt, "decimal", $"decimal(20,0){(type.IsEnum ? " NOT NULL" : "")}", false, type.IsEnum ? false : true, Enum.GetValues(enumType).GetValue(0)) :
 | 
				
			||||||
                    (OleDbType.Integer, "decimal", $"decimal(11,0){(type.IsEnum ? " NOT NULL" : "")}", false, type.IsEnum ? false : true, Enum.GetValues(enumType).GetValue(0));
 | 
					                    CsToDb.New(OleDbType.Integer, "decimal", $"decimal(11,0){(type.IsEnum ? " NOT NULL" : "")}", false, type.IsEnum ? false : true, Enum.GetValues(enumType).GetValue(0));
 | 
				
			||||||
                if (_dicCsToDb.ContainsKey(type.FullName) == false)
 | 
					                if (_dicCsToDb.ContainsKey(type.FullName) == false)
 | 
				
			||||||
                {
 | 
					                {
 | 
				
			||||||
                    lock (_dicCsToDbLock)
 | 
					                    lock (_dicCsToDbLock)
 | 
				
			||||||
@@ -66,12 +66,12 @@ namespace FreeSql.MsAccess
 | 
				
			|||||||
                            _dicCsToDb.Add(type.FullName, newItem);
 | 
					                            _dicCsToDb.Add(type.FullName, newItem);
 | 
				
			||||||
                    }
 | 
					                    }
 | 
				
			||||||
                }
 | 
					                }
 | 
				
			||||||
                return ((int)newItem.Item1, newItem.Item2, newItem.Item3, newItem.Item5, newItem.Item6);
 | 
					                return new DbInfoResult((int)newItem.type, newItem.dbtype, newItem.dbtypeFull, newItem.isnullable, newItem.defaultValue);
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
            return null;
 | 
					            return null;
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        protected override string GetComparisonDDLStatements(params (Type entityType, string tableName)[] objects)
 | 
					        protected override string GetComparisonDDLStatements(params TypeAndName[] objects)
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
            var sb = new StringBuilder();
 | 
					            var sb = new StringBuilder();
 | 
				
			||||||
            var sbDeclare = new StringBuilder();
 | 
					            var sbDeclare = new StringBuilder();
 | 
				
			||||||
@@ -252,7 +252,7 @@ namespace FreeSql.MsAccess
 | 
				
			|||||||
                    }
 | 
					                    }
 | 
				
			||||||
                    return idxs;
 | 
					                    return idxs;
 | 
				
			||||||
                };
 | 
					                };
 | 
				
			||||||
                Func<string, Dictionary<string, (string column, string sqlType, bool is_nullable, bool is_identity, string comment)>> getColumnsByTableName = tn =>
 | 
					                Func<string, Dictionary<string, getColumnsByTableNameResult>> getColumnsByTableName = tn =>
 | 
				
			||||||
                {
 | 
					                {
 | 
				
			||||||
                    int table_name_index = 0, column_name_index = 0, is_nullable_index = 0, data_type_index = 0,
 | 
					                    int table_name_index = 0, column_name_index = 0, is_nullable_index = 0, data_type_index = 0,
 | 
				
			||||||
                        character_maximum_length_index = 0, character_octet_length_index = 0, numeric_precision_index = 0, numeric_scale_index = 0,
 | 
					                        character_maximum_length_index = 0, character_octet_length_index = 0, numeric_precision_index = 0, numeric_scale_index = 0,
 | 
				
			||||||
@@ -322,7 +322,7 @@ namespace FreeSql.MsAccess
 | 
				
			|||||||
                        }
 | 
					                        }
 | 
				
			||||||
                        return dtRow;
 | 
					                        return dtRow;
 | 
				
			||||||
                    };
 | 
					                    };
 | 
				
			||||||
                    var ret = new Dictionary<string, (string column, string sqlType, bool is_nullable, bool is_identity, string comment)>();
 | 
					                    var ret = new Dictionary<string, getColumnsByTableNameResult>();
 | 
				
			||||||
                    foreach (DataRow row in schemaColumns.Rows)
 | 
					                    foreach (DataRow row in schemaColumns.Rows)
 | 
				
			||||||
                    {
 | 
					                    {
 | 
				
			||||||
                        if (string.Compare(row[table_name_index]?.ToString(), tn, true) != 0) continue;
 | 
					                        if (string.Compare(row[table_name_index]?.ToString(), tn, true) != 0) continue;
 | 
				
			||||||
@@ -341,7 +341,7 @@ namespace FreeSql.MsAccess
 | 
				
			|||||||
                        var datatype = dataTypeRow[datatype_TypeName_index]?.ToString().ToUpper();
 | 
					                        var datatype = dataTypeRow[datatype_TypeName_index]?.ToString().ToUpper();
 | 
				
			||||||
                        if (numeric_precision > 0 && numeric_scale > 0) datatype = $"{datatype}({numeric_precision},{numeric_scale})";
 | 
					                        if (numeric_precision > 0 && numeric_scale > 0) datatype = $"{datatype}({numeric_precision},{numeric_scale})";
 | 
				
			||||||
                        else if (character_maximum_length > 0 && character_octet_length > 0) datatype = $"{datatype}({character_maximum_length})";
 | 
					                        else if (character_maximum_length > 0 && character_octet_length > 0) datatype = $"{datatype}({character_maximum_length})";
 | 
				
			||||||
                        ret.Add(column_name, (column_name, datatype, is_nullable, is_identity, comment));
 | 
					                        ret.Add(column_name, new getColumnsByTableNameResult(column_name, datatype, is_nullable, is_identity, comment));
 | 
				
			||||||
                    }
 | 
					                    }
 | 
				
			||||||
                    return ret;
 | 
					                    return ret;
 | 
				
			||||||
                };
 | 
					                };
 | 
				
			||||||
@@ -441,6 +441,23 @@ namespace FreeSql.MsAccess
 | 
				
			|||||||
            return sb.Length == 0 ? null : sb.ToString();
 | 
					            return sb.Length == 0 ? null : sb.ToString();
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        class getColumnsByTableNameResult
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            public string column { get; }
 | 
				
			||||||
 | 
					            public string sqlType { get; }
 | 
				
			||||||
 | 
					            public bool is_nullable { get; }
 | 
				
			||||||
 | 
					            public bool is_identity { get; }
 | 
				
			||||||
 | 
					            public string comment { get; }
 | 
				
			||||||
 | 
					            public getColumnsByTableNameResult(string column, string sqlType, bool is_nullable, bool is_identity, string comment)
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					                this.column = column;
 | 
				
			||||||
 | 
					                this.sqlType = sqlType;
 | 
				
			||||||
 | 
					                this.is_nullable = is_nullable;
 | 
				
			||||||
 | 
					                this.is_identity = is_identity;
 | 
				
			||||||
 | 
					                this.comment = comment;
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        public override int ExecuteDDLStatements(string ddl)
 | 
					        public override int ExecuteDDLStatements(string ddl)
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
            if (string.IsNullOrEmpty(ddl)) return 0;
 | 
					            if (string.IsNullOrEmpty(ddl)) return 0;
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,4 +1,5 @@
 | 
				
			|||||||
using FreeSql.Internal;
 | 
					using FreeSql.Internal;
 | 
				
			||||||
 | 
					using FreeSql.Internal.Model;
 | 
				
			||||||
using MySql.Data.MySqlClient;
 | 
					using MySql.Data.MySqlClient;
 | 
				
			||||||
using System;
 | 
					using System;
 | 
				
			||||||
using System.Collections.Generic;
 | 
					using System.Collections.Generic;
 | 
				
			||||||
@@ -16,42 +17,42 @@ namespace FreeSql.MySql
 | 
				
			|||||||
        public MySqlCodeFirst(IFreeSql orm, CommonUtils commonUtils, CommonExpression commonExpression) : base(orm, commonUtils, commonExpression) { }
 | 
					        public MySqlCodeFirst(IFreeSql orm, CommonUtils commonUtils, CommonExpression commonExpression) : base(orm, commonUtils, commonExpression) { }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        static object _dicCsToDbLock = new object();
 | 
					        static object _dicCsToDbLock = new object();
 | 
				
			||||||
        static Dictionary<string, (MySqlDbType type, string dbtype, string dbtypeFull, bool? isUnsigned, bool? isnullable, object defaultValue)> _dicCsToDb = new Dictionary<string, (MySqlDbType type, string dbtype, string dbtypeFull, bool? isUnsigned, bool? isnullable, object defaultValue)>() {
 | 
					        static Dictionary<string, CsToDb<MySqlDbType>> _dicCsToDb = new Dictionary<string, CsToDb<MySqlDbType>>() {
 | 
				
			||||||
                { typeof(bool).FullName,  (MySqlDbType.Bit, "bit","bit(1) NOT NULL", null, false, false) },{ typeof(bool?).FullName,  (MySqlDbType.Bit, "bit","bit(1)", null, true, null) },
 | 
					                { typeof(bool).FullName, CsToDb.New(MySqlDbType.Bit, "bit","bit(1) NOT NULL", null, false, false) },{ typeof(bool?).FullName, CsToDb.New(MySqlDbType.Bit, "bit","bit(1)", null, true, null) },
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                { typeof(sbyte).FullName,  (MySqlDbType.Byte, "tinyint", "tinyint(3) NOT NULL", false, false, 0) },{ typeof(sbyte?).FullName,  (MySqlDbType.Byte, "tinyint", "tinyint(3)", false, true, null) },
 | 
					                { typeof(sbyte).FullName, CsToDb.New(MySqlDbType.Byte, "tinyint", "tinyint(3) NOT NULL", false, false, 0) },{ typeof(sbyte?).FullName, CsToDb.New(MySqlDbType.Byte, "tinyint", "tinyint(3)", false, true, null) },
 | 
				
			||||||
                { typeof(short).FullName,  (MySqlDbType.Int16, "smallint","smallint(6) NOT NULL", false, false, 0) },{ typeof(short?).FullName,  (MySqlDbType.Int16, "smallint", "smallint(6)", false, true, null) },
 | 
					                { typeof(short).FullName, CsToDb.New(MySqlDbType.Int16, "smallint","smallint(6) NOT NULL", false, false, 0) },{ typeof(short?).FullName, CsToDb.New(MySqlDbType.Int16, "smallint", "smallint(6)", false, true, null) },
 | 
				
			||||||
                { typeof(int).FullName,  (MySqlDbType.Int32, "int", "int(11) NOT NULL", false, false, 0) },{ typeof(int?).FullName,  (MySqlDbType.Int32, "int", "int(11)", false, true, null) },
 | 
					                { typeof(int).FullName, CsToDb.New(MySqlDbType.Int32, "int", "int(11) NOT NULL", false, false, 0) },{ typeof(int?).FullName, CsToDb.New(MySqlDbType.Int32, "int", "int(11)", false, true, null) },
 | 
				
			||||||
                { typeof(long).FullName,  (MySqlDbType.Int64, "bigint","bigint(20) NOT NULL", false, false, 0) },{ typeof(long?).FullName,  (MySqlDbType.Int64, "bigint","bigint(20)", false, true, null) },
 | 
					                { typeof(long).FullName, CsToDb.New(MySqlDbType.Int64, "bigint","bigint(20) NOT NULL", false, false, 0) },{ typeof(long?).FullName, CsToDb.New(MySqlDbType.Int64, "bigint","bigint(20)", false, true, null) },
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                { typeof(byte).FullName,  (MySqlDbType.UByte, "tinyint","tinyint(3) unsigned NOT NULL", true, false, 0) },{ typeof(byte?).FullName,  (MySqlDbType.UByte, "tinyint","tinyint(3) unsigned", true, true, null) },
 | 
					                { typeof(byte).FullName, CsToDb.New(MySqlDbType.UByte, "tinyint","tinyint(3) unsigned NOT NULL", true, false, 0) },{ typeof(byte?).FullName, CsToDb.New(MySqlDbType.UByte, "tinyint","tinyint(3) unsigned", true, true, null) },
 | 
				
			||||||
                { typeof(ushort).FullName,  (MySqlDbType.UInt16, "smallint","smallint(5) unsigned NOT NULL", true, false, 0) },{ typeof(ushort?).FullName,  (MySqlDbType.UInt16, "smallint", "smallint(5) unsigned", true, true, null) },
 | 
					                { typeof(ushort).FullName, CsToDb.New(MySqlDbType.UInt16, "smallint","smallint(5) unsigned NOT NULL", true, false, 0) },{ typeof(ushort?).FullName, CsToDb.New(MySqlDbType.UInt16, "smallint", "smallint(5) unsigned", true, true, null) },
 | 
				
			||||||
                { typeof(uint).FullName,  (MySqlDbType.UInt32, "int", "int(10) unsigned NOT NULL", true, false, 0) },{ typeof(uint?).FullName,  (MySqlDbType.UInt32, "int", "int(10) unsigned", true, true, null) },
 | 
					                { typeof(uint).FullName, CsToDb.New(MySqlDbType.UInt32, "int", "int(10) unsigned NOT NULL", true, false, 0) },{ typeof(uint?).FullName, CsToDb.New(MySqlDbType.UInt32, "int", "int(10) unsigned", true, true, null) },
 | 
				
			||||||
                { typeof(ulong).FullName,  (MySqlDbType.UInt64, "bigint", "bigint(20) unsigned NOT NULL", true, false, 0) },{ typeof(ulong?).FullName,  (MySqlDbType.UInt64, "bigint", "bigint(20) unsigned", true, true, null) },
 | 
					                { typeof(ulong).FullName, CsToDb.New(MySqlDbType.UInt64, "bigint", "bigint(20) unsigned NOT NULL", true, false, 0) },{ typeof(ulong?).FullName, CsToDb.New(MySqlDbType.UInt64, "bigint", "bigint(20) unsigned", true, true, null) },
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                { typeof(double).FullName,  (MySqlDbType.Double, "double", "double NOT NULL", false, false, 0) },{ typeof(double?).FullName,  (MySqlDbType.Double, "double", "double", false, true, null) },
 | 
					                { typeof(double).FullName, CsToDb.New(MySqlDbType.Double, "double", "double NOT NULL", false, false, 0) },{ typeof(double?).FullName, CsToDb.New(MySqlDbType.Double, "double", "double", false, true, null) },
 | 
				
			||||||
                { typeof(float).FullName,  (MySqlDbType.Float, "float","float NOT NULL", false, false, 0) },{ typeof(float?).FullName,  (MySqlDbType.Float, "float","float", false, true, null) },
 | 
					                { typeof(float).FullName, CsToDb.New(MySqlDbType.Float, "float","float NOT NULL", false, false, 0) },{ typeof(float?).FullName, CsToDb.New(MySqlDbType.Float, "float","float", false, true, null) },
 | 
				
			||||||
                { typeof(decimal).FullName,  (MySqlDbType.Decimal, "decimal", "decimal(10,2) NOT NULL", false, false, 0) },{ typeof(decimal?).FullName,  (MySqlDbType.Decimal, "decimal", "decimal(10,2)", false, true, null) },
 | 
					                { typeof(decimal).FullName, CsToDb.New(MySqlDbType.Decimal, "decimal", "decimal(10,2) NOT NULL", false, false, 0) },{ typeof(decimal?).FullName, CsToDb.New(MySqlDbType.Decimal, "decimal", "decimal(10,2)", false, true, null) },
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                { typeof(TimeSpan).FullName,  (MySqlDbType.Time, "time","time NOT NULL", false, false, 0) },{ typeof(TimeSpan?).FullName,  (MySqlDbType.Time, "time", "time",false, true, null) },
 | 
					                { typeof(TimeSpan).FullName, CsToDb.New(MySqlDbType.Time, "time","time NOT NULL", false, false, 0) },{ typeof(TimeSpan?).FullName, CsToDb.New(MySqlDbType.Time, "time", "time",false, true, null) },
 | 
				
			||||||
                { typeof(DateTime).FullName,  (MySqlDbType.DateTime, "datetime(3)", "datetime(3) NOT NULL", false, false, new DateTime(1970,1,1)) },{ typeof(DateTime?).FullName,  (MySqlDbType.DateTime, "datetime(3)", "datetime(3)", false, true, null) },
 | 
					                { typeof(DateTime).FullName, CsToDb.New(MySqlDbType.DateTime, "datetime(3)", "datetime(3) NOT NULL", false, false, new DateTime(1970,1,1)) },{ typeof(DateTime?).FullName, CsToDb.New(MySqlDbType.DateTime, "datetime(3)", "datetime(3)", false, true, null) },
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                { typeof(byte[]).FullName,  (MySqlDbType.VarBinary, "varbinary", "varbinary(255)", false, null, new byte[0]) },
 | 
					                { typeof(byte[]).FullName, CsToDb.New(MySqlDbType.VarBinary, "varbinary", "varbinary(255)", false, null, new byte[0]) },
 | 
				
			||||||
                { typeof(string).FullName,  (MySqlDbType.VarChar, "varchar", "varchar(255)", false, null, "") },
 | 
					                { typeof(string).FullName, CsToDb.New(MySqlDbType.VarChar, "varchar", "varchar(255)", false, null, "") },
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                { typeof(Guid).FullName,  (MySqlDbType.VarChar, "char", "char(36) NOT NULL", false, false, Guid.Empty) },{ typeof(Guid?).FullName,  (MySqlDbType.VarChar, "char", "char(36)", false, true, null) },
 | 
					                { typeof(Guid).FullName, CsToDb.New(MySqlDbType.VarChar, "char", "char(36) NOT NULL", false, false, Guid.Empty) },{ typeof(Guid?).FullName, CsToDb.New(MySqlDbType.VarChar, "char", "char(36)", false, true, null) },
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                { typeof(MygisPoint).FullName,  (MySqlDbType.Geometry, "point", "point", false, null, new MygisPoint(0, 0)) },
 | 
					                { typeof(MygisPoint).FullName, CsToDb.New(MySqlDbType.Geometry, "point", "point", false, null, new MygisPoint(0, 0)) },
 | 
				
			||||||
                { typeof(MygisLineString).FullName,  (MySqlDbType.Geometry, "linestring", "linestring", false, null, new MygisLineString(new[]{new MygisCoordinate2D(),new MygisCoordinate2D()})) },
 | 
					                { typeof(MygisLineString).FullName, CsToDb.New(MySqlDbType.Geometry, "linestring", "linestring", false, null, new MygisLineString(new[]{new MygisCoordinate2D(),new MygisCoordinate2D()})) },
 | 
				
			||||||
                { typeof(MygisPolygon).FullName,  (MySqlDbType.Geometry, "polygon", "polygon", false, null, new MygisPolygon(new[]{new[]{new MygisCoordinate2D(),new MygisCoordinate2D()},new[]{new MygisCoordinate2D(),new MygisCoordinate2D()}})) },
 | 
					                { typeof(MygisPolygon).FullName, CsToDb.New(MySqlDbType.Geometry, "polygon", "polygon", false, null, new MygisPolygon(new[]{new[]{new MygisCoordinate2D(),new MygisCoordinate2D()},new[]{new MygisCoordinate2D(),new MygisCoordinate2D()}})) },
 | 
				
			||||||
                { typeof(MygisMultiPoint).FullName,  (MySqlDbType.Geometry, "multipoint","multipoint", false, null, new MygisMultiPoint(new[]{new MygisCoordinate2D(),new MygisCoordinate2D()})) },
 | 
					                { typeof(MygisMultiPoint).FullName, CsToDb.New(MySqlDbType.Geometry, "multipoint","multipoint", false, null, new MygisMultiPoint(new[]{new MygisCoordinate2D(),new MygisCoordinate2D()})) },
 | 
				
			||||||
                { typeof(MygisMultiLineString).FullName,  (MySqlDbType.Geometry, "multilinestring","multilinestring", false, null, new MygisMultiLineString(new[]{new[]{new MygisCoordinate2D(),new MygisCoordinate2D()},new[]{new MygisCoordinate2D(),new MygisCoordinate2D()}})) },
 | 
					                { typeof(MygisMultiLineString).FullName, CsToDb.New(MySqlDbType.Geometry, "multilinestring","multilinestring", false, null, new MygisMultiLineString(new[]{new[]{new MygisCoordinate2D(),new MygisCoordinate2D()},new[]{new MygisCoordinate2D(),new MygisCoordinate2D()}})) },
 | 
				
			||||||
                { typeof(MygisMultiPolygon).FullName,  (MySqlDbType.Geometry, "multipolygon", "multipolygon", false, null, new MygisMultiPolygon(new[]{new MygisPolygon(new[]{new[]{new MygisCoordinate2D(),new MygisCoordinate2D()},new[]{new MygisCoordinate2D(),new MygisCoordinate2D()}}),new MygisPolygon(new[]{new[]{new MygisCoordinate2D(),new MygisCoordinate2D()},new[]{new MygisCoordinate2D(),new MygisCoordinate2D()}})})) },
 | 
					                { typeof(MygisMultiPolygon).FullName, CsToDb.New(MySqlDbType.Geometry, "multipolygon", "multipolygon", false, null, new MygisMultiPolygon(new[]{new MygisPolygon(new[]{new[]{new MygisCoordinate2D(),new MygisCoordinate2D()},new[]{new MygisCoordinate2D(),new MygisCoordinate2D()}}),new MygisPolygon(new[]{new[]{new MygisCoordinate2D(),new MygisCoordinate2D()},new[]{new MygisCoordinate2D(),new MygisCoordinate2D()}})})) },
 | 
				
			||||||
            };
 | 
					            };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        public override (int type, string dbtype, string dbtypeFull, bool? isnullable, object defaultValue)? GetDbInfo(Type type)
 | 
					        public override DbInfoResult 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 (_dicCsToDb.TryGetValue(type.FullName, out var trydc)) return new DbInfoResult((int)trydc.type, trydc.dbtype, trydc.dbtypeFull, trydc.isnullable, trydc.defaultValue);
 | 
				
			||||||
            if (type.IsArray) return null;
 | 
					            if (type.IsArray) return null;
 | 
				
			||||||
            var enumType = type.IsEnum ? type : null;
 | 
					            var enumType = type.IsEnum ? type : null;
 | 
				
			||||||
            if (enumType == null && type.IsNullableType()) 
 | 
					            if (enumType == null && type.IsNullableType()) 
 | 
				
			||||||
@@ -63,8 +64,8 @@ namespace FreeSql.MySql
 | 
				
			|||||||
            {
 | 
					            {
 | 
				
			||||||
                var names = string.Join(",", Enum.GetNames(enumType).Select(a => _commonUtils.FormatSql("{0}", a)));
 | 
					                var names = string.Join(",", Enum.GetNames(enumType).Select(a => _commonUtils.FormatSql("{0}", a)));
 | 
				
			||||||
                var newItem = enumType.GetCustomAttributes(typeof(FlagsAttribute), false).Any() ?
 | 
					                var newItem = enumType.GetCustomAttributes(typeof(FlagsAttribute), false).Any() ?
 | 
				
			||||||
                    (MySqlDbType.Set, "set", $"set({names}){(type.IsEnum ? " NOT NULL" : "")}", false, type.IsEnum ? false : true, Enum.GetValues(enumType).GetValue(0)) :
 | 
					                    CsToDb.New(MySqlDbType.Set, "set", $"set({names}){(type.IsEnum ? " NOT NULL" : "")}", false, type.IsEnum ? false : true, Enum.GetValues(enumType).GetValue(0)) :
 | 
				
			||||||
                    (MySqlDbType.Enum, "enum", $"enum({names}){(type.IsEnum ? " NOT NULL" : "")}", false, type.IsEnum ? false : true, Enum.GetValues(enumType).GetValue(0));
 | 
					                    CsToDb.New(MySqlDbType.Enum, "enum", $"enum({names}){(type.IsEnum ? " NOT NULL" : "")}", false, type.IsEnum ? false : true, Enum.GetValues(enumType).GetValue(0));
 | 
				
			||||||
                if (_dicCsToDb.ContainsKey(type.FullName) == false)
 | 
					                if (_dicCsToDb.ContainsKey(type.FullName) == false)
 | 
				
			||||||
                {
 | 
					                {
 | 
				
			||||||
                    lock (_dicCsToDbLock)
 | 
					                    lock (_dicCsToDbLock)
 | 
				
			||||||
@@ -73,12 +74,12 @@ namespace FreeSql.MySql
 | 
				
			|||||||
                            _dicCsToDb.Add(type.FullName, newItem);
 | 
					                            _dicCsToDb.Add(type.FullName, newItem);
 | 
				
			||||||
                    }
 | 
					                    }
 | 
				
			||||||
                }
 | 
					                }
 | 
				
			||||||
                return ((int)newItem.Item1, newItem.Item2, newItem.Item3, newItem.Item5, newItem.Item6);
 | 
					                return new DbInfoResult((int)newItem.type, newItem.dbtype, newItem.dbtypeFull, newItem.isnullable, newItem.defaultValue);
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
            return null;
 | 
					            return null;
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        protected override string GetComparisonDDLStatements(params (Type entityType, string tableName)[] objects)
 | 
					        protected override string GetComparisonDDLStatements(params TypeAndName[] objects)
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
            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;
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,5 +1,6 @@
 | 
				
			|||||||
using FreeSql.DatabaseModel;
 | 
					using FreeSql.DatabaseModel;
 | 
				
			||||||
using FreeSql.Internal;
 | 
					using FreeSql.Internal;
 | 
				
			||||||
 | 
					using FreeSql.Internal.Model;
 | 
				
			||||||
using MySql.Data.MySqlClient;
 | 
					using MySql.Data.MySqlClient;
 | 
				
			||||||
using System;
 | 
					using System;
 | 
				
			||||||
using System.Collections.Generic;
 | 
					using System.Collections.Generic;
 | 
				
			||||||
@@ -79,53 +80,53 @@ namespace FreeSql.MySql
 | 
				
			|||||||
            }
 | 
					            }
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        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, DbToCs> _dicDbToCs = new Dictionary<int, DbToCs>() {
 | 
				
			||||||
                { (int)MySqlDbType.Bit, ("(bool?)", "{0} == \"1\"", "{0} == true ? \"1\" : \"0\"", "bool?", typeof(bool), typeof(bool?), "{0}.Value", "GetBoolean") },
 | 
					                { (int)MySqlDbType.Bit, new DbToCs("(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.Byte, new DbToCs("(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.Int16, new DbToCs("(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.Int24, new DbToCs("(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.Int32, new DbToCs("(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.Int64, new DbToCs("(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.UByte, new DbToCs("(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.UInt16, new DbToCs("(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.UInt24, new DbToCs("(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.UInt32, new DbToCs("(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.UInt64, new DbToCs("(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.Double, new DbToCs("(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.Float, new DbToCs("(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.Decimal, new DbToCs("(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.Year, new DbToCs("(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.Time, new DbToCs("(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.Date, new DbToCs("(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.Timestamp, new DbToCs("(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.DateTime, new DbToCs("(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.TinyBlob, new DbToCs("(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.Blob, new DbToCs("(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.MediumBlob, new DbToCs("(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.LongBlob, new DbToCs("(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.Binary, new DbToCs("(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.VarBinary, new DbToCs("(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.TinyText, new DbToCs("", "{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.Text, new DbToCs("", "{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.MediumText, new DbToCs("", "{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.LongText, new DbToCs("", "{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.Guid, new DbToCs("(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.String, new DbToCs("", "{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.VarString, new DbToCs("", "{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, new DbToCs("", "{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(Enum), typeof(Enum), "{0}", "GetInt64") },
 | 
					                { (int)MySqlDbType.Set, new DbToCs("(long?)", "long.Parse({0})", "{0}.ToInt64().ToString()", "Set", typeof(Enum), typeof(Enum), "{0}", "GetInt64") },
 | 
				
			||||||
                { (int)MySqlDbType.Enum, ("(long?)", "long.Parse({0})", "{0}.ToInt64().ToString()", "Enum", typeof(Enum), typeof(Enum), "{0}", "GetInt64") },
 | 
					                { (int)MySqlDbType.Enum, new DbToCs("(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, new DbToCs("(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 GetCsConvert(DbColumnInfo column) => _dicDbToCs.TryGetValue(column.DbType, out var trydc) ? (column.IsNullable ? trydc.csConvert : trydc.csConvert.Replace("?", "")) : null;
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -19,37 +19,37 @@ namespace FreeSql.Odbc.Dameng
 | 
				
			|||||||
        public OdbcDamengCodeFirst(IFreeSql orm, CommonUtils commonUtils, CommonExpression commonExpression) : base(orm, commonUtils, commonExpression) { }
 | 
					        public OdbcDamengCodeFirst(IFreeSql orm, CommonUtils commonUtils, CommonExpression commonExpression) : base(orm, commonUtils, commonExpression) { }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        static object _dicCsToDbLock = new object();
 | 
					        static object _dicCsToDbLock = new object();
 | 
				
			||||||
        static Dictionary<string, (OdbcType type, string dbtype, string dbtypeFull, bool? isUnsigned, bool? isnullable, object defaultValue)> _dicCsToDb = new Dictionary<string, (OdbcType type, string dbtype, string dbtypeFull, bool? isUnsigned, bool? isnullable, object defaultValue)>() {
 | 
					        static Dictionary<string, CsToDb<OdbcType>> _dicCsToDb = new Dictionary<string, CsToDb<OdbcType>>() {
 | 
				
			||||||
                { typeof(bool).FullName,  (OdbcType.Bit, "number","number(1) NOT NULL", null, false, false) },{ typeof(bool?).FullName,  (OdbcType.Bit, "number","number(1) NULL", null, true, null) },
 | 
					                { typeof(bool).FullName, CsToDb.New(OdbcType.Bit, "number","number(1) NOT NULL", null, false, false) },{ typeof(bool?).FullName, CsToDb.New(OdbcType.Bit, "number","number(1) NULL", null, true, null) },
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                { typeof(sbyte).FullName,  (OdbcType.SmallInt, "number", "number(4) NOT NULL", false, false, 0) },{ typeof(sbyte?).FullName,  (OdbcType.SmallInt, "number", "number(4) NULL", false, true, null) },
 | 
					                { typeof(sbyte).FullName, CsToDb.New(OdbcType.SmallInt, "number", "number(4) NOT NULL", false, false, 0) },{ typeof(sbyte?).FullName, CsToDb.New(OdbcType.SmallInt, "number", "number(4) NULL", false, true, null) },
 | 
				
			||||||
                { typeof(short).FullName,  (OdbcType.SmallInt, "number","number(6) NOT NULL", false, false, 0) },{ typeof(short?).FullName,  (OdbcType.SmallInt, "number", "number(6) NULL", false, true, null) },
 | 
					                { typeof(short).FullName, CsToDb.New(OdbcType.SmallInt, "number","number(6) NOT NULL", false, false, 0) },{ typeof(short?).FullName, CsToDb.New(OdbcType.SmallInt, "number", "number(6) NULL", false, true, null) },
 | 
				
			||||||
                { typeof(int).FullName,  (OdbcType.Int, "number", "number(11) NOT NULL", false, false, 0) },{ typeof(int?).FullName,  (OdbcType.Int, "number", "number(11) NULL", false, true, null) },
 | 
					                { typeof(int).FullName, CsToDb.New(OdbcType.Int, "number", "number(11) NOT NULL", false, false, 0) },{ typeof(int?).FullName, CsToDb.New(OdbcType.Int, "number", "number(11) NULL", false, true, null) },
 | 
				
			||||||
                { typeof(long).FullName,  (OdbcType.BigInt, "number","number(21) NOT NULL", false, false, 0) },{ typeof(long?).FullName,  (OdbcType.BigInt, "number","number(21) NULL", false, true, null) },
 | 
					                { typeof(long).FullName, CsToDb.New(OdbcType.BigInt, "number","number(21) NOT NULL", false, false, 0) },{ typeof(long?).FullName, CsToDb.New(OdbcType.BigInt, "number","number(21) NULL", false, true, null) },
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                { typeof(byte).FullName,  (OdbcType.TinyInt, "number","number(3) NOT NULL", true, false, 0) },{ typeof(byte?).FullName,  (OdbcType.TinyInt, "number","number(3) NULL", true, true, null) },
 | 
					                { typeof(byte).FullName, CsToDb.New(OdbcType.TinyInt, "number","number(3) NOT NULL", true, false, 0) },{ typeof(byte?).FullName, CsToDb.New(OdbcType.TinyInt, "number","number(3) NULL", true, true, null) },
 | 
				
			||||||
                { typeof(ushort).FullName,  (OdbcType.Int, "number","number(5) NOT NULL", true, false, 0) },{ typeof(ushort?).FullName,  (OdbcType.Int, "number", "number(5) NULL", true, true, null) },
 | 
					                { typeof(ushort).FullName, CsToDb.New(OdbcType.Int, "number","number(5) NOT NULL", true, false, 0) },{ typeof(ushort?).FullName, CsToDb.New(OdbcType.Int, "number", "number(5) NULL", true, true, null) },
 | 
				
			||||||
                { typeof(uint).FullName,  (OdbcType.BigInt, "number", "number(10) NOT NULL", true, false, 0) },{ typeof(uint?).FullName,  (OdbcType.BigInt, "number", "number(10) NULL", true, true, null) },
 | 
					                { typeof(uint).FullName, CsToDb.New(OdbcType.BigInt, "number", "number(10) NOT NULL", true, false, 0) },{ typeof(uint?).FullName, CsToDb.New(OdbcType.BigInt, "number", "number(10) NULL", true, true, null) },
 | 
				
			||||||
                { typeof(ulong).FullName,  (OdbcType.Decimal, "number", "number(20) NOT NULL", true, false, 0) },{ typeof(ulong?).FullName,  (OdbcType.Decimal, "number", "number(20) NULL", true, true, null) },
 | 
					                { typeof(ulong).FullName, CsToDb.New(OdbcType.Decimal, "number", "number(20) NOT NULL", true, false, 0) },{ typeof(ulong?).FullName, CsToDb.New(OdbcType.Decimal, "number", "number(20) NULL", true, true, null) },
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                { typeof(double).FullName,  (OdbcType.Double, "double", "double NOT NULL", false, false, 0) },{ typeof(double?).FullName,  (OdbcType.Double, "double", "double NULL", false, true, null) },
 | 
					                { typeof(double).FullName, CsToDb.New(OdbcType.Double, "double", "double NOT NULL", false, false, 0) },{ typeof(double?).FullName, CsToDb.New(OdbcType.Double, "double", "double NULL", false, true, null) },
 | 
				
			||||||
                { typeof(float).FullName,  (OdbcType.Real, "real","real NOT NULL", false, false, 0) },{ typeof(float?).FullName,  (OdbcType.Real, "real","real NULL", false, true, null) },
 | 
					                { typeof(float).FullName, CsToDb.New(OdbcType.Real, "real","real NOT NULL", false, false, 0) },{ typeof(float?).FullName, CsToDb.New(OdbcType.Real, "real","real NULL", false, true, null) },
 | 
				
			||||||
                { typeof(decimal).FullName,  (OdbcType.Decimal, "number", "number(10,2) NOT NULL", false, false, 0) },{ typeof(decimal?).FullName,  (OdbcType.Decimal, "number", "number(10,2) NULL", false, true, null) },
 | 
					                { typeof(decimal).FullName, CsToDb.New(OdbcType.Decimal, "number", "number(10,2) NOT NULL", false, false, 0) },{ typeof(decimal?).FullName, CsToDb.New(OdbcType.Decimal, "number", "number(10,2) NULL", false, true, null) },
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                //达梦8 ODBC 不支持 TimeSpan
 | 
					                //达梦8 ODBC 不支持 TimeSpan
 | 
				
			||||||
                //{ typeof(TimeSpan).FullName,  (OdbcType.Time, "interval day to second","interval day(2) to second(6) NOT NULL", false, false, 0) },{ typeof(TimeSpan?).FullName,  (OdbcType.Time, "interval day to second", "interval day(2) to second(6) NULL",false, true, null) },
 | 
					                //{ typeof(TimeSpan).FullName, CsToDb.NewInfo(OdbcType.Time, "interval day to second","interval day(2) to second(6) NOT NULL", false, false, 0) },{ typeof(TimeSpan?).FullName,  (OdbcType.Time, "interval day to second", "interval day(2) to second(6) NULL",false, true, null) },
 | 
				
			||||||
                { typeof(DateTime).FullName,  (OdbcType.DateTime, "timestamp", "timestamp(6) NOT NULL", false, false, new DateTime(1970,1,1)) },{ typeof(DateTime?).FullName,  (OdbcType.DateTime, "timestamp", "timestamp(6) NULL", false, true, null) },
 | 
					                { typeof(DateTime).FullName, CsToDb.New(OdbcType.DateTime, "timestamp", "timestamp(6) NOT NULL", false, false, new DateTime(1970,1,1)) },{ typeof(DateTime?).FullName, CsToDb.New(OdbcType.DateTime, "timestamp", "timestamp(6) NULL", false, true, null) },
 | 
				
			||||||
                { typeof(DateTimeOffset).FullName,  (OdbcType.DateTime, "timestamp", "timestamp(6) NOT NULL", false, false, new DateTime(1970,1,1)) },{ typeof(DateTimeOffset?).FullName,  (OdbcType.DateTime, "timestamp", "timestamp(6) NULL", false, true, null) },
 | 
					                { typeof(DateTimeOffset).FullName, CsToDb.New(OdbcType.DateTime, "timestamp", "timestamp(6) NOT NULL", false, false, new DateTime(1970,1,1)) },{ typeof(DateTimeOffset?).FullName, CsToDb.New(OdbcType.DateTime, "timestamp", "timestamp(6) NULL", false, true, null) },
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                { typeof(byte[]).FullName,  (OdbcType.VarBinary, "blob", "blob NULL", false, null, new byte[0]) },
 | 
					                { typeof(byte[]).FullName, CsToDb.New(OdbcType.VarBinary, "blob", "blob NULL", false, null, new byte[0]) },
 | 
				
			||||||
                { typeof(string).FullName,  (OdbcType.NVarChar, "nvarchar2", "nvarchar2(255) NULL", false, null, "") },
 | 
					                { typeof(string).FullName, CsToDb.New(OdbcType.NVarChar, "nvarchar2", "nvarchar2(255) NULL", false, null, "") },
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                { typeof(Guid).FullName,  (OdbcType.Char, "char", "char(36) NOT NULL", false, false, Guid.Empty) },{ typeof(Guid?).FullName,  (OdbcType.Char, "char", "char(36) NULL", false, true, null) },
 | 
					                { typeof(Guid).FullName, CsToDb.New(OdbcType.Char, "char", "char(36) NOT NULL", false, false, Guid.Empty) },{ typeof(Guid?).FullName, CsToDb.New(OdbcType.Char, "char", "char(36) NULL", false, true, null) },
 | 
				
			||||||
            };
 | 
					            };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        public override (int type, string dbtype, string dbtypeFull, bool? isnullable, object defaultValue)? GetDbInfo(Type type)
 | 
					        public override DbInfoResult 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 (_dicCsToDb.TryGetValue(type.FullName, out var trydc)) return new DbInfoResult((int)trydc.type, trydc.dbtype, trydc.dbtypeFull, trydc.isnullable, trydc.defaultValue);
 | 
				
			||||||
            if (type.IsArray) return null;
 | 
					            if (type.IsArray) return null;
 | 
				
			||||||
            var enumType = type.IsEnum ? type : null;
 | 
					            var enumType = type.IsEnum ? type : null;
 | 
				
			||||||
            if (enumType == null && type.IsNullableType())
 | 
					            if (enumType == null && type.IsNullableType())
 | 
				
			||||||
@@ -60,8 +60,8 @@ namespace FreeSql.Odbc.Dameng
 | 
				
			|||||||
            if (enumType != null)
 | 
					            if (enumType != null)
 | 
				
			||||||
            {
 | 
					            {
 | 
				
			||||||
                var newItem = enumType.GetCustomAttributes(typeof(FlagsAttribute), false).Any() ?
 | 
					                var newItem = enumType.GetCustomAttributes(typeof(FlagsAttribute), false).Any() ?
 | 
				
			||||||
                    (OdbcType.Int, "number", $"number(16){(type.IsEnum ? " NOT NULL" : "")}", false, type.IsEnum ? false : true, Enum.GetValues(enumType).GetValue(0)) :
 | 
					                    CsToDb.New(OdbcType.Int, "number", $"number(16){(type.IsEnum ? " NOT NULL" : "")}", false, type.IsEnum ? false : true, Enum.GetValues(enumType).GetValue(0)) :
 | 
				
			||||||
                    (OdbcType.BigInt, "number", $"number(32){(type.IsEnum ? " NOT NULL" : "")}", false, type.IsEnum ? false : true, Enum.GetValues(enumType).GetValue(0));
 | 
					                    CsToDb.New(OdbcType.BigInt, "number", $"number(32){(type.IsEnum ? " NOT NULL" : "")}", false, type.IsEnum ? false : true, Enum.GetValues(enumType).GetValue(0));
 | 
				
			||||||
                if (_dicCsToDb.ContainsKey(type.FullName) == false)
 | 
					                if (_dicCsToDb.ContainsKey(type.FullName) == false)
 | 
				
			||||||
                {
 | 
					                {
 | 
				
			||||||
                    lock (_dicCsToDbLock)
 | 
					                    lock (_dicCsToDbLock)
 | 
				
			||||||
@@ -70,12 +70,12 @@ namespace FreeSql.Odbc.Dameng
 | 
				
			|||||||
                            _dicCsToDb.Add(type.FullName, newItem);
 | 
					                            _dicCsToDb.Add(type.FullName, newItem);
 | 
				
			||||||
                    }
 | 
					                    }
 | 
				
			||||||
                }
 | 
					                }
 | 
				
			||||||
                return ((int)newItem.Item1, newItem.Item2, newItem.Item3, newItem.Item5, newItem.Item6);
 | 
					                return new DbInfoResult((int)newItem.type, newItem.dbtype, newItem.dbtypeFull, newItem.isnullable, newItem.defaultValue);
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
            return null;
 | 
					            return null;
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        protected override string GetComparisonDDLStatements(params (Type entityType, string tableName)[] objects)
 | 
					        protected override string GetComparisonDDLStatements(params TypeAndName[] objects)
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
            var userId = (_orm.Ado.MasterPool as OdbcDamengConnectionPool)?.UserId;
 | 
					            var userId = (_orm.Ado.MasterPool as OdbcDamengConnectionPool)?.UserId;
 | 
				
			||||||
            if (string.IsNullOrEmpty(userId))
 | 
					            if (string.IsNullOrEmpty(userId))
 | 
				
			||||||
@@ -83,7 +83,7 @@ namespace FreeSql.Odbc.Dameng
 | 
				
			|||||||
                {
 | 
					                {
 | 
				
			||||||
                    userId = OdbcDamengConnectionPool.GetUserId(conn.Value.ConnectionString);
 | 
					                    userId = OdbcDamengConnectionPool.GetUserId(conn.Value.ConnectionString);
 | 
				
			||||||
                }
 | 
					                }
 | 
				
			||||||
            var seqcols = new List<(ColumnInfo, string[], bool)>(); //序列:列,表,自增
 | 
					            var seqcols = new List<NaviteTuple<ColumnInfo, string[], bool>>(); //序列:列,表,自增
 | 
				
			||||||
            var seqnameDel = new List<string>(); //要删除的序列+触发器
 | 
					            var seqnameDel = new List<string>(); //要删除的序列+触发器
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            var sb = new StringBuilder();
 | 
					            var sb = new StringBuilder();
 | 
				
			||||||
@@ -134,7 +134,7 @@ namespace FreeSql.Odbc.Dameng
 | 
				
			|||||||
                        foreach (var tbcol in tb.ColumnsByPosition)
 | 
					                        foreach (var tbcol in tb.ColumnsByPosition)
 | 
				
			||||||
                        {
 | 
					                        {
 | 
				
			||||||
                            sb.Append(" \r\n  ").Append(_commonUtils.QuoteSqlName(tbcol.Attribute.Name)).Append(" ").Append(tbcol.Attribute.DbType).Append(",");
 | 
					                            sb.Append(" \r\n  ").Append(_commonUtils.QuoteSqlName(tbcol.Attribute.Name)).Append(" ").Append(tbcol.Attribute.DbType).Append(",");
 | 
				
			||||||
                            if (tbcol.Attribute.IsIdentity == true) seqcols.Add((tbcol, tbname, true));
 | 
					                            if (tbcol.Attribute.IsIdentity == true) seqcols.Add(NaviteTuple.Create(tbcol, tbname, true));
 | 
				
			||||||
                        }
 | 
					                        }
 | 
				
			||||||
                        if (tb.Primarys.Any())
 | 
					                        if (tb.Primarys.Any())
 | 
				
			||||||
                        {
 | 
					                        {
 | 
				
			||||||
@@ -234,10 +234,10 @@ where a.owner={{0}} and a.table_name={{1}}", tboldname ?? tbname);
 | 
				
			|||||||
                                //修改列名
 | 
					                                //修改列名
 | 
				
			||||||
                                sbalter.Append("execute immediate 'ALTER TABLE ").Append(_commonUtils.QuoteSqlName($"{tbname[0]}.{tbname[1]}")).Append(" RENAME COLUMN ").Append(_commonUtils.QuoteSqlName(tbstructcol.column)).Append(" TO ").Append(_commonUtils.QuoteSqlName(tbcol.Attribute.Name)).Append("';\r\n");
 | 
					                                sbalter.Append("execute immediate 'ALTER TABLE ").Append(_commonUtils.QuoteSqlName($"{tbname[0]}.{tbname[1]}")).Append(" RENAME COLUMN ").Append(_commonUtils.QuoteSqlName(tbstructcol.column)).Append(" TO ").Append(_commonUtils.QuoteSqlName(tbcol.Attribute.Name)).Append("';\r\n");
 | 
				
			||||||
                                if (tbcol.Attribute.IsIdentity)
 | 
					                                if (tbcol.Attribute.IsIdentity)
 | 
				
			||||||
                                    seqcols.Add((tbcol, tbname, tbcol.Attribute.IsIdentity == true));
 | 
					                                    seqcols.Add(NaviteTuple.Create(tbcol, tbname, tbcol.Attribute.IsIdentity == true));
 | 
				
			||||||
                            }
 | 
					                            }
 | 
				
			||||||
                            else if (tbcol.Attribute.IsIdentity != tbstructcol.is_identity)
 | 
					                            else if (tbcol.Attribute.IsIdentity != tbstructcol.is_identity)
 | 
				
			||||||
                                seqcols.Add((tbcol, tbname, tbcol.Attribute.IsIdentity == true));
 | 
					                                seqcols.Add(NaviteTuple.Create(tbcol, tbname, tbcol.Attribute.IsIdentity == true));
 | 
				
			||||||
                            if (isCommentChanged)
 | 
					                            if (isCommentChanged)
 | 
				
			||||||
                                sbalter.Append("execute immediate 'COMMENT ON COLUMN ").Append(_commonUtils.QuoteSqlName($"{tbname[0]}.{tbname[1]}.{tbcol.Attribute.Name}")).Append(" IS ").Append(_commonUtils.FormatSql("{0}", tbcol.Comment ?? "").Replace("'", "''")).Append("';\r\n");
 | 
					                                sbalter.Append("execute immediate 'COMMENT ON COLUMN ").Append(_commonUtils.QuoteSqlName($"{tbname[0]}.{tbname[1]}.{tbcol.Attribute.Name}")).Append(" IS ").Append(_commonUtils.FormatSql("{0}", tbcol.Comment ?? "").Replace("'", "''")).Append("';\r\n");
 | 
				
			||||||
                            continue;
 | 
					                            continue;
 | 
				
			||||||
@@ -249,7 +249,7 @@ where a.owner={{0}} and a.table_name={{1}}", tboldname ?? tbname);
 | 
				
			|||||||
                            sbalter.Append("execute immediate 'UPDATE ").Append(_commonUtils.QuoteSqlName($"{tbname[0]}.{tbname[1]}")).Append(" SET ").Append(_commonUtils.QuoteSqlName(tbcol.Attribute.Name)).Append(" = ").Append(tbcol.DbDefaultValue.Replace("'", "''")).Append("';\r\n");
 | 
					                            sbalter.Append("execute immediate 'UPDATE ").Append(_commonUtils.QuoteSqlName($"{tbname[0]}.{tbname[1]}")).Append(" SET ").Append(_commonUtils.QuoteSqlName(tbcol.Attribute.Name)).Append(" = ").Append(tbcol.DbDefaultValue.Replace("'", "''")).Append("';\r\n");
 | 
				
			||||||
                            sbalter.Append("execute immediate 'ALTER TABLE ").Append(_commonUtils.QuoteSqlName($"{tbname[0]}.{tbname[1]}")).Append(" MODIFY ").Append(_commonUtils.QuoteSqlName(tbcol.Attribute.Name)).Append(" NOT NULL';\r\n");
 | 
					                            sbalter.Append("execute immediate 'ALTER TABLE ").Append(_commonUtils.QuoteSqlName($"{tbname[0]}.{tbname[1]}")).Append(" MODIFY ").Append(_commonUtils.QuoteSqlName(tbcol.Attribute.Name)).Append(" NOT NULL';\r\n");
 | 
				
			||||||
                        }
 | 
					                        }
 | 
				
			||||||
                        if (tbcol.Attribute.IsIdentity == true) seqcols.Add((tbcol, tbname, tbcol.Attribute.IsIdentity == true));
 | 
					                        if (tbcol.Attribute.IsIdentity == true) seqcols.Add(NaviteTuple.Create(tbcol, tbname, tbcol.Attribute.IsIdentity == true));
 | 
				
			||||||
                        if (string.IsNullOrEmpty(tbcol.Comment) == false) sbalter.Append("execute immediate 'COMMENT ON COLUMN ").Append(_commonUtils.QuoteSqlName($"{tbname[0]}.{tbname[1]}.{tbcol.Attribute.Name}")).Append(" IS ").Append(_commonUtils.FormatSql("{0}", tbcol.Comment ?? "").Replace("'", "''")).Append("';\r\n");
 | 
					                        if (string.IsNullOrEmpty(tbcol.Comment) == false) sbalter.Append("execute immediate 'COMMENT ON COLUMN ").Append(_commonUtils.QuoteSqlName($"{tbname[0]}.{tbname[1]}.{tbcol.Attribute.Name}")).Append(" IS ").Append(_commonUtils.FormatSql("{0}", tbcol.Comment ?? "").Replace("'", "''")).Append("';\r\n");
 | 
				
			||||||
                    }
 | 
					                    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -304,7 +304,7 @@ and not exists(select 1 from all_constraints where index_name = a.index_name and
 | 
				
			|||||||
                foreach (var tbcol in tb.ColumnsByPosition)
 | 
					                foreach (var tbcol in tb.ColumnsByPosition)
 | 
				
			||||||
                {
 | 
					                {
 | 
				
			||||||
                    sb.Append(" \r\n  ").Append(_commonUtils.QuoteSqlName(tbcol.Attribute.Name)).Append(" ").Append(tbcol.Attribute.DbType).Append(",");
 | 
					                    sb.Append(" \r\n  ").Append(_commonUtils.QuoteSqlName(tbcol.Attribute.Name)).Append(" ").Append(tbcol.Attribute.DbType).Append(",");
 | 
				
			||||||
                    if (tbcol.Attribute.IsIdentity == true) seqcols.Add((tbcol, tbname, true));
 | 
					                    if (tbcol.Attribute.IsIdentity == true) seqcols.Add(NaviteTuple.Create(tbcol, tbname, true));
 | 
				
			||||||
                }
 | 
					                }
 | 
				
			||||||
                if (tb.Primarys.Any())
 | 
					                if (tb.Primarys.Any())
 | 
				
			||||||
                {
 | 
					                {
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,5 +1,6 @@
 | 
				
			|||||||
using FreeSql.DatabaseModel;
 | 
					using FreeSql.DatabaseModel;
 | 
				
			||||||
using FreeSql.Internal;
 | 
					using FreeSql.Internal;
 | 
				
			||||||
 | 
					using FreeSql.Internal.Model;
 | 
				
			||||||
using System;
 | 
					using System;
 | 
				
			||||||
using System.Collections.Concurrent;
 | 
					using System.Collections.Concurrent;
 | 
				
			||||||
using System.Collections.Generic;
 | 
					using System.Collections.Generic;
 | 
				
			||||||
@@ -161,35 +162,35 @@ namespace FreeSql.Odbc.Dameng
 | 
				
			|||||||
            throw new NotImplementedException($"未实现 {column.DbTypeTextFull} 类型映射");
 | 
					            throw new NotImplementedException($"未实现 {column.DbTypeTextFull} 类型映射");
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        static ConcurrentDictionary<string, (string csConvert, string csParse, string csStringify, string csType, Type csTypeInfo, Type csNullableTypeInfo, string csTypeValue, string dataReaderMethod)> _dicDbToCs = new ConcurrentDictionary<string, (string csConvert, string csParse, string csStringify, string csType, Type csTypeInfo, Type csNullableTypeInfo, string csTypeValue, string dataReaderMethod)>(StringComparer.CurrentCultureIgnoreCase);
 | 
					        static ConcurrentDictionary<string, DbToCs> _dicDbToCs = new ConcurrentDictionary<string, DbToCs>(StringComparer.CurrentCultureIgnoreCase);
 | 
				
			||||||
        static OdbcDamengDbFirst()
 | 
					        static OdbcDamengDbFirst()
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
            var defaultDbToCs = new Dictionary<string, (string csConvert, string csParse, string csStringify, string csType, Type csTypeInfo, Type csNullableTypeInfo, string csTypeValue, string dataReaderMethod)>() {
 | 
					            var defaultDbToCs = new Dictionary<string, DbToCs>() {
 | 
				
			||||||
                { "number(1)", ("(bool?)", "{0} == \"1\"", "{0} == true ? \"1\" : \"0\"", "bool?", typeof(bool), typeof(bool?), "{0}.Value", "GetBoolean") },
 | 
					                { "number(1)", new DbToCs("(bool?)", "{0} == \"1\"", "{0} == true ? \"1\" : \"0\"", "bool?", typeof(bool), typeof(bool?), "{0}.Value", "GetBoolean") },
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                { "number(4)", ("(sbyte?)", "sbyte.Parse({0})", "{0}.ToString()", "sbyte?", typeof(sbyte), typeof(sbyte?), "{0}.Value", "GetInt16") },
 | 
					                { "number(4)", new DbToCs("(sbyte?)", "sbyte.Parse({0})", "{0}.ToString()", "sbyte?", typeof(sbyte), typeof(sbyte?), "{0}.Value", "GetInt16") },
 | 
				
			||||||
                { "number(6)", ("(short?)", "short.Parse({0})", "{0}.ToString()", "short?", typeof(short), typeof(short?), "{0}.Value", "GetInt16") },
 | 
					                { "number(6)", new DbToCs("(short?)", "short.Parse({0})", "{0}.ToString()", "short?", typeof(short), typeof(short?), "{0}.Value", "GetInt16") },
 | 
				
			||||||
                { "number(11)", ("(int?)", "int.Parse({0})", "{0}.ToString()", "int?", typeof(int), typeof(int?), "{0}.Value", "GetInt32") },
 | 
					                { "number(11)", new DbToCs("(int?)", "int.Parse({0})", "{0}.ToString()", "int?", typeof(int), typeof(int?), "{0}.Value", "GetInt32") },
 | 
				
			||||||
                { "number(21)", ("(long?)", "long.Parse({0})", "{0}.ToString()", "long?", typeof(long), typeof(long?), "{0}.Value", "GetInt64") },
 | 
					                { "number(21)", new DbToCs("(long?)", "long.Parse({0})", "{0}.ToString()", "long?", typeof(long), typeof(long?), "{0}.Value", "GetInt64") },
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                { "number(3)", ("(byte?)", "byte.Parse({0})", "{0}.ToString()", "byte?", typeof(byte), typeof(byte?), "{0}.Value", "GetByte") },
 | 
					                { "number(3)", new DbToCs("(byte?)", "byte.Parse({0})", "{0}.ToString()", "byte?", typeof(byte), typeof(byte?), "{0}.Value", "GetByte") },
 | 
				
			||||||
                { "number(5)", ("(ushort?)", "ushort.Parse({0})", "{0}.ToString()", "ushort?", typeof(ushort), typeof(ushort?), "{0}.Value", "GetInt32") },
 | 
					                { "number(5)", new DbToCs("(ushort?)", "ushort.Parse({0})", "{0}.ToString()", "ushort?", typeof(ushort), typeof(ushort?), "{0}.Value", "GetInt32") },
 | 
				
			||||||
                { "number(10)", ("(uint?)", "uint.Parse({0})", "{0}.ToString()", "uint?", typeof(uint), typeof(uint?), "{0}.Value", "GetInt64") },
 | 
					                { "number(10)", new DbToCs("(uint?)", "uint.Parse({0})", "{0}.ToString()", "uint?", typeof(uint), typeof(uint?), "{0}.Value", "GetInt64") },
 | 
				
			||||||
                { "number(20)", ("(ulong?)", "ulong.Parse({0})", "{0}.ToString()", "ulong?", typeof(ulong), typeof(ulong?), "{0}.Value", "GetDecimal") },
 | 
					                { "number(20)", new DbToCs("(ulong?)", "ulong.Parse({0})", "{0}.ToString()", "ulong?", typeof(ulong), typeof(ulong?), "{0}.Value", "GetDecimal") },
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                { "float(126)", ("(double?)", "double.Parse({0})", "{0}.ToString()", "double?", typeof(double), typeof(double?), "{0}.Value", "GetDouble") },
 | 
					                { "float(126)", new DbToCs("(double?)", "double.Parse({0})", "{0}.ToString()", "double?", typeof(double), typeof(double?), "{0}.Value", "GetDouble") },
 | 
				
			||||||
                { "float(63)", ("(float?)", "float.Parse({0})", "{0}.ToString()", "float?", typeof(float), typeof(float?), "{0}.Value", "GetFloat") },
 | 
					                { "float(63)", new DbToCs("(float?)", "float.Parse({0})", "{0}.ToString()", "float?", typeof(float), typeof(float?), "{0}.Value", "GetFloat") },
 | 
				
			||||||
                { "number(10,2)", ("(decimal?)", "decimal.Parse({0})", "{0}.ToString()", "decimal?", typeof(decimal), typeof(decimal?), "{0}.Value", "GetDecimal") },
 | 
					                { "number(10,2)", new DbToCs("(decimal?)", "decimal.Parse({0})", "{0}.ToString()", "decimal?", typeof(decimal), typeof(decimal?), "{0}.Value", "GetDecimal") },
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                { "interval day(2) to second(6)", ("(TimeSpan?)", "TimeSpan.Parse(double.Parse({0}))", "{0}.Ticks.ToString()", "TimeSpan?", typeof(TimeSpan), typeof(TimeSpan?), "{0}.Value", "GetValue") },
 | 
					                { "interval day(2) to second(6)", new DbToCs("(TimeSpan?)", "TimeSpan.Parse(double.Parse({0}))", "{0}.Ticks.ToString()", "TimeSpan?", typeof(TimeSpan), typeof(TimeSpan?), "{0}.Value", "GetValue") },
 | 
				
			||||||
                { "date(7)", ("(DateTime?)", "new DateTime(long.Parse({0}))", "{0}.Ticks.ToString()", "DateTime?", typeof(DateTime), typeof(DateTime?), "{0}.Value", "GetValue") },
 | 
					                { "date(7)", new DbToCs("(DateTime?)", "new DateTime(long.Parse({0}))", "{0}.Ticks.ToString()", "DateTime?", typeof(DateTime), typeof(DateTime?), "{0}.Value", "GetValue") },
 | 
				
			||||||
                { "timestamp(6)", ("(DateTime?)", "new DateTime(long.Parse({0}))", "{0}.Ticks.ToString()", "DateTime?", typeof(DateTime), typeof(DateTime?), "{0}.Value", "GetValue") },
 | 
					                { "timestamp(6)", new DbToCs("(DateTime?)", "new DateTime(long.Parse({0}))", "{0}.Ticks.ToString()", "DateTime?", typeof(DateTime), typeof(DateTime?), "{0}.Value", "GetValue") },
 | 
				
			||||||
                { "timestamp(6) with local time zone", ("(DateTime?)", "new DateTime(long.Parse({0}))", "{0}.Ticks.ToString()", "DateTime?", typeof(DateTime), typeof(DateTime?), "{0}.Value", "GetValue") },
 | 
					                { "timestamp(6) with local time zone", new DbToCs("(DateTime?)", "new DateTime(long.Parse({0}))", "{0}.Ticks.ToString()", "DateTime?", typeof(DateTime), typeof(DateTime?), "{0}.Value", "GetValue") },
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                { "blob", ("(byte[])", "Convert.FromBase64String({0})", "Convert.ToBase64String({0})", "byte[]", typeof(byte[]), typeof(byte[]), "{0}", "GetValue") },
 | 
					                { "blob", new DbToCs("(byte[])", "Convert.FromBase64String({0})", "Convert.ToBase64String({0})", "byte[]", typeof(byte[]), typeof(byte[]), "{0}", "GetValue") },
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                { "nvarchar2(255)", ("", "{0}.Replace(StringifySplit, \"|\")", "{0}.Replace(\"|\", StringifySplit)", "string", typeof(string), typeof(string), "{0}", "GetString") },
 | 
					                { "nvarchar2(255)", new DbToCs("", "{0}.Replace(StringifySplit, \"|\")", "{0}.Replace(\"|\", StringifySplit)", "string", typeof(string), typeof(string), "{0}", "GetString") },
 | 
				
			||||||
                { "char(36 char)", ("(Guid?)", "Guid.Parse({0})", "{0}.ToString()", "Guid?", typeof(Guid), typeof(Guid?), "{0}.Value", "GetGuid") },
 | 
					                { "char(36 char)", new DbToCs("(Guid?)", "Guid.Parse({0})", "{0}.ToString()", "Guid?", typeof(Guid), typeof(Guid?), "{0}.Value", "GetGuid") },
 | 
				
			||||||
            };
 | 
					            };
 | 
				
			||||||
            foreach (var kv in defaultDbToCs)
 | 
					            foreach (var kv in defaultDbToCs)
 | 
				
			||||||
                _dicDbToCs.TryAdd(kv.Key, kv.Value);
 | 
					                _dicDbToCs.TryAdd(kv.Key, kv.Value);
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -22,9 +22,9 @@ namespace FreeSql.Odbc.Default
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
        OdbcUtils _utils;
 | 
					        OdbcUtils _utils;
 | 
				
			||||||
        object _dicCsToDbLock = new object();
 | 
					        object _dicCsToDbLock = new object();
 | 
				
			||||||
        Dictionary<string, (OdbcType type, string dbtype, string dbtypeFull, bool? isUnsigned, bool? isnullable, object defaultValue)> _dicCsToDb;
 | 
					        Dictionary<string, CsToDb<OdbcType>> _dicCsToDb;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        public override (int type, string dbtype, string dbtypeFull, bool? isnullable, object defaultValue)? GetDbInfo(Type type)
 | 
					        public override DbInfoResult GetDbInfo(Type type)
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
            if (_dicCsToDb == null)
 | 
					            if (_dicCsToDb == null)
 | 
				
			||||||
            {
 | 
					            {
 | 
				
			||||||
@@ -35,35 +35,35 @@ namespace FreeSql.Odbc.Default
 | 
				
			|||||||
                        var reg = new Regex(@"\([^\)]+\)", RegexOptions.IgnoreCase | RegexOptions.Compiled);
 | 
					                        var reg = new Regex(@"\([^\)]+\)", RegexOptions.IgnoreCase | RegexOptions.Compiled);
 | 
				
			||||||
                        Func<string, string> deleteBrackets = str => reg.Replace(str, "");
 | 
					                        Func<string, string> deleteBrackets = str => reg.Replace(str, "");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                        _dicCsToDb = new Dictionary<string, (OdbcType type, string dbtype, string dbtypeFull, bool? isUnsigned, bool? isnullable, object defaultValue)>() {
 | 
					                        _dicCsToDb = new Dictionary<string, CsToDb<OdbcType>>() {
 | 
				
			||||||
                            { typeof(bool).FullName,  (OdbcType.Bit, _utils.Adapter.MappingOdbcTypeBit,$"{_utils.Adapter.MappingOdbcTypeBit} NOT NULL", null, false, false) },{ typeof(bool?).FullName,  (OdbcType.Bit, _utils.Adapter.MappingOdbcTypeBit,_utils.Adapter.MappingOdbcTypeBit, null, true, null) },
 | 
					                            { typeof(bool).FullName, CsToDb.New(OdbcType.Bit, _utils.Adapter.MappingOdbcTypeBit,$"{_utils.Adapter.MappingOdbcTypeBit} NOT NULL", null, false, false) },{ typeof(bool?).FullName, CsToDb.New(OdbcType.Bit, _utils.Adapter.MappingOdbcTypeBit,_utils.Adapter.MappingOdbcTypeBit, null, true, null) },
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                            { typeof(sbyte).FullName,  (OdbcType.SmallInt, _utils.Adapter.MappingOdbcTypeSmallInt, $"{_utils.Adapter.MappingOdbcTypeSmallInt} NOT NULL", false, false, 0) },{ typeof(sbyte?).FullName,  (OdbcType.SmallInt, _utils.Adapter.MappingOdbcTypeSmallInt, _utils.Adapter.MappingOdbcTypeSmallInt, false, true, null) },
 | 
					                            { typeof(sbyte).FullName, CsToDb.New(OdbcType.SmallInt, _utils.Adapter.MappingOdbcTypeSmallInt, $"{_utils.Adapter.MappingOdbcTypeSmallInt} NOT NULL", false, false, 0) },{ typeof(sbyte?).FullName, CsToDb.New(OdbcType.SmallInt, _utils.Adapter.MappingOdbcTypeSmallInt, _utils.Adapter.MappingOdbcTypeSmallInt, false, true, null) },
 | 
				
			||||||
                            { typeof(short).FullName,  (OdbcType.SmallInt, _utils.Adapter.MappingOdbcTypeSmallInt,$"{_utils.Adapter.MappingOdbcTypeSmallInt} NOT NULL", false, false, 0) },{ typeof(short?).FullName,  (OdbcType.SmallInt, _utils.Adapter.MappingOdbcTypeSmallInt, _utils.Adapter.MappingOdbcTypeSmallInt, false, true, null) },
 | 
					                            { typeof(short).FullName, CsToDb.New(OdbcType.SmallInt, _utils.Adapter.MappingOdbcTypeSmallInt,$"{_utils.Adapter.MappingOdbcTypeSmallInt} NOT NULL", false, false, 0) },{ typeof(short?).FullName, CsToDb.New(OdbcType.SmallInt, _utils.Adapter.MappingOdbcTypeSmallInt, _utils.Adapter.MappingOdbcTypeSmallInt, false, true, null) },
 | 
				
			||||||
                            { typeof(int).FullName,  (OdbcType.Int, _utils.Adapter.MappingOdbcTypeInt, $"{_utils.Adapter.MappingOdbcTypeInt} NOT NULL", false, false, 0) },{ typeof(int?).FullName,  (OdbcType.Int, _utils.Adapter.MappingOdbcTypeInt, _utils.Adapter.MappingOdbcTypeInt, false, true, null) },
 | 
					                            { typeof(int).FullName, CsToDb.New(OdbcType.Int, _utils.Adapter.MappingOdbcTypeInt, $"{_utils.Adapter.MappingOdbcTypeInt} NOT NULL", false, false, 0) },{ typeof(int?).FullName, CsToDb.New(OdbcType.Int, _utils.Adapter.MappingOdbcTypeInt, _utils.Adapter.MappingOdbcTypeInt, false, true, null) },
 | 
				
			||||||
                            { typeof(long).FullName,  (OdbcType.BigInt, _utils.Adapter.MappingOdbcTypeBigInt,$"{_utils.Adapter.MappingOdbcTypeBigInt} NOT NULL", false, false, 0) },{ typeof(long?).FullName,  (OdbcType.BigInt, _utils.Adapter.MappingOdbcTypeBigInt,_utils.Adapter.MappingOdbcTypeBigInt, false, true, null) },
 | 
					                            { typeof(long).FullName, CsToDb.New(OdbcType.BigInt, _utils.Adapter.MappingOdbcTypeBigInt,$"{_utils.Adapter.MappingOdbcTypeBigInt} NOT NULL", false, false, 0) },{ typeof(long?).FullName, CsToDb.New(OdbcType.BigInt, _utils.Adapter.MappingOdbcTypeBigInt,_utils.Adapter.MappingOdbcTypeBigInt, false, true, null) },
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                            { typeof(byte).FullName,  (OdbcType.TinyInt, _utils.Adapter.MappingOdbcTypeTinyInt,$"{_utils.Adapter.MappingOdbcTypeTinyInt} NOT NULL", true, false, 0) },{ typeof(byte?).FullName,  (OdbcType.TinyInt, _utils.Adapter.MappingOdbcTypeTinyInt,_utils.Adapter.MappingOdbcTypeTinyInt, true, true, null) },
 | 
					                            { typeof(byte).FullName, CsToDb.New(OdbcType.TinyInt, _utils.Adapter.MappingOdbcTypeTinyInt,$"{_utils.Adapter.MappingOdbcTypeTinyInt} NOT NULL", true, false, 0) },{ typeof(byte?).FullName, CsToDb.New(OdbcType.TinyInt, _utils.Adapter.MappingOdbcTypeTinyInt,_utils.Adapter.MappingOdbcTypeTinyInt, true, true, null) },
 | 
				
			||||||
                            { typeof(ushort).FullName,  (OdbcType.Int, _utils.Adapter.MappingOdbcTypeInt,$"{_utils.Adapter.MappingOdbcTypeInt} NOT NULL", true, false, 0) },{ typeof(ushort?).FullName,  (OdbcType.Int, _utils.Adapter.MappingOdbcTypeInt, _utils.Adapter.MappingOdbcTypeInt, true, true, null) },
 | 
					                            { typeof(ushort).FullName, CsToDb.New(OdbcType.Int, _utils.Adapter.MappingOdbcTypeInt,$"{_utils.Adapter.MappingOdbcTypeInt} NOT NULL", true, false, 0) },{ typeof(ushort?).FullName, CsToDb.New(OdbcType.Int, _utils.Adapter.MappingOdbcTypeInt, _utils.Adapter.MappingOdbcTypeInt, true, true, null) },
 | 
				
			||||||
                            { typeof(uint).FullName,  (OdbcType.BigInt, _utils.Adapter.MappingOdbcTypeBigInt, $"{_utils.Adapter.MappingOdbcTypeBigInt} NOT NULL", true, false, 0) },{ typeof(uint?).FullName,  (OdbcType.BigInt, _utils.Adapter.MappingOdbcTypeBigInt, _utils.Adapter.MappingOdbcTypeBigInt, true, true, null) },
 | 
					                            { typeof(uint).FullName, CsToDb.New(OdbcType.BigInt, _utils.Adapter.MappingOdbcTypeBigInt, $"{_utils.Adapter.MappingOdbcTypeBigInt} NOT NULL", true, false, 0) },{ typeof(uint?).FullName, CsToDb.New(OdbcType.BigInt, _utils.Adapter.MappingOdbcTypeBigInt, _utils.Adapter.MappingOdbcTypeBigInt, true, true, null) },
 | 
				
			||||||
                            { typeof(ulong).FullName,  (OdbcType.Decimal, _utils.Adapter.MappingOdbcTypeDecimal, $"{_utils.Adapter.MappingOdbcTypeDecimal}(20,0) NOT NULL", true, false, 0) },{ typeof(ulong?).FullName,  (OdbcType.Decimal, _utils.Adapter.MappingOdbcTypeDecimal, $"{_utils.Adapter.MappingOdbcTypeDecimal}(20,0)", true, true, null) },
 | 
					                            { typeof(ulong).FullName, CsToDb.New(OdbcType.Decimal, _utils.Adapter.MappingOdbcTypeDecimal, $"{_utils.Adapter.MappingOdbcTypeDecimal}(20,0) NOT NULL", true, false, 0) },{ typeof(ulong?).FullName, CsToDb.New(OdbcType.Decimal, _utils.Adapter.MappingOdbcTypeDecimal, $"{_utils.Adapter.MappingOdbcTypeDecimal}(20,0)", true, true, null) },
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                            { typeof(double).FullName,  (OdbcType.Double, _utils.Adapter.MappingOdbcTypeDouble, $"{_utils.Adapter.MappingOdbcTypeDouble} NOT NULL", false, false, 0) },{ typeof(double?).FullName,  (OdbcType.Double, _utils.Adapter.MappingOdbcTypeDouble, _utils.Adapter.MappingOdbcTypeDouble, false, true, null) },
 | 
					                            { typeof(double).FullName, CsToDb.New(OdbcType.Double, _utils.Adapter.MappingOdbcTypeDouble, $"{_utils.Adapter.MappingOdbcTypeDouble} NOT NULL", false, false, 0) },{ typeof(double?).FullName, CsToDb.New(OdbcType.Double, _utils.Adapter.MappingOdbcTypeDouble, _utils.Adapter.MappingOdbcTypeDouble, false, true, null) },
 | 
				
			||||||
                            { typeof(float).FullName,  (OdbcType.Real, _utils.Adapter.MappingOdbcTypeReal,$"{_utils.Adapter.MappingOdbcTypeReal} NOT NULL", false, false, 0) },{ typeof(float?).FullName,  (OdbcType.Real, _utils.Adapter.MappingOdbcTypeReal,_utils.Adapter.MappingOdbcTypeReal, false, true, null) },
 | 
					                            { typeof(float).FullName, CsToDb.New(OdbcType.Real, _utils.Adapter.MappingOdbcTypeReal,$"{_utils.Adapter.MappingOdbcTypeReal} NOT NULL", false, false, 0) },{ typeof(float?).FullName, CsToDb.New(OdbcType.Real, _utils.Adapter.MappingOdbcTypeReal,_utils.Adapter.MappingOdbcTypeReal, false, true, null) },
 | 
				
			||||||
                            { typeof(decimal).FullName,  (OdbcType.Decimal, _utils.Adapter.MappingOdbcTypeDecimal, $"{_utils.Adapter.MappingOdbcTypeDecimal}(10,2) NOT NULL", false, false, 0) },{ typeof(decimal?).FullName,  (OdbcType.Decimal, _utils.Adapter.MappingOdbcTypeDecimal, $"{_utils.Adapter.MappingOdbcTypeDecimal}(10,2)", false, true, null) },
 | 
					                            { typeof(decimal).FullName, CsToDb.New(OdbcType.Decimal, _utils.Adapter.MappingOdbcTypeDecimal, $"{_utils.Adapter.MappingOdbcTypeDecimal}(10,2) NOT NULL", false, false, 0) },{ typeof(decimal?).FullName, CsToDb.New(OdbcType.Decimal, _utils.Adapter.MappingOdbcTypeDecimal, $"{_utils.Adapter.MappingOdbcTypeDecimal}(10,2)", false, true, null) },
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                            { typeof(DateTime).FullName,  (OdbcType.DateTime, _utils.Adapter.MappingOdbcTypeDateTime, $"{_utils.Adapter.MappingOdbcTypeDateTime} NOT NULL", false, false, new DateTime(1970,1,1)) },{ typeof(DateTime?).FullName,  (OdbcType.DateTime, _utils.Adapter.MappingOdbcTypeDateTime, _utils.Adapter.MappingOdbcTypeDateTime, false, true, null) },
 | 
					                            { typeof(DateTime).FullName, CsToDb.New(OdbcType.DateTime, _utils.Adapter.MappingOdbcTypeDateTime, $"{_utils.Adapter.MappingOdbcTypeDateTime} NOT NULL", false, false, new DateTime(1970,1,1)) },{ typeof(DateTime?).FullName, CsToDb.New(OdbcType.DateTime, _utils.Adapter.MappingOdbcTypeDateTime, _utils.Adapter.MappingOdbcTypeDateTime, false, true, null) },
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                            { typeof(byte[]).FullName,  (OdbcType.VarBinary, _utils.Adapter.MappingOdbcTypeVarBinary, $"{_utils.Adapter.MappingOdbcTypeVarBinary}(255)", false, null, new byte[0]) },
 | 
					                            { typeof(byte[]).FullName, CsToDb.New(OdbcType.VarBinary, _utils.Adapter.MappingOdbcTypeVarBinary, $"{_utils.Adapter.MappingOdbcTypeVarBinary}(255)", false, null, new byte[0]) },
 | 
				
			||||||
                            { typeof(string).FullName,  (OdbcType.VarChar, _utils.Adapter.MappingOdbcTypeVarChar, $"{_utils.Adapter.MappingOdbcTypeVarChar}(255)", false, null, "") },
 | 
					                            { typeof(string).FullName, CsToDb.New(OdbcType.VarChar, _utils.Adapter.MappingOdbcTypeVarChar, $"{_utils.Adapter.MappingOdbcTypeVarChar}(255)", false, null, "") },
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                            { typeof(Guid).FullName,  (OdbcType.UniqueIdentifier, deleteBrackets(_utils.Adapter.MappingOdbcTypeUniqueIdentifier), $"{_utils.Adapter.MappingOdbcTypeUniqueIdentifier} NOT NULL", false, false, Guid.Empty) },{ typeof(Guid?).FullName,  (OdbcType.UniqueIdentifier, deleteBrackets(_utils.Adapter.MappingOdbcTypeUniqueIdentifier), _utils.Adapter.MappingOdbcTypeUniqueIdentifier, false, true, null) },
 | 
					                            { typeof(Guid).FullName, CsToDb.New(OdbcType.UniqueIdentifier, deleteBrackets(_utils.Adapter.MappingOdbcTypeUniqueIdentifier), $"{_utils.Adapter.MappingOdbcTypeUniqueIdentifier} NOT NULL", false, false, Guid.Empty) },{ typeof(Guid?).FullName, CsToDb.New(OdbcType.UniqueIdentifier, deleteBrackets(_utils.Adapter.MappingOdbcTypeUniqueIdentifier), _utils.Adapter.MappingOdbcTypeUniqueIdentifier, false, true, null) },
 | 
				
			||||||
                        };
 | 
					                        };
 | 
				
			||||||
                    }
 | 
					                    }
 | 
				
			||||||
                }
 | 
					                }
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            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 (_dicCsToDb.TryGetValue(type.FullName, out var trydc)) return new DbInfoResult((int)trydc.type, trydc.dbtype, trydc.dbtypeFull, trydc.isnullable, trydc.defaultValue);
 | 
				
			||||||
            if (type.IsArray) return null;
 | 
					            if (type.IsArray) return null;
 | 
				
			||||||
            var enumType = type.IsEnum ? type : null;
 | 
					            var enumType = type.IsEnum ? type : null;
 | 
				
			||||||
            if (enumType == null && type.IsNullableType())
 | 
					            if (enumType == null && type.IsNullableType())
 | 
				
			||||||
@@ -74,8 +74,8 @@ namespace FreeSql.Odbc.Default
 | 
				
			|||||||
            if (enumType != null)
 | 
					            if (enumType != null)
 | 
				
			||||||
            {
 | 
					            {
 | 
				
			||||||
                var newItem = enumType.GetCustomAttributes(typeof(FlagsAttribute), false).Any() ?
 | 
					                var newItem = enumType.GetCustomAttributes(typeof(FlagsAttribute), false).Any() ?
 | 
				
			||||||
                    (OdbcType.BigInt, _utils.Adapter.MappingOdbcTypeBigInt, $"{_utils.Adapter.MappingOdbcTypeBigInt}{(type.IsEnum ? " NOT NULL" : "")}", false, type.IsEnum ? false : true, Enum.GetValues(enumType).GetValue(0)) :
 | 
					                    CsToDb.New(OdbcType.BigInt, _utils.Adapter.MappingOdbcTypeBigInt, $"{_utils.Adapter.MappingOdbcTypeBigInt}{(type.IsEnum ? " NOT NULL" : "")}", false, type.IsEnum ? false : true, Enum.GetValues(enumType).GetValue(0)) :
 | 
				
			||||||
                    (OdbcType.Int, _utils.Adapter.MappingOdbcTypeInt, $"{_utils.Adapter.MappingOdbcTypeInt}{(type.IsEnum ? " NOT NULL" : "")}", false, type.IsEnum ? false : true, Enum.GetValues(enumType).GetValue(0));
 | 
					                    CsToDb.New(OdbcType.Int, _utils.Adapter.MappingOdbcTypeInt, $"{_utils.Adapter.MappingOdbcTypeInt}{(type.IsEnum ? " NOT NULL" : "")}", false, type.IsEnum ? false : true, Enum.GetValues(enumType).GetValue(0));
 | 
				
			||||||
                if (_dicCsToDb.ContainsKey(type.FullName) == false)
 | 
					                if (_dicCsToDb.ContainsKey(type.FullName) == false)
 | 
				
			||||||
                {
 | 
					                {
 | 
				
			||||||
                    lock (_dicCsToDbLock)
 | 
					                    lock (_dicCsToDbLock)
 | 
				
			||||||
@@ -84,11 +84,11 @@ namespace FreeSql.Odbc.Default
 | 
				
			|||||||
                            _dicCsToDb.Add(type.FullName, newItem);
 | 
					                            _dicCsToDb.Add(type.FullName, newItem);
 | 
				
			||||||
                    }
 | 
					                    }
 | 
				
			||||||
                }
 | 
					                }
 | 
				
			||||||
                return ((int)newItem.Item1, newItem.Item2, newItem.Item3, newItem.Item5, newItem.Item6);
 | 
					                return new DbInfoResult((int)newItem.type, newItem.dbtype, newItem.dbtypeFull, newItem.isnullable, newItem.defaultValue);
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
            return null;
 | 
					            return null;
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        protected override string GetComparisonDDLStatements(params (Type entityType, string tableName)[] objects) => throw new NotImplementedException("FreeSql.Odbc.Default 未实现该功能");
 | 
					        protected override string GetComparisonDDLStatements(params TypeAndName[] objects) => throw new NotImplementedException("FreeSql.Odbc.Default 未实现该功能");
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
@@ -1,31 +0,0 @@
 | 
				
			|||||||
using FreeSql.Internal;
 | 
					 | 
				
			||||||
using System;
 | 
					 | 
				
			||||||
using System.Collections.Generic;
 | 
					 | 
				
			||||||
using System.Data;
 | 
					 | 
				
			||||||
using System.Text;
 | 
					 | 
				
			||||||
using System.Threading.Tasks;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
namespace FreeSql.Odbc.GBase
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    class OdbcGBaseDelete<T1> : Internal.CommonProvider.DeleteProvider<T1> where T1 : class
 | 
					 | 
				
			||||||
    {
 | 
					 | 
				
			||||||
        public OdbcGBaseDelete(IFreeSql orm, CommonUtils commonUtils, CommonExpression commonExpression, object dywhere)
 | 
					 | 
				
			||||||
            : base(orm, commonUtils, commonExpression, dywhere)
 | 
					 | 
				
			||||||
        {
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        public override List<T1> ExecuteDeleted()
 | 
					 | 
				
			||||||
        {
 | 
					 | 
				
			||||||
            throw new NotImplementedException();
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#if net40
 | 
					 | 
				
			||||||
#else
 | 
					 | 
				
			||||||
        public override Task<List<T1>> ExecuteDeletedAsync()
 | 
					 | 
				
			||||||
        {
 | 
					 | 
				
			||||||
            throw new NotImplementedException();
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
#endif
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
@@ -1,176 +0,0 @@
 | 
				
			|||||||
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.Odbc.GBase
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    class OdbcGBaseSelect<T1> : FreeSql.Internal.CommonProvider.Select1Provider<T1> where T1 : class
 | 
					 | 
				
			||||||
    {
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        internal static string ToSqlStatic(CommonUtils _commonUtils, CommonExpression _commonExpression, string _select, bool _distinct, string field, StringBuilder _join, StringBuilder _where, string _groupby, string _having, string _orderby, int _skip, int _limit, List<SelectTableInfo> _tables, List<Dictionary<Type, string>> tbUnions, Func<Type, string, string> _aliasRule, string _tosqlAppendContent, List<LambdaExpression> _whereCascadeExpression, IFreeSql _orm)
 | 
					 | 
				
			||||||
        {
 | 
					 | 
				
			||||||
            if (_orm.CodeFirst.IsAutoSyncStructure)
 | 
					 | 
				
			||||||
                _orm.CodeFirst.SyncStructure(_tables.Select(a => a.Table.Type).ToArray());
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
            if (_whereCascadeExpression.Any())
 | 
					 | 
				
			||||||
                foreach (var tb in _tables.Where(a => a.Type != SelectTableInfoType.Parent))
 | 
					 | 
				
			||||||
                    tb.Cascade = _commonExpression.GetWhereCascadeSql(tb, _whereCascadeExpression);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
            var sb = new StringBuilder();
 | 
					 | 
				
			||||||
            var tbUnionsGt0 = tbUnions.Count > 1;
 | 
					 | 
				
			||||||
            for (var tbUnionsIdx = 0; tbUnionsIdx < tbUnions.Count; tbUnionsIdx++)
 | 
					 | 
				
			||||||
            {
 | 
					 | 
				
			||||||
                if (tbUnionsIdx > 0) sb.Append(" \r\n\r\nUNION ALL\r\n\r\n");
 | 
					 | 
				
			||||||
                if (tbUnionsGt0) sb.Append(_select).Append(" * from (");
 | 
					 | 
				
			||||||
                var tbUnion = tbUnions[tbUnionsIdx];
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
                var sbnav = new StringBuilder();
 | 
					 | 
				
			||||||
                sb.Append(_select);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
                if (_skip > 0)
 | 
					 | 
				
			||||||
                    sb.Append("SKIP ").Append(_skip).Append(" ");
 | 
					 | 
				
			||||||
                if (_limit > 0)
 | 
					 | 
				
			||||||
                    sb.Append("FIRST ").Append(_limit).Append(" ");
 | 
					 | 
				
			||||||
               
 | 
					 | 
				
			||||||
                if (_distinct) sb.Append("DISTINCT ");
 | 
					 | 
				
			||||||
                sb.Append(field).Append(" \r\nFROM ");
 | 
					 | 
				
			||||||
                var tbsjoin = _tables.Where(a => a.Type != SelectTableInfoType.From).ToArray();
 | 
					 | 
				
			||||||
                var tbsfrom = _tables.Where(a => a.Type == SelectTableInfoType.From).ToArray();
 | 
					 | 
				
			||||||
                for (var a = 0; a < tbsfrom.Length; a++)
 | 
					 | 
				
			||||||
                {
 | 
					 | 
				
			||||||
                    sb.Append(_commonUtils.QuoteSqlName(tbUnion[tbsfrom[a].Table.Type])).Append(" ").Append(_aliasRule?.Invoke(tbsfrom[a].Table.Type, tbsfrom[a].Alias) ?? tbsfrom[a].Alias);
 | 
					 | 
				
			||||||
                    if (tbsjoin.Length > 0)
 | 
					 | 
				
			||||||
                    {
 | 
					 | 
				
			||||||
                        //如果存在 join 查询,则处理 from t1, t2 改为 from t1 inner join t2 on 1 = 1
 | 
					 | 
				
			||||||
                        for (var b = 1; b < tbsfrom.Length; b++)
 | 
					 | 
				
			||||||
                        {
 | 
					 | 
				
			||||||
                            sb.Append(" \r\nLEFT JOIN ").Append(_commonUtils.QuoteSqlName(tbUnion[tbsfrom[b].Table.Type])).Append(" ").Append(_aliasRule?.Invoke(tbsfrom[b].Table.Type, tbsfrom[b].Alias) ?? tbsfrom[b].Alias);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
                            if (string.IsNullOrEmpty(tbsfrom[b].NavigateCondition) && string.IsNullOrEmpty(tbsfrom[b].On) && string.IsNullOrEmpty(tbsfrom[b].Cascade)) sb.Append(" ON 1 = 1");
 | 
					 | 
				
			||||||
                            else
 | 
					 | 
				
			||||||
                            {
 | 
					 | 
				
			||||||
                                var onSql = tbsfrom[b].NavigateCondition ?? tbsfrom[b].On;
 | 
					 | 
				
			||||||
                                sb.Append(" ON ").Append(onSql);
 | 
					 | 
				
			||||||
                                if (string.IsNullOrEmpty(tbsfrom[b].Cascade) == false)
 | 
					 | 
				
			||||||
                                {
 | 
					 | 
				
			||||||
                                    if (string.IsNullOrEmpty(onSql)) sb.Append(tbsfrom[b].Cascade);
 | 
					 | 
				
			||||||
                                    else sb.Append(" AND (").Append(tbsfrom[b].Cascade).Append(")");
 | 
					 | 
				
			||||||
                                }
 | 
					 | 
				
			||||||
                            }
 | 
					 | 
				
			||||||
                        }
 | 
					 | 
				
			||||||
                        break;
 | 
					 | 
				
			||||||
                    }
 | 
					 | 
				
			||||||
                    else
 | 
					 | 
				
			||||||
                    {
 | 
					 | 
				
			||||||
                        if (!string.IsNullOrEmpty(tbsfrom[a].NavigateCondition)) sbnav.Append(" AND (").Append(tbsfrom[a].NavigateCondition).Append(")");
 | 
					 | 
				
			||||||
                        if (!string.IsNullOrEmpty(tbsfrom[a].On)) sbnav.Append(" AND (").Append(tbsfrom[a].On).Append(")");
 | 
					 | 
				
			||||||
                        if (a > 0 && !string.IsNullOrEmpty(tbsfrom[a].Cascade)) sbnav.Append(" AND (").Append(tbsfrom[a].Cascade).Append(")");
 | 
					 | 
				
			||||||
                    }
 | 
					 | 
				
			||||||
                    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(tbUnion[tb.Table.Type])).Append(" ").Append(_aliasRule?.Invoke(tb.Table.Type, tb.Alias) ?? tb.Alias).Append(" ON ").Append(tb.On ?? tb.NavigateCondition);
 | 
					 | 
				
			||||||
                    if (!string.IsNullOrEmpty(tb.Cascade)) sb.Append(" AND (").Append(tb.Cascade).Append(")");
 | 
					 | 
				
			||||||
                    if (!string.IsNullOrEmpty(tb.On) && !string.IsNullOrEmpty(tb.NavigateCondition)) sbnav.Append(" AND (").Append(tb.NavigateCondition).Append(")");
 | 
					 | 
				
			||||||
                }
 | 
					 | 
				
			||||||
                if (_join.Length > 0) sb.Append(_join);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
                sbnav.Append(_where);
 | 
					 | 
				
			||||||
                if (!string.IsNullOrEmpty(_tables[0].Cascade))
 | 
					 | 
				
			||||||
                    sbnav.Append(" AND (").Append(_tables[0].Cascade).Append(")");
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
                if (sbnav.Length > 0)
 | 
					 | 
				
			||||||
                {
 | 
					 | 
				
			||||||
                    sb.Append(" \r\nWHERE ").Append(sbnav.Remove(0, 5));
 | 
					 | 
				
			||||||
                }
 | 
					 | 
				
			||||||
                if (string.IsNullOrEmpty(_groupby) == false)
 | 
					 | 
				
			||||||
                {
 | 
					 | 
				
			||||||
                    sb.Append(_groupby);
 | 
					 | 
				
			||||||
                    if (string.IsNullOrEmpty(_having) == false)
 | 
					 | 
				
			||||||
                        sb.Append(" \r\nHAVING ").Append(_having.Substring(5));
 | 
					 | 
				
			||||||
                }
 | 
					 | 
				
			||||||
                sb.Append(_orderby);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
                sbnav.Clear();
 | 
					 | 
				
			||||||
                if (tbUnionsGt0) sb.Append(") ftb");
 | 
					 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
            return sb.Append(_tosqlAppendContent).ToString();
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        public OdbcGBaseSelect(IFreeSql orm, CommonUtils commonUtils, CommonExpression commonExpression, object dywhere) : base(orm, commonUtils, commonExpression, dywhere) { }
 | 
					 | 
				
			||||||
        public override ISelect<T1, T2> From<T2>(Expression<Func<ISelectFromExpression<T1>, T2, ISelectFromExpression<T1>>> exp) { this.InternalFrom(exp); var ret = new OdbcPostgreSQLSelect<T1, T2>(_orm, _commonUtils, _commonExpression, null); OdbcGBaseSelect<T1>.CopyData(this, ret, exp?.Parameters); return ret; }
 | 
					 | 
				
			||||||
        public override ISelect<T1, T2, T3> From<T2, T3>(Expression<Func<ISelectFromExpression<T1>, T2, T3, ISelectFromExpression<T1>>> exp) { this.InternalFrom(exp); var ret = new OdbcPostgreSQLSelect<T1, T2, T3>(_orm, _commonUtils, _commonExpression, null); OdbcGBaseSelect<T1>.CopyData(this, ret, exp?.Parameters); return ret; }
 | 
					 | 
				
			||||||
        public override ISelect<T1, T2, T3, T4> From<T2, T3, T4>(Expression<Func<ISelectFromExpression<T1>, T2, T3, T4, ISelectFromExpression<T1>>> exp) { this.InternalFrom(exp); var ret = new OdbcPostgreSQLSelect<T1, T2, T3, T4>(_orm, _commonUtils, _commonExpression, null); OdbcGBaseSelect<T1>.CopyData(this, ret, exp?.Parameters); return ret; }
 | 
					 | 
				
			||||||
        public override ISelect<T1, T2, T3, T4, T5> From<T2, T3, T4, T5>(Expression<Func<ISelectFromExpression<T1>, T2, T3, T4, T5, ISelectFromExpression<T1>>> exp) { this.InternalFrom(exp); var ret = new OdbcPostgreSQLSelect<T1, T2, T3, T4, T5>(_orm, _commonUtils, _commonExpression, null); OdbcGBaseSelect<T1>.CopyData(this, ret, exp?.Parameters); return ret; }
 | 
					 | 
				
			||||||
        public override ISelect<T1, T2, T3, T4, T5, T6> From<T2, T3, T4, T5, T6>(Expression<Func<ISelectFromExpression<T1>, T2, T3, T4, T5, T6, ISelectFromExpression<T1>>> exp) { this.InternalFrom(exp); var ret = new OdbcPostgreSQLSelect<T1, T2, T3, T4, T5, T6>(_orm, _commonUtils, _commonExpression, null); OdbcGBaseSelect<T1>.CopyData(this, ret, exp?.Parameters); return ret; }
 | 
					 | 
				
			||||||
        public override ISelect<T1, T2, T3, T4, T5, T6, T7> From<T2, T3, T4, T5, T6, T7>(Expression<Func<ISelectFromExpression<T1>, T2, T3, T4, T5, T6, T7, ISelectFromExpression<T1>>> exp) { this.InternalFrom(exp); var ret = new OdbcPostgreSQLSelect<T1, T2, T3, T4, T5, T6, T7>(_orm, _commonUtils, _commonExpression, null); OdbcGBaseSelect<T1>.CopyData(this, ret, exp?.Parameters); return ret; }
 | 
					 | 
				
			||||||
        public override ISelect<T1, T2, T3, T4, T5, T6, T7, T8> From<T2, T3, T4, T5, T6, T7, T8>(Expression<Func<ISelectFromExpression<T1>, T2, T3, T4, T5, T6, T7, T8, ISelectFromExpression<T1>>> exp) { this.InternalFrom(exp); var ret = new OdbcPostgreSQLSelect<T1, T2, T3, T4, T5, T6, T7, T8>(_orm, _commonUtils, _commonExpression, null); OdbcGBaseSelect<T1>.CopyData(this, ret, exp?.Parameters); return ret; }
 | 
					 | 
				
			||||||
        public override ISelect<T1, T2, T3, T4, T5, T6, T7, T8, T9> From<T2, T3, T4, T5, T6, T7, T8, T9>(Expression<Func<ISelectFromExpression<T1>, T2, T3, T4, T5, T6, T7, T8, T9, ISelectFromExpression<T1>>> exp) { this.InternalFrom(exp); var ret = new OdbcPostgreSQLSelect<T1, T2, T3, T4, T5, T6, T7, T8, T9>(_orm, _commonUtils, _commonExpression, null); OdbcGBaseSelect<T1>.CopyData(this, ret, exp?.Parameters); return ret; }
 | 
					 | 
				
			||||||
        public override ISelect<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10> From<T2, T3, T4, T5, T6, T7, T8, T9, T10>(Expression<Func<ISelectFromExpression<T1>, T2, T3, T4, T5, T6, T7, T8, T9, T10, ISelectFromExpression<T1>>> exp) { this.InternalFrom(exp); var ret = new OdbcPostgreSQLSelect<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10>(_orm, _commonUtils, _commonExpression, null); OdbcGBaseSelect<T1>.CopyData(this, ret, exp?.Parameters); return ret; }
 | 
					 | 
				
			||||||
        public override string ToSql(string field = null) => ToSqlStatic(_commonUtils, _commonExpression, _select, _distinct, field ?? this.GetAllFieldExpressionTreeLevel2().Field, _join, _where, _groupby, _having, _orderby, _skip, _limit, _tables, this.GetTableRuleUnions(), _aliasRule, _tosqlAppendContent, _whereCascadeExpression, _orm);
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
    class OdbcPostgreSQLSelect<T1, T2> : FreeSql.Internal.CommonProvider.Select2Provider<T1, T2> where T1 : class where T2 : class
 | 
					 | 
				
			||||||
    {
 | 
					 | 
				
			||||||
        public OdbcPostgreSQLSelect(IFreeSql orm, CommonUtils commonUtils, CommonExpression commonExpression, object dywhere) : base(orm, commonUtils, commonExpression, dywhere) { }
 | 
					 | 
				
			||||||
        public override string ToSql(string field = null) => OdbcGBaseSelect<T1>.ToSqlStatic(_commonUtils, _commonExpression, _select, _distinct, field ?? this.GetAllFieldExpressionTreeLevel2().Field, _join, _where, _groupby, _having, _orderby, _skip, _limit, _tables, this.GetTableRuleUnions(), _aliasRule, _tosqlAppendContent, _whereCascadeExpression, _orm);
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
    class OdbcPostgreSQLSelect<T1, T2, T3> : FreeSql.Internal.CommonProvider.Select3Provider<T1, T2, T3> where T1 : class where T2 : class where T3 : class
 | 
					 | 
				
			||||||
    {
 | 
					 | 
				
			||||||
        public OdbcPostgreSQLSelect(IFreeSql orm, CommonUtils commonUtils, CommonExpression commonExpression, object dywhere) : base(orm, commonUtils, commonExpression, dywhere) { }
 | 
					 | 
				
			||||||
        public override string ToSql(string field = null) => OdbcGBaseSelect<T1>.ToSqlStatic(_commonUtils, _commonExpression, _select, _distinct, field ?? this.GetAllFieldExpressionTreeLevel2().Field, _join, _where, _groupby, _having, _orderby, _skip, _limit, _tables, this.GetTableRuleUnions(), _aliasRule, _tosqlAppendContent, _whereCascadeExpression, _orm);
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
    class OdbcPostgreSQLSelect<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 OdbcPostgreSQLSelect(IFreeSql orm, CommonUtils commonUtils, CommonExpression commonExpression, object dywhere) : base(orm, commonUtils, commonExpression, dywhere) { }
 | 
					 | 
				
			||||||
        public override string ToSql(string field = null) => OdbcGBaseSelect<T1>.ToSqlStatic(_commonUtils, _commonExpression, _select, _distinct, field ?? this.GetAllFieldExpressionTreeLevel2().Field, _join, _where, _groupby, _having, _orderby, _skip, _limit, _tables, this.GetTableRuleUnions(), _aliasRule, _tosqlAppendContent, _whereCascadeExpression, _orm);
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
    class OdbcPostgreSQLSelect<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 OdbcPostgreSQLSelect(IFreeSql orm, CommonUtils commonUtils, CommonExpression commonExpression, object dywhere) : base(orm, commonUtils, commonExpression, dywhere) { }
 | 
					 | 
				
			||||||
        public override string ToSql(string field = null) => OdbcGBaseSelect<T1>.ToSqlStatic(_commonUtils, _commonExpression, _select, _distinct, field ?? this.GetAllFieldExpressionTreeLevel2().Field, _join, _where, _groupby, _having, _orderby, _skip, _limit, _tables, this.GetTableRuleUnions(), _aliasRule, _tosqlAppendContent, _whereCascadeExpression, _orm);
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
    class OdbcPostgreSQLSelect<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 OdbcPostgreSQLSelect(IFreeSql orm, CommonUtils commonUtils, CommonExpression commonExpression, object dywhere) : base(orm, commonUtils, commonExpression, dywhere) { }
 | 
					 | 
				
			||||||
        public override string ToSql(string field = null) => OdbcGBaseSelect<T1>.ToSqlStatic(_commonUtils, _commonExpression, _select, _distinct, field ?? this.GetAllFieldExpressionTreeLevel2().Field, _join, _where, _groupby, _having, _orderby, _skip, _limit, _tables, this.GetTableRuleUnions(), _aliasRule, _tosqlAppendContent, _whereCascadeExpression, _orm);
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
    class OdbcPostgreSQLSelect<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 OdbcPostgreSQLSelect(IFreeSql orm, CommonUtils commonUtils, CommonExpression commonExpression, object dywhere) : base(orm, commonUtils, commonExpression, dywhere) { }
 | 
					 | 
				
			||||||
        public override string ToSql(string field = null) => OdbcGBaseSelect<T1>.ToSqlStatic(_commonUtils, _commonExpression, _select, _distinct, field ?? this.GetAllFieldExpressionTreeLevel2().Field, _join, _where, _groupby, _having, _orderby, _skip, _limit, _tables, this.GetTableRuleUnions(), _aliasRule, _tosqlAppendContent, _whereCascadeExpression, _orm);
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
    class OdbcPostgreSQLSelect<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 OdbcPostgreSQLSelect(IFreeSql orm, CommonUtils commonUtils, CommonExpression commonExpression, object dywhere) : base(orm, commonUtils, commonExpression, dywhere) { }
 | 
					 | 
				
			||||||
        public override string ToSql(string field = null) => OdbcGBaseSelect<T1>.ToSqlStatic(_commonUtils, _commonExpression, _select, _distinct, field ?? this.GetAllFieldExpressionTreeLevel2().Field, _join, _where, _groupby, _having, _orderby, _skip, _limit, _tables, this.GetTableRuleUnions(), _aliasRule, _tosqlAppendContent, _whereCascadeExpression, _orm);
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
    class OdbcPostgreSQLSelect<T1, T2, T3, T4, T5, T6, T7, T8, T9> : FreeSql.Internal.CommonProvider.Select9Provider<T1, T2, T3, T4, T5, T6, T7, T8, T9> where 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 OdbcPostgreSQLSelect(IFreeSql orm, CommonUtils commonUtils, CommonExpression commonExpression, object dywhere) : base(orm, commonUtils, commonExpression, dywhere) { }
 | 
					 | 
				
			||||||
        public override string ToSql(string field = null) => OdbcGBaseSelect<T1>.ToSqlStatic(_commonUtils, _commonExpression, _select, _distinct, field ?? this.GetAllFieldExpressionTreeLevel2().Field, _join, _where, _groupby, _having, _orderby, _skip, _limit, _tables, this.GetTableRuleUnions(), _aliasRule, _tosqlAppendContent, _whereCascadeExpression, _orm);
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
    class OdbcPostgreSQLSelect<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10> : FreeSql.Internal.CommonProvider.Select10Provider<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10> where 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 OdbcPostgreSQLSelect(IFreeSql orm, CommonUtils commonUtils, CommonExpression commonExpression, object dywhere) : base(orm, commonUtils, commonExpression, dywhere) { }
 | 
					 | 
				
			||||||
        public override string ToSql(string field = null) => OdbcGBaseSelect<T1>.ToSqlStatic(_commonUtils, _commonExpression, _select, _distinct, field ?? this.GetAllFieldExpressionTreeLevel2().Field, _join, _where, _groupby, _having, _orderby, _skip, _limit, _tables, this.GetTableRuleUnions(), _aliasRule, _tosqlAppendContent, _whereCascadeExpression, _orm);
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
@@ -1,86 +0,0 @@
 | 
				
			|||||||
using FreeSql.Internal;
 | 
					 | 
				
			||||||
using FreeSql.Internal.Model;
 | 
					 | 
				
			||||||
using System;
 | 
					 | 
				
			||||||
using System.Collections.Generic;
 | 
					 | 
				
			||||||
using System.Data;
 | 
					 | 
				
			||||||
using System.Linq;
 | 
					 | 
				
			||||||
using System.Text;
 | 
					 | 
				
			||||||
using System.Threading.Tasks;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
namespace FreeSql.Odbc.GBase
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    class OdbcGBaseUpdate<T1> : Internal.CommonProvider.UpdateProvider<T1> where T1 : class
 | 
					 | 
				
			||||||
    {
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        public OdbcGBaseUpdate(IFreeSql orm, CommonUtils commonUtils, CommonExpression commonExpression, object dywhere)
 | 
					 | 
				
			||||||
            : base(orm, commonUtils, commonExpression, dywhere)
 | 
					 | 
				
			||||||
        {
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        public override int ExecuteAffrows() => base.SplitExecuteAffrows(_batchRowsLimit > 0 ? _batchRowsLimit : 500, _batchParameterLimit > 0 ? _batchParameterLimit : 3000);
 | 
					 | 
				
			||||||
        public override List<T1> ExecuteUpdated() => base.SplitExecuteUpdated(_batchRowsLimit > 0 ? _batchRowsLimit : 500, _batchParameterLimit > 0 ? _batchParameterLimit : 3000);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        protected override List<T1> RawExecuteUpdated()
 | 
					 | 
				
			||||||
        {
 | 
					 | 
				
			||||||
            throw new NotImplementedException();
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        protected override void ToSqlCase(StringBuilder caseWhen, ColumnInfo[] primarys)
 | 
					 | 
				
			||||||
        {
 | 
					 | 
				
			||||||
            if (_table.Primarys.Length == 1)
 | 
					 | 
				
			||||||
            {
 | 
					 | 
				
			||||||
                var pk = _table.Primarys.First();
 | 
					 | 
				
			||||||
                caseWhen.Append(_commonUtils.QuoteReadColumn(pk.CsType, pk.Attribute.MapType, _commonUtils.QuoteSqlName(pk.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, pk.Attribute.MapType, _commonUtils.QuoteSqlName(pk.Attribute.Name))).Append("::varchar");
 | 
					 | 
				
			||||||
                ++pkidx;
 | 
					 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
            caseWhen.Append(")");
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        protected override void ToSqlWhen(StringBuilder sb, ColumnInfo[] primarys, object d)
 | 
					 | 
				
			||||||
        {
 | 
					 | 
				
			||||||
            if (_table.Primarys.Length == 1)
 | 
					 | 
				
			||||||
            {
 | 
					 | 
				
			||||||
                sb.Append(_commonUtils.FormatSql("{0}", _table.Primarys.First().GetMapValue(d)));
 | 
					 | 
				
			||||||
                return;
 | 
					 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
            sb.Append("(");
 | 
					 | 
				
			||||||
            var pkidx = 0;
 | 
					 | 
				
			||||||
            foreach (var pk in _table.Primarys)
 | 
					 | 
				
			||||||
            {
 | 
					 | 
				
			||||||
                if (pkidx > 0) sb.Append(" || '+' || ");
 | 
					 | 
				
			||||||
                sb.Append(_commonUtils.FormatSql("{0}", pk.GetMapValue(d))).Append("::varchar");
 | 
					 | 
				
			||||||
                ++pkidx;
 | 
					 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
            sb.Append(")");
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        protected override void ToSqlCaseWhenEnd(StringBuilder sb, ColumnInfo col)
 | 
					 | 
				
			||||||
        {
 | 
					 | 
				
			||||||
            if (_noneParameter == false) return;
 | 
					 | 
				
			||||||
            var dbtype = _commonUtils.CodeFirst.GetDbInfo(col.Attribute.MapType)?.dbtype;
 | 
					 | 
				
			||||||
            if (dbtype == null) return;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
            sb.Append("::").Append(dbtype);
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#if net40
 | 
					 | 
				
			||||||
#else
 | 
					 | 
				
			||||||
        public override Task<int> ExecuteAffrowsAsync() => base.SplitExecuteAffrowsAsync(500, 3000);
 | 
					 | 
				
			||||||
        public override Task<List<T1>> ExecuteUpdatedAsync() => base.SplitExecuteUpdatedAsync(500, 3000);
 | 
					 | 
				
			||||||
        
 | 
					 | 
				
			||||||
        protected override Task<List<T1>> RawExecuteUpdatedAsync()
 | 
					 | 
				
			||||||
        {
 | 
					 | 
				
			||||||
            throw new NotImplementedException();
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
#endif
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
@@ -1,149 +0,0 @@
 | 
				
			|||||||
using FreeSql.Internal;
 | 
					 | 
				
			||||||
using System;
 | 
					 | 
				
			||||||
using System.Collections.Generic;
 | 
					 | 
				
			||||||
using System.Data;
 | 
					 | 
				
			||||||
using System.Linq;
 | 
					 | 
				
			||||||
using System.Text;
 | 
					 | 
				
			||||||
using System.Threading.Tasks;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
namespace FreeSql.Odbc.GBase
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    class OdbcGBaseInsert<T1> : Internal.CommonProvider.InsertProvider<T1> where T1 : class
 | 
					 | 
				
			||||||
    {
 | 
					 | 
				
			||||||
        public OdbcGBaseInsert(IFreeSql orm, CommonUtils commonUtils, CommonExpression commonExpression)
 | 
					 | 
				
			||||||
            : base(orm, commonUtils, commonExpression)
 | 
					 | 
				
			||||||
        {
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        public override int ExecuteAffrows() => base.SplitExecuteAffrows(_batchValuesLimit > 0 ? _batchValuesLimit : 5000, _batchParameterLimit > 0 ? _batchParameterLimit : 3000);
 | 
					 | 
				
			||||||
        public override long ExecuteIdentity() => base.SplitExecuteIdentity(_batchValuesLimit > 0 ? _batchValuesLimit : 5000, _batchParameterLimit > 0 ? _batchParameterLimit : 3000);
 | 
					 | 
				
			||||||
        public override List<T1> ExecuteInserted() => base.SplitExecuteInserted(_batchValuesLimit > 0 ? _batchValuesLimit : 5000, _batchParameterLimit > 0 ? _batchParameterLimit : 3000);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        protected override long RawExecuteIdentity()
 | 
					 | 
				
			||||||
        {
 | 
					 | 
				
			||||||
            var sql = this.ToSql();
 | 
					 | 
				
			||||||
            if (string.IsNullOrEmpty(sql)) return 0;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
            long ret = 0;
 | 
					 | 
				
			||||||
            Exception exception = null;
 | 
					 | 
				
			||||||
            Aop.CurdBeforeEventArgs before = null;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
            var identCols = _table.Columns.Where(a => a.Value.Attribute.IsIdentity == true);
 | 
					 | 
				
			||||||
            if (identCols.Any() == false)
 | 
					 | 
				
			||||||
            {
 | 
					 | 
				
			||||||
                before = new Aop.CurdBeforeEventArgs(_table.Type, _table, Aop.CurdType.Insert, sql, _params);
 | 
					 | 
				
			||||||
                _orm.Aop.CurdBeforeHandler?.Invoke(this, before);
 | 
					 | 
				
			||||||
                try
 | 
					 | 
				
			||||||
                {
 | 
					 | 
				
			||||||
                    ret = _orm.Ado.ExecuteNonQuery(_connection, _transaction, CommandType.Text, sql, _params);
 | 
					 | 
				
			||||||
                }
 | 
					 | 
				
			||||||
                catch (Exception ex)
 | 
					 | 
				
			||||||
                {
 | 
					 | 
				
			||||||
                    exception = ex;
 | 
					 | 
				
			||||||
                    throw ex;
 | 
					 | 
				
			||||||
                }
 | 
					 | 
				
			||||||
                finally
 | 
					 | 
				
			||||||
                {
 | 
					 | 
				
			||||||
                    var after = new Aop.CurdAfterEventArgs(before, exception, ret);
 | 
					 | 
				
			||||||
                    _orm.Aop.CurdAfterHandler?.Invoke(this, after);
 | 
					 | 
				
			||||||
                }
 | 
					 | 
				
			||||||
                return 0;
 | 
					 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
            sql = string.Concat(sql, " RETURNING ", _commonUtils.QuoteSqlName(identCols.First().Value.Attribute.Name));
 | 
					 | 
				
			||||||
            before = new Aop.CurdBeforeEventArgs(_table.Type, _table, Aop.CurdType.Insert, sql, _params);
 | 
					 | 
				
			||||||
            _orm.Aop.CurdBeforeHandler?.Invoke(this, before);
 | 
					 | 
				
			||||||
            try
 | 
					 | 
				
			||||||
            {
 | 
					 | 
				
			||||||
                long.TryParse(string.Concat(_orm.Ado.ExecuteScalar(_connection, _transaction, CommandType.Text, sql, _params)), out ret);
 | 
					 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
            catch (Exception ex)
 | 
					 | 
				
			||||||
            {
 | 
					 | 
				
			||||||
                exception = ex;
 | 
					 | 
				
			||||||
                throw ex;
 | 
					 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
            finally
 | 
					 | 
				
			||||||
            {
 | 
					 | 
				
			||||||
                var after = new Aop.CurdAfterEventArgs(before, exception, ret);
 | 
					 | 
				
			||||||
                _orm.Aop.CurdAfterHandler?.Invoke(this, after);
 | 
					 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
            return ret;
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        protected override List<T1> RawExecuteInserted()
 | 
					 | 
				
			||||||
        {
 | 
					 | 
				
			||||||
            var sql = this.ToSql();
 | 
					 | 
				
			||||||
            if (string.IsNullOrEmpty(sql)) return new List<T1>();
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
            var ret = _source.ToList();
 | 
					 | 
				
			||||||
            this.RawExecuteAffrows();
 | 
					 | 
				
			||||||
            return ret;
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#if net40
 | 
					 | 
				
			||||||
#else
 | 
					 | 
				
			||||||
        public override Task<int> ExecuteAffrowsAsync() => base.SplitExecuteAffrowsAsync(5000, 3000);
 | 
					 | 
				
			||||||
        public override Task<long> ExecuteIdentityAsync() => base.SplitExecuteIdentityAsync(5000, 3000);
 | 
					 | 
				
			||||||
        public override Task<List<T1>> ExecuteInsertedAsync() => base.SplitExecuteInsertedAsync(5000, 3000);
 | 
					 | 
				
			||||||
        
 | 
					 | 
				
			||||||
        async protected override Task<long> RawExecuteIdentityAsync()
 | 
					 | 
				
			||||||
        {
 | 
					 | 
				
			||||||
            var sql = this.ToSql();
 | 
					 | 
				
			||||||
            if (string.IsNullOrEmpty(sql)) return 0;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
            long ret = 0;
 | 
					 | 
				
			||||||
            Exception exception = null;
 | 
					 | 
				
			||||||
            Aop.CurdBeforeEventArgs before = null;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
            var identCols = _table.Columns.Where(a => a.Value.Attribute.IsIdentity == true);
 | 
					 | 
				
			||||||
            if (identCols.Any() == false)
 | 
					 | 
				
			||||||
            {
 | 
					 | 
				
			||||||
                before = new Aop.CurdBeforeEventArgs(_table.Type, _table, Aop.CurdType.Insert, sql, _params);
 | 
					 | 
				
			||||||
                _orm.Aop.CurdBeforeHandler?.Invoke(this, before);
 | 
					 | 
				
			||||||
                try
 | 
					 | 
				
			||||||
                {
 | 
					 | 
				
			||||||
                    ret = await _orm.Ado.ExecuteNonQueryAsync(_connection, _transaction, CommandType.Text, sql, _params);
 | 
					 | 
				
			||||||
                }
 | 
					 | 
				
			||||||
                catch (Exception ex)
 | 
					 | 
				
			||||||
                {
 | 
					 | 
				
			||||||
                    exception = ex;
 | 
					 | 
				
			||||||
                    throw ex;
 | 
					 | 
				
			||||||
                }
 | 
					 | 
				
			||||||
                finally
 | 
					 | 
				
			||||||
                {
 | 
					 | 
				
			||||||
                    var after = new Aop.CurdAfterEventArgs(before, exception, ret);
 | 
					 | 
				
			||||||
                    _orm.Aop.CurdAfterHandler?.Invoke(this, after);
 | 
					 | 
				
			||||||
                }
 | 
					 | 
				
			||||||
                return 0;
 | 
					 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
            sql = string.Concat(sql, " RETURNING ", _commonUtils.QuoteSqlName(identCols.First().Value.Attribute.Name));
 | 
					 | 
				
			||||||
            before = new Aop.CurdBeforeEventArgs(_table.Type, _table, Aop.CurdType.Insert, sql, _params);
 | 
					 | 
				
			||||||
            _orm.Aop.CurdBeforeHandler?.Invoke(this, before);
 | 
					 | 
				
			||||||
            try
 | 
					 | 
				
			||||||
            {
 | 
					 | 
				
			||||||
                long.TryParse(string.Concat(await _orm.Ado.ExecuteScalarAsync(_connection, _transaction, CommandType.Text, sql, _params)), out ret);
 | 
					 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
            catch (Exception ex)
 | 
					 | 
				
			||||||
            {
 | 
					 | 
				
			||||||
                exception = ex;
 | 
					 | 
				
			||||||
                throw ex;
 | 
					 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
            finally
 | 
					 | 
				
			||||||
            {
 | 
					 | 
				
			||||||
                var after = new Aop.CurdAfterEventArgs(before, exception, ret);
 | 
					 | 
				
			||||||
                _orm.Aop.CurdAfterHandler?.Invoke(this, after);
 | 
					 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
            return ret;
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
        async protected override Task<List<T1>> RawExecuteInsertedAsync()
 | 
					 | 
				
			||||||
        {
 | 
					 | 
				
			||||||
            var sql = this.ToSql();
 | 
					 | 
				
			||||||
            if (string.IsNullOrEmpty(sql)) return new List<T1>();
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
            var ret = _source.ToList();
 | 
					 | 
				
			||||||
            await this.RawExecuteAffrowsAsync();
 | 
					 | 
				
			||||||
            return ret;
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
#endif
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
@@ -1,249 +0,0 @@
 | 
				
			|||||||
using SafeObjectPool;
 | 
					 | 
				
			||||||
using System;
 | 
					 | 
				
			||||||
using System.Collections.Concurrent;
 | 
					 | 
				
			||||||
using System.Collections.Generic;
 | 
					 | 
				
			||||||
using System.Data;
 | 
					 | 
				
			||||||
using System.Data.Common;
 | 
					 | 
				
			||||||
using System.Data.Odbc;
 | 
					 | 
				
			||||||
using System.Text;
 | 
					 | 
				
			||||||
using System.Text.RegularExpressions;
 | 
					 | 
				
			||||||
using System.Threading.Tasks;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
//jdbc:gbasedbt-sqli://192.168.164.10:9088/gbasedb:GBASEDBTSERVER=gbaseserver;DB_LOCALE=zh_CN.GB18030-2000;CLIENT_LOCALE=zh_CN.GB18030-2000;NEWCODESET=GB18030,GB18030-2000,5488;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
namespace FreeSql.Odbc.GBase
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    class OdbcGBaseConnectionPool : ObjectPool<DbConnection>
 | 
					 | 
				
			||||||
    {
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        internal Action availableHandler;
 | 
					 | 
				
			||||||
        internal Action unavailableHandler;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        public OdbcGBaseConnectionPool(string name, string connectionString, Action availableHandler, Action unavailableHandler) : base(null)
 | 
					 | 
				
			||||||
        {
 | 
					 | 
				
			||||||
            this.availableHandler = availableHandler;
 | 
					 | 
				
			||||||
            this.unavailableHandler = unavailableHandler;
 | 
					 | 
				
			||||||
            var policy = new OdbcPostgreSQLConnectionPoolPolicy
 | 
					 | 
				
			||||||
            {
 | 
					 | 
				
			||||||
                _pool = this,
 | 
					 | 
				
			||||||
                Name = name
 | 
					 | 
				
			||||||
            };
 | 
					 | 
				
			||||||
            this.Policy = policy;
 | 
					 | 
				
			||||||
            policy.ConnectionString = connectionString;
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        public void Return(Object<DbConnection> obj, Exception exception, bool isRecreate = false)
 | 
					 | 
				
			||||||
        {
 | 
					 | 
				
			||||||
            if (exception != null && exception is OdbcException)
 | 
					 | 
				
			||||||
            {
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
                if (exception is System.IO.IOException)
 | 
					 | 
				
			||||||
                {
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
                    base.SetUnavailable(exception);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
                }
 | 
					 | 
				
			||||||
                else if (obj.Value.Ping() == false)
 | 
					 | 
				
			||||||
                {
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
                    base.SetUnavailable(exception);
 | 
					 | 
				
			||||||
                }
 | 
					 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
            base.Return(obj, isRecreate);
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    class OdbcPostgreSQLConnectionPoolPolicy : IPolicy<DbConnection>
 | 
					 | 
				
			||||||
    {
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        internal OdbcGBaseConnectionPool _pool;
 | 
					 | 
				
			||||||
        public string Name { get; set; } = "GBase OdbcConnection 对象池";
 | 
					 | 
				
			||||||
        public int PoolSize { get; set; } = 50;
 | 
					 | 
				
			||||||
        public TimeSpan SyncGetTimeout { get; set; } = TimeSpan.FromSeconds(10);
 | 
					 | 
				
			||||||
        public TimeSpan IdleTimeout { get; set; } = TimeSpan.FromSeconds(20);
 | 
					 | 
				
			||||||
        public int AsyncGetCapacity { get; set; } = 10000;
 | 
					 | 
				
			||||||
        public bool IsThrowGetTimeoutException { get; set; } = true;
 | 
					 | 
				
			||||||
        public int CheckAvailableInterval { get; set; } = 5;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        static ConcurrentDictionary<string, int> dicConnStrIncr = new ConcurrentDictionary<string, int>(StringComparer.CurrentCultureIgnoreCase);
 | 
					 | 
				
			||||||
        private string _connectionString;
 | 
					 | 
				
			||||||
        public string ConnectionString
 | 
					 | 
				
			||||||
        {
 | 
					 | 
				
			||||||
            get => _connectionString;
 | 
					 | 
				
			||||||
            set
 | 
					 | 
				
			||||||
            {
 | 
					 | 
				
			||||||
                _connectionString = value ?? "";
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
                var pattern = @"Max\s*pool\s*size\s*=\s*(\d+)";
 | 
					 | 
				
			||||||
                Match m = Regex.Match(_connectionString, pattern, RegexOptions.IgnoreCase);
 | 
					 | 
				
			||||||
                if (m.Success == false || int.TryParse(m.Groups[1].Value, out var poolsize) == false || poolsize <= 0) poolsize = 100;
 | 
					 | 
				
			||||||
                var connStrIncr = dicConnStrIncr.AddOrUpdate(_connectionString, 1, (oldkey, oldval) => Math.Min(5, oldval + 1));
 | 
					 | 
				
			||||||
                PoolSize = poolsize + connStrIncr;
 | 
					 | 
				
			||||||
                _connectionString = m.Success ?
 | 
					 | 
				
			||||||
                    Regex.Replace(_connectionString, pattern, $"Max pool size={PoolSize}", RegexOptions.IgnoreCase) :
 | 
					 | 
				
			||||||
                    $"{_connectionString};Max pool size={PoolSize}";
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
                pattern = @"Connection\s*LifeTime\s*=\s*(\d+)";
 | 
					 | 
				
			||||||
                m = Regex.Match(_connectionString, pattern, RegexOptions.IgnoreCase);
 | 
					 | 
				
			||||||
                if (m.Success)
 | 
					 | 
				
			||||||
                {
 | 
					 | 
				
			||||||
                    IdleTimeout = TimeSpan.FromSeconds(int.Parse(m.Groups[1].Value));
 | 
					 | 
				
			||||||
                    _connectionString = Regex.Replace(_connectionString, pattern, "", RegexOptions.IgnoreCase);
 | 
					 | 
				
			||||||
                }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
                var minPoolSize = 0;
 | 
					 | 
				
			||||||
                pattern = @"Min\s*pool\s*size\s*=\s*(\d+)";
 | 
					 | 
				
			||||||
                m = Regex.Match(_connectionString, pattern, RegexOptions.IgnoreCase);
 | 
					 | 
				
			||||||
                if (m.Success)
 | 
					 | 
				
			||||||
                {
 | 
					 | 
				
			||||||
                    minPoolSize = int.Parse(m.Groups[1].Value);
 | 
					 | 
				
			||||||
                    _connectionString = Regex.Replace(_connectionString, pattern, "", RegexOptions.IgnoreCase);
 | 
					 | 
				
			||||||
                }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
                FreeSql.Internal.CommonUtils.PrevReheatConnectionPool(_pool, minPoolSize);
 | 
					 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        public bool OnCheckAvailable(Object<DbConnection> obj)
 | 
					 | 
				
			||||||
        {
 | 
					 | 
				
			||||||
            if (obj.Value.State == ConnectionState.Closed) obj.Value.Open();
 | 
					 | 
				
			||||||
            return obj.Value.Ping(true);
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        public DbConnection OnCreate()
 | 
					 | 
				
			||||||
        {
 | 
					 | 
				
			||||||
            var conn = new OdbcConnection(_connectionString);
 | 
					 | 
				
			||||||
            return conn;
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        public void OnDestroy(DbConnection obj)
 | 
					 | 
				
			||||||
        {
 | 
					 | 
				
			||||||
            if (obj.State != ConnectionState.Closed) obj.Close();
 | 
					 | 
				
			||||||
            obj.Dispose();
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        public void OnGet(Object<DbConnection> obj)
 | 
					 | 
				
			||||||
        {
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
            if (_pool.IsAvailable)
 | 
					 | 
				
			||||||
            {
 | 
					 | 
				
			||||||
                if (obj.Value == null)
 | 
					 | 
				
			||||||
                {
 | 
					 | 
				
			||||||
                    if (_pool.SetUnavailable(new Exception("连接字符串错误")) == true)
 | 
					 | 
				
			||||||
                        throw new Exception($"【{this.Name}】连接字符串错误,请检查。");
 | 
					 | 
				
			||||||
                    return;
 | 
					 | 
				
			||||||
                }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
                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}");
 | 
					 | 
				
			||||||
                    }
 | 
					 | 
				
			||||||
                }
 | 
					 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#if net40
 | 
					 | 
				
			||||||
#else
 | 
					 | 
				
			||||||
        async public Task OnGetAsync(Object<DbConnection> obj)
 | 
					 | 
				
			||||||
        {
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
            if (_pool.IsAvailable)
 | 
					 | 
				
			||||||
            {
 | 
					 | 
				
			||||||
                if (obj.Value == null)
 | 
					 | 
				
			||||||
                {
 | 
					 | 
				
			||||||
                    if (_pool.SetUnavailable(new Exception("连接字符串错误")) == true)
 | 
					 | 
				
			||||||
                        throw new Exception($"【{this.Name}】连接字符串错误,请检查。");
 | 
					 | 
				
			||||||
                    return;
 | 
					 | 
				
			||||||
                }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
                if (obj.Value.State != ConnectionState.Open || DateTime.Now.Subtract(obj.LastReturnTime).TotalSeconds > 60 && (await obj.Value.PingAsync()) == false)
 | 
					 | 
				
			||||||
                {
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
                    try
 | 
					 | 
				
			||||||
                    {
 | 
					 | 
				
			||||||
                        await obj.Value.OpenAsync();
 | 
					 | 
				
			||||||
                    }
 | 
					 | 
				
			||||||
                    catch (Exception ex)
 | 
					 | 
				
			||||||
                    {
 | 
					 | 
				
			||||||
                        if (_pool.SetUnavailable(ex) == true)
 | 
					 | 
				
			||||||
                            throw new Exception($"【{this.Name}】状态不可用,等待后台检查程序恢复方可使用。{ex.Message}");
 | 
					 | 
				
			||||||
                    }
 | 
					 | 
				
			||||||
                }
 | 
					 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
#endif
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        public void OnGetTimeout()
 | 
					 | 
				
			||||||
        {
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        public void OnReturn(Object<DbConnection> obj)
 | 
					 | 
				
			||||||
        {
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        public void OnAvailable()
 | 
					 | 
				
			||||||
        {
 | 
					 | 
				
			||||||
            _pool.availableHandler?.Invoke();
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        public void OnUnavailable()
 | 
					 | 
				
			||||||
        {
 | 
					 | 
				
			||||||
            _pool.unavailableHandler?.Invoke();
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    static class DbConnectionExtensions
 | 
					 | 
				
			||||||
    {
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        static DbCommand PingCommand(DbConnection conn)
 | 
					 | 
				
			||||||
        {
 | 
					 | 
				
			||||||
            var cmd = conn.CreateCommand();
 | 
					 | 
				
			||||||
            cmd.CommandTimeout = 5;
 | 
					 | 
				
			||||||
            cmd.CommandText = "select 1";
 | 
					 | 
				
			||||||
            return cmd;
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
        public static bool Ping(this DbConnection that, bool isThrow = false)
 | 
					 | 
				
			||||||
        {
 | 
					 | 
				
			||||||
            try
 | 
					 | 
				
			||||||
            {
 | 
					 | 
				
			||||||
                PingCommand(that).ExecuteNonQuery();
 | 
					 | 
				
			||||||
                return true;
 | 
					 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
            catch
 | 
					 | 
				
			||||||
            {
 | 
					 | 
				
			||||||
                if (that.State != ConnectionState.Closed) try { that.Close(); } catch { }
 | 
					 | 
				
			||||||
                if (isThrow) throw;
 | 
					 | 
				
			||||||
                return false;
 | 
					 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#if net40
 | 
					 | 
				
			||||||
#else
 | 
					 | 
				
			||||||
        async public static Task<bool> PingAsync(this DbConnection that, bool isThrow = false)
 | 
					 | 
				
			||||||
        {
 | 
					 | 
				
			||||||
            try
 | 
					 | 
				
			||||||
            {
 | 
					 | 
				
			||||||
                await PingCommand(that).ExecuteNonQueryAsync();
 | 
					 | 
				
			||||||
                return true;
 | 
					 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
            catch
 | 
					 | 
				
			||||||
            {
 | 
					 | 
				
			||||||
                if (that.State != ConnectionState.Closed) try { that.Close(); } catch { }
 | 
					 | 
				
			||||||
                if (isThrow) throw;
 | 
					 | 
				
			||||||
                return false;
 | 
					 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
#endif
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
@@ -1,76 +0,0 @@
 | 
				
			|||||||
using FreeSql.Internal;
 | 
					 | 
				
			||||||
using FreeSql.Internal.Model;
 | 
					 | 
				
			||||||
using SafeObjectPool;
 | 
					 | 
				
			||||||
using System;
 | 
					 | 
				
			||||||
using System.Collections;
 | 
					 | 
				
			||||||
using System.Collections.Generic;
 | 
					 | 
				
			||||||
using System.Data.Common;
 | 
					 | 
				
			||||||
using System.Data.Odbc;
 | 
					 | 
				
			||||||
using System.Text;
 | 
					 | 
				
			||||||
using System.Threading;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
namespace FreeSql.Odbc.GBase
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
    class OdbcGBaseAdo : FreeSql.Internal.CommonProvider.AdoProvider
 | 
					 | 
				
			||||||
    {
 | 
					 | 
				
			||||||
        public OdbcGBaseAdo() : base(DataType.PostgreSQL) { }
 | 
					 | 
				
			||||||
        public OdbcGBaseAdo(CommonUtils util, string masterConnectionString, string[] slaveConnectionStrings, Func<DbConnection> connectionFactory) : base(DataType.PostgreSQL)
 | 
					 | 
				
			||||||
        {
 | 
					 | 
				
			||||||
            base._util = util;
 | 
					 | 
				
			||||||
            if (connectionFactory != null)
 | 
					 | 
				
			||||||
            {
 | 
					 | 
				
			||||||
                MasterPool = new FreeSql.Internal.CommonProvider.DbConnectionPool(DataType.PostgreSQL, connectionFactory);
 | 
					 | 
				
			||||||
                return;
 | 
					 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
            if (!string.IsNullOrEmpty(masterConnectionString))
 | 
					 | 
				
			||||||
                MasterPool = new OdbcGBaseConnectionPool("主库", masterConnectionString, null, null);
 | 
					 | 
				
			||||||
            if (slaveConnectionStrings != null)
 | 
					 | 
				
			||||||
            {
 | 
					 | 
				
			||||||
                foreach (var slaveConnectionString in slaveConnectionStrings)
 | 
					 | 
				
			||||||
                {
 | 
					 | 
				
			||||||
                    var slavePool = new OdbcGBaseConnectionPool($"从库{SlavePools.Count + 1}", slaveConnectionString, () => Interlocked.Decrement(ref slaveUnavailables), () => Interlocked.Increment(ref slaveUnavailables));
 | 
					 | 
				
			||||||
                    SlavePools.Add(slavePool);
 | 
					 | 
				
			||||||
                }
 | 
					 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        public override object AddslashesProcessParam(object param, Type mapType, ColumnInfo mapColumn)
 | 
					 | 
				
			||||||
        {
 | 
					 | 
				
			||||||
            if (param == null) return "NULL";
 | 
					 | 
				
			||||||
            if (mapType != null && mapType != param.GetType() && (param is IEnumerable == false))
 | 
					 | 
				
			||||||
                param = Utils.GetDataReaderValue(mapType, param);
 | 
					 | 
				
			||||||
            if (param is bool || param is bool?)
 | 
					 | 
				
			||||||
                return (bool)param ? "'t'" : "'f'";
 | 
					 | 
				
			||||||
            else if (param is string || param is char)
 | 
					 | 
				
			||||||
                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 || param is DateTime?)
 | 
					 | 
				
			||||||
                return string.Concat("'", ((DateTime)param).ToString("yyyy-MM-dd HH:mm:ss.ffffff"), "'");
 | 
					 | 
				
			||||||
            else if (param is TimeSpan || param is TimeSpan?)
 | 
					 | 
				
			||||||
                return ((TimeSpan)param).Ticks / 10;
 | 
					 | 
				
			||||||
            else if (param is byte[])
 | 
					 | 
				
			||||||
                return $"'\\x{CommonUtils.BytesSqlRaw(param as byte[])}'";
 | 
					 | 
				
			||||||
            else if (param is IEnumerable)
 | 
					 | 
				
			||||||
                return AddslashesIEnumerable(param, mapType, mapColumn);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
            return string.Concat("'", param.ToString().Replace("'", "''"), "'");
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        protected override DbCommand CreateCommand()
 | 
					 | 
				
			||||||
        {
 | 
					 | 
				
			||||||
            return new OdbcCommand();
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        protected override void ReturnConnection(IObjectPool<DbConnection> pool, Object<DbConnection> conn, Exception ex)
 | 
					 | 
				
			||||||
        {
 | 
					 | 
				
			||||||
            var rawPool = pool as OdbcGBaseConnectionPool;
 | 
					 | 
				
			||||||
            if (rawPool != null) rawPool.Return(conn, ex);
 | 
					 | 
				
			||||||
            else pool.Return(conn);
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        protected override DbParameter[] GetDbParamtersByObject(string sql, object obj) => _util.GetDbParamtersByObject(sql, obj);
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
@@ -1,64 +0,0 @@
 | 
				
			|||||||
using FreeSql.Internal;
 | 
					 | 
				
			||||||
using FreeSql.Internal.CommonProvider;
 | 
					 | 
				
			||||||
using System;
 | 
					 | 
				
			||||||
using System.Collections.Generic;
 | 
					 | 
				
			||||||
using System.Data;
 | 
					 | 
				
			||||||
using System.Data.Common;
 | 
					 | 
				
			||||||
using System.Threading;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
namespace FreeSql.Odbc.GBase
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    public class OdbcGBaseProvider<TMark> : IFreeSql<TMark>
 | 
					 | 
				
			||||||
    {
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        static OdbcGBaseProvider()
 | 
					 | 
				
			||||||
        {
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        public ISelect<T1> Select<T1>() where T1 : class => new OdbcGBaseSelect<T1>(this, this.InternalCommonUtils, this.InternalCommonExpression, null);
 | 
					 | 
				
			||||||
        public ISelect<T1> Select<T1>(object dywhere) where T1 : class => new OdbcGBaseSelect<T1>(this, this.InternalCommonUtils, this.InternalCommonExpression, dywhere);
 | 
					 | 
				
			||||||
        public IInsert<T1> Insert<T1>() where T1 : class => new OdbcGBaseInsert<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>(T1[] source) where T1 : class => this.Insert<T1>().AppendData(source);
 | 
					 | 
				
			||||||
        public IInsert<T1> Insert<T1>(List<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 OdbcGBaseUpdate<T1>(this, this.InternalCommonUtils, this.InternalCommonExpression, null);
 | 
					 | 
				
			||||||
        public IUpdate<T1> Update<T1>(object dywhere) where T1 : class => new OdbcGBaseUpdate<T1>(this, this.InternalCommonUtils, this.InternalCommonExpression, dywhere);
 | 
					 | 
				
			||||||
        public IDelete<T1> Delete<T1>() where T1 : class => new OdbcGBaseDelete<T1>(this, this.InternalCommonUtils, this.InternalCommonExpression, null);
 | 
					 | 
				
			||||||
        public IDelete<T1> Delete<T1>(object dywhere) where T1 : class => new OdbcGBaseDelete<T1>(this, this.InternalCommonUtils, this.InternalCommonExpression, dywhere);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        public IAdo Ado { get; }
 | 
					 | 
				
			||||||
        public IAop Aop { get; }
 | 
					 | 
				
			||||||
        public ICodeFirst CodeFirst { get; }
 | 
					 | 
				
			||||||
        public IDbFirst DbFirst { get; }
 | 
					 | 
				
			||||||
        public OdbcGBaseProvider(string masterConnectionString, string[] slaveConnectionString, Func<DbConnection> connectionFactory = null)
 | 
					 | 
				
			||||||
        {
 | 
					 | 
				
			||||||
            this.InternalCommonUtils = new OdbcGBaseUtils(this);
 | 
					 | 
				
			||||||
            this.InternalCommonExpression = new OdbcGBaseExpression(this.InternalCommonUtils);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
            this.Ado = new OdbcGBaseAdo(this.InternalCommonUtils, masterConnectionString, slaveConnectionString, connectionFactory);
 | 
					 | 
				
			||||||
            this.Aop = new AopProvider();
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
            this.DbFirst = new OdbcGBaseDbFirst(this, this.InternalCommonUtils, this.InternalCommonExpression);
 | 
					 | 
				
			||||||
            this.CodeFirst = new OdbcGBaseCodeFirst(this, this.InternalCommonUtils, this.InternalCommonExpression);
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        internal CommonUtils InternalCommonUtils { get; }
 | 
					 | 
				
			||||||
        internal CommonExpression InternalCommonExpression { get; }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        public void Transaction(Action handler) => Ado.Transaction(handler);
 | 
					 | 
				
			||||||
        public void Transaction(TimeSpan timeout, Action handler) => Ado.Transaction(timeout, handler);
 | 
					 | 
				
			||||||
        public void Transaction(IsolationLevel isolationLevel, TimeSpan timeout, Action handler) => Ado.Transaction(isolationLevel, timeout, handler);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        public GlobalFilter GlobalFilter { get; } = new GlobalFilter();
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        ~OdbcGBaseProvider() => this.Dispose();
 | 
					 | 
				
			||||||
        int _disposeCounter;
 | 
					 | 
				
			||||||
        public void Dispose()
 | 
					 | 
				
			||||||
        {
 | 
					 | 
				
			||||||
            if (Interlocked.Increment(ref _disposeCounter) != 1) return;
 | 
					 | 
				
			||||||
            (this.Ado as AdoProvider)?.Dispose();
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
@@ -1,388 +0,0 @@
 | 
				
			|||||||
using FreeSql.Internal;
 | 
					 | 
				
			||||||
using FreeSql.Internal.Model;
 | 
					 | 
				
			||||||
using System;
 | 
					 | 
				
			||||||
using System.Collections.Generic;
 | 
					 | 
				
			||||||
using System.Data;
 | 
					 | 
				
			||||||
using System.Data.Odbc;
 | 
					 | 
				
			||||||
using System.Linq;
 | 
					 | 
				
			||||||
using System.Text;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
namespace FreeSql.Odbc.GBase
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    class OdbcGBaseCodeFirst : Internal.CommonProvider.CodeFirstProvider
 | 
					 | 
				
			||||||
    {
 | 
					 | 
				
			||||||
        public override bool IsNoneCommandParameter { get => true; set => base.IsNoneCommandParameter = true; }
 | 
					 | 
				
			||||||
        public OdbcGBaseCodeFirst(IFreeSql orm, CommonUtils commonUtils, CommonExpression commonExpression) : base(orm, commonUtils, commonExpression) { }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        static object _dicCsToDbLock = new object();
 | 
					 | 
				
			||||||
        static Dictionary<string, (OdbcType type, string dbtype, string dbtypeFull, bool? isUnsigned, bool? isnullable, object defaultValue)> _dicCsToDb = new Dictionary<string, (OdbcType type, string dbtype, string dbtypeFull, bool? isUnsigned, bool? isnullable, object defaultValue)>() {
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
                { typeof(sbyte).FullName,  (OdbcType.SmallInt, "smallint","smallint NOT NULL", false, false, 0) },{ typeof(sbyte?).FullName,  (OdbcType.SmallInt, "smallint", "smallint", false, true, null) },
 | 
					 | 
				
			||||||
                { typeof(short).FullName,  (OdbcType.SmallInt, "smallint","smallint NOT NULL", false, false, 0) },{ typeof(short?).FullName,  (OdbcType.SmallInt, "smallint", "smallint", false, true, null) },
 | 
					 | 
				
			||||||
                { typeof(int).FullName,  (OdbcType.Int, "integer","integer NOT NULL", false, false, 0) },{ typeof(int?).FullName,  (OdbcType.Int, "integer", "integer", false, true, null) },
 | 
					 | 
				
			||||||
                { typeof(long).FullName,  (OdbcType.BigInt, "bigint","bigint NOT NULL", false, false, 0) },{ typeof(long?).FullName,  (OdbcType.BigInt, "bigint", "bigint", false, true, null) },
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
                { typeof(byte).FullName,  (OdbcType.SmallInt, "byte","byte NOT NULL", false, false, 0) },{ typeof(byte?).FullName,  (OdbcType.SmallInt, "byte", "byte", false, true, null) },
 | 
					 | 
				
			||||||
                { typeof(ushort).FullName,  (OdbcType.Int, "integer","integer NOT NULL", false, false, 0) },{ typeof(ushort?).FullName,  (OdbcType.Int, "integer", "integer", false, true, null) },
 | 
					 | 
				
			||||||
                { typeof(uint).FullName,  (OdbcType.BigInt, "bigint","bigint NOT NULL", false, false, 0) },{ typeof(uint?).FullName,  (OdbcType.BigInt, "bigint", "bigint", false, true, null) },
 | 
					 | 
				
			||||||
                { typeof(ulong).FullName,  (OdbcType.Decimal, "decimal","decimal(20,0) NOT NULL", false, false, 0) },{ typeof(ulong?).FullName,  (OdbcType.Decimal, "decimal", "decimal(20,0)", false, true, null) },
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
                { typeof(float).FullName,  (OdbcType.Real, "smallfloat","smallfloat NOT NULL", false, false, 0) },{ typeof(float?).FullName,  (OdbcType.Real, "smallfloat", "smallfloat", false, true, null) },
 | 
					 | 
				
			||||||
                { typeof(double).FullName,  (OdbcType.Double, "float","float NOT NULL", false, false, 0) },{ typeof(double?).FullName,  (OdbcType.Double, "float", "float", false, true, null) },
 | 
					 | 
				
			||||||
                { typeof(decimal).FullName,  (OdbcType.Decimal, "decimal", "decimal(10,2) NOT NULL", false, false, 0) },{ typeof(decimal?).FullName,  (OdbcType.Decimal, "decimal", "decimal(10,2)", false, true, null) },
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
                { typeof(string).FullName,  (OdbcType.NVarChar, "nvarchar", "nvarchar(255)", false, null, "") },
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
                { typeof(TimeSpan).FullName,  (OdbcType.Time, "time","time NOT NULL", false, false, 0) },{ typeof(TimeSpan?).FullName,  (OdbcType.Time, "time", "time",false, true, null) },
 | 
					 | 
				
			||||||
                { typeof(DateTime).FullName,  (OdbcType.DateTime, "timestamp", "timestamp NOT NULL", false, false, new DateTime(1970,1,1)) },{ typeof(DateTime?).FullName,  (OdbcType.DateTime, "timestamp", "timestamp", false, true, null) },
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
                { typeof(bool).FullName,  (OdbcType.Bit, "char","char(1) NOT NULL", null, false, false) },{ typeof(bool?).FullName,  (OdbcType.Bit, "char","char(1)", null, true, null) },
 | 
					 | 
				
			||||||
                { typeof(Byte[]).FullName,  (OdbcType.VarBinary, "blob", "blob", false, null, new byte[0]) },
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
                { typeof(Guid).FullName,  (OdbcType.Char, "char", "char(36) NOT NULL", false, false, Guid.Empty) },{ typeof(Guid?).FullName,  (OdbcType.Char, "char", "char(36)", false, true, null) },
 | 
					 | 
				
			||||||
            };
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        public override (int type, string dbtype, string dbtypeFull, bool? isnullable, object defaultValue)? GetDbInfo(Type type)
 | 
					 | 
				
			||||||
        {
 | 
					 | 
				
			||||||
            var isarray = type.FullName != "System.Byte[]" && type.IsArray;
 | 
					 | 
				
			||||||
            var elementType = isarray ? type.GetElementType() : type;
 | 
					 | 
				
			||||||
            var info = GetDbInfoNoneArray(elementType);
 | 
					 | 
				
			||||||
            if (info == null) return null;
 | 
					 | 
				
			||||||
            return ((int)info.Value.type, info.Value.dbtype, info.Value.dbtypeFull, info.Value.isnullable, info.Value.defaultValue);
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
        (OdbcType type, string dbtype, string dbtypeFull, bool? isnullable, object defaultValue)? GetDbInfoNoneArray(Type type)
 | 
					 | 
				
			||||||
        {
 | 
					 | 
				
			||||||
            if (_dicCsToDb.TryGetValue(type.FullName, out var trydc)) return new (OdbcType, string, string, bool?, object)?((trydc.type, trydc.dbtype, trydc.dbtypeFull, trydc.isnullable, trydc.defaultValue));
 | 
					 | 
				
			||||||
            if (type.IsArray) return null;
 | 
					 | 
				
			||||||
            var enumType = type.IsEnum ? type : null;
 | 
					 | 
				
			||||||
            if (enumType == null && type.IsNullableType())
 | 
					 | 
				
			||||||
            {
 | 
					 | 
				
			||||||
                var genericTypes = type.GetGenericArguments();
 | 
					 | 
				
			||||||
                if (genericTypes.Length == 1 && genericTypes.First().IsEnum) enumType = genericTypes.First();
 | 
					 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
            if (enumType != null)
 | 
					 | 
				
			||||||
            {
 | 
					 | 
				
			||||||
                var newItem = enumType.GetCustomAttributes(typeof(FlagsAttribute), false).Any() ?
 | 
					 | 
				
			||||||
                    (OdbcType.Int, "bigint", $"bigint{(type.IsEnum ? " NOT NULL" : "")}", false, type.IsEnum ? false : true, Enum.GetValues(enumType).GetValue(0)) :
 | 
					 | 
				
			||||||
                    (OdbcType.BigInt, "integer", $"integer{(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 (newItem.Item1, newItem.Item2, newItem.Item3, newItem.Item5, newItem.Item6);
 | 
					 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
            return null;
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        protected override string GetComparisonDDLStatements(params (Type entityType, string tableName)[] objects)
 | 
					 | 
				
			||||||
        {
 | 
					 | 
				
			||||||
            var sb = new StringBuilder();
 | 
					 | 
				
			||||||
            var seqcols = new List<(ColumnInfo, string[], bool)>(); //序列
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
            foreach (var obj in objects)
 | 
					 | 
				
			||||||
            {
 | 
					 | 
				
			||||||
                if (sb.Length > 0) sb.Append("\r\n");
 | 
					 | 
				
			||||||
                var tb = _commonUtils.GetTableByEntity(obj.entityType);
 | 
					 | 
				
			||||||
                if (tb == null) throw new Exception($"类型 {obj.entityType.FullName} 不可迁移");
 | 
					 | 
				
			||||||
                if (tb.Columns.Any() == false) throw new Exception($"类型 {obj.entityType.FullName} 不可迁移,可迁移属性0个");
 | 
					 | 
				
			||||||
                var tbname = _commonUtils.SplitTableName(tb.DbName);
 | 
					 | 
				
			||||||
                if (tbname?.Length == 1) tbname = new[] { "public", tbname[0] };
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
                var tboldname = _commonUtils.SplitTableName(tb.DbOldName); //旧表名
 | 
					 | 
				
			||||||
                if (tboldname?.Length == 1) tboldname = new[] { "public", tboldname[0] };
 | 
					 | 
				
			||||||
                if (string.IsNullOrEmpty(obj.tableName) == false)
 | 
					 | 
				
			||||||
                {
 | 
					 | 
				
			||||||
                    var tbtmpname = _commonUtils.SplitTableName(obj.tableName);
 | 
					 | 
				
			||||||
                    if (tbtmpname?.Length == 1) tbtmpname = new[] { "public", tbtmpname[0] };
 | 
					 | 
				
			||||||
                    if (tbname[0] != tbtmpname[0] || tbname[1] != tbtmpname[1])
 | 
					 | 
				
			||||||
                    {
 | 
					 | 
				
			||||||
                        tbname = tbtmpname;
 | 
					 | 
				
			||||||
                        tboldname = null;
 | 
					 | 
				
			||||||
                    }
 | 
					 | 
				
			||||||
                }
 | 
					 | 
				
			||||||
                //codefirst 不支持表名、模式名、数据库名中带 .
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
                if (string.Compare(tbname[0], "public", true) != 0 && _orm.Ado.ExecuteScalar(CommandType.Text, _commonUtils.FormatSql(" select 1 from pg_namespace where nspname={0}", tbname[0])) == null) //创建模式
 | 
					 | 
				
			||||||
                    sb.Append("CREATE SCHEMA IF NOT EXISTS ").Append(tbname[0]).Append(";\r\n");
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
                var sbalter = new StringBuilder();
 | 
					 | 
				
			||||||
                var istmpatler = false; //创建临时表,导入数据,删除旧表,修改
 | 
					 | 
				
			||||||
                if (_orm.Ado.ExecuteScalar(CommandType.Text, string.Format(" select 1 from pg_tables a inner join pg_namespace b on b.nspname = a.schemaname where b.nspname || '.' || a.tablename = '{0}.{1}'", tbname)) == null)
 | 
					 | 
				
			||||||
                { //表不存在
 | 
					 | 
				
			||||||
                    if (tboldname != null)
 | 
					 | 
				
			||||||
                    {
 | 
					 | 
				
			||||||
                        if (_orm.Ado.ExecuteScalar(CommandType.Text, string.Format(" select 1 from pg_tables a inner join pg_namespace b on b.nspname = a.schemaname where b.nspname || '.' || a.tablename = '{0}.{1}'", tboldname)) == null)
 | 
					 | 
				
			||||||
                            //旧表不存在
 | 
					 | 
				
			||||||
                            tboldname = null;
 | 
					 | 
				
			||||||
                    }
 | 
					 | 
				
			||||||
                    if (tboldname == null)
 | 
					 | 
				
			||||||
                    {
 | 
					 | 
				
			||||||
                        //创建表
 | 
					 | 
				
			||||||
                        var createTableName = _commonUtils.QuoteSqlName($"{tbname[0]}.{tbname[1]}");
 | 
					 | 
				
			||||||
                        sb.Append("CREATE TABLE IF NOT EXISTS ").Append(createTableName).Append(" ( ");
 | 
					 | 
				
			||||||
                        foreach (var tbcol in tb.ColumnsByPosition)
 | 
					 | 
				
			||||||
                        {
 | 
					 | 
				
			||||||
                            sb.Append(" \r\n  ").Append(_commonUtils.QuoteSqlName(tbcol.Attribute.Name)).Append(" ").Append(tbcol.Attribute.DbType).Append(",");
 | 
					 | 
				
			||||||
                            if (tbcol.Attribute.IsIdentity == true) seqcols.Add((tbcol, tbname, true));
 | 
					 | 
				
			||||||
                        }
 | 
					 | 
				
			||||||
                        if (tb.Primarys.Any())
 | 
					 | 
				
			||||||
                        {
 | 
					 | 
				
			||||||
                            sb.Append(" \r\n  CONSTRAINT ").Append(tbname[0]).Append("_").Append(tbname[1]).Append("_pkey PRIMARY KEY (");
 | 
					 | 
				
			||||||
                            foreach (var tbcol in tb.Primarys) sb.Append(_commonUtils.QuoteSqlName(tbcol.Attribute.Name)).Append(", ");
 | 
					 | 
				
			||||||
                            sb.Remove(sb.Length - 2, 2).Append("),");
 | 
					 | 
				
			||||||
                        }
 | 
					 | 
				
			||||||
                        sb.Remove(sb.Length - 1, 1);
 | 
					 | 
				
			||||||
                        sb.Append("\r\n) WITH (OIDS=FALSE);\r\n");
 | 
					 | 
				
			||||||
                        //创建表的索引
 | 
					 | 
				
			||||||
                        foreach (var uk in tb.Indexes)
 | 
					 | 
				
			||||||
                        {
 | 
					 | 
				
			||||||
                            sb.Append("CREATE ");
 | 
					 | 
				
			||||||
                            if (uk.IsUnique) sb.Append("UNIQUE ");
 | 
					 | 
				
			||||||
                            sb.Append("INDEX ").Append(_commonUtils.QuoteSqlName(uk.Name)).Append(" ON ").Append(createTableName).Append("(");
 | 
					 | 
				
			||||||
                            foreach (var tbcol in uk.Columns)
 | 
					 | 
				
			||||||
                            {
 | 
					 | 
				
			||||||
                                sb.Append(_commonUtils.QuoteSqlName(tbcol.Column.Attribute.Name));
 | 
					 | 
				
			||||||
                                if (tbcol.IsDesc) sb.Append(" DESC");
 | 
					 | 
				
			||||||
                                sb.Append(", ");
 | 
					 | 
				
			||||||
                            }
 | 
					 | 
				
			||||||
                            sb.Remove(sb.Length - 2, 2).Append(");\r\n");
 | 
					 | 
				
			||||||
                        }
 | 
					 | 
				
			||||||
                        //备注
 | 
					 | 
				
			||||||
                        foreach (var tbcol in tb.ColumnsByPosition)
 | 
					 | 
				
			||||||
                        {
 | 
					 | 
				
			||||||
                            if (string.IsNullOrEmpty(tbcol.Comment) == false)
 | 
					 | 
				
			||||||
                                sb.Append("COMMENT ON COLUMN ").Append(_commonUtils.QuoteSqlName($"{tbname[0]}.{tbname[1]}.{tbcol.Attribute.Name}")).Append(" IS ").Append(_commonUtils.FormatSql("{0}", tbcol.Comment)).Append(";\r\n");
 | 
					 | 
				
			||||||
                        }
 | 
					 | 
				
			||||||
                        continue;
 | 
					 | 
				
			||||||
                    }
 | 
					 | 
				
			||||||
                    //如果新表,旧表在一个数据库和模式下,直接修改表名
 | 
					 | 
				
			||||||
                    if (string.Compare(tbname[0], tboldname[0], true) == 0)
 | 
					 | 
				
			||||||
                        sbalter.Append("ALTER TABLE ").Append(_commonUtils.QuoteSqlName($"{tboldname[0]}.{tboldname[1]}")).Append(" RENAME TO ").Append(_commonUtils.QuoteSqlName($"{tbname[1]}")).Append(";\r\n");
 | 
					 | 
				
			||||||
                    else
 | 
					 | 
				
			||||||
                    {
 | 
					 | 
				
			||||||
                        //如果新表,旧表不在一起,创建新表,导入数据,删除旧表
 | 
					 | 
				
			||||||
                        istmpatler = true;
 | 
					 | 
				
			||||||
                    }
 | 
					 | 
				
			||||||
                }
 | 
					 | 
				
			||||||
                else
 | 
					 | 
				
			||||||
                    tboldname = null; //如果新表已经存在,不走改表名逻辑
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
                //对比字段,只可以修改类型、增加字段、有限的修改字段名;保证安全不删除字段
 | 
					 | 
				
			||||||
                var sql = _commonUtils.FormatSql(@"
 | 
					 | 
				
			||||||
select
 | 
					 | 
				
			||||||
a.attname,
 | 
					 | 
				
			||||||
t.typname,
 | 
					 | 
				
			||||||
case when a.atttypmod > 0 and a.atttypmod < 32767 then a.atttypmod - 4 else a.attlen end len,
 | 
					 | 
				
			||||||
case when t.typelem > 0 and t.typinput::varchar = 'array_in' then t2.typname else t.typname end,
 | 
					 | 
				
			||||||
case when a.attnotnull then '0' else '1' end as is_nullable,
 | 
					 | 
				
			||||||
coalesce((select 1 from pg_sequences where sequencename = {0} || '_' || {1} || '_' || a.attname || '_sequence_name' limit 1),0) is_identity,
 | 
					 | 
				
			||||||
--e.adsrc,
 | 
					 | 
				
			||||||
a.attndims,
 | 
					 | 
				
			||||||
d.description as comment
 | 
					 | 
				
			||||||
from pg_class c
 | 
					 | 
				
			||||||
inner join pg_attribute a on a.attnum > 0 and a.attrelid = c.oid
 | 
					 | 
				
			||||||
inner join pg_type t on t.oid = a.atttypid
 | 
					 | 
				
			||||||
left join pg_type t2 on t2.oid = t.typelem
 | 
					 | 
				
			||||||
left join pg_description d on d.objoid = a.attrelid and d.objsubid = a.attnum
 | 
					 | 
				
			||||||
left join pg_attrdef e on e.adrelid = a.attrelid and e.adnum = a.attnum
 | 
					 | 
				
			||||||
inner join pg_namespace ns on ns.oid = c.relnamespace
 | 
					 | 
				
			||||||
inner join pg_namespace ns2 on ns2.oid = t.typnamespace
 | 
					 | 
				
			||||||
where ns.nspname = {0} and c.relname = {1}", tboldname ?? tbname);
 | 
					 | 
				
			||||||
                var ds = _orm.Ado.ExecuteArray(CommandType.Text, sql);
 | 
					 | 
				
			||||||
                var tbstruct = ds.ToDictionary(a => string.Concat(a[0]), a =>
 | 
					 | 
				
			||||||
                {
 | 
					 | 
				
			||||||
                    var attndims = int.Parse(string.Concat(a[6]));
 | 
					 | 
				
			||||||
                    var type = string.Concat(a[1]);
 | 
					 | 
				
			||||||
                    var sqlType = string.Concat(a[3]);
 | 
					 | 
				
			||||||
                    var max_length = long.Parse(string.Concat(a[2]));
 | 
					 | 
				
			||||||
                    switch (sqlType.ToLower())
 | 
					 | 
				
			||||||
                    {
 | 
					 | 
				
			||||||
                        case "bool": case "name": case "bit": case "varbit": case "bpchar": case "varchar": case "bytea": case "text": case "uuid": break;
 | 
					 | 
				
			||||||
                        default: max_length *= 8; break;
 | 
					 | 
				
			||||||
                    }
 | 
					 | 
				
			||||||
                    if (type.StartsWith("_"))
 | 
					 | 
				
			||||||
                    {
 | 
					 | 
				
			||||||
                        type = type.Substring(1);
 | 
					 | 
				
			||||||
                        if (attndims == 0) attndims++;
 | 
					 | 
				
			||||||
                    }
 | 
					 | 
				
			||||||
                    if (sqlType.StartsWith("_")) sqlType = sqlType.Substring(1);
 | 
					 | 
				
			||||||
                    return new
 | 
					 | 
				
			||||||
                    {
 | 
					 | 
				
			||||||
                        column = string.Concat(a[0]),
 | 
					 | 
				
			||||||
                        sqlType = string.Concat(sqlType),
 | 
					 | 
				
			||||||
                        max_length = long.Parse(string.Concat(a[2])),
 | 
					 | 
				
			||||||
                        is_nullable = string.Concat(a[4]) == "1",
 | 
					 | 
				
			||||||
                        is_identity = string.Concat(a[5]) == "1", //string.Concat(a[5]).StartsWith(@"nextval('") && string.Concat(a[5]).EndsWith(@"'::regclass)"),
 | 
					 | 
				
			||||||
                        attndims,
 | 
					 | 
				
			||||||
                        comment = string.Concat(a[7])
 | 
					 | 
				
			||||||
                    };
 | 
					 | 
				
			||||||
                }, StringComparer.CurrentCultureIgnoreCase);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
                if (istmpatler == false)
 | 
					 | 
				
			||||||
                {
 | 
					 | 
				
			||||||
                    foreach (var tbcol in tb.ColumnsByPosition)
 | 
					 | 
				
			||||||
                    {
 | 
					 | 
				
			||||||
                        if (tbstruct.TryGetValue(tbcol.Attribute.Name, out var tbstructcol) ||
 | 
					 | 
				
			||||||
                            string.IsNullOrEmpty(tbcol.Attribute.OldName) == false && tbstruct.TryGetValue(tbcol.Attribute.OldName, out tbstructcol))
 | 
					 | 
				
			||||||
                        {
 | 
					 | 
				
			||||||
                            var isCommentChanged = tbstructcol.comment != (tbcol.Comment ?? "");
 | 
					 | 
				
			||||||
                            if (tbcol.Attribute.DbType.StartsWith(tbstructcol.sqlType, StringComparison.CurrentCultureIgnoreCase) == false ||
 | 
					 | 
				
			||||||
                                tbcol.Attribute.DbType.Contains("[]") != (tbstructcol.attndims > 0))
 | 
					 | 
				
			||||||
                                sbalter.Append("ALTER TABLE ").Append(_commonUtils.QuoteSqlName($"{tbname[0]}.{tbname[1]}")).Append(" ALTER COLUMN ").Append(_commonUtils.QuoteSqlName(tbstructcol.column)).Append(" TYPE ").Append(tbcol.Attribute.DbType.Split(' ').First()).Append(";\r\n");
 | 
					 | 
				
			||||||
                            if (tbcol.Attribute.IsNullable != tbstructcol.is_nullable)
 | 
					 | 
				
			||||||
                            {
 | 
					 | 
				
			||||||
                                if (tbcol.Attribute.IsNullable != true || tbcol.Attribute.IsNullable == true && tbcol.Attribute.IsPrimary == false)
 | 
					 | 
				
			||||||
                                {
 | 
					 | 
				
			||||||
                                    if (tbcol.Attribute.IsNullable == false)
 | 
					 | 
				
			||||||
                                        sbalter.Append("UPDATE ").Append(_commonUtils.QuoteSqlName($"{tbname[0]}.{tbname[1]}")).Append(" SET ").Append(_commonUtils.QuoteSqlName(tbstructcol.column)).Append(" = ").Append(tbcol.DbDefaultValue).Append(" WHERE ").Append(_commonUtils.QuoteSqlName(tbstructcol.column)).Append(" IS NULL;\r\n");
 | 
					 | 
				
			||||||
                                    sbalter.Append("ALTER TABLE ").Append(_commonUtils.QuoteSqlName($"{tbname[0]}.{tbname[1]}")).Append(" ALTER COLUMN ").Append(_commonUtils.QuoteSqlName(tbstructcol.column)).Append(" ").Append(tbcol.Attribute.IsNullable == true ? "DROP" : "SET").Append(" NOT NULL;\r\n");
 | 
					 | 
				
			||||||
                                }
 | 
					 | 
				
			||||||
                            }
 | 
					 | 
				
			||||||
                            if (tbcol.Attribute.IsIdentity != tbstructcol.is_identity)
 | 
					 | 
				
			||||||
                                seqcols.Add((tbcol, tbname, tbcol.Attribute.IsIdentity == true));
 | 
					 | 
				
			||||||
                            if (string.Compare(tbstructcol.column, tbcol.Attribute.OldName, true) == 0)
 | 
					 | 
				
			||||||
                                //修改列名
 | 
					 | 
				
			||||||
                                sbalter.Append("ALTER TABLE ").Append(_commonUtils.QuoteSqlName($"{tbname[0]}.{tbname[1]}")).Append(" RENAME COLUMN ").Append(_commonUtils.QuoteSqlName(tbstructcol.column)).Append(" TO ").Append(_commonUtils.QuoteSqlName(tbcol.Attribute.Name)).Append(";\r\n");
 | 
					 | 
				
			||||||
                            if (isCommentChanged)
 | 
					 | 
				
			||||||
                                sbalter.Append("COMMENT ON COLUMN ").Append(_commonUtils.QuoteSqlName($"{tbname[0]}.{tbname[1]}.{tbcol.Attribute.Name}")).Append(" IS ").Append(_commonUtils.FormatSql("{0}", tbcol.Comment)).Append(";\r\n");
 | 
					 | 
				
			||||||
                            continue;
 | 
					 | 
				
			||||||
                        }
 | 
					 | 
				
			||||||
                        //添加列
 | 
					 | 
				
			||||||
                        sbalter.Append("ALTER TABLE ").Append(_commonUtils.QuoteSqlName($"{tbname[0]}.{tbname[1]}")).Append(" ADD COLUMN ").Append(_commonUtils.QuoteSqlName(tbcol.Attribute.Name)).Append(" ").Append(tbcol.Attribute.DbType.Split(' ').First()).Append(";\r\n");
 | 
					 | 
				
			||||||
                        sbalter.Append("UPDATE ").Append(_commonUtils.QuoteSqlName($"{tbname[0]}.{tbname[1]}")).Append(" SET ").Append(_commonUtils.QuoteSqlName(tbcol.Attribute.Name)).Append(" = ").Append(tbcol.DbDefaultValue).Append(";\r\n");
 | 
					 | 
				
			||||||
                        if (tbcol.Attribute.IsNullable == false) sbalter.Append("ALTER TABLE ").Append(_commonUtils.QuoteSqlName($"{tbname[0]}.{tbname[1]}")).Append(" ALTER COLUMN ").Append(_commonUtils.QuoteSqlName(tbcol.Attribute.Name)).Append(" SET NOT NULL;\r\n");
 | 
					 | 
				
			||||||
                        if (tbcol.Attribute.IsIdentity == true) seqcols.Add((tbcol, tbname, tbcol.Attribute.IsIdentity == true));
 | 
					 | 
				
			||||||
                        if (string.IsNullOrEmpty(tbcol.Comment) == false) sbalter.Append("COMMENT ON COLUMN ").Append(_commonUtils.QuoteSqlName($"{tbname[0]}.{tbname[1]}.{tbcol.Attribute.Name}")).Append(" IS ").Append(_commonUtils.FormatSql("{0}", tbcol.Comment)).Append(";\r\n");
 | 
					 | 
				
			||||||
                    }
 | 
					 | 
				
			||||||
                    var dsuksql = _commonUtils.FormatSql(@"
 | 
					 | 
				
			||||||
select
 | 
					 | 
				
			||||||
c.attname,
 | 
					 | 
				
			||||||
b.relname,
 | 
					 | 
				
			||||||
case when pg_index_column_has_property(b.oid, c.attnum, 'desc') = 't' then 1 else 0 end IsDesc,
 | 
					 | 
				
			||||||
case when indisunique = 't' then 1 else 0 end IsUnique
 | 
					 | 
				
			||||||
from pg_index a
 | 
					 | 
				
			||||||
inner join pg_class b on b.oid = a.indexrelid
 | 
					 | 
				
			||||||
inner join pg_attribute c on c.attnum > 0 and c.attrelid = b.oid
 | 
					 | 
				
			||||||
inner join pg_namespace ns on ns.oid = b.relnamespace
 | 
					 | 
				
			||||||
inner join pg_class d on d.oid = a.indrelid
 | 
					 | 
				
			||||||
where ns.nspname in ({0}) and d.relname in ({1}) and a.indisprimary = 'f'", tboldname ?? tbname);
 | 
					 | 
				
			||||||
                    var dsuk = _orm.Ado.ExecuteArray(CommandType.Text, dsuksql).Select(a => new[] { string.Concat(a[0]), string.Concat(a[1]), string.Concat(a[2]), string.Concat(a[3]) });
 | 
					 | 
				
			||||||
                    foreach (var uk in tb.Indexes)
 | 
					 | 
				
			||||||
                    {
 | 
					 | 
				
			||||||
                        if (string.IsNullOrEmpty(uk.Name) || uk.Columns.Any() == false) continue;
 | 
					 | 
				
			||||||
                        var dsukfind1 = dsuk.Where(a => string.Compare(a[1], uk.Name, true) == 0).ToArray();
 | 
					 | 
				
			||||||
                        if (dsukfind1.Any() == false || dsukfind1.Length != uk.Columns.Length || dsukfind1.Where(a => uk.Columns.Where(b => (a[3] == "1") == uk.IsUnique && string.Compare(b.Column.Attribute.Name, a[0], true) == 0 && (a[2] == "1") == b.IsDesc).Any()).Count() != uk.Columns.Length)
 | 
					 | 
				
			||||||
                        {
 | 
					 | 
				
			||||||
                            if (dsukfind1.Any()) sbalter.Append("DROP INDEX ").Append(_commonUtils.QuoteSqlName(uk.Name)).Append(";\r\n");
 | 
					 | 
				
			||||||
                            sbalter.Append("CREATE ");
 | 
					 | 
				
			||||||
                            if (uk.IsUnique) sbalter.Append("UNIQUE ");
 | 
					 | 
				
			||||||
                            sbalter.Append("INDEX ").Append(_commonUtils.QuoteSqlName(uk.Name)).Append(" ON ").Append(_commonUtils.QuoteSqlName($"{tbname[0]}.{tbname[1]}")).Append("(");
 | 
					 | 
				
			||||||
                            foreach (var tbcol in uk.Columns)
 | 
					 | 
				
			||||||
                            {
 | 
					 | 
				
			||||||
                                sbalter.Append(_commonUtils.QuoteSqlName(tbcol.Column.Attribute.Name));
 | 
					 | 
				
			||||||
                                if (tbcol.IsDesc) sbalter.Append(" DESC");
 | 
					 | 
				
			||||||
                                sbalter.Append(", ");
 | 
					 | 
				
			||||||
                            }
 | 
					 | 
				
			||||||
                            sbalter.Remove(sbalter.Length - 2, 2).Append(");\r\n");
 | 
					 | 
				
			||||||
                        }
 | 
					 | 
				
			||||||
                    }
 | 
					 | 
				
			||||||
                }
 | 
					 | 
				
			||||||
                if (istmpatler == false)
 | 
					 | 
				
			||||||
                {
 | 
					 | 
				
			||||||
                    sb.Append(sbalter);
 | 
					 | 
				
			||||||
                    continue;
 | 
					 | 
				
			||||||
                }
 | 
					 | 
				
			||||||
                var oldpk = _orm.Ado.ExecuteScalar(CommandType.Text, _commonUtils.FormatSql(@" select pg_constraint.conname as pk_name from pg_constraint
 | 
					 | 
				
			||||||
inner join pg_class on pg_constraint.conrelid = pg_class.oid
 | 
					 | 
				
			||||||
inner join pg_namespace on pg_namespace.oid = pg_class.relnamespace
 | 
					 | 
				
			||||||
where pg_namespace.nspname={0} and pg_class.relname={1} and pg_constraint.contype='p'
 | 
					 | 
				
			||||||
", tbname))?.ToString();
 | 
					 | 
				
			||||||
                if (string.IsNullOrEmpty(oldpk) == false)
 | 
					 | 
				
			||||||
                    sb.Append("ALTER TABLE ").Append(_commonUtils.QuoteSqlName($"{tbname[0]}.{tbname[1]}")).Append(" DROP CONSTRAINT ").Append(oldpk).Append(";\r\n");
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
                //创建临时表,数据导进临时表,然后删除原表,将临时表改名为原表名
 | 
					 | 
				
			||||||
                var tablename = tboldname == null ? _commonUtils.QuoteSqlName($"{tbname[0]}.{tbname[1]}") : _commonUtils.QuoteSqlName($"{tboldname[0]}.{tboldname[1]}");
 | 
					 | 
				
			||||||
                var tmptablename = _commonUtils.QuoteSqlName($"{tbname[0]}.FreeSqlTmp_{tbname[1]}");
 | 
					 | 
				
			||||||
                //创建临时表
 | 
					 | 
				
			||||||
                sb.Append("CREATE TABLE IF NOT EXISTS ").Append(tmptablename).Append(" ( ");
 | 
					 | 
				
			||||||
                foreach (var tbcol in tb.ColumnsByPosition)
 | 
					 | 
				
			||||||
                {
 | 
					 | 
				
			||||||
                    sb.Append(" \r\n  ").Append(_commonUtils.QuoteSqlName(tbcol.Attribute.Name)).Append(" ").Append(tbcol.Attribute.DbType).Append(",");
 | 
					 | 
				
			||||||
                    if (tbcol.Attribute.IsIdentity == true) seqcols.Add((tbcol, tbname, true));
 | 
					 | 
				
			||||||
                }
 | 
					 | 
				
			||||||
                if (tb.Primarys.Any())
 | 
					 | 
				
			||||||
                {
 | 
					 | 
				
			||||||
                    sb.Append(" \r\n  CONSTRAINT ").Append(tbname[0]).Append("_").Append(tbname[1]).Append("_pkey PRIMARY KEY (");
 | 
					 | 
				
			||||||
                    foreach (var tbcol in tb.Primarys) sb.Append(_commonUtils.QuoteSqlName(tbcol.Attribute.Name)).Append(", ");
 | 
					 | 
				
			||||||
                    sb.Remove(sb.Length - 2, 2).Append("),");
 | 
					 | 
				
			||||||
                }
 | 
					 | 
				
			||||||
                sb.Remove(sb.Length - 1, 1);
 | 
					 | 
				
			||||||
                sb.Append("\r\n) WITH (OIDS=FALSE);\r\n");
 | 
					 | 
				
			||||||
                //备注
 | 
					 | 
				
			||||||
                foreach (var tbcol in tb.ColumnsByPosition)
 | 
					 | 
				
			||||||
                {
 | 
					 | 
				
			||||||
                    if (string.IsNullOrEmpty(tbcol.Comment) == false)
 | 
					 | 
				
			||||||
                        sb.Append("COMMENT ON COLUMN ").Append(_commonUtils.QuoteSqlName($"{tbname[0]}.FreeSqlTmp_{tbname[1]}.{tbcol.Attribute.Name}")).Append(" IS ").Append(_commonUtils.FormatSql("{0}", tbcol.Comment)).Append(";\r\n");
 | 
					 | 
				
			||||||
                }
 | 
					 | 
				
			||||||
                sb.Append("INSERT INTO ").Append(tmptablename).Append(" (");
 | 
					 | 
				
			||||||
                foreach (var tbcol in tb.ColumnsByPosition)
 | 
					 | 
				
			||||||
                    sb.Append(_commonUtils.QuoteSqlName(tbcol.Attribute.Name)).Append(", ");
 | 
					 | 
				
			||||||
                sb.Remove(sb.Length - 2, 2).Append(")\r\nSELECT ");
 | 
					 | 
				
			||||||
                foreach (var tbcol in tb.ColumnsByPosition)
 | 
					 | 
				
			||||||
                {
 | 
					 | 
				
			||||||
                    var insertvalue = "NULL";
 | 
					 | 
				
			||||||
                    if (tbstruct.TryGetValue(tbcol.Attribute.Name, out var tbstructcol) ||
 | 
					 | 
				
			||||||
                        string.IsNullOrEmpty(tbcol.Attribute.OldName) == false && tbstruct.TryGetValue(tbcol.Attribute.OldName, out tbstructcol))
 | 
					 | 
				
			||||||
                    {
 | 
					 | 
				
			||||||
                        insertvalue = _commonUtils.QuoteSqlName(tbstructcol.column);
 | 
					 | 
				
			||||||
                        if (tbcol.Attribute.DbType.StartsWith(tbstructcol.sqlType, StringComparison.CurrentCultureIgnoreCase) == false)
 | 
					 | 
				
			||||||
                            insertvalue = $"cast({insertvalue} as {tbcol.Attribute.DbType.Split(' ').First()})";
 | 
					 | 
				
			||||||
                        if (tbcol.Attribute.IsNullable != tbstructcol.is_nullable)
 | 
					 | 
				
			||||||
                            insertvalue = $"coalesce({insertvalue},{tbcol.DbDefaultValue})";
 | 
					 | 
				
			||||||
                    }
 | 
					 | 
				
			||||||
                    else if (tbcol.Attribute.IsNullable == false)
 | 
					 | 
				
			||||||
                        insertvalue = tbcol.DbDefaultValue;
 | 
					 | 
				
			||||||
                    sb.Append(insertvalue).Append(", ");
 | 
					 | 
				
			||||||
                }
 | 
					 | 
				
			||||||
                sb.Remove(sb.Length - 2, 2).Append(" FROM ").Append(tablename).Append(";\r\n");
 | 
					 | 
				
			||||||
                sb.Append("DROP TABLE ").Append(tablename).Append(";\r\n");
 | 
					 | 
				
			||||||
                sb.Append("ALTER TABLE ").Append(tmptablename).Append(" RENAME TO ").Append(_commonUtils.QuoteSqlName(tbname[1])).Append(";\r\n");
 | 
					 | 
				
			||||||
                //创建表的索引
 | 
					 | 
				
			||||||
                foreach (var uk in tb.Indexes)
 | 
					 | 
				
			||||||
                {
 | 
					 | 
				
			||||||
                    sb.Append("CREATE ");
 | 
					 | 
				
			||||||
                    if (uk.IsUnique) sb.Append("UNIQUE ");
 | 
					 | 
				
			||||||
                    sb.Append("INDEX ").Append(_commonUtils.QuoteSqlName(uk.Name)).Append(" ON ").Append(tablename).Append("(");
 | 
					 | 
				
			||||||
                    foreach (var tbcol in uk.Columns)
 | 
					 | 
				
			||||||
                    {
 | 
					 | 
				
			||||||
                        sb.Append(_commonUtils.QuoteSqlName(tbcol.Column.Attribute.Name));
 | 
					 | 
				
			||||||
                        if (tbcol.IsDesc) sb.Append(" DESC");
 | 
					 | 
				
			||||||
                        sb.Append(", ");
 | 
					 | 
				
			||||||
                    }
 | 
					 | 
				
			||||||
                    sb.Remove(sb.Length - 2, 2).Append(");\r\n");
 | 
					 | 
				
			||||||
                }
 | 
					 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
            foreach (var seqcol in seqcols)
 | 
					 | 
				
			||||||
            {
 | 
					 | 
				
			||||||
                var tbname = seqcol.Item2;
 | 
					 | 
				
			||||||
                var seqname = Utils.GetCsName($"{tbname[0]}.{tbname[1]}_{seqcol.Item1.Attribute.Name}_sequence_name");
 | 
					 | 
				
			||||||
                var tbname2 = _commonUtils.QuoteSqlName($"{tbname[0]}.{tbname[1]}");
 | 
					 | 
				
			||||||
                var colname2 = _commonUtils.QuoteSqlName(seqcol.Item1.Attribute.Name);
 | 
					 | 
				
			||||||
                sb.Append("ALTER TABLE ").Append(tbname2).Append(" ALTER COLUMN ").Append(colname2).Append(" SET DEFAULT null;\r\n");
 | 
					 | 
				
			||||||
                sb.Append("DROP SEQUENCE IF EXISTS ").Append(seqname).Append(";\r\n");
 | 
					 | 
				
			||||||
                if (seqcol.Item3)
 | 
					 | 
				
			||||||
                {
 | 
					 | 
				
			||||||
                    sb.Append("CREATE SEQUENCE ").Append(seqname).Append(";\r\n");
 | 
					 | 
				
			||||||
                    sb.Append("ALTER TABLE ").Append(tbname2).Append(" ALTER COLUMN ").Append(colname2).Append(" SET DEFAULT nextval('").Append(seqname).Append("'::regclass);\r\n");
 | 
					 | 
				
			||||||
                    sb.Append(" SELECT case when max(").Append(colname2).Append(") is null then 0 else setval('").Append(seqname).Append("', max(").Append(colname2).Append(")) end FROM ").Append(tbname2).Append(";\r\n");
 | 
					 | 
				
			||||||
                }
 | 
					 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
            return sb.Length == 0 ? null : sb.ToString();
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
@@ -1,480 +0,0 @@
 | 
				
			|||||||
using FreeSql.DatabaseModel;
 | 
					 | 
				
			||||||
using FreeSql.Internal;
 | 
					 | 
				
			||||||
using System;
 | 
					 | 
				
			||||||
using System.Collections.Generic;
 | 
					 | 
				
			||||||
using System.Data;
 | 
					 | 
				
			||||||
using System.Data.Odbc;
 | 
					 | 
				
			||||||
using System.Linq;
 | 
					 | 
				
			||||||
using System.Text;
 | 
					 | 
				
			||||||
using System.Text.RegularExpressions;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
namespace FreeSql.Odbc.GBase
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
    class OdbcGBaseDbFirst : IDbFirst
 | 
					 | 
				
			||||||
    {
 | 
					 | 
				
			||||||
        IFreeSql _orm;
 | 
					 | 
				
			||||||
        protected CommonUtils _commonUtils;
 | 
					 | 
				
			||||||
        protected CommonExpression _commonExpression;
 | 
					 | 
				
			||||||
        public OdbcGBaseDbFirst(IFreeSql orm, CommonUtils commonUtils, CommonExpression commonExpression)
 | 
					 | 
				
			||||||
        {
 | 
					 | 
				
			||||||
            _orm = orm;
 | 
					 | 
				
			||||||
            _commonUtils = commonUtils;
 | 
					 | 
				
			||||||
            _commonExpression = commonExpression;
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        public int GetDbType(DbColumnInfo column) => (int)GetOdbcType(column);
 | 
					 | 
				
			||||||
        OdbcType GetOdbcType(DbColumnInfo column)
 | 
					 | 
				
			||||||
        {
 | 
					 | 
				
			||||||
            var dbtype = column.DbTypeText;
 | 
					 | 
				
			||||||
            var isarray = dbtype.EndsWith("[]");
 | 
					 | 
				
			||||||
            if (isarray) dbtype = dbtype.Remove(dbtype.Length - 2);
 | 
					 | 
				
			||||||
            OdbcType ret = OdbcType.VarChar;
 | 
					 | 
				
			||||||
            switch (dbtype.ToLower().TrimStart('_'))
 | 
					 | 
				
			||||||
            {
 | 
					 | 
				
			||||||
                case "int2": ret = OdbcType.SmallInt; break;
 | 
					 | 
				
			||||||
                case "int4": ret = OdbcType.Int; break;
 | 
					 | 
				
			||||||
                case "int8": ret = OdbcType.BigInt; break;
 | 
					 | 
				
			||||||
                case "numeric": ret = OdbcType.Numeric; break;
 | 
					 | 
				
			||||||
                case "float4": ret = OdbcType.Real; break;
 | 
					 | 
				
			||||||
                case "float8": ret = OdbcType.Double; break;
 | 
					 | 
				
			||||||
                case "money": ret = OdbcType.Numeric; break;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
                case "bpchar": ret = OdbcType.Char; break;
 | 
					 | 
				
			||||||
                case "varchar": ret = OdbcType.VarChar; break;
 | 
					 | 
				
			||||||
                case "text": ret = OdbcType.Text; break;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
                case "timestamp": ret = OdbcType.DateTime; break;
 | 
					 | 
				
			||||||
                case "timestamptz": ret = OdbcType.DateTime; break;
 | 
					 | 
				
			||||||
                case "date": ret = OdbcType.Date; break;
 | 
					 | 
				
			||||||
                case "time": ret = OdbcType.Time; break;
 | 
					 | 
				
			||||||
                case "timetz": ret = OdbcType.Time; break;
 | 
					 | 
				
			||||||
                case "interval": ret = OdbcType.Time; break;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
                case "bool": ret = OdbcType.Bit; break;
 | 
					 | 
				
			||||||
                case "bytea": ret = OdbcType.VarBinary; break;
 | 
					 | 
				
			||||||
                case "bit": ret = OdbcType.Bit; break;
 | 
					 | 
				
			||||||
                case "varbit": ret = OdbcType.VarBinary; break;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
                case "json": ret = OdbcType.VarChar; break;
 | 
					 | 
				
			||||||
                case "jsonb": ret = OdbcType.VarChar; break;
 | 
					 | 
				
			||||||
                case "uuid": ret = OdbcType.UniqueIdentifier; break;
 | 
					 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
            return 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)>() {
 | 
					 | 
				
			||||||
                { (int)OdbcType.SmallInt, ("(short?)", "short.Parse({0})", "{0}.ToString()", "short?", typeof(short), typeof(short?), "{0}.Value", "GetInt16") },
 | 
					 | 
				
			||||||
                { (int)OdbcType.Int, ("(int?)", "int.Parse({0})", "{0}.ToString()", "int?", typeof(int), typeof(int?), "{0}.Value", "GetInt32") },
 | 
					 | 
				
			||||||
                { (int)OdbcType.BigInt, ("(long?)", "long.Parse({0})", "{0}.ToString()", "long?", typeof(long), typeof(long?), "{0}.Value", "GetInt64") },
 | 
					 | 
				
			||||||
                { (int)OdbcType.Numeric, ("(decimal?)", "decimal.Parse({0})", "{0}.ToString()", "decimal?", typeof(decimal), typeof(decimal?), "{0}.Value", "GetDecimal") },
 | 
					 | 
				
			||||||
                { (int)OdbcType.Real, ("(float?)", "float.Parse({0})", "{0}.ToString()", "float?", typeof(float), typeof(float?), "{0}.Value", "GetFloat") },
 | 
					 | 
				
			||||||
                { (int)OdbcType.Double, ("(double?)", "double.Parse({0})", "{0}.ToString()", "double?", typeof(double), typeof(double?), "{0}.Value", "GetDouble") },
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
                { (int)OdbcType.Char, ("", "{0}.Replace(StringifySplit, \"|\")", "{0}.Replace(\"|\", StringifySplit)", "string", typeof(string), typeof(string), "{0}", "GetString") },
 | 
					 | 
				
			||||||
                { (int)OdbcType.VarChar, ("", "{0}.Replace(StringifySplit, \"|\")", "{0}.Replace(\"|\", StringifySplit)", "string", typeof(string), typeof(string), "{0}", "GetString") },
 | 
					 | 
				
			||||||
                { (int)OdbcType.Text, ("", "{0}.Replace(StringifySplit, \"|\")", "{0}.Replace(\"|\", StringifySplit)", "string", typeof(string), typeof(string), "{0}", "GetString") },
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
                { (int)OdbcType.DateTime,  ("(DateTime?)", "new DateTime(long.Parse({0}))", "{0}.Ticks.ToString()", "DateTime?", typeof(DateTime), typeof(DateTime?), "{0}.Value", "GetDateTime") },
 | 
					 | 
				
			||||||
                { (int)OdbcType.Date,  ("(DateTime?)", "new DateTime(long.Parse({0}))", "{0}.Ticks.ToString()", "DateTime?", typeof(DateTime), typeof(DateTime?), "{0}.Value", "GetDateTime") },
 | 
					 | 
				
			||||||
                { (int)OdbcType.Time, ("(TimeSpan?)", "TimeSpan.Parse(double.Parse({0}))", "{0}.Ticks.ToString()", "TimeSpan?", typeof(TimeSpan), typeof(TimeSpan?), "{0}.Value", "GetValue") },
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
                { (int)OdbcType.Bit, ("(bool?)", "{0} == \"1\"", "{0} == true ? \"1\" : \"0\"", "bool?", typeof(bool), typeof(bool?), "{0}.Value", "GetBoolean") },
 | 
					 | 
				
			||||||
                { (int)OdbcType.VarBinary, ("(byte[])", "Convert.FromBase64String({0})", "Convert.ToBase64String({0})", "byte[]", typeof(byte[]), typeof(byte[]), "{0}", "GetValue") },
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
                { (int)OdbcType.UniqueIdentifier, ("(Guid?)", "Guid.Parse({0})", "{0}.ToString()", "Guid", typeof(Guid), typeof(Guid?), "{0}", "GetString") },
 | 
					 | 
				
			||||||
            };
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        public string GetCsConvert(DbColumnInfo column) => _dicDbToCs.TryGetValue(column.DbType, out var trydc) ? (column.IsNullable ? trydc.csConvert : trydc.csConvert.Replace("?", "")) : null;
 | 
					 | 
				
			||||||
        public string GetCsParse(DbColumnInfo column) => _dicDbToCs.TryGetValue(column.DbType, out var trydc) ? trydc.csParse : null;
 | 
					 | 
				
			||||||
        public string GetCsStringify(DbColumnInfo column) => _dicDbToCs.TryGetValue(column.DbType, out var trydc) ? trydc.csStringify : null;
 | 
					 | 
				
			||||||
        public string GetCsType(DbColumnInfo column) => _dicDbToCs.TryGetValue(column.DbType, out var trydc) ? (column.IsNullable ? trydc.csType : trydc.csType.Replace("?", "")) : null;
 | 
					 | 
				
			||||||
        public Type GetCsTypeInfo(DbColumnInfo column) => _dicDbToCs.TryGetValue(column.DbType, out var trydc) ? trydc.csTypeInfo : null;
 | 
					 | 
				
			||||||
        public string GetCsTypeValue(DbColumnInfo column) => _dicDbToCs.TryGetValue(column.DbType, out var trydc) ? trydc.csTypeValue : null;
 | 
					 | 
				
			||||||
        public string GetDataReaderMethod(DbColumnInfo column) => _dicDbToCs.TryGetValue(column.DbType, out var trydc) ? trydc.dataReaderMethod : null;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        public List<string> GetDatabases()
 | 
					 | 
				
			||||||
        {
 | 
					 | 
				
			||||||
            var sql = @" select datname from pg_database where datname not in ('template1', 'template0')";
 | 
					 | 
				
			||||||
            var ds = _orm.Ado.ExecuteArray(CommandType.Text, sql);
 | 
					 | 
				
			||||||
            return ds.Select(a => a.FirstOrDefault()?.ToString()).ToList();
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        public List<DbTableInfo> GetTablesByDatabase(params string[] database)
 | 
					 | 
				
			||||||
        {
 | 
					 | 
				
			||||||
            var olddatabase = "";
 | 
					 | 
				
			||||||
            using (var conn = _orm.Ado.MasterPool.Get(TimeSpan.FromSeconds(5)))
 | 
					 | 
				
			||||||
            {
 | 
					 | 
				
			||||||
                olddatabase = conn.Value.Database;
 | 
					 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
            var dbs = database == null || database.Any() == false ? new[] { olddatabase } : database;
 | 
					 | 
				
			||||||
            var tables = new List<DbTableInfo>();
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
            foreach (var db in dbs)
 | 
					 | 
				
			||||||
            {
 | 
					 | 
				
			||||||
                if (string.IsNullOrEmpty(db) || string.Compare(db, olddatabase, true) != 0) continue;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
                var loc1 = new List<DbTableInfo>();
 | 
					 | 
				
			||||||
                var loc2 = new Dictionary<string, DbTableInfo>();
 | 
					 | 
				
			||||||
                var loc3 = new Dictionary<string, Dictionary<string, DbColumnInfo>>();
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
                var sql = $@"
 | 
					 | 
				
			||||||
select
 | 
					 | 
				
			||||||
b.nspname || '.' || a.tablename,
 | 
					 | 
				
			||||||
a.schemaname,
 | 
					 | 
				
			||||||
a.tablename ,
 | 
					 | 
				
			||||||
d.description,
 | 
					 | 
				
			||||||
'TABLE'
 | 
					 | 
				
			||||||
from pg_tables a
 | 
					 | 
				
			||||||
inner join pg_namespace b on b.nspname = a.schemaname
 | 
					 | 
				
			||||||
inner join pg_class c on c.relnamespace = b.oid and c.relname = a.tablename
 | 
					 | 
				
			||||||
left join pg_description d on d.objoid = c.oid and objsubid = 0
 | 
					 | 
				
			||||||
where a.schemaname not in ('pg_catalog', 'information_schema', 'topology')
 | 
					 | 
				
			||||||
and b.nspname || '.' || a.tablename not in ('public.spatial_ref_sys')
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
union all
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
select
 | 
					 | 
				
			||||||
b.nspname || '.' || a.relname,
 | 
					 | 
				
			||||||
b.nspname,
 | 
					 | 
				
			||||||
a.relname,
 | 
					 | 
				
			||||||
d.description,
 | 
					 | 
				
			||||||
'VIEW'
 | 
					 | 
				
			||||||
from pg_class a
 | 
					 | 
				
			||||||
inner join pg_namespace b on b.oid = a.relnamespace
 | 
					 | 
				
			||||||
left join pg_description d on d.objoid = a.oid and objsubid = 0
 | 
					 | 
				
			||||||
where b.nspname not in ('pg_catalog', 'information_schema') and a.relkind in ('m','v') 
 | 
					 | 
				
			||||||
and b.nspname || '.' || a.relname not in ('public.geography_columns','public.geometry_columns','public.raster_columns','public.raster_overviews')
 | 
					 | 
				
			||||||
";
 | 
					 | 
				
			||||||
                var ds = _orm.Ado.ExecuteArray(CommandType.Text, sql);
 | 
					 | 
				
			||||||
                if (ds == null) return loc1;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
                var loc6 = new List<string[]>();
 | 
					 | 
				
			||||||
                var loc66 = new List<string[]>();
 | 
					 | 
				
			||||||
                var loc6_1000 = new List<string>();
 | 
					 | 
				
			||||||
                var loc66_1000 = new List<string>();
 | 
					 | 
				
			||||||
                foreach (object[] row in ds)
 | 
					 | 
				
			||||||
                {
 | 
					 | 
				
			||||||
                    var object_id = string.Concat(row[0]);
 | 
					 | 
				
			||||||
                    var owner = string.Concat(row[1]);
 | 
					 | 
				
			||||||
                    var table = string.Concat(row[2]);
 | 
					 | 
				
			||||||
                    var comment = string.Concat(row[3]);
 | 
					 | 
				
			||||||
                    Enum.TryParse<DbTableType>(string.Concat(row[4]), out var type);
 | 
					 | 
				
			||||||
                    loc2.Add(object_id, new DbTableInfo { Id = object_id.ToString(), Schema = owner, Name = table, Comment = comment, Type = type });
 | 
					 | 
				
			||||||
                    loc3.Add(object_id, new Dictionary<string, DbColumnInfo>());
 | 
					 | 
				
			||||||
                    switch (type)
 | 
					 | 
				
			||||||
                    {
 | 
					 | 
				
			||||||
                        case DbTableType.VIEW:
 | 
					 | 
				
			||||||
                        case DbTableType.TABLE:
 | 
					 | 
				
			||||||
                            loc6_1000.Add(object_id);
 | 
					 | 
				
			||||||
                            if (loc6_1000.Count >= 500)
 | 
					 | 
				
			||||||
                            {
 | 
					 | 
				
			||||||
                                loc6.Add(loc6_1000.ToArray());
 | 
					 | 
				
			||||||
                                loc6_1000.Clear();
 | 
					 | 
				
			||||||
                            }
 | 
					 | 
				
			||||||
                            break;
 | 
					 | 
				
			||||||
                        case DbTableType.StoreProcedure:
 | 
					 | 
				
			||||||
                            loc66_1000.Add(object_id);
 | 
					 | 
				
			||||||
                            if (loc66_1000.Count >= 500)
 | 
					 | 
				
			||||||
                            {
 | 
					 | 
				
			||||||
                                loc66.Add(loc66_1000.ToArray());
 | 
					 | 
				
			||||||
                                loc66_1000.Clear();
 | 
					 | 
				
			||||||
                            }
 | 
					 | 
				
			||||||
                            break;
 | 
					 | 
				
			||||||
                    }
 | 
					 | 
				
			||||||
                }
 | 
					 | 
				
			||||||
                if (loc6_1000.Count > 0) loc6.Add(loc6_1000.ToArray());
 | 
					 | 
				
			||||||
                if (loc66_1000.Count > 0) loc66.Add(loc66_1000.ToArray());
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
                if (loc6.Count == 0) return loc1;
 | 
					 | 
				
			||||||
                var loc8 = new StringBuilder().Append("(");
 | 
					 | 
				
			||||||
                for (var loc8idx = 0; loc8idx < loc6.Count; loc8idx++)
 | 
					 | 
				
			||||||
                {
 | 
					 | 
				
			||||||
                    if (loc8idx > 0) loc8.Append(" OR ");
 | 
					 | 
				
			||||||
                    loc8.Append("a.table_name in (");
 | 
					 | 
				
			||||||
                    for (var loc8idx2 = 0; loc8idx2 < loc6[loc8idx].Length; loc8idx2++)
 | 
					 | 
				
			||||||
                    {
 | 
					 | 
				
			||||||
                        if (loc8idx2 > 0) loc8.Append(",");
 | 
					 | 
				
			||||||
                        loc8.Append($"'{loc6[loc8idx][loc8idx2]}'");
 | 
					 | 
				
			||||||
                    }
 | 
					 | 
				
			||||||
                    loc8.Append(")");
 | 
					 | 
				
			||||||
                }
 | 
					 | 
				
			||||||
                loc8.Append(")");
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
                sql = $@"
 | 
					 | 
				
			||||||
select
 | 
					 | 
				
			||||||
ns.nspname || '.' || c.relname as id, 
 | 
					 | 
				
			||||||
a.attname,
 | 
					 | 
				
			||||||
t.typname,
 | 
					 | 
				
			||||||
case when a.atttypmod > 0 and a.atttypmod < 32767 then a.atttypmod - 4 else a.attlen end len,
 | 
					 | 
				
			||||||
case when t.typelem = 0 then t.typname else t2.typname end,
 | 
					 | 
				
			||||||
case when a.attnotnull then 0 else 1 end as is_nullable,
 | 
					 | 
				
			||||||
coalesce((select 1 from pg_sequences where sequencename = {0} || '_' || {1} || '_' || a.attname || '_sequence_name' limit 1),0) is_identity,
 | 
					 | 
				
			||||||
--e.adsrc as is_identity,
 | 
					 | 
				
			||||||
d.description as comment,
 | 
					 | 
				
			||||||
a.attndims,
 | 
					 | 
				
			||||||
case when t.typelem = 0 then t.typtype else t2.typtype end,
 | 
					 | 
				
			||||||
ns2.nspname,
 | 
					 | 
				
			||||||
a.attnum
 | 
					 | 
				
			||||||
from pg_class c
 | 
					 | 
				
			||||||
inner join pg_attribute a on a.attnum > 0 and a.attrelid = c.oid
 | 
					 | 
				
			||||||
inner join pg_type t on t.oid = a.atttypid
 | 
					 | 
				
			||||||
left join pg_type t2 on t2.oid = t.typelem
 | 
					 | 
				
			||||||
left join pg_description d on d.objoid = a.attrelid and d.objsubid = a.attnum
 | 
					 | 
				
			||||||
left join pg_attrdef e on e.adrelid = a.attrelid and e.adnum = a.attnum
 | 
					 | 
				
			||||||
inner join pg_namespace ns on ns.oid = c.relnamespace
 | 
					 | 
				
			||||||
inner join pg_namespace ns2 on ns2.oid = t.typnamespace
 | 
					 | 
				
			||||||
where {loc8.ToString().Replace("a.table_name", "ns.nspname || '.' || c.relname")}";
 | 
					 | 
				
			||||||
                ds = _orm.Ado.ExecuteArray(CommandType.Text, sql);
 | 
					 | 
				
			||||||
                if (ds == null) return loc1;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
                foreach (object[] row in ds)
 | 
					 | 
				
			||||||
                {
 | 
					 | 
				
			||||||
                    var object_id = string.Concat(row[0]);
 | 
					 | 
				
			||||||
                    var column = string.Concat(row[1]);
 | 
					 | 
				
			||||||
                    var type = string.Concat(row[2]);
 | 
					 | 
				
			||||||
                    var max_length = int.Parse(string.Concat(row[3]));
 | 
					 | 
				
			||||||
                    var sqlType = string.Concat(row[4]);
 | 
					 | 
				
			||||||
                    var is_nullable = string.Concat(row[5]) == "1";
 | 
					 | 
				
			||||||
                    var is_identity = string.Concat(row[6]) == "1"; //string.Concat(row[6]).StartsWith(@"nextval('") && string.Concat(row[6]).EndsWith(@"'::regclass)");
 | 
					 | 
				
			||||||
                    var comment = string.Concat(row[7]);
 | 
					 | 
				
			||||||
                    int attndims = int.Parse(string.Concat(row[8]));
 | 
					 | 
				
			||||||
                    string typtype = string.Concat(row[9]);
 | 
					 | 
				
			||||||
                    string owner = string.Concat(row[10]);
 | 
					 | 
				
			||||||
                    int attnum = int.Parse(string.Concat(row[11]));
 | 
					 | 
				
			||||||
                    switch (sqlType.ToLower())
 | 
					 | 
				
			||||||
                    {
 | 
					 | 
				
			||||||
                        case "bool": case "name": case "bit": case "varbit": case "bpchar": case "varchar": case "bytea": case "text": case "uuid": break;
 | 
					 | 
				
			||||||
                        default: max_length *= 8; break;
 | 
					 | 
				
			||||||
                    }
 | 
					 | 
				
			||||||
                    if (max_length <= 0) max_length = -1;
 | 
					 | 
				
			||||||
                    if (type.StartsWith("_"))
 | 
					 | 
				
			||||||
                    {
 | 
					 | 
				
			||||||
                        type = type.Substring(1);
 | 
					 | 
				
			||||||
                        if (attndims == 0) attndims++;
 | 
					 | 
				
			||||||
                    }
 | 
					 | 
				
			||||||
                    if (sqlType.StartsWith("_")) sqlType = sqlType.Substring(1);
 | 
					 | 
				
			||||||
                    if (max_length > 0)
 | 
					 | 
				
			||||||
                    {
 | 
					 | 
				
			||||||
                        switch (sqlType.ToLower())
 | 
					 | 
				
			||||||
                        {
 | 
					 | 
				
			||||||
                            //case "numeric": sqlType += $"({max_length})"; break;
 | 
					 | 
				
			||||||
                            case "bpchar": case "varchar": case "bytea": case "bit": case "varbit": sqlType += $"({max_length})"; break;
 | 
					 | 
				
			||||||
                        }
 | 
					 | 
				
			||||||
                    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
                    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]);
 | 
					 | 
				
			||||||
                }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
                sql = $@"
 | 
					 | 
				
			||||||
select
 | 
					 | 
				
			||||||
ns.nspname || '.' || d.relname as table_id, 
 | 
					 | 
				
			||||||
c.attname,
 | 
					 | 
				
			||||||
b.relname as index_id,
 | 
					 | 
				
			||||||
case when a.indisunique then 1 else 0 end IsUnique,
 | 
					 | 
				
			||||||
case when a.indisprimary then 1 else 0 end IsPrimary,
 | 
					 | 
				
			||||||
case when a.indisclustered then 0 else 1 end IsClustered,
 | 
					 | 
				
			||||||
case when pg_index_column_has_property(b.oid, c.attnum, 'desc') = 't' then 1 else 0 end IsDesc,
 | 
					 | 
				
			||||||
a.indkey::text,
 | 
					 | 
				
			||||||
c.attnum
 | 
					 | 
				
			||||||
from pg_index a
 | 
					 | 
				
			||||||
inner join pg_class b on b.oid = a.indexrelid
 | 
					 | 
				
			||||||
inner join pg_attribute c on c.attnum > 0 and c.attrelid = b.oid
 | 
					 | 
				
			||||||
inner join pg_namespace ns on ns.oid = b.relnamespace
 | 
					 | 
				
			||||||
inner join pg_class d on d.oid = a.indrelid
 | 
					 | 
				
			||||||
where {loc8.ToString().Replace("a.table_name", "ns.nspname || '.' || d.relname")}
 | 
					 | 
				
			||||||
";
 | 
					 | 
				
			||||||
                ds = _orm.Ado.ExecuteArray(CommandType.Text, sql);
 | 
					 | 
				
			||||||
                if (ds == null) return loc1;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
                var indexColumns = new Dictionary<string, Dictionary<string, DbIndexInfo>>();
 | 
					 | 
				
			||||||
                var uniqueColumns = new Dictionary<string, Dictionary<string, DbIndexInfo>>();
 | 
					 | 
				
			||||||
                foreach (object[] row in ds)
 | 
					 | 
				
			||||||
                {
 | 
					 | 
				
			||||||
                    var object_id = string.Concat(row[0]);
 | 
					 | 
				
			||||||
                    var column = string.Concat(row[1]);
 | 
					 | 
				
			||||||
                    var index_id = string.Concat(row[2]);
 | 
					 | 
				
			||||||
                    var is_unique = string.Concat(row[3]) == "1";
 | 
					 | 
				
			||||||
                    var is_primary_key = string.Concat(row[4]) == "1";
 | 
					 | 
				
			||||||
                    var is_clustered = string.Concat(row[5]) == "1";
 | 
					 | 
				
			||||||
                    var is_desc = string.Concat(row[6]) == "1";
 | 
					 | 
				
			||||||
                    var inkey = string.Concat(row[7]).Split(' ');
 | 
					 | 
				
			||||||
                    var attnum = int.Parse(string.Concat(row[8]));
 | 
					 | 
				
			||||||
                    attnum = int.Parse(inkey[attnum - 1]);
 | 
					 | 
				
			||||||
                    foreach (string tc in loc3[object_id].Keys)
 | 
					 | 
				
			||||||
                    {
 | 
					 | 
				
			||||||
                        if (loc3[object_id][tc].DbTypeText.EndsWith("[]"))
 | 
					 | 
				
			||||||
                        {
 | 
					 | 
				
			||||||
                            column = tc;
 | 
					 | 
				
			||||||
                            break;
 | 
					 | 
				
			||||||
                        }
 | 
					 | 
				
			||||||
                    }
 | 
					 | 
				
			||||||
                    if (loc3.ContainsKey(object_id) == false || loc3[object_id].ContainsKey(column) == false) continue;
 | 
					 | 
				
			||||||
                    var loc9 = loc3[object_id][column];
 | 
					 | 
				
			||||||
                    if (loc9.IsPrimary == false && is_primary_key) loc9.IsPrimary = is_primary_key;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
                    Dictionary<string, DbIndexInfo> loc10 = null;
 | 
					 | 
				
			||||||
                    DbIndexInfo loc11 = null;
 | 
					 | 
				
			||||||
                    if (!indexColumns.TryGetValue(object_id, out loc10))
 | 
					 | 
				
			||||||
                        indexColumns.Add(object_id, loc10 = new Dictionary<string, DbIndexInfo>());
 | 
					 | 
				
			||||||
                    if (!loc10.TryGetValue(index_id, out loc11))
 | 
					 | 
				
			||||||
                        loc10.Add(index_id, loc11 = new DbIndexInfo());
 | 
					 | 
				
			||||||
                    loc11.Columns.Add(new DbIndexColumnInfo { Column = loc9, IsDesc = is_desc });
 | 
					 | 
				
			||||||
                    if (is_unique && !is_primary_key)
 | 
					 | 
				
			||||||
                    {
 | 
					 | 
				
			||||||
                        if (!uniqueColumns.TryGetValue(object_id, out loc10))
 | 
					 | 
				
			||||||
                            uniqueColumns.Add(object_id, loc10 = new Dictionary<string, DbIndexInfo>());
 | 
					 | 
				
			||||||
                        if (!loc10.TryGetValue(index_id, out loc11))
 | 
					 | 
				
			||||||
                            loc10.Add(index_id, loc11 = new DbIndexInfo());
 | 
					 | 
				
			||||||
                        loc11.Columns.Add(new DbIndexColumnInfo { Column = loc9, IsDesc = is_desc });
 | 
					 | 
				
			||||||
                    }
 | 
					 | 
				
			||||||
                }
 | 
					 | 
				
			||||||
                foreach (var object_id in indexColumns.Keys)
 | 
					 | 
				
			||||||
                {
 | 
					 | 
				
			||||||
                    foreach (var column in indexColumns[object_id])
 | 
					 | 
				
			||||||
                        loc2[object_id].IndexesDict.Add(column.Key, column.Value);
 | 
					 | 
				
			||||||
                }
 | 
					 | 
				
			||||||
                foreach (var object_id in uniqueColumns.Keys)
 | 
					 | 
				
			||||||
                {
 | 
					 | 
				
			||||||
                    foreach (var column in uniqueColumns[object_id])
 | 
					 | 
				
			||||||
                    {
 | 
					 | 
				
			||||||
                        column.Value.Columns.Sort((c1, c2) => c1.Column.Name.CompareTo(c2.Column.Name));
 | 
					 | 
				
			||||||
                        loc2[object_id].UniquesDict.Add(column.Key, column.Value);
 | 
					 | 
				
			||||||
                    }
 | 
					 | 
				
			||||||
                }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
                sql = $@"
 | 
					 | 
				
			||||||
select
 | 
					 | 
				
			||||||
ns.nspname || '.' || b.relname as table_id, 
 | 
					 | 
				
			||||||
array(select attname from pg_attribute where attrelid = a.conrelid and attnum = any(a.conkey)) as column_name,
 | 
					 | 
				
			||||||
a.conname as FKId,
 | 
					 | 
				
			||||||
ns2.nspname || '.' || c.relname as ref_table_id, 
 | 
					 | 
				
			||||||
1 as IsForeignKey,
 | 
					 | 
				
			||||||
array(select attname from pg_attribute where attrelid = a.confrelid and attnum = any(a.confkey)) as ref_column,
 | 
					 | 
				
			||||||
null ref_sln,
 | 
					 | 
				
			||||||
null ref_table
 | 
					 | 
				
			||||||
from  pg_constraint a
 | 
					 | 
				
			||||||
inner join pg_class b on b.oid = a.conrelid
 | 
					 | 
				
			||||||
inner join pg_class c on c.oid = a.confrelid
 | 
					 | 
				
			||||||
inner join pg_namespace ns on ns.oid = b.relnamespace
 | 
					 | 
				
			||||||
inner join pg_namespace ns2 on ns2.oid = c.relnamespace
 | 
					 | 
				
			||||||
where {loc8.ToString().Replace("a.table_name", "ns.nspname || '.' || b.relname")}
 | 
					 | 
				
			||||||
";
 | 
					 | 
				
			||||||
                ds = _orm.Ado.ExecuteArray(CommandType.Text, sql);
 | 
					 | 
				
			||||||
                if (ds == null) return loc1;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
                var fkColumns = new Dictionary<string, Dictionary<string, DbForeignInfo>>();
 | 
					 | 
				
			||||||
                foreach (object[] row in ds)
 | 
					 | 
				
			||||||
                {
 | 
					 | 
				
			||||||
                    var table_id = string.Concat(row[0]);
 | 
					 | 
				
			||||||
                    var column = row[1] as string[];
 | 
					 | 
				
			||||||
                    var fk_id = string.Concat(row[2]);
 | 
					 | 
				
			||||||
                    var ref_table_id = string.Concat(row[3]);
 | 
					 | 
				
			||||||
                    var is_foreign_key = string.Concat(row[4]) == "1";
 | 
					 | 
				
			||||||
                    var referenced_column = row[5] as string[];
 | 
					 | 
				
			||||||
                    var referenced_db = string.Concat(row[6]);
 | 
					 | 
				
			||||||
                    var referenced_table = string.Concat(row[7]);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
                    if (loc2.ContainsKey(ref_table_id) == false) continue;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
                    Dictionary<string, DbForeignInfo> loc12 = null;
 | 
					 | 
				
			||||||
                    DbForeignInfo loc13 = null;
 | 
					 | 
				
			||||||
                    if (!fkColumns.TryGetValue(table_id, out loc12))
 | 
					 | 
				
			||||||
                        fkColumns.Add(table_id, loc12 = new Dictionary<string, DbForeignInfo>());
 | 
					 | 
				
			||||||
                    if (!loc12.TryGetValue(fk_id, out loc13))
 | 
					 | 
				
			||||||
                        loc12.Add(fk_id, loc13 = new DbForeignInfo { Table = loc2[table_id], ReferencedTable = loc2[ref_table_id] });
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
                    for (int a = 0; a < column.Length; a++)
 | 
					 | 
				
			||||||
                    {
 | 
					 | 
				
			||||||
                        loc13.Columns.Add(loc3[table_id][column[a]]);
 | 
					 | 
				
			||||||
                        loc13.ReferencedColumns.Add(loc3[ref_table_id][referenced_column[a]]);
 | 
					 | 
				
			||||||
                    }
 | 
					 | 
				
			||||||
                }
 | 
					 | 
				
			||||||
                foreach (var table_id in fkColumns.Keys)
 | 
					 | 
				
			||||||
                    foreach (var fk in fkColumns[table_id])
 | 
					 | 
				
			||||||
                        loc2[table_id].ForeignsDict.Add(fk.Key, fk.Value);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
                foreach (var table_id in loc3.Keys)
 | 
					 | 
				
			||||||
                {
 | 
					 | 
				
			||||||
                    foreach (var loc5 in loc3[table_id].Values)
 | 
					 | 
				
			||||||
                    {
 | 
					 | 
				
			||||||
                        loc2[table_id].Columns.Add(loc5);
 | 
					 | 
				
			||||||
                        if (loc5.IsIdentity) loc2[table_id].Identitys.Add(loc5);
 | 
					 | 
				
			||||||
                        if (loc5.IsPrimary) loc2[table_id].Primarys.Add(loc5);
 | 
					 | 
				
			||||||
                    }
 | 
					 | 
				
			||||||
                }
 | 
					 | 
				
			||||||
                foreach (var loc4 in loc2.Values)
 | 
					 | 
				
			||||||
                {
 | 
					 | 
				
			||||||
                    //if (loc4.Primarys.Count == 0 && loc4.UniquesDict.Count > 0)
 | 
					 | 
				
			||||||
                    //{
 | 
					 | 
				
			||||||
                    //    foreach (var loc5 in loc4.UniquesDict.First().Value.Columns)
 | 
					 | 
				
			||||||
                    //    {
 | 
					 | 
				
			||||||
                    //        loc5.Column.IsPrimary = true;
 | 
					 | 
				
			||||||
                    //        loc4.Primarys.Add(loc5.Column);
 | 
					 | 
				
			||||||
                    //    }
 | 
					 | 
				
			||||||
                    //}
 | 
					 | 
				
			||||||
                    loc4.Primarys.Sort((c1, c2) => c1.Name.CompareTo(c2.Name));
 | 
					 | 
				
			||||||
                    loc4.Columns.Sort((c1, c2) =>
 | 
					 | 
				
			||||||
                    {
 | 
					 | 
				
			||||||
                        int compare = c2.IsPrimary.CompareTo(c1.IsPrimary);
 | 
					 | 
				
			||||||
                        if (compare == 0)
 | 
					 | 
				
			||||||
                        {
 | 
					 | 
				
			||||||
                            bool b1 = loc4.ForeignsDict.Values.Where(fk => fk.Columns.Where(c3 => c3.Name == c1.Name).Any()).Any();
 | 
					 | 
				
			||||||
                            bool b2 = loc4.ForeignsDict.Values.Where(fk => fk.Columns.Where(c3 => c3.Name == c2.Name).Any()).Any();
 | 
					 | 
				
			||||||
                            compare = b2.CompareTo(b1);
 | 
					 | 
				
			||||||
                        }
 | 
					 | 
				
			||||||
                        if (compare == 0) compare = c1.Name.CompareTo(c2.Name);
 | 
					 | 
				
			||||||
                        return compare;
 | 
					 | 
				
			||||||
                    });
 | 
					 | 
				
			||||||
                    loc1.Add(loc4);
 | 
					 | 
				
			||||||
                }
 | 
					 | 
				
			||||||
                loc1.Sort((t1, t2) =>
 | 
					 | 
				
			||||||
                {
 | 
					 | 
				
			||||||
                    var ret = t1.Schema.CompareTo(t2.Schema);
 | 
					 | 
				
			||||||
                    if (ret == 0) ret = t1.Name.CompareTo(t2.Name);
 | 
					 | 
				
			||||||
                    return ret;
 | 
					 | 
				
			||||||
                });
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
                loc2.Clear();
 | 
					 | 
				
			||||||
                loc3.Clear();
 | 
					 | 
				
			||||||
                tables.AddRange(loc1);
 | 
					 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
            return tables;
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        public List<DbEnumInfo> GetEnumsByDatabase(params string[] database)
 | 
					 | 
				
			||||||
        {
 | 
					 | 
				
			||||||
            if (database == null || database.Length == 0) return new List<DbEnumInfo>();
 | 
					 | 
				
			||||||
            var drs = _orm.Ado.Query<(string name, string label)>(CommandType.Text, _commonUtils.FormatSql(@"
 | 
					 | 
				
			||||||
select
 | 
					 | 
				
			||||||
ns.nspname || '.' || a.typname,
 | 
					 | 
				
			||||||
b.enumlabel
 | 
					 | 
				
			||||||
from pg_type a
 | 
					 | 
				
			||||||
inner join pg_enum b on b.enumtypid = a.oid
 | 
					 | 
				
			||||||
inner join pg_namespace ns on ns.oid = a.typnamespace
 | 
					 | 
				
			||||||
where a.typtype = 'e' and ns.nspname in (SELECT ""schema_name"" FROM information_schema.schemata where catalog_name in {0})", database));
 | 
					 | 
				
			||||||
            var ret = new Dictionary<string, Dictionary<string, string>>();
 | 
					 | 
				
			||||||
            foreach (var dr in drs)
 | 
					 | 
				
			||||||
            {
 | 
					 | 
				
			||||||
                if (ret.TryGetValue(dr.name, out var labels) == false) ret.Add(dr.name, labels = new Dictionary<string, string>());
 | 
					 | 
				
			||||||
                var key = dr.label;
 | 
					 | 
				
			||||||
                if (Regex.IsMatch(key, @"^[\u0391-\uFFE5a-zA-Z_\$][\u0391-\uFFE5a-zA-Z_\$\d]*$") == false)
 | 
					 | 
				
			||||||
                    key = $"Unkown{ret[dr.name].Count + 1}";
 | 
					 | 
				
			||||||
                if (labels.ContainsKey(key) == false) labels.Add(key, dr.label);
 | 
					 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
            return ret.Select(a => new DbEnumInfo { Name = a.Key, Labels = a.Value }).ToList();
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
@@ -1,554 +0,0 @@
 | 
				
			|||||||
using FreeSql.Internal;
 | 
					 | 
				
			||||||
using FreeSql.Internal.Model;
 | 
					 | 
				
			||||||
using System;
 | 
					 | 
				
			||||||
using System.Collections;
 | 
					 | 
				
			||||||
using System.Collections.Generic;
 | 
					 | 
				
			||||||
using System.Linq;
 | 
					 | 
				
			||||||
using System.Linq.Expressions;
 | 
					 | 
				
			||||||
using System.Text;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
namespace FreeSql.Odbc.GBase
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
    class OdbcGBaseExpression : CommonExpression
 | 
					 | 
				
			||||||
    {
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        public OdbcGBaseExpression(CommonUtils common) : base(common) { }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        public override string ExpressionLambdaToSqlOther(Expression exp, ExpTSC tsc)
 | 
					 | 
				
			||||||
        {
 | 
					 | 
				
			||||||
            Func<Expression, string> getExp = exparg => ExpressionLambdaToSql(exparg, tsc);
 | 
					 | 
				
			||||||
            switch (exp.NodeType)
 | 
					 | 
				
			||||||
            {
 | 
					 | 
				
			||||||
                case ExpressionType.Convert:
 | 
					 | 
				
			||||||
                    var operandExp = (exp as UnaryExpression)?.Operand;
 | 
					 | 
				
			||||||
                    var gentype = exp.Type.NullableTypeOrThis();
 | 
					 | 
				
			||||||
                    if (gentype != operandExp.Type.NullableTypeOrThis())
 | 
					 | 
				
			||||||
                    {
 | 
					 | 
				
			||||||
                        switch (exp.Type.NullableTypeOrThis().ToString())
 | 
					 | 
				
			||||||
                        {
 | 
					 | 
				
			||||||
                            case "System.Boolean": return $"(({getExp(operandExp)})::varchar not in ('0','false','f','no'))";
 | 
					 | 
				
			||||||
                            case "System.Byte": return $"({getExp(operandExp)})::byte";
 | 
					 | 
				
			||||||
                            case "System.Char": return $"substr(({getExp(operandExp)})::char, 1, 1)";
 | 
					 | 
				
			||||||
                            case "System.DateTime": return $"({getExp(operandExp)})::timestamp";
 | 
					 | 
				
			||||||
                            case "System.Decimal": return $"({getExp(operandExp)})::decimal";
 | 
					 | 
				
			||||||
                            case "System.Double": return $"({getExp(operandExp)})::float";
 | 
					 | 
				
			||||||
                            case "System.Int16": return $"({getExp(operandExp)})::smallint";
 | 
					 | 
				
			||||||
                            case "System.Int32": return $"({getExp(operandExp)})::integer";
 | 
					 | 
				
			||||||
                            case "System.Int64": return $"({getExp(operandExp)})::bigint";
 | 
					 | 
				
			||||||
                            case "System.SByte": return $"({getExp(operandExp)})::smallint";
 | 
					 | 
				
			||||||
                            case "System.Single": return $"({getExp(operandExp)})::smallfloat";
 | 
					 | 
				
			||||||
                            case "System.String": return $"({getExp(operandExp)})::nvarchar";
 | 
					 | 
				
			||||||
                            case "System.UInt16": return $"({getExp(operandExp)})::integer";
 | 
					 | 
				
			||||||
                            case "System.UInt32": return $"({getExp(operandExp)})::bigint";
 | 
					 | 
				
			||||||
                            case "System.UInt64": return $"({getExp(operandExp)})::decimal";
 | 
					 | 
				
			||||||
                            case "System.Guid": return $"({getExp(operandExp)})::char";
 | 
					 | 
				
			||||||
                        }
 | 
					 | 
				
			||||||
                    }
 | 
					 | 
				
			||||||
                    break;
 | 
					 | 
				
			||||||
                case ExpressionType.ArrayLength:
 | 
					 | 
				
			||||||
                    var arrOperExp = getExp((exp as UnaryExpression).Operand);
 | 
					 | 
				
			||||||
                    if (arrOperExp.StartsWith("(") || arrOperExp.EndsWith(")")) return $"array_length(array[{arrOperExp.TrimStart('(').TrimEnd(')')}],1)";
 | 
					 | 
				
			||||||
                    return $"case when {arrOperExp} is null then 0 else array_length({arrOperExp},1) end";
 | 
					 | 
				
			||||||
                case ExpressionType.Call:
 | 
					 | 
				
			||||||
                    var callExp = exp as MethodCallExpression;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
                    switch (callExp.Method.Name)
 | 
					 | 
				
			||||||
                    {
 | 
					 | 
				
			||||||
                        case "Parse":
 | 
					 | 
				
			||||||
                        case "TryParse":
 | 
					 | 
				
			||||||
                            switch (callExp.Method.DeclaringType.NullableTypeOrThis().ToString())
 | 
					 | 
				
			||||||
                            {
 | 
					 | 
				
			||||||
                                case "System.Boolean": return $"(({getExp(callExp.Arguments[0])})::varchar not in ('0','false','f','no'))";
 | 
					 | 
				
			||||||
                                case "System.Byte": return $"({getExp(callExp.Arguments[0])})::byte";
 | 
					 | 
				
			||||||
                                case "System.Char": return $"substr(({getExp(callExp.Arguments[0])})::char, 1, 1)";
 | 
					 | 
				
			||||||
                                case "System.DateTime": return $"({getExp(callExp.Arguments[0])})::timestamp";
 | 
					 | 
				
			||||||
                                case "System.Decimal": return $"({getExp(callExp.Arguments[0])})::decimal";
 | 
					 | 
				
			||||||
                                case "System.Double": return $"({getExp(callExp.Arguments[0])})::float";
 | 
					 | 
				
			||||||
                                case "System.Int16": return $"({getExp(callExp.Arguments[0])})::smallint";
 | 
					 | 
				
			||||||
                                case "System.Int32": return $"({getExp(callExp.Arguments[0])})::integer";
 | 
					 | 
				
			||||||
                                case "System.Int64": return $"({getExp(callExp.Arguments[0])})::bigint";
 | 
					 | 
				
			||||||
                                case "System.SByte": return $"({getExp(callExp.Arguments[0])})::smallint";
 | 
					 | 
				
			||||||
                                case "System.Single": return $"({getExp(callExp.Arguments[0])})::smallfloat";
 | 
					 | 
				
			||||||
                                case "System.UInt16": return $"({getExp(callExp.Arguments[0])})::integer";
 | 
					 | 
				
			||||||
                                case "System.UInt32": return $"({getExp(callExp.Arguments[0])})::bigint";
 | 
					 | 
				
			||||||
                                case "System.UInt64": return $"({getExp(callExp.Arguments[0])})::decimal";
 | 
					 | 
				
			||||||
                                case "System.Guid": return $"({getExp(callExp.Arguments[0])})::char";
 | 
					 | 
				
			||||||
                            }
 | 
					 | 
				
			||||||
                            break;
 | 
					 | 
				
			||||||
                        case "NewGuid":
 | 
					 | 
				
			||||||
                            return null;
 | 
					 | 
				
			||||||
                        case "Next":
 | 
					 | 
				
			||||||
                            if (callExp.Object?.Type == typeof(Random)) return "(random()*1000000000)::integer";
 | 
					 | 
				
			||||||
                            return null;
 | 
					 | 
				
			||||||
                        case "NextDouble":
 | 
					 | 
				
			||||||
                            if (callExp.Object?.Type == typeof(Random)) return "random()";
 | 
					 | 
				
			||||||
                            return null;
 | 
					 | 
				
			||||||
                        case "Random":
 | 
					 | 
				
			||||||
                            if (callExp.Method.DeclaringType.IsNumberType()) return "random()";
 | 
					 | 
				
			||||||
                            return null;
 | 
					 | 
				
			||||||
                        case "ToString":
 | 
					 | 
				
			||||||
                            if (callExp.Object != null) return callExp.Arguments.Count == 0 ? $"({getExp(callExp.Object)})::varchar" : null;
 | 
					 | 
				
			||||||
                            return null;
 | 
					 | 
				
			||||||
                    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
                    var objExp = callExp.Object;
 | 
					 | 
				
			||||||
                    var objType = objExp?.Type;
 | 
					 | 
				
			||||||
                    if (objType?.FullName == "System.Byte[]") return null;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
                    var argIndex = 0;
 | 
					 | 
				
			||||||
                    if (objType == null && callExp.Method.DeclaringType == typeof(Enumerable))
 | 
					 | 
				
			||||||
                    {
 | 
					 | 
				
			||||||
                        objExp = callExp.Arguments.FirstOrDefault();
 | 
					 | 
				
			||||||
                        objType = objExp?.Type;
 | 
					 | 
				
			||||||
                        argIndex++;
 | 
					 | 
				
			||||||
                    }
 | 
					 | 
				
			||||||
                    if (objType == null) objType = callExp.Method.DeclaringType;
 | 
					 | 
				
			||||||
                    if (objType != null || objType.IsArrayOrList())
 | 
					 | 
				
			||||||
                    {
 | 
					 | 
				
			||||||
                        string left = null;
 | 
					 | 
				
			||||||
                        if (objType.FullName == typeof(Dictionary<string, string>).FullName)
 | 
					 | 
				
			||||||
                        {
 | 
					 | 
				
			||||||
                            left = objExp == null ? null : getExp(objExp);
 | 
					 | 
				
			||||||
                            switch (callExp.Method.Name)
 | 
					 | 
				
			||||||
                            {
 | 
					 | 
				
			||||||
                                case "Contains":
 | 
					 | 
				
			||||||
                                    var right = getExp(callExp.Arguments[argIndex]);
 | 
					 | 
				
			||||||
                                    return $"({left} @> ({right}))";
 | 
					 | 
				
			||||||
                                case "ContainsKey": return $"({left} ? {getExp(callExp.Arguments[argIndex])})";
 | 
					 | 
				
			||||||
                                case "Concat": return $"({left} || {getExp(callExp.Arguments[argIndex])})";
 | 
					 | 
				
			||||||
                                case "GetLength":
 | 
					 | 
				
			||||||
                                case "GetLongLength":
 | 
					 | 
				
			||||||
                                case "Count": return $"case when {left} is null then 0 else array_length(akeys({left}),1) end";
 | 
					 | 
				
			||||||
                                case "Keys": return $"akeys({left})";
 | 
					 | 
				
			||||||
                                case "Values": return $"avals({left})";
 | 
					 | 
				
			||||||
                            }
 | 
					 | 
				
			||||||
                        }
 | 
					 | 
				
			||||||
                        switch (callExp.Method.Name)
 | 
					 | 
				
			||||||
                        {
 | 
					 | 
				
			||||||
                            case "Any":
 | 
					 | 
				
			||||||
                                left = objExp == null ? null : getExp(objExp);
 | 
					 | 
				
			||||||
                                if (left.StartsWith("(") || left.EndsWith(")")) left = $"array[{left.TrimStart('(').TrimEnd(')')}]";
 | 
					 | 
				
			||||||
                                return $"(case when {left} is null then 0 else array_length({left},1) end > 0)";
 | 
					 | 
				
			||||||
                            case "Contains":
 | 
					 | 
				
			||||||
                                tsc.SetMapColumnTmp(null);
 | 
					 | 
				
			||||||
                                var args1 = getExp(callExp.Arguments[argIndex]);
 | 
					 | 
				
			||||||
                                var oldMapType = tsc.SetMapTypeReturnOld(tsc.mapTypeTmp);
 | 
					 | 
				
			||||||
                                var oldDbParams = tsc.SetDbParamsReturnOld(null);
 | 
					 | 
				
			||||||
                                left = objExp == null ? null : getExp(objExp);
 | 
					 | 
				
			||||||
                                tsc.SetMapColumnTmp(null).SetMapTypeReturnOld(oldMapType);
 | 
					 | 
				
			||||||
                                tsc.SetDbParamsReturnOld(oldDbParams);
 | 
					 | 
				
			||||||
                                //判断 in 或 array @> array
 | 
					 | 
				
			||||||
                                if (left.StartsWith("array[") || left.EndsWith("]"))
 | 
					 | 
				
			||||||
                                    return $"({args1}) in ({left.Substring(6, left.Length - 7)})";
 | 
					 | 
				
			||||||
                                if (left.StartsWith("(") || left.EndsWith(")")) //在各大 Provider AdoProvider 中已约定,500元素分割, 3空格\r\n4空格
 | 
					 | 
				
			||||||
                                    return $"(({args1}) in {left.Replace(",   \r\n    \r\n", $") \r\n OR ({args1}) in (")})";
 | 
					 | 
				
			||||||
                                if (args1.StartsWith("(") || args1.EndsWith(")")) args1 = $"array[{args1.TrimStart('(').TrimEnd(')')}]";
 | 
					 | 
				
			||||||
                                args1 = $"array[{args1}]";
 | 
					 | 
				
			||||||
                                if (objExp != null)
 | 
					 | 
				
			||||||
                                {
 | 
					 | 
				
			||||||
                                    var dbinfo = _common._orm.CodeFirst.GetDbInfo(objExp.Type);
 | 
					 | 
				
			||||||
                                    if (dbinfo.HasValue) args1 = $"{args1}::{dbinfo.Value.dbtype}";
 | 
					 | 
				
			||||||
                                }
 | 
					 | 
				
			||||||
                                return $"({left} @> {args1})";
 | 
					 | 
				
			||||||
                            case "Concat":
 | 
					 | 
				
			||||||
                                left = objExp == null ? null : getExp(objExp);
 | 
					 | 
				
			||||||
                                if (left.StartsWith("(") || left.EndsWith(")")) left = $"array[{left.TrimStart('(').TrimEnd(')')}]";
 | 
					 | 
				
			||||||
                                var right2 = getExp(callExp.Arguments[argIndex]);
 | 
					 | 
				
			||||||
                                if (right2.StartsWith("(") || right2.EndsWith(")")) right2 = $"array[{right2.TrimStart('(').TrimEnd(')')}]";
 | 
					 | 
				
			||||||
                                return $"({left} || {right2})";
 | 
					 | 
				
			||||||
                            case "GetLength":
 | 
					 | 
				
			||||||
                            case "GetLongLength":
 | 
					 | 
				
			||||||
                            case "Length":
 | 
					 | 
				
			||||||
                            case "Count":
 | 
					 | 
				
			||||||
                                left = objExp == null ? null : getExp(objExp);
 | 
					 | 
				
			||||||
                                if (left.StartsWith("(") || left.EndsWith(")")) left = $"array[{left.TrimStart('(').TrimEnd(')')}]";
 | 
					 | 
				
			||||||
                                return $"case when {left} is null then 0 else array_length({left},1) end";
 | 
					 | 
				
			||||||
                        }
 | 
					 | 
				
			||||||
                    }
 | 
					 | 
				
			||||||
                    break;
 | 
					 | 
				
			||||||
                case ExpressionType.MemberAccess:
 | 
					 | 
				
			||||||
                    var memExp = exp as MemberExpression;
 | 
					 | 
				
			||||||
                    var memParentExp = memExp.Expression?.Type;
 | 
					 | 
				
			||||||
                    if (memParentExp?.FullName == "System.Byte[]") return null;
 | 
					 | 
				
			||||||
                    if (memParentExp != null)
 | 
					 | 
				
			||||||
                    {
 | 
					 | 
				
			||||||
                        if (memParentExp.IsArray == true)
 | 
					 | 
				
			||||||
                        {
 | 
					 | 
				
			||||||
                            var left = getExp(memExp.Expression);
 | 
					 | 
				
			||||||
                            if (left.StartsWith("(") || left.EndsWith(")")) left = $"array[{left.TrimStart('(').TrimEnd(')')}]";
 | 
					 | 
				
			||||||
                            switch (memExp.Member.Name)
 | 
					 | 
				
			||||||
                            {
 | 
					 | 
				
			||||||
                                case "Length":
 | 
					 | 
				
			||||||
                                case "Count": return $"case when {left} is null then 0 else array_length({left},1) end";
 | 
					 | 
				
			||||||
                            }
 | 
					 | 
				
			||||||
                        }
 | 
					 | 
				
			||||||
                        switch (memParentExp.FullName)
 | 
					 | 
				
			||||||
                        {
 | 
					 | 
				
			||||||
                            case "Newtonsoft.Json.Linq.JToken":
 | 
					 | 
				
			||||||
                            case "Newtonsoft.Json.Linq.JObject":
 | 
					 | 
				
			||||||
                            case "Newtonsoft.Json.Linq.JArray":
 | 
					 | 
				
			||||||
                                var left = getExp(memExp.Expression);
 | 
					 | 
				
			||||||
                                switch (memExp.Member.Name)
 | 
					 | 
				
			||||||
                                {
 | 
					 | 
				
			||||||
                                    case "Count": return $"jsonb_array_length(coalesce({left},'[]'))";
 | 
					 | 
				
			||||||
                                }
 | 
					 | 
				
			||||||
                                break;
 | 
					 | 
				
			||||||
                        }
 | 
					 | 
				
			||||||
                        if (memParentExp.FullName == typeof(Dictionary<string, string>).FullName)
 | 
					 | 
				
			||||||
                        {
 | 
					 | 
				
			||||||
                            var left = getExp(memExp.Expression);
 | 
					 | 
				
			||||||
                            switch (memExp.Member.Name)
 | 
					 | 
				
			||||||
                            {
 | 
					 | 
				
			||||||
                                case "Count": return $"case when {left} is null then 0 else array_length(akeys({left}),1) end";
 | 
					 | 
				
			||||||
                                case "Keys": return $"akeys({left})";
 | 
					 | 
				
			||||||
                                case "Values": return $"avals({left})";
 | 
					 | 
				
			||||||
                            }
 | 
					 | 
				
			||||||
                        }
 | 
					 | 
				
			||||||
                    }
 | 
					 | 
				
			||||||
                    break;
 | 
					 | 
				
			||||||
                case ExpressionType.NewArrayInit:
 | 
					 | 
				
			||||||
                    var arrExp = exp as NewArrayExpression;
 | 
					 | 
				
			||||||
                    var arrSb = new StringBuilder();
 | 
					 | 
				
			||||||
                    arrSb.Append("array[");
 | 
					 | 
				
			||||||
                    for (var a = 0; a < arrExp.Expressions.Count; a++)
 | 
					 | 
				
			||||||
                    {
 | 
					 | 
				
			||||||
                        if (a > 0) arrSb.Append(",");
 | 
					 | 
				
			||||||
                        arrSb.Append(getExp(arrExp.Expressions[a]));
 | 
					 | 
				
			||||||
                    }
 | 
					 | 
				
			||||||
                    if (arrSb.Length == 1) arrSb.Append("NULL");
 | 
					 | 
				
			||||||
                    return arrSb.Append("]").ToString();
 | 
					 | 
				
			||||||
                case ExpressionType.ListInit:
 | 
					 | 
				
			||||||
                    var listExp = exp as ListInitExpression;
 | 
					 | 
				
			||||||
                    var listSb = new StringBuilder();
 | 
					 | 
				
			||||||
                    listSb.Append("(");
 | 
					 | 
				
			||||||
                    for (var a = 0; a < listExp.Initializers.Count; a++)
 | 
					 | 
				
			||||||
                    {
 | 
					 | 
				
			||||||
                        if (listExp.Initializers[a].Arguments.Any() == false) continue;
 | 
					 | 
				
			||||||
                        if (a > 0) listSb.Append(",");
 | 
					 | 
				
			||||||
                        listSb.Append(getExp(listExp.Initializers[a].Arguments.FirstOrDefault()));
 | 
					 | 
				
			||||||
                    }
 | 
					 | 
				
			||||||
                    if (listSb.Length == 1) listSb.Append("NULL");
 | 
					 | 
				
			||||||
                    return listSb.Append(")").ToString();
 | 
					 | 
				
			||||||
                case ExpressionType.New:
 | 
					 | 
				
			||||||
                    var newExp = exp as NewExpression;
 | 
					 | 
				
			||||||
                    if (typeof(IList).IsAssignableFrom(newExp.Type))
 | 
					 | 
				
			||||||
                    {
 | 
					 | 
				
			||||||
                        if (newExp.Arguments.Count == 0) return "(NULL)";
 | 
					 | 
				
			||||||
                        if (typeof(IEnumerable).IsAssignableFrom(newExp.Arguments[0].Type) == false) return "(NULL)";
 | 
					 | 
				
			||||||
                        return getExp(newExp.Arguments[0]);
 | 
					 | 
				
			||||||
                    }
 | 
					 | 
				
			||||||
                    return null;
 | 
					 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
            return null;
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        public override string ExpressionLambdaToSqlMemberAccessString(MemberExpression exp, ExpTSC tsc)
 | 
					 | 
				
			||||||
        {
 | 
					 | 
				
			||||||
            if (exp.Expression == null)
 | 
					 | 
				
			||||||
            {
 | 
					 | 
				
			||||||
                switch (exp.Member.Name)
 | 
					 | 
				
			||||||
                {
 | 
					 | 
				
			||||||
                    case "Empty": return "''";
 | 
					 | 
				
			||||||
                }
 | 
					 | 
				
			||||||
                return null;
 | 
					 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
            var left = ExpressionLambdaToSql(exp.Expression, tsc);
 | 
					 | 
				
			||||||
            switch (exp.Member.Name)
 | 
					 | 
				
			||||||
            {
 | 
					 | 
				
			||||||
                case "Length": return $"char_length({left})";
 | 
					 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
            return null;
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
        public override string ExpressionLambdaToSqlMemberAccessDateTime(MemberExpression exp, ExpTSC tsc)
 | 
					 | 
				
			||||||
        {
 | 
					 | 
				
			||||||
            if (exp.Expression == null)
 | 
					 | 
				
			||||||
            {
 | 
					 | 
				
			||||||
                switch (exp.Member.Name)
 | 
					 | 
				
			||||||
                {
 | 
					 | 
				
			||||||
                    case "Now": return _common.Now;
 | 
					 | 
				
			||||||
                    case "UtcNow": return _common.NowUtc;
 | 
					 | 
				
			||||||
                    case "Today": return "current_date";
 | 
					 | 
				
			||||||
                    case "MinValue": return "'0001/1/1 0:00:00'::timestamp";
 | 
					 | 
				
			||||||
                    case "MaxValue": return "'9999/12/31 23:59:59'::timestamp";
 | 
					 | 
				
			||||||
                }
 | 
					 | 
				
			||||||
                return null;
 | 
					 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
            var left = ExpressionLambdaToSql(exp.Expression, tsc);
 | 
					 | 
				
			||||||
            switch (exp.Member.Name)
 | 
					 | 
				
			||||||
            {
 | 
					 | 
				
			||||||
                case "Date": return $"({left})::date";
 | 
					 | 
				
			||||||
                case "TimeOfDay": return $"(extract(epoch from ({left})::time)*1000000)";
 | 
					 | 
				
			||||||
                case "DayOfWeek": return $"extract(dow from ({left})::timestamp)";
 | 
					 | 
				
			||||||
                case "Day": return $"extract(day from ({left})::timestamp)";
 | 
					 | 
				
			||||||
                case "DayOfYear": return $"extract(doy from ({left})::timestamp)";
 | 
					 | 
				
			||||||
                case "Month": return $"extract(month from ({left})::timestamp)";
 | 
					 | 
				
			||||||
                case "Year": return $"extract(year from ({left})::timestamp)";
 | 
					 | 
				
			||||||
                case "Hour": return $"extract(hour from ({left})::timestamp)";
 | 
					 | 
				
			||||||
                case "Minute": return $"extract(minute from ({left})::timestamp)";
 | 
					 | 
				
			||||||
                case "Second": return $"extract(second from ({left})::timestamp)";
 | 
					 | 
				
			||||||
                case "Millisecond": return $"(extract(milliseconds from ({left})::timestamp)-extract(second from ({left})::timestamp)*1000)";
 | 
					 | 
				
			||||||
                case "Ticks": return $"(extract(epoch from ({left})::timestamp)*10000000+621355968000000000)";
 | 
					 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
            return null;
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
        public override string ExpressionLambdaToSqlMemberAccessTimeSpan(MemberExpression exp, ExpTSC tsc)
 | 
					 | 
				
			||||||
        {
 | 
					 | 
				
			||||||
            if (exp.Expression == null)
 | 
					 | 
				
			||||||
            {
 | 
					 | 
				
			||||||
                switch (exp.Member.Name)
 | 
					 | 
				
			||||||
                {
 | 
					 | 
				
			||||||
                    case "Zero": return "0";
 | 
					 | 
				
			||||||
                    case "MinValue": return "-922337203685477580"; //微秒 Ticks / 10
 | 
					 | 
				
			||||||
                    case "MaxValue": return "922337203685477580";
 | 
					 | 
				
			||||||
                }
 | 
					 | 
				
			||||||
                return null;
 | 
					 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
            var left = ExpressionLambdaToSql(exp.Expression, tsc);
 | 
					 | 
				
			||||||
            switch (exp.Member.Name)
 | 
					 | 
				
			||||||
            {
 | 
					 | 
				
			||||||
                case "Days": return $"floor(({left})/{(long)1000000 * 60 * 60 * 24})";
 | 
					 | 
				
			||||||
                case "Hours": return $"floor(({left})/{(long)1000000 * 60 * 60}%24)";
 | 
					 | 
				
			||||||
                case "Milliseconds": return $"(floor(({left})/1000)::int8%1000)";
 | 
					 | 
				
			||||||
                case "Minutes": return $"(floor(({left})/{(long)1000000 * 60})::int8%60)";
 | 
					 | 
				
			||||||
                case "Seconds": return $"(floor(({left})/1000000)::int8%60)";
 | 
					 | 
				
			||||||
                case "Ticks": return $"(({left})*10)";
 | 
					 | 
				
			||||||
                case "TotalDays": return $"(({left})/{(long)1000000 * 60 * 60 * 24})";
 | 
					 | 
				
			||||||
                case "TotalHours": return $"(({left})/{(long)1000000 * 60 * 60})";
 | 
					 | 
				
			||||||
                case "TotalMilliseconds": return $"(({left})/1000)";
 | 
					 | 
				
			||||||
                case "TotalMinutes": return $"(({left})/{(long)1000000 * 60})";
 | 
					 | 
				
			||||||
                case "TotalSeconds": return $"(({left})/1000000)";
 | 
					 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
            return null;
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        public override string ExpressionLambdaToSqlCallString(MethodCallExpression exp, ExpTSC tsc)
 | 
					 | 
				
			||||||
        {
 | 
					 | 
				
			||||||
            Func<Expression, string> getExp = exparg => ExpressionLambdaToSql(exparg, tsc);
 | 
					 | 
				
			||||||
            if (exp.Object == null)
 | 
					 | 
				
			||||||
            {
 | 
					 | 
				
			||||||
                switch (exp.Method.Name)
 | 
					 | 
				
			||||||
                {
 | 
					 | 
				
			||||||
                    case "IsNullOrEmpty":
 | 
					 | 
				
			||||||
                        var arg1 = getExp(exp.Arguments[0]);
 | 
					 | 
				
			||||||
                        return $"({arg1} is null or {arg1} = '')";
 | 
					 | 
				
			||||||
                    case "IsNullOrWhiteSpace":
 | 
					 | 
				
			||||||
                        var arg2 = getExp(exp.Arguments[0]);
 | 
					 | 
				
			||||||
                        return $"({arg2} is null or {arg2} = '' or ltrim({arg2}) = '')";
 | 
					 | 
				
			||||||
                    case "Concat":
 | 
					 | 
				
			||||||
                        return _common.StringConcat(exp.Arguments.Select(a => getExp(a)).ToArray(), null);
 | 
					 | 
				
			||||||
                }
 | 
					 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
            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";
 | 
					 | 
				
			||||||
                        var likeOpt = "LIKE";
 | 
					 | 
				
			||||||
                        if (exp.Arguments.Count > 1)
 | 
					 | 
				
			||||||
                        {
 | 
					 | 
				
			||||||
                            if (exp.Arguments[1].Type == typeof(bool) ||
 | 
					 | 
				
			||||||
                                exp.Arguments[1].Type == typeof(StringComparison) && getExp(exp.Arguments[0]).Contains("IgnoreCase")) likeOpt = "ILIKE";
 | 
					 | 
				
			||||||
                        }
 | 
					 | 
				
			||||||
                        if (exp.Method.Name == "StartsWith") return $"({left}) {likeOpt} {(args0Value.EndsWith("'") ? args0Value.Insert(args0Value.Length - 1, "%") : $"(({args0Value})::varchar || '%')")}";
 | 
					 | 
				
			||||||
                        if (exp.Method.Name == "EndsWith") return $"({left}) {likeOpt} {(args0Value.StartsWith("'") ? args0Value.Insert(1, "%") : $"('%' || ({args0Value})::varchar)")}";
 | 
					 | 
				
			||||||
                        if (args0Value.StartsWith("'") && args0Value.EndsWith("'")) return $"({left}) {likeOpt} {args0Value.Insert(1, "%").Insert(args0Value.Length, "%")}";
 | 
					 | 
				
			||||||
                        return $"({left}) {likeOpt} ('%' || ({args0Value})::varchar || '%')";
 | 
					 | 
				
			||||||
                    case "ToLower": return $"lower({left})";
 | 
					 | 
				
			||||||
                    case "ToUpper": return $"upper({left})";
 | 
					 | 
				
			||||||
                    case "Substring":
 | 
					 | 
				
			||||||
                        var substrArgs1 = getExp(exp.Arguments[0]);
 | 
					 | 
				
			||||||
                        if (long.TryParse(substrArgs1, out var testtrylng1)) substrArgs1 = (testtrylng1 + 1).ToString();
 | 
					 | 
				
			||||||
                        else substrArgs1 += "+1";
 | 
					 | 
				
			||||||
                        if (exp.Arguments.Count == 1) return $"substr({left}, {substrArgs1})";
 | 
					 | 
				
			||||||
                        return $"substr({left}, {substrArgs1}, {getExp(exp.Arguments[1])})";
 | 
					 | 
				
			||||||
                    case "IndexOf": return $"(strpos({left}, {getExp(exp.Arguments[0])})-1)";
 | 
					 | 
				
			||||||
                    case "PadLeft":
 | 
					 | 
				
			||||||
                        if (exp.Arguments.Count == 1) return $"lpad({left}, {getExp(exp.Arguments[0])})";
 | 
					 | 
				
			||||||
                        return $"lpad({left}, {getExp(exp.Arguments[0])}, {getExp(exp.Arguments[1])})";
 | 
					 | 
				
			||||||
                    case "PadRight":
 | 
					 | 
				
			||||||
                        if (exp.Arguments.Count == 1) return $"rpad({left}, {getExp(exp.Arguments[0])})";
 | 
					 | 
				
			||||||
                        return $"rpad({left}, {getExp(exp.Arguments[0])}, {getExp(exp.Arguments[1])})";
 | 
					 | 
				
			||||||
                    case "Trim":
 | 
					 | 
				
			||||||
                    case "TrimStart":
 | 
					 | 
				
			||||||
                    case "TrimEnd":
 | 
					 | 
				
			||||||
                        if (exp.Arguments.Count == 0)
 | 
					 | 
				
			||||||
                        {
 | 
					 | 
				
			||||||
                            if (exp.Method.Name == "Trim") return $"trim({left})";
 | 
					 | 
				
			||||||
                            if (exp.Method.Name == "TrimStart") return $"ltrim({left})";
 | 
					 | 
				
			||||||
                            if (exp.Method.Name == "TrimEnd") return $"rtrim({left})";
 | 
					 | 
				
			||||||
                        }
 | 
					 | 
				
			||||||
                        var trimArg1 = "";
 | 
					 | 
				
			||||||
                        var trimArg2 = "";
 | 
					 | 
				
			||||||
                        foreach (var argsTrim02 in exp.Arguments)
 | 
					 | 
				
			||||||
                        {
 | 
					 | 
				
			||||||
                            var argsTrim01s = new[] { argsTrim02 };
 | 
					 | 
				
			||||||
                            if (argsTrim02.NodeType == ExpressionType.NewArrayInit)
 | 
					 | 
				
			||||||
                            {
 | 
					 | 
				
			||||||
                                var arritem = argsTrim02 as NewArrayExpression;
 | 
					 | 
				
			||||||
                                argsTrim01s = arritem.Expressions.ToArray();
 | 
					 | 
				
			||||||
                            }
 | 
					 | 
				
			||||||
                            foreach (var argsTrim01 in argsTrim01s)
 | 
					 | 
				
			||||||
                            {
 | 
					 | 
				
			||||||
                                var trimChr = getExp(argsTrim01).Trim('\'');
 | 
					 | 
				
			||||||
                                if (trimChr.Length == 1) trimArg1 += trimChr;
 | 
					 | 
				
			||||||
                                else trimArg2 += $" || ({trimChr})";
 | 
					 | 
				
			||||||
                            }
 | 
					 | 
				
			||||||
                        }
 | 
					 | 
				
			||||||
                        if (exp.Method.Name == "Trim") left = $"trim({left}, {_common.FormatSql("{0}", trimArg1)}{trimArg2})";
 | 
					 | 
				
			||||||
                        if (exp.Method.Name == "TrimStart") left = $"ltrim({left}, {_common.FormatSql("{0}", trimArg1)}{trimArg2})";
 | 
					 | 
				
			||||||
                        if (exp.Method.Name == "TrimEnd") left = $"rtrim({left}, {_common.FormatSql("{0}", trimArg1)}{trimArg2})";
 | 
					 | 
				
			||||||
                        return left;
 | 
					 | 
				
			||||||
                    case "Replace": return $"replace({left}, {getExp(exp.Arguments[0])}, {getExp(exp.Arguments[1])})";
 | 
					 | 
				
			||||||
                    case "CompareTo": return $"case when {left} = {getExp(exp.Arguments[0])} then 0 when {left} > {getExp(exp.Arguments[0])} then 1 else -1 end";
 | 
					 | 
				
			||||||
                    case "Equals": return $"({left} = ({getExp(exp.Arguments[0])})::varchar)";
 | 
					 | 
				
			||||||
                }
 | 
					 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
            return null;
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
        public override string ExpressionLambdaToSqlCallMath(MethodCallExpression exp, ExpTSC tsc)
 | 
					 | 
				
			||||||
        {
 | 
					 | 
				
			||||||
            Func<Expression, string> getExp = exparg => ExpressionLambdaToSql(exparg, tsc);
 | 
					 | 
				
			||||||
            switch (exp.Method.Name)
 | 
					 | 
				
			||||||
            {
 | 
					 | 
				
			||||||
                case "Abs": return $"abs({getExp(exp.Arguments[0])})";
 | 
					 | 
				
			||||||
                case "Sign": return $"sign({getExp(exp.Arguments[0])})";
 | 
					 | 
				
			||||||
                case "Floor": return $"floor({getExp(exp.Arguments[0])})";
 | 
					 | 
				
			||||||
                case "Ceiling": return $"ceiling({getExp(exp.Arguments[0])})";
 | 
					 | 
				
			||||||
                case "Round":
 | 
					 | 
				
			||||||
                    if (exp.Arguments.Count > 1 && exp.Arguments[1].Type.FullName == "System.Int32") return $"round({getExp(exp.Arguments[0])}, {getExp(exp.Arguments[1])})";
 | 
					 | 
				
			||||||
                    return $"round({getExp(exp.Arguments[0])})";
 | 
					 | 
				
			||||||
                case "Exp": return $"exp({getExp(exp.Arguments[0])})";
 | 
					 | 
				
			||||||
                case "Log": return $"log({getExp(exp.Arguments[0])})";
 | 
					 | 
				
			||||||
                case "Log10": return $"log10({getExp(exp.Arguments[0])})";
 | 
					 | 
				
			||||||
                case "Pow": return $"pow({getExp(exp.Arguments[0])}, {getExp(exp.Arguments[1])})";
 | 
					 | 
				
			||||||
                case "Sqrt": return $"sqrt({getExp(exp.Arguments[0])})";
 | 
					 | 
				
			||||||
                case "Cos": return $"cos({getExp(exp.Arguments[0])})";
 | 
					 | 
				
			||||||
                case "Sin": return $"sin({getExp(exp.Arguments[0])})";
 | 
					 | 
				
			||||||
                case "Tan": return $"tan({getExp(exp.Arguments[0])})";
 | 
					 | 
				
			||||||
                case "Acos": return $"acos({getExp(exp.Arguments[0])})";
 | 
					 | 
				
			||||||
                case "Asin": return $"asin({getExp(exp.Arguments[0])})";
 | 
					 | 
				
			||||||
                case "Atan": return $"atan({getExp(exp.Arguments[0])})";
 | 
					 | 
				
			||||||
                case "Atan2": return $"atan2({getExp(exp.Arguments[0])}, {getExp(exp.Arguments[1])})";
 | 
					 | 
				
			||||||
                case "Truncate": return $"trunc({getExp(exp.Arguments[0])}, 0)";
 | 
					 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
            return null;
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
        public override string ExpressionLambdaToSqlCallDateTime(MethodCallExpression exp, ExpTSC tsc)
 | 
					 | 
				
			||||||
        {
 | 
					 | 
				
			||||||
            Func<Expression, string> getExp = exparg => ExpressionLambdaToSql(exparg, tsc);
 | 
					 | 
				
			||||||
            if (exp.Object == null)
 | 
					 | 
				
			||||||
            {
 | 
					 | 
				
			||||||
                switch (exp.Method.Name)
 | 
					 | 
				
			||||||
                {
 | 
					 | 
				
			||||||
                    case "Compare": return $"extract(epoch from ({getExp(exp.Arguments[0])})::timestamp-({getExp(exp.Arguments[1])})::timestamp)";
 | 
					 | 
				
			||||||
                    case "DaysInMonth": return $"extract(day from ({getExp(exp.Arguments[0])} || '-' || {getExp(exp.Arguments[1])} || '-01')::timestamp+'1 month'::interval-'1 day'::interval)";
 | 
					 | 
				
			||||||
                    case "Equals": return $"(({getExp(exp.Arguments[0])})::timestamp = ({getExp(exp.Arguments[1])})::timestamp)";
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
                    case "IsLeapYear":
 | 
					 | 
				
			||||||
                        var isLeapYearArgs1 = getExp(exp.Arguments[0]);
 | 
					 | 
				
			||||||
                        return $"(({isLeapYearArgs1})::int8%4=0 AND ({isLeapYearArgs1})::int8%100<>0 OR ({isLeapYearArgs1})::int8%400=0)";
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
                    case "Parse": return $"({getExp(exp.Arguments[0])})::timestamp";
 | 
					 | 
				
			||||||
                    case "ParseExact":
 | 
					 | 
				
			||||||
                    case "TryParse":
 | 
					 | 
				
			||||||
                    case "TryParseExact": return $"({getExp(exp.Arguments[0])})::timestamp";
 | 
					 | 
				
			||||||
                }
 | 
					 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
            else
 | 
					 | 
				
			||||||
            {
 | 
					 | 
				
			||||||
                var left = getExp(exp.Object);
 | 
					 | 
				
			||||||
                var args1 = exp.Arguments.Count == 0 ? null : getExp(exp.Arguments[0]);
 | 
					 | 
				
			||||||
                switch (exp.Method.Name)
 | 
					 | 
				
			||||||
                {
 | 
					 | 
				
			||||||
                    case "Add": return $"(({left})::timestamp+(({args1})||' microseconds')::interval)";
 | 
					 | 
				
			||||||
                    case "AddDays": return $"(({left})::timestamp+(({args1})||' day')::interval)";
 | 
					 | 
				
			||||||
                    case "AddHours": return $"(({left})::timestamp+(({args1})||' hour')::interval)";
 | 
					 | 
				
			||||||
                    case "AddMilliseconds": return $"(({left})::timestamp+(({args1})||' milliseconds')::interval)";
 | 
					 | 
				
			||||||
                    case "AddMinutes": return $"(({left})::timestamp+(({args1})||' minute')::interval)";
 | 
					 | 
				
			||||||
                    case "AddMonths": return $"(({left})::timestamp+(({args1})||' month')::interval)";
 | 
					 | 
				
			||||||
                    case "AddSeconds": return $"(({left})::timestamp+(({args1})||' second')::interval)";
 | 
					 | 
				
			||||||
                    case "AddTicks": return $"(({left})::timestamp+(({args1})/10||' microseconds')::interval)";
 | 
					 | 
				
			||||||
                    case "AddYears": return $"(({left})::timestamp+(({args1})||' year')::interval)";
 | 
					 | 
				
			||||||
                    case "Subtract":
 | 
					 | 
				
			||||||
                        switch ((exp.Arguments[0].Type.IsNullableType() ? exp.Arguments[0].Type.GetGenericArguments().FirstOrDefault() : exp.Arguments[0].Type).FullName)
 | 
					 | 
				
			||||||
                        {
 | 
					 | 
				
			||||||
                            case "System.DateTime": return $"(extract(epoch from ({left})::timestamp-({args1})::timestamp)*1000000)";
 | 
					 | 
				
			||||||
                            case "System.TimeSpan": return $"(({left})::timestamp-(({args1})||' microseconds')::interval)";
 | 
					 | 
				
			||||||
                        }
 | 
					 | 
				
			||||||
                        break;
 | 
					 | 
				
			||||||
                    case "Equals": return $"({left} = ({args1})::timestamp)";
 | 
					 | 
				
			||||||
                    case "CompareTo": return $"extract(epoch from ({left})::timestamp-({args1})::timestamp)";
 | 
					 | 
				
			||||||
                    case "ToString": return exp.Arguments.Count == 0 ? $"to_char({left}, 'YYYY-MM-DD HH24:MI:SS.US')" : null;
 | 
					 | 
				
			||||||
                }
 | 
					 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
            return null;
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
        public override string ExpressionLambdaToSqlCallTimeSpan(MethodCallExpression exp, ExpTSC tsc)
 | 
					 | 
				
			||||||
        {
 | 
					 | 
				
			||||||
            Func<Expression, string> getExp = exparg => ExpressionLambdaToSql(exparg, tsc);
 | 
					 | 
				
			||||||
            if (exp.Object == null)
 | 
					 | 
				
			||||||
            {
 | 
					 | 
				
			||||||
                switch (exp.Method.Name)
 | 
					 | 
				
			||||||
                {
 | 
					 | 
				
			||||||
                    case "Compare": return $"({getExp(exp.Arguments[0])}-({getExp(exp.Arguments[1])}))";
 | 
					 | 
				
			||||||
                    case "Equals": return $"({getExp(exp.Arguments[0])} = {getExp(exp.Arguments[1])})";
 | 
					 | 
				
			||||||
                    case "FromDays": return $"(({getExp(exp.Arguments[0])})*{(long)1000000 * 60 * 60 * 24})";
 | 
					 | 
				
			||||||
                    case "FromHours": return $"(({getExp(exp.Arguments[0])})*{(long)1000000 * 60 * 60})";
 | 
					 | 
				
			||||||
                    case "FromMilliseconds": return $"(({getExp(exp.Arguments[0])})*1000)";
 | 
					 | 
				
			||||||
                    case "FromMinutes": return $"(({getExp(exp.Arguments[0])})*{(long)1000000 * 60})";
 | 
					 | 
				
			||||||
                    case "FromSeconds": return $"(({getExp(exp.Arguments[0])})*1000000)";
 | 
					 | 
				
			||||||
                    case "FromTicks": return $"(({getExp(exp.Arguments[0])})/10)";
 | 
					 | 
				
			||||||
                    case "Parse": return $"({getExp(exp.Arguments[0])})::int8";
 | 
					 | 
				
			||||||
                    case "ParseExact":
 | 
					 | 
				
			||||||
                    case "TryParse":
 | 
					 | 
				
			||||||
                    case "TryParseExact": return $"({getExp(exp.Arguments[0])})::int8";
 | 
					 | 
				
			||||||
                }
 | 
					 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
            else
 | 
					 | 
				
			||||||
            {
 | 
					 | 
				
			||||||
                var left = getExp(exp.Object);
 | 
					 | 
				
			||||||
                var args1 = exp.Arguments.Count == 0 ? null : getExp(exp.Arguments[0]);
 | 
					 | 
				
			||||||
                switch (exp.Method.Name)
 | 
					 | 
				
			||||||
                {
 | 
					 | 
				
			||||||
                    case "Add": return $"({left}+{args1})";
 | 
					 | 
				
			||||||
                    case "Subtract": return $"({left}-({args1}))";
 | 
					 | 
				
			||||||
                    case "Equals": return $"({left} = {args1})";
 | 
					 | 
				
			||||||
                    case "CompareTo": return $"({left}-({args1}))";
 | 
					 | 
				
			||||||
                    case "ToString": return $"({left})::varchar";
 | 
					 | 
				
			||||||
                }
 | 
					 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
            return null;
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
        public override string ExpressionLambdaToSqlCallConvert(MethodCallExpression exp, ExpTSC tsc)
 | 
					 | 
				
			||||||
        {
 | 
					 | 
				
			||||||
            Func<Expression, string> getExp = exparg => ExpressionLambdaToSql(exparg, tsc);
 | 
					 | 
				
			||||||
            if (exp.Object == null)
 | 
					 | 
				
			||||||
            {
 | 
					 | 
				
			||||||
                switch (exp.Method.Name)
 | 
					 | 
				
			||||||
                {
 | 
					 | 
				
			||||||
                    case "ToBoolean": return $"(({getExp(exp.Arguments[0])})::varchar not in ('0','false','f','no'))";
 | 
					 | 
				
			||||||
                    case "ToByte": return $"({getExp(exp.Arguments[0])})::int2";
 | 
					 | 
				
			||||||
                    case "ToChar": return $"substr(({getExp(exp.Arguments[0])})::char, 1, 1)";
 | 
					 | 
				
			||||||
                    case "ToDateTime": return $"({getExp(exp.Arguments[0])})::timestamp";
 | 
					 | 
				
			||||||
                    case "ToDecimal": return $"({getExp(exp.Arguments[0])})::numeric";
 | 
					 | 
				
			||||||
                    case "ToDouble": return $"({getExp(exp.Arguments[0])})::float8";
 | 
					 | 
				
			||||||
                    case "ToInt16": return $"({getExp(exp.Arguments[0])})::int2";
 | 
					 | 
				
			||||||
                    case "ToInt32": return $"({getExp(exp.Arguments[0])})::int4";
 | 
					 | 
				
			||||||
                    case "ToInt64": return $"({getExp(exp.Arguments[0])})::int8";
 | 
					 | 
				
			||||||
                    case "ToSByte": return $"({getExp(exp.Arguments[0])})::int2";
 | 
					 | 
				
			||||||
                    case "ToSingle": return $"({getExp(exp.Arguments[0])})::float4";
 | 
					 | 
				
			||||||
                    case "ToString": return $"({getExp(exp.Arguments[0])})::varchar";
 | 
					 | 
				
			||||||
                    case "ToUInt16": return $"({getExp(exp.Arguments[0])})::int2";
 | 
					 | 
				
			||||||
                    case "ToUInt32": return $"({getExp(exp.Arguments[0])})::int4";
 | 
					 | 
				
			||||||
                    case "ToUInt64": return $"({getExp(exp.Arguments[0])})::int8";
 | 
					 | 
				
			||||||
                }
 | 
					 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
            return null;
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
@@ -1,159 +0,0 @@
 | 
				
			|||||||
using FreeSql.Internal;
 | 
					 | 
				
			||||||
using FreeSql.Internal.Model;
 | 
					 | 
				
			||||||
using System;
 | 
					 | 
				
			||||||
using System.Collections.Generic;
 | 
					 | 
				
			||||||
using System.Data.Common;
 | 
					 | 
				
			||||||
using System.Data.Odbc;
 | 
					 | 
				
			||||||
using System.Linq;
 | 
					 | 
				
			||||||
using System.Text;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
namespace FreeSql.Odbc.GBase
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    class OdbcGBaseUtils : CommonUtils
 | 
					 | 
				
			||||||
    {
 | 
					 | 
				
			||||||
        public OdbcGBaseUtils(IFreeSql orm) : base(orm)
 | 
					 | 
				
			||||||
        {
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        static Array getParamterArrayValue(Type arrayType, object value, object defaultValue)
 | 
					 | 
				
			||||||
        {
 | 
					 | 
				
			||||||
            var valueArr = value as Array;
 | 
					 | 
				
			||||||
            var len = valueArr.GetLength(0);
 | 
					 | 
				
			||||||
            var ret = Array.CreateInstance(arrayType, len);
 | 
					 | 
				
			||||||
            for (var a = 0; a < len; a++)
 | 
					 | 
				
			||||||
            {
 | 
					 | 
				
			||||||
                var item = valueArr.GetValue(a);
 | 
					 | 
				
			||||||
                ret.SetValue(item == null ? defaultValue : getParamterValue(item.GetType(), item, 1), a);
 | 
					 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
            return ret;
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
        static Dictionary<string, Func<object, object>> dicGetParamterValue = new Dictionary<string, Func<object, object>> {
 | 
					 | 
				
			||||||
            { typeof(uint).FullName, a => long.Parse(string.Concat(a)) }, { typeof(uint[]).FullName, a => getParamterArrayValue(typeof(long), a, 0) }, { typeof(uint?[]).FullName, a => getParamterArrayValue(typeof(long?), a, null) },
 | 
					 | 
				
			||||||
            { typeof(ulong).FullName, a => decimal.Parse(string.Concat(a)) }, { typeof(ulong[]).FullName, a => getParamterArrayValue(typeof(decimal), a, 0) }, { typeof(ulong?[]).FullName, a => getParamterArrayValue(typeof(decimal?), a, null) },
 | 
					 | 
				
			||||||
            { typeof(ushort).FullName, a => int.Parse(string.Concat(a)) }, { typeof(ushort[]).FullName, a => getParamterArrayValue(typeof(int), a, 0) }, { typeof(ushort?[]).FullName, a => getParamterArrayValue(typeof(int?), a, null) },
 | 
					 | 
				
			||||||
            { typeof(byte).FullName, a => short.Parse(string.Concat(a)) }, { typeof(byte[]).FullName, a => getParamterArrayValue(typeof(short), a, 0) }, { typeof(byte?[]).FullName, a => getParamterArrayValue(typeof(short?), a, null) },
 | 
					 | 
				
			||||||
            { typeof(sbyte).FullName, a => short.Parse(string.Concat(a)) }, { typeof(sbyte[]).FullName, a => getParamterArrayValue(typeof(short), a, 0) }, { typeof(sbyte?[]).FullName, a => getParamterArrayValue(typeof(short?), a, null) },
 | 
					 | 
				
			||||||
        };
 | 
					 | 
				
			||||||
        static object getParamterValue(Type type, object value, int level = 0)
 | 
					 | 
				
			||||||
        {
 | 
					 | 
				
			||||||
            if (type.FullName == "System.Byte[]") return value;
 | 
					 | 
				
			||||||
            if (type.IsArray && level == 0)
 | 
					 | 
				
			||||||
            {
 | 
					 | 
				
			||||||
                var elementType = type.GetElementType();
 | 
					 | 
				
			||||||
                Type enumType = null;
 | 
					 | 
				
			||||||
                if (elementType.IsEnum) enumType = elementType;
 | 
					 | 
				
			||||||
                else if (elementType.IsNullableType())
 | 
					 | 
				
			||||||
                {
 | 
					 | 
				
			||||||
                    var genericTypesFirst = elementType.GetGenericArguments().First();
 | 
					 | 
				
			||||||
                    if (genericTypesFirst.IsEnum) enumType = genericTypesFirst;
 | 
					 | 
				
			||||||
                }
 | 
					 | 
				
			||||||
                if (enumType != null) return enumType.GetCustomAttributes(typeof(FlagsAttribute), false).Any() ?
 | 
					 | 
				
			||||||
                    getParamterArrayValue(typeof(long), value, elementType.IsEnum ? null : Enum.GetValues(enumType).GetValue(0)) :
 | 
					 | 
				
			||||||
                    getParamterArrayValue(typeof(int), value, elementType.IsEnum ? null : Enum.GetValues(enumType).GetValue(0));
 | 
					 | 
				
			||||||
                return dicGetParamterValue.TryGetValue(type.FullName, out var trydicarr) ? trydicarr(value) : value;
 | 
					 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
            if (type.IsNullableType()) type = type.GetGenericArguments().First();
 | 
					 | 
				
			||||||
            if (type.IsEnum) return (int)value;
 | 
					 | 
				
			||||||
            if (dicGetParamterValue.TryGetValue(type.FullName, out var trydic)) return trydic(value);
 | 
					 | 
				
			||||||
            return value;
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        public override DbParameter AppendParamter(List<DbParameter> _params, string parameterName, ColumnInfo col, Type type, object value)
 | 
					 | 
				
			||||||
        {
 | 
					 | 
				
			||||||
            if (string.IsNullOrEmpty(parameterName)) parameterName = $"p_{_params?.Count}";
 | 
					 | 
				
			||||||
            if (value != null) value = getParamterValue(type, value);
 | 
					 | 
				
			||||||
            var ret = new OdbcParameter { ParameterName = QuoteParamterName(parameterName), Value = value };
 | 
					 | 
				
			||||||
            //if (value.GetType().IsEnum || value.GetType().GenericTypeArguments.FirstOrDefault()?.IsEnum == true) {
 | 
					 | 
				
			||||||
            //	ret.DataTypeName = "";
 | 
					 | 
				
			||||||
            //} else {
 | 
					 | 
				
			||||||
            var tp = _orm.CodeFirst.GetDbInfo(type)?.type;
 | 
					 | 
				
			||||||
            if (tp != null) ret.OdbcType = (OdbcType)tp.Value;
 | 
					 | 
				
			||||||
            //}
 | 
					 | 
				
			||||||
            _params?.Add(ret);
 | 
					 | 
				
			||||||
            return ret;
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        public override DbParameter[] GetDbParamtersByObject(string sql, object obj) =>
 | 
					 | 
				
			||||||
            Utils.GetDbParamtersByObject<OdbcParameter>(sql, obj, null, (name, type, value) =>
 | 
					 | 
				
			||||||
            {
 | 
					 | 
				
			||||||
                if (value != null) value = getParamterValue(type, value);
 | 
					 | 
				
			||||||
                var ret = new OdbcParameter { ParameterName = $"@{name}", Value = value };
 | 
					 | 
				
			||||||
                //if (value.GetType().IsEnum || value.GetType().GenericTypeArguments.FirstOrDefault()?.IsEnum == true) {
 | 
					 | 
				
			||||||
                //	ret.DataTypeName = "";
 | 
					 | 
				
			||||||
                //} else {
 | 
					 | 
				
			||||||
                var tp = _orm.CodeFirst.GetDbInfo(type)?.type;
 | 
					 | 
				
			||||||
                if (tp != null) ret.OdbcType = (OdbcType)tp.Value;
 | 
					 | 
				
			||||||
                //}
 | 
					 | 
				
			||||||
                return ret;
 | 
					 | 
				
			||||||
            });
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        public override string FormatSql(string sql, params object[] args) => sql?.FormatOdbcPostgreSQL(args);
 | 
					 | 
				
			||||||
        public override string QuoteSqlName(params string[] name)
 | 
					 | 
				
			||||||
        {
 | 
					 | 
				
			||||||
            if (name.Length == 1)
 | 
					 | 
				
			||||||
            {
 | 
					 | 
				
			||||||
                var nametrim = name[0].Trim();
 | 
					 | 
				
			||||||
                if (nametrim.StartsWith("(") && nametrim.EndsWith(")"))
 | 
					 | 
				
			||||||
                    return nametrim; //原生SQL
 | 
					 | 
				
			||||||
                if (nametrim.StartsWith("\"") && nametrim.EndsWith("\""))
 | 
					 | 
				
			||||||
                    return nametrim;
 | 
					 | 
				
			||||||
                return $"\"{nametrim.Replace(".", "\".\"")}\"";
 | 
					 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
            return $"\"{string.Join("\".\"", name)}\"";
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
        public override string TrimQuoteSqlName(string name)
 | 
					 | 
				
			||||||
        {
 | 
					 | 
				
			||||||
            var nametrim = name.Trim();
 | 
					 | 
				
			||||||
            if (nametrim.StartsWith("(") && nametrim.EndsWith(")"))
 | 
					 | 
				
			||||||
                return nametrim; //原生SQL
 | 
					 | 
				
			||||||
            return $"{nametrim.Trim('"').Replace("\".\"", ".").Replace(".\"", ".")}";
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
        public override string[] SplitTableName(string name) => GetSplitTableNames(name, '"', '"', 2);
 | 
					 | 
				
			||||||
        public override string QuoteParamterName(string name) => $"@{(_orm.CodeFirst.IsSyncStructureToLower ? name.ToLower() : name)}";
 | 
					 | 
				
			||||||
        public override string IsNull(string sql, object value) => $"coalesce({sql}, {value})";
 | 
					 | 
				
			||||||
        public override string StringConcat(string[] objs, Type[] types) => $"{string.Join(" || ", objs)}";
 | 
					 | 
				
			||||||
        public override string Mod(string left, string right, Type leftType, Type rightType) => $"{left} % {right}";
 | 
					 | 
				
			||||||
        public override string Div(string left, string right, Type leftType, Type rightType) => $"{left} / {right}";
 | 
					 | 
				
			||||||
        public override string Now => "current_timestamp";
 | 
					 | 
				
			||||||
        public override string NowUtc => "(current_timestamp at time zone 'UTC')";
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        public override string QuoteWriteParamter(Type type, string paramterName) => paramterName;
 | 
					 | 
				
			||||||
        public override string QuoteReadColumn(Type type, Type mapType, string columnName) => columnName;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        public override string GetNoneParamaterSqlValue(List<DbParameter> specialParams, Type type, object value)
 | 
					 | 
				
			||||||
        {
 | 
					 | 
				
			||||||
            if (value == null) return "NULL";
 | 
					 | 
				
			||||||
            value = getParamterValue(type, value);
 | 
					 | 
				
			||||||
            var type2 = value.GetType();
 | 
					 | 
				
			||||||
            if (type2 == typeof(byte[])) return $"'\\x{CommonUtils.BytesSqlRaw(value as byte[])}'";
 | 
					 | 
				
			||||||
            if (type2 == typeof(TimeSpan) || type2 == typeof(TimeSpan?))
 | 
					 | 
				
			||||||
            {
 | 
					 | 
				
			||||||
                var ts = (TimeSpan)value;
 | 
					 | 
				
			||||||
                return $"'{Math.Min(24, (int)Math.Floor(ts.TotalHours))}:{ts.Minutes}:{ts.Seconds}'";
 | 
					 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
            else if (value is Array)
 | 
					 | 
				
			||||||
            {
 | 
					 | 
				
			||||||
                var valueArr = value as Array;
 | 
					 | 
				
			||||||
                var eleType = type2.GetElementType();
 | 
					 | 
				
			||||||
                var len = valueArr.GetLength(0);
 | 
					 | 
				
			||||||
                var sb = new StringBuilder().Append("ARRAY[");
 | 
					 | 
				
			||||||
                for (var a = 0; a < len; a++)
 | 
					 | 
				
			||||||
                {
 | 
					 | 
				
			||||||
                    var item = valueArr.GetValue(a);
 | 
					 | 
				
			||||||
                    if (a > 0) sb.Append(",");
 | 
					 | 
				
			||||||
                    sb.Append(GetNoneParamaterSqlValue(specialParams, eleType, item));
 | 
					 | 
				
			||||||
                }
 | 
					 | 
				
			||||||
                sb.Append("]");
 | 
					 | 
				
			||||||
                var dbinfo = _orm.CodeFirst.GetDbInfo(type);
 | 
					 | 
				
			||||||
                if (dbinfo.HasValue) sb.Append("::").Append(dbinfo.Value.dbtype);
 | 
					 | 
				
			||||||
                return sb.ToString();
 | 
					 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
            else if (dicGetParamterValue.ContainsKey(type2.FullName))
 | 
					 | 
				
			||||||
            {
 | 
					 | 
				
			||||||
                value = string.Concat(value);
 | 
					 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
            return FormatSql("{0}", value, 1);
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
@@ -1,4 +1,5 @@
 | 
				
			|||||||
using FreeSql.Internal;
 | 
					using FreeSql.Internal;
 | 
				
			||||||
 | 
					using FreeSql.Internal.Model;
 | 
				
			||||||
using System;
 | 
					using System;
 | 
				
			||||||
using System.Collections.Generic;
 | 
					using System.Collections.Generic;
 | 
				
			||||||
using System.Data;
 | 
					using System.Data;
 | 
				
			||||||
@@ -16,35 +17,35 @@ namespace FreeSql.Odbc.MySql
 | 
				
			|||||||
        public OdbcMySqlCodeFirst(IFreeSql orm, CommonUtils commonUtils, CommonExpression commonExpression) : base(orm, commonUtils, commonExpression) { }
 | 
					        public OdbcMySqlCodeFirst(IFreeSql orm, CommonUtils commonUtils, CommonExpression commonExpression) : base(orm, commonUtils, commonExpression) { }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        static object _dicCsToDbLock = new object();
 | 
					        static object _dicCsToDbLock = new object();
 | 
				
			||||||
        static Dictionary<string, (OdbcType type, string dbtype, string dbtypeFull, bool? isUnsigned, bool? isnullable, object defaultValue)> _dicCsToDb = new Dictionary<string, (OdbcType type, string dbtype, string dbtypeFull, bool? isUnsigned, bool? isnullable, object defaultValue)>() {
 | 
					        static Dictionary<string, CsToDb<OdbcType>> _dicCsToDb = new Dictionary<string, CsToDb<OdbcType>>() {
 | 
				
			||||||
                { typeof(bool).FullName,  (OdbcType.Bit, "bit","bit(1) NOT NULL", null, false, false) },{ typeof(bool?).FullName,  (OdbcType.Bit, "bit","bit(1)", null, true, null) },
 | 
					                { typeof(bool).FullName, CsToDb.New(OdbcType.Bit, "bit","bit(1) NOT NULL", null, false, false) },{ typeof(bool?).FullName, CsToDb.New(OdbcType.Bit, "bit","bit(1)", null, true, null) },
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                { typeof(sbyte).FullName,  (OdbcType.SmallInt, "tinyint", "tinyint(3) NOT NULL", false, false, 0) },{ typeof(sbyte?).FullName,  (OdbcType.SmallInt, "tinyint", "tinyint(3)", false, true, null) },
 | 
					                { typeof(sbyte).FullName, CsToDb.New(OdbcType.SmallInt, "tinyint", "tinyint(3) NOT NULL", false, false, 0) },{ typeof(sbyte?).FullName, CsToDb.New(OdbcType.SmallInt, "tinyint", "tinyint(3)", false, true, null) },
 | 
				
			||||||
                { typeof(short).FullName,  (OdbcType.SmallInt, "smallint","smallint(6) NOT NULL", false, false, 0) },{ typeof(short?).FullName,  (OdbcType.SmallInt, "smallint", "smallint(6)", false, true, null) },
 | 
					                { typeof(short).FullName, CsToDb.New(OdbcType.SmallInt, "smallint","smallint(6) NOT NULL", false, false, 0) },{ typeof(short?).FullName, CsToDb.New(OdbcType.SmallInt, "smallint", "smallint(6)", false, true, null) },
 | 
				
			||||||
                { typeof(int).FullName,  (OdbcType.Int, "int", "int(11) NOT NULL", false, false, 0) },{ typeof(int?).FullName,  (OdbcType.Int, "int", "int(11)", false, true, null) },
 | 
					                { typeof(int).FullName, CsToDb.New(OdbcType.Int, "int", "int(11) NOT NULL", false, false, 0) },{ typeof(int?).FullName, CsToDb.New(OdbcType.Int, "int", "int(11)", false, true, null) },
 | 
				
			||||||
                { typeof(long).FullName,  (OdbcType.BigInt, "bigint","bigint(20) NOT NULL", false, false, 0) },{ typeof(long?).FullName,  (OdbcType.BigInt, "bigint","bigint(20)", false, true, null) },
 | 
					                { typeof(long).FullName, CsToDb.New(OdbcType.BigInt, "bigint","bigint(20) NOT NULL", false, false, 0) },{ typeof(long?).FullName, CsToDb.New(OdbcType.BigInt, "bigint","bigint(20)", false, true, null) },
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                { typeof(byte).FullName,  (OdbcType.TinyInt, "tinyint","tinyint(3) unsigned NOT NULL", true, false, 0) },{ typeof(byte?).FullName,  (OdbcType.TinyInt, "tinyint","tinyint(3) unsigned", true, true, null) },
 | 
					                { typeof(byte).FullName, CsToDb.New(OdbcType.TinyInt, "tinyint","tinyint(3) unsigned NOT NULL", true, false, 0) },{ typeof(byte?).FullName, CsToDb.New(OdbcType.TinyInt, "tinyint","tinyint(3) unsigned", true, true, null) },
 | 
				
			||||||
                { typeof(ushort).FullName,  (OdbcType.Int, "smallint","smallint(5) unsigned NOT NULL", true, false, 0) },{ typeof(ushort?).FullName,  (OdbcType.Int, "smallint", "smallint(5) unsigned", true, true, null) },
 | 
					                { typeof(ushort).FullName, CsToDb.New(OdbcType.Int, "smallint","smallint(5) unsigned NOT NULL", true, false, 0) },{ typeof(ushort?).FullName, CsToDb.New(OdbcType.Int, "smallint", "smallint(5) unsigned", true, true, null) },
 | 
				
			||||||
                { typeof(uint).FullName,  (OdbcType.BigInt, "int", "int(10) unsigned NOT NULL", true, false, 0) },{ typeof(uint?).FullName,  (OdbcType.BigInt, "int", "int(10) unsigned", true, true, null) },
 | 
					                { typeof(uint).FullName, CsToDb.New(OdbcType.BigInt, "int", "int(10) unsigned NOT NULL", true, false, 0) },{ typeof(uint?).FullName, CsToDb.New(OdbcType.BigInt, "int", "int(10) unsigned", true, true, null) },
 | 
				
			||||||
                { typeof(ulong).FullName,  (OdbcType.Decimal, "bigint", "bigint(20) unsigned NOT NULL", true, false, 0) },{ typeof(ulong?).FullName,  (OdbcType.Decimal, "bigint", "bigint(20) unsigned", true, true, null) },
 | 
					                { typeof(ulong).FullName, CsToDb.New(OdbcType.Decimal, "bigint", "bigint(20) unsigned NOT NULL", true, false, 0) },{ typeof(ulong?).FullName, CsToDb.New(OdbcType.Decimal, "bigint", "bigint(20) unsigned", true, true, null) },
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                { typeof(double).FullName,  (OdbcType.Double, "double", "double NOT NULL", false, false, 0) },{ typeof(double?).FullName,  (OdbcType.Double, "double", "double", false, true, null) },
 | 
					                { typeof(double).FullName, CsToDb.New(OdbcType.Double, "double", "double NOT NULL", false, false, 0) },{ typeof(double?).FullName, CsToDb.New(OdbcType.Double, "double", "double", false, true, null) },
 | 
				
			||||||
                { typeof(float).FullName,  (OdbcType.Real, "float","float NOT NULL", false, false, 0) },{ typeof(float?).FullName,  (OdbcType.Real, "float","float", false, true, null) },
 | 
					                { typeof(float).FullName, CsToDb.New(OdbcType.Real, "float","float NOT NULL", false, false, 0) },{ typeof(float?).FullName, CsToDb.New(OdbcType.Real, "float","float", false, true, null) },
 | 
				
			||||||
                { typeof(decimal).FullName,  (OdbcType.Decimal, "decimal", "decimal(10,2) NOT NULL", false, false, 0) },{ typeof(decimal?).FullName,  (OdbcType.Decimal, "decimal", "decimal(10,2)", false, true, null) },
 | 
					                { typeof(decimal).FullName, CsToDb.New(OdbcType.Decimal, "decimal", "decimal(10,2) NOT NULL", false, false, 0) },{ typeof(decimal?).FullName, CsToDb.New(OdbcType.Decimal, "decimal", "decimal(10,2)", false, true, null) },
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                { typeof(TimeSpan).FullName,  (OdbcType.Time, "time","time NOT NULL", false, false, 0) },{ typeof(TimeSpan?).FullName,  (OdbcType.Time, "time", "time",false, true, null) },
 | 
					                { typeof(TimeSpan).FullName, CsToDb.New(OdbcType.Time, "time","time NOT NULL", false, false, 0) },{ typeof(TimeSpan?).FullName, CsToDb.New(OdbcType.Time, "time", "time",false, true, null) },
 | 
				
			||||||
                { typeof(DateTime).FullName,  (OdbcType.DateTime, "datetime(3)", "datetime(3) NOT NULL", false, false, new DateTime(1970,1,1)) },{ typeof(DateTime?).FullName,  (OdbcType.DateTime, "datetime(3)", "datetime(3)", false, true, null) },
 | 
					                { typeof(DateTime).FullName, CsToDb.New(OdbcType.DateTime, "datetime(3)", "datetime(3) NOT NULL", false, false, new DateTime(1970,1,1)) },{ typeof(DateTime?).FullName, CsToDb.New(OdbcType.DateTime, "datetime(3)", "datetime(3)", false, true, null) },
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                { typeof(byte[]).FullName,  (OdbcType.VarBinary, "varbinary", "varbinary(255)", false, null, new byte[0]) },
 | 
					                { typeof(byte[]).FullName, CsToDb.New(OdbcType.VarBinary, "varbinary", "varbinary(255)", false, null, new byte[0]) },
 | 
				
			||||||
                { typeof(string).FullName,  (OdbcType.VarChar, "varchar", "varchar(255)", false, null, "") },
 | 
					                { typeof(string).FullName, CsToDb.New(OdbcType.VarChar, "varchar", "varchar(255)", false, null, "") },
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                { typeof(Guid).FullName,  (OdbcType.VarChar, "char", "char(36) NOT NULL", false, false, Guid.Empty) },{ typeof(Guid?).FullName,  (OdbcType.VarChar, "char", "char(36)", false, true, null) },
 | 
					                { typeof(Guid).FullName, CsToDb.New(OdbcType.VarChar, "char", "char(36) NOT NULL", false, false, Guid.Empty) },{ typeof(Guid?).FullName, CsToDb.New(OdbcType.VarChar, "char", "char(36)", false, true, null) },
 | 
				
			||||||
            };
 | 
					            };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        public override (int type, string dbtype, string dbtypeFull, bool? isnullable, object defaultValue)? GetDbInfo(Type type)
 | 
					        public override DbInfoResult 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 (_dicCsToDb.TryGetValue(type.FullName, out var trydc)) return new DbInfoResult((int)trydc.type, trydc.dbtype, trydc.dbtypeFull, trydc.isnullable, trydc.defaultValue);
 | 
				
			||||||
            if (type.IsArray) return null;
 | 
					            if (type.IsArray) return null;
 | 
				
			||||||
            var enumType = type.IsEnum ? type : null;
 | 
					            var enumType = type.IsEnum ? type : null;
 | 
				
			||||||
            if (enumType == null && type.IsNullableType())
 | 
					            if (enumType == null && type.IsNullableType())
 | 
				
			||||||
@@ -56,8 +57,8 @@ namespace FreeSql.Odbc.MySql
 | 
				
			|||||||
            {
 | 
					            {
 | 
				
			||||||
                var names = string.Join(",", Enum.GetNames(enumType).Select(a => _commonUtils.FormatSql("{0}", a)));
 | 
					                var names = string.Join(",", Enum.GetNames(enumType).Select(a => _commonUtils.FormatSql("{0}", a)));
 | 
				
			||||||
                var newItem = enumType.GetCustomAttributes(typeof(FlagsAttribute), false).Any() ?
 | 
					                var newItem = enumType.GetCustomAttributes(typeof(FlagsAttribute), false).Any() ?
 | 
				
			||||||
                    (OdbcType.VarChar, "set", $"set({names}){(type.IsEnum ? " NOT NULL" : "")}", false, type.IsEnum ? false : true, Enum.GetValues(enumType).GetValue(0)) :
 | 
					                    CsToDb.New(OdbcType.VarChar, "set", $"set({names}){(type.IsEnum ? " NOT NULL" : "")}", false, type.IsEnum ? false : true, Enum.GetValues(enumType).GetValue(0)) :
 | 
				
			||||||
                    (OdbcType.VarChar, "enum", $"enum({names}){(type.IsEnum ? " NOT NULL" : "")}", false, type.IsEnum ? false : true, Enum.GetValues(enumType).GetValue(0));
 | 
					                    CsToDb.New(OdbcType.VarChar, "enum", $"enum({names}){(type.IsEnum ? " NOT NULL" : "")}", false, type.IsEnum ? false : true, Enum.GetValues(enumType).GetValue(0));
 | 
				
			||||||
                if (_dicCsToDb.ContainsKey(type.FullName) == false)
 | 
					                if (_dicCsToDb.ContainsKey(type.FullName) == false)
 | 
				
			||||||
                {
 | 
					                {
 | 
				
			||||||
                    lock (_dicCsToDbLock)
 | 
					                    lock (_dicCsToDbLock)
 | 
				
			||||||
@@ -66,12 +67,12 @@ namespace FreeSql.Odbc.MySql
 | 
				
			|||||||
                            _dicCsToDb.Add(type.FullName, newItem);
 | 
					                            _dicCsToDb.Add(type.FullName, newItem);
 | 
				
			||||||
                    }
 | 
					                    }
 | 
				
			||||||
                }
 | 
					                }
 | 
				
			||||||
                return ((int)newItem.Item1, newItem.Item2, newItem.Item3, newItem.Item5, newItem.Item6);
 | 
					                return new DbInfoResult((int)newItem.type, newItem.dbtype, newItem.dbtypeFull, newItem.isnullable, newItem.defaultValue);
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
            return null;
 | 
					            return null;
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        protected override string GetComparisonDDLStatements(params (Type entityType, string tableName)[] objects)
 | 
					        protected override string GetComparisonDDLStatements(params TypeAndName[] objects)
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
            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;
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,5 +1,6 @@
 | 
				
			|||||||
using FreeSql.DatabaseModel;
 | 
					using FreeSql.DatabaseModel;
 | 
				
			||||||
using FreeSql.Internal;
 | 
					using FreeSql.Internal;
 | 
				
			||||||
 | 
					using FreeSql.Internal.Model;
 | 
				
			||||||
using System;
 | 
					using System;
 | 
				
			||||||
using System.Collections.Generic;
 | 
					using System.Collections.Generic;
 | 
				
			||||||
using System.Data;
 | 
					using System.Data;
 | 
				
			||||||
@@ -71,31 +72,31 @@ namespace FreeSql.Odbc.MySql
 | 
				
			|||||||
            }
 | 
					            }
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        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, DbToCs> _dicDbToCs = new Dictionary<int, DbToCs>() {
 | 
				
			||||||
                { (int)OdbcType.Bit, ("(bool?)", "{0} == \"1\"", "{0} == true ? \"1\" : \"0\"", "bool?", typeof(bool), typeof(bool?), "{0}.Value", "GetBoolean") },
 | 
					                { (int)OdbcType.Bit, new DbToCs("(bool?)", "{0} == \"1\"", "{0} == true ? \"1\" : \"0\"", "bool?", typeof(bool), typeof(bool?), "{0}.Value", "GetBoolean") },
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                { (int)OdbcType.TinyInt, ("(sbyte?)", "sbyte.Parse({0})", "{0}.ToString()", "sbyte?", typeof(sbyte), typeof(sbyte?), "{0}.Value", "GetByte") },
 | 
					                { (int)OdbcType.TinyInt, new DbToCs("(sbyte?)", "sbyte.Parse({0})", "{0}.ToString()", "sbyte?", typeof(sbyte), typeof(sbyte?), "{0}.Value", "GetByte") },
 | 
				
			||||||
                { (int)OdbcType.SmallInt, ("(short?)", "short.Parse({0})", "{0}.ToString()", "short?", typeof(short), typeof(short?), "{0}.Value", "GetInt16") },
 | 
					                { (int)OdbcType.SmallInt, new DbToCs("(short?)", "short.Parse({0})", "{0}.ToString()", "short?", typeof(short), typeof(short?), "{0}.Value", "GetInt16") },
 | 
				
			||||||
                { (int)OdbcType.Int, ("(int?)", "int.Parse({0})", "{0}.ToString()", "int?", typeof(int), typeof(int?), "{0}.Value", "GetInt32") },
 | 
					                { (int)OdbcType.Int, new DbToCs("(int?)", "int.Parse({0})", "{0}.ToString()", "int?", typeof(int), typeof(int?), "{0}.Value", "GetInt32") },
 | 
				
			||||||
                { (int)OdbcType.BigInt, ("(long?)", "long.Parse({0})", "{0}.ToString()", "long?", typeof(long), typeof(long?), "{0}.Value", "GetInt64") },
 | 
					                { (int)OdbcType.BigInt, new DbToCs("(long?)", "long.Parse({0})", "{0}.ToString()", "long?", typeof(long), typeof(long?), "{0}.Value", "GetInt64") },
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                { (int)OdbcType.Double, ("(double?)", "double.Parse({0})", "{0}.ToString()", "double?", typeof(double), typeof(double?), "{0}.Value", "GetDouble") },
 | 
					                { (int)OdbcType.Double, new DbToCs("(double?)", "double.Parse({0})", "{0}.ToString()", "double?", typeof(double), typeof(double?), "{0}.Value", "GetDouble") },
 | 
				
			||||||
                { (int)OdbcType.Real, ("(float?)", "float.Parse({0})", "{0}.ToString()", "float?", typeof(float), typeof(float?), "{0}.Value", "GetFloat") },
 | 
					                { (int)OdbcType.Real, new DbToCs("(float?)", "float.Parse({0})", "{0}.ToString()", "float?", typeof(float), typeof(float?), "{0}.Value", "GetFloat") },
 | 
				
			||||||
                { (int)OdbcType.Decimal, ("(decimal?)", "decimal.Parse({0})", "{0}.ToString()", "decimal?", typeof(decimal), typeof(decimal?), "{0}.Value", "GetDecimal") },
 | 
					                { (int)OdbcType.Decimal, new DbToCs("(decimal?)", "decimal.Parse({0})", "{0}.ToString()", "decimal?", typeof(decimal), typeof(decimal?), "{0}.Value", "GetDecimal") },
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                { (int)OdbcType.Time, ("(TimeSpan?)", "TimeSpan.Parse(double.Parse({0}))", "{0}.Ticks.ToString()", "TimeSpan?", typeof(TimeSpan), typeof(TimeSpan?), "{0}.Value", "GetValue") },
 | 
					                { (int)OdbcType.Time, new DbToCs("(TimeSpan?)", "TimeSpan.Parse(double.Parse({0}))", "{0}.Ticks.ToString()", "TimeSpan?", typeof(TimeSpan), typeof(TimeSpan?), "{0}.Value", "GetValue") },
 | 
				
			||||||
                { (int)OdbcType.Date, ("(DateTime?)", "new DateTime(long.Parse({0}))", "{0}.Ticks.ToString()", "DateTime?", typeof(DateTime), typeof(DateTime?), "{0}.Value", "GetDateTime") },
 | 
					                { (int)OdbcType.Date, new DbToCs("(DateTime?)", "new DateTime(long.Parse({0}))", "{0}.Ticks.ToString()", "DateTime?", typeof(DateTime), typeof(DateTime?), "{0}.Value", "GetDateTime") },
 | 
				
			||||||
                { (int)OdbcType.Timestamp, ("(DateTime?)", "new DateTime(long.Parse({0}))", "{0}.Ticks.ToString()", "DateTime?", typeof(DateTime), typeof(DateTime?), "{0}.Value", "GetDateTime") },
 | 
					                { (int)OdbcType.Timestamp, new DbToCs("(DateTime?)", "new DateTime(long.Parse({0}))", "{0}.Ticks.ToString()", "DateTime?", typeof(DateTime), typeof(DateTime?), "{0}.Value", "GetDateTime") },
 | 
				
			||||||
                { (int)OdbcType.DateTime, ("(DateTime?)", "new DateTime(long.Parse({0}))", "{0}.Ticks.ToString()", "DateTime?", typeof(DateTime), typeof(DateTime?), "{0}.Value", "GetDateTime") },
 | 
					                { (int)OdbcType.DateTime, new DbToCs("(DateTime?)", "new DateTime(long.Parse({0}))", "{0}.Ticks.ToString()", "DateTime?", typeof(DateTime), typeof(DateTime?), "{0}.Value", "GetDateTime") },
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                { (int)OdbcType.Binary, ("(byte[])", "Convert.FromBase64String({0})", "Convert.ToBase64String({0})", "byte[]", typeof(byte[]), typeof(byte[]), "{0}", "GetValue") },
 | 
					                { (int)OdbcType.Binary, new DbToCs("(byte[])", "Convert.FromBase64String({0})", "Convert.ToBase64String({0})", "byte[]", typeof(byte[]), typeof(byte[]), "{0}", "GetValue") },
 | 
				
			||||||
                { (int)OdbcType.VarBinary, ("(byte[])", "Convert.FromBase64String({0})", "Convert.ToBase64String({0})", "byte[]", typeof(byte[]), typeof(byte[]), "{0}", "GetValue") },
 | 
					                { (int)OdbcType.VarBinary, new DbToCs("(byte[])", "Convert.FromBase64String({0})", "Convert.ToBase64String({0})", "byte[]", typeof(byte[]), typeof(byte[]), "{0}", "GetValue") },
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                { (int)OdbcType.Text, ("", "{0}.Replace(StringifySplit, \"|\")", "{0}.Replace(\"|\", StringifySplit)", "string", typeof(string), typeof(string), "{0}", "GetString") },
 | 
					                { (int)OdbcType.Text, new DbToCs("", "{0}.Replace(StringifySplit, \"|\")", "{0}.Replace(\"|\", StringifySplit)", "string", typeof(string), typeof(string), "{0}", "GetString") },
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                { (int)OdbcType.Char, ("", "{0}.Replace(StringifySplit, \"|\")", "{0}.Replace(\"|\", StringifySplit)", "string", typeof(string), typeof(string), "{0}", "GetString") },
 | 
					                { (int)OdbcType.Char, new DbToCs("", "{0}.Replace(StringifySplit, \"|\")", "{0}.Replace(\"|\", StringifySplit)", "string", typeof(string), typeof(string), "{0}", "GetString") },
 | 
				
			||||||
                { (int)OdbcType.UniqueIdentifier, ("(Guid?)", "Guid.Parse({0})", "{0}.ToString()", "Guid?", typeof(Guid), typeof(Guid?), "{0}", "GetString") },
 | 
					                { (int)OdbcType.UniqueIdentifier, new DbToCs("(Guid?)", "Guid.Parse({0})", "{0}.ToString()", "Guid?", typeof(Guid), typeof(Guid?), "{0}", "GetString") },
 | 
				
			||||||
                { (int)OdbcType.VarChar, ("", "{0}.Replace(StringifySplit, \"|\")", "{0}.Replace(\"|\", StringifySplit)", "string", typeof(string), typeof(string), "{0}", "GetString") },
 | 
					                { (int)OdbcType.VarChar, new DbToCs("", "{0}.Replace(StringifySplit, \"|\")", "{0}.Replace(\"|\", StringifySplit)", "string", typeof(string), typeof(string), "{0}", "GetString") },
 | 
				
			||||||
            };
 | 
					            };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        public string GetCsConvert(DbColumnInfo column) => _dicDbToCs.TryGetValue(column.DbType, out var trydc) ? (column.IsNullable ? trydc.csConvert : trydc.csConvert.Replace("?", "")) : null;
 | 
					        public string GetCsConvert(DbColumnInfo column) => _dicDbToCs.TryGetValue(column.DbType, out var trydc) ? (column.IsNullable ? trydc.csConvert : trydc.csConvert.Replace("?", "")) : null;
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -19,37 +19,37 @@ namespace FreeSql.Odbc.Oracle
 | 
				
			|||||||
        public OdbcOracleCodeFirst(IFreeSql orm, CommonUtils commonUtils, CommonExpression commonExpression) : base(orm, commonUtils, commonExpression) { }
 | 
					        public OdbcOracleCodeFirst(IFreeSql orm, CommonUtils commonUtils, CommonExpression commonExpression) : base(orm, commonUtils, commonExpression) { }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        static object _dicCsToDbLock = new object();
 | 
					        static object _dicCsToDbLock = new object();
 | 
				
			||||||
        static Dictionary<string, (OdbcType type, string dbtype, string dbtypeFull, bool? isUnsigned, bool? isnullable, object defaultValue)> _dicCsToDb = new Dictionary<string, (OdbcType type, string dbtype, string dbtypeFull, bool? isUnsigned, bool? isnullable, object defaultValue)>() {
 | 
					        static Dictionary<string, CsToDb<OdbcType>> _dicCsToDb = new Dictionary<string, CsToDb<OdbcType>>() {
 | 
				
			||||||
                { typeof(bool).FullName,  (OdbcType.Bit, "number","number(1) NOT NULL", null, false, false) },{ typeof(bool?).FullName,  (OdbcType.Bit, "number","number(1) NULL", null, true, null) },
 | 
					                { typeof(bool).FullName, CsToDb.New(OdbcType.Bit, "number","number(1) NOT NULL", null, false, false) },{ typeof(bool?).FullName, CsToDb.New(OdbcType.Bit, "number","number(1) NULL", null, true, null) },
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                { typeof(sbyte).FullName,  (OdbcType.SmallInt, "number", "number(4) NOT NULL", false, false, 0) },{ typeof(sbyte?).FullName,  (OdbcType.SmallInt, "number", "number(4) NULL", false, true, null) },
 | 
					                { typeof(sbyte).FullName, CsToDb.New(OdbcType.SmallInt, "number", "number(4) NOT NULL", false, false, 0) },{ typeof(sbyte?).FullName, CsToDb.New(OdbcType.SmallInt, "number", "number(4) NULL", false, true, null) },
 | 
				
			||||||
                { typeof(short).FullName,  (OdbcType.SmallInt, "number","number(6) NOT NULL", false, false, 0) },{ typeof(short?).FullName,  (OdbcType.SmallInt, "number", "number(6) NULL", false, true, null) },
 | 
					                { typeof(short).FullName, CsToDb.New(OdbcType.SmallInt, "number","number(6) NOT NULL", false, false, 0) },{ typeof(short?).FullName, CsToDb.New(OdbcType.SmallInt, "number", "number(6) NULL", false, true, null) },
 | 
				
			||||||
                { typeof(int).FullName,  (OdbcType.Int, "number", "number(11) NOT NULL", false, false, 0) },{ typeof(int?).FullName,  (OdbcType.Int, "number", "number(11) NULL", false, true, null) },
 | 
					                { typeof(int).FullName, CsToDb.New(OdbcType.Int, "number", "number(11) NOT NULL", false, false, 0) },{ typeof(int?).FullName, CsToDb.New(OdbcType.Int, "number", "number(11) NULL", false, true, null) },
 | 
				
			||||||
                { typeof(long).FullName,  (OdbcType.BigInt, "number","number(21) NOT NULL", false, false, 0) },{ typeof(long?).FullName,  (OdbcType.BigInt, "number","number(21) NULL", false, true, null) },
 | 
					                { typeof(long).FullName, CsToDb.New(OdbcType.BigInt, "number","number(21) NOT NULL", false, false, 0) },{ typeof(long?).FullName, CsToDb.New(OdbcType.BigInt, "number","number(21) NULL", false, true, null) },
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                { typeof(byte).FullName,  (OdbcType.TinyInt, "number","number(3) NOT NULL", true, false, 0) },{ typeof(byte?).FullName,  (OdbcType.TinyInt, "number","number(3) NULL", true, true, null) },
 | 
					                { typeof(byte).FullName, CsToDb.New(OdbcType.TinyInt, "number","number(3) NOT NULL", true, false, 0) },{ typeof(byte?).FullName, CsToDb.New(OdbcType.TinyInt, "number","number(3) NULL", true, true, null) },
 | 
				
			||||||
                { typeof(ushort).FullName,  (OdbcType.Int, "number","number(5) NOT NULL", true, false, 0) },{ typeof(ushort?).FullName,  (OdbcType.Int, "number", "number(5) NULL", true, true, null) },
 | 
					                { typeof(ushort).FullName, CsToDb.New(OdbcType.Int, "number","number(5) NOT NULL", true, false, 0) },{ typeof(ushort?).FullName, CsToDb.New(OdbcType.Int, "number", "number(5) NULL", true, true, null) },
 | 
				
			||||||
                { typeof(uint).FullName,  (OdbcType.BigInt, "number", "number(10) NOT NULL", true, false, 0) },{ typeof(uint?).FullName,  (OdbcType.BigInt, "number", "number(10) NULL", true, true, null) },
 | 
					                { typeof(uint).FullName, CsToDb.New(OdbcType.BigInt, "number", "number(10) NOT NULL", true, false, 0) },{ typeof(uint?).FullName, CsToDb.New(OdbcType.BigInt, "number", "number(10) NULL", true, true, null) },
 | 
				
			||||||
                { typeof(ulong).FullName,  (OdbcType.Decimal, "number", "number(20) NOT NULL", true, false, 0) },{ typeof(ulong?).FullName,  (OdbcType.Decimal, "number", "number(20) NULL", true, true, null) },
 | 
					                { typeof(ulong).FullName, CsToDb.New(OdbcType.Decimal, "number", "number(20) NOT NULL", true, false, 0) },{ typeof(ulong?).FullName, CsToDb.New(OdbcType.Decimal, "number", "number(20) NULL", true, true, null) },
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                { typeof(double).FullName,  (OdbcType.Double, "float", "float(126) NOT NULL", false, false, 0) },{ typeof(double?).FullName,  (OdbcType.Double, "float", "float(126) NULL", false, true, null) },
 | 
					                { typeof(double).FullName, CsToDb.New(OdbcType.Double, "float", "float(126) NOT NULL", false, false, 0) },{ typeof(double?).FullName, CsToDb.New(OdbcType.Double, "float", "float(126) NULL", false, true, null) },
 | 
				
			||||||
                { typeof(float).FullName,  (OdbcType.Real, "float","float(63) NOT NULL", false, false, 0) },{ typeof(float?).FullName,  (OdbcType.Real, "float","float(63) NULL", false, true, null) },
 | 
					                { typeof(float).FullName, CsToDb.New(OdbcType.Real, "float","float(63) NOT NULL", false, false, 0) },{ typeof(float?).FullName, CsToDb.New(OdbcType.Real, "float","float(63) NULL", false, true, null) },
 | 
				
			||||||
                { typeof(decimal).FullName,  (OdbcType.Decimal, "number", "number(10,2) NOT NULL", false, false, 0) },{ typeof(decimal?).FullName,  (OdbcType.Decimal, "number", "number(10,2) NULL", false, true, null) },
 | 
					                { typeof(decimal).FullName, CsToDb.New(OdbcType.Decimal, "number", "number(10,2) NOT NULL", false, false, 0) },{ typeof(decimal?).FullName, CsToDb.New(OdbcType.Decimal, "number", "number(10,2) NULL", false, true, null) },
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                //oracle odbc driver 不支持 TimeSpan 类型的读取
 | 
					                //oracle odbc driver 不支持 TimeSpan 类型的读取
 | 
				
			||||||
                //{ typeof(TimeSpan).FullName,  (OdbcType.Time, "interval day to second","interval day(2) to second(6) NOT NULL", false, false, 0) },{ typeof(TimeSpan?).FullName,  (OdbcType.Time, "interval day to second", "interval day(2) to second(6) NULL",false, true, null) },
 | 
					                //{ typeof(TimeSpan).FullName, CsToDb.NewInfo(OdbcType.Time, "interval day to second","interval day(2) to second(6) NOT NULL", false, false, 0) },{ typeof(TimeSpan?).FullName, CsToDb.NewInfo(OdbcType.Time, "interval day to second", "interval day(2) to second(6) NULL",false, true, null) },
 | 
				
			||||||
                { typeof(DateTime).FullName,  (OdbcType.DateTime, "timestamp", "timestamp(6) NOT NULL", false, false, new DateTime(1970,1,1)) },{ typeof(DateTime?).FullName,  (OdbcType.DateTime, "timestamp", "timestamp(6) NULL", false, true, null) },
 | 
					                { typeof(DateTime).FullName, CsToDb.New(OdbcType.DateTime, "timestamp", "timestamp(6) NOT NULL", false, false, new DateTime(1970,1,1)) },{ typeof(DateTime?).FullName, CsToDb.New(OdbcType.DateTime, "timestamp", "timestamp(6) NULL", false, true, null) },
 | 
				
			||||||
                { typeof(DateTimeOffset).FullName,  (OdbcType.DateTime, "timestamp with local time zone", "timestamp(6) with local time zone NOT NULL", false, false, new DateTime(1970,1,1)) },{ typeof(DateTimeOffset?).FullName,  (OdbcType.DateTime, "timestamp with local time zone", "timestamp(6) with local time zone NULL", false, true, null) },
 | 
					                { typeof(DateTimeOffset).FullName, CsToDb.New(OdbcType.DateTime, "timestamp with local time zone", "timestamp(6) with local time zone NOT NULL", false, false, new DateTime(1970,1,1)) },{ typeof(DateTimeOffset?).FullName, CsToDb.New(OdbcType.DateTime, "timestamp with local time zone", "timestamp(6) with local time zone NULL", false, true, null) },
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                { typeof(byte[]).FullName,  (OdbcType.VarBinary, "blob", "blob NULL", false, null, new byte[0]) },
 | 
					                { typeof(byte[]).FullName, CsToDb.New(OdbcType.VarBinary, "blob", "blob NULL", false, null, new byte[0]) },
 | 
				
			||||||
                { typeof(string).FullName,  (OdbcType.NVarChar, "nvarchar2", "nvarchar2(255) NULL", false, null, "") },
 | 
					                { typeof(string).FullName, CsToDb.New(OdbcType.NVarChar, "nvarchar2", "nvarchar2(255) NULL", false, null, "") },
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                { typeof(Guid).FullName,  (OdbcType.Char, "char", "char(36 CHAR) NOT NULL", false, false, Guid.Empty) },{ typeof(Guid?).FullName,  (OdbcType.Char, "char", "char(36 CHAR) NULL", false, true, null) },
 | 
					                { typeof(Guid).FullName, CsToDb.New(OdbcType.Char, "char", "char(36 CHAR) NOT NULL", false, false, Guid.Empty) },{ typeof(Guid?).FullName, CsToDb.New(OdbcType.Char, "char", "char(36 CHAR) NULL", false, true, null) },
 | 
				
			||||||
            };
 | 
					            };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        public override (int type, string dbtype, string dbtypeFull, bool? isnullable, object defaultValue)? GetDbInfo(Type type)
 | 
					        public override DbInfoResult 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 (_dicCsToDb.TryGetValue(type.FullName, out var trydc)) return new DbInfoResult((int)trydc.type, trydc.dbtype, trydc.dbtypeFull, trydc.isnullable, trydc.defaultValue);
 | 
				
			||||||
            if (type.IsArray) return null;
 | 
					            if (type.IsArray) return null;
 | 
				
			||||||
            var enumType = type.IsEnum ? type : null;
 | 
					            var enumType = type.IsEnum ? type : null;
 | 
				
			||||||
            if (enumType == null && type.IsNullableType())
 | 
					            if (enumType == null && type.IsNullableType())
 | 
				
			||||||
@@ -60,8 +60,8 @@ namespace FreeSql.Odbc.Oracle
 | 
				
			|||||||
            if (enumType != null)
 | 
					            if (enumType != null)
 | 
				
			||||||
            {
 | 
					            {
 | 
				
			||||||
                var newItem = enumType.GetCustomAttributes(typeof(FlagsAttribute), false).Any() ?
 | 
					                var newItem = enumType.GetCustomAttributes(typeof(FlagsAttribute), false).Any() ?
 | 
				
			||||||
                    (OdbcType.Int, "number", $"number(16){(type.IsEnum ? " NOT NULL" : "")}", false, type.IsEnum ? false : true, Enum.GetValues(enumType).GetValue(0)) :
 | 
					                    CsToDb.New(OdbcType.Int, "number", $"number(16){(type.IsEnum ? " NOT NULL" : "")}", false, type.IsEnum ? false : true, Enum.GetValues(enumType).GetValue(0)) :
 | 
				
			||||||
                    (OdbcType.BigInt, "number", $"number(32){(type.IsEnum ? " NOT NULL" : "")}", false, type.IsEnum ? false : true, Enum.GetValues(enumType).GetValue(0));
 | 
					                    CsToDb.New(OdbcType.BigInt, "number", $"number(32){(type.IsEnum ? " NOT NULL" : "")}", false, type.IsEnum ? false : true, Enum.GetValues(enumType).GetValue(0));
 | 
				
			||||||
                if (_dicCsToDb.ContainsKey(type.FullName) == false)
 | 
					                if (_dicCsToDb.ContainsKey(type.FullName) == false)
 | 
				
			||||||
                {
 | 
					                {
 | 
				
			||||||
                    lock (_dicCsToDbLock)
 | 
					                    lock (_dicCsToDbLock)
 | 
				
			||||||
@@ -70,12 +70,12 @@ namespace FreeSql.Odbc.Oracle
 | 
				
			|||||||
                            _dicCsToDb.Add(type.FullName, newItem);
 | 
					                            _dicCsToDb.Add(type.FullName, newItem);
 | 
				
			||||||
                    }
 | 
					                    }
 | 
				
			||||||
                }
 | 
					                }
 | 
				
			||||||
                return ((int)newItem.Item1, newItem.Item2, newItem.Item3, newItem.Item5, newItem.Item6);
 | 
					                return new DbInfoResult((int)newItem.type, newItem.dbtype, newItem.dbtypeFull, newItem.isnullable, newItem.defaultValue);
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
            return null;
 | 
					            return null;
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        protected override string GetComparisonDDLStatements(params (Type entityType, string tableName)[] objects)
 | 
					        protected override string GetComparisonDDLStatements(params TypeAndName[] objects)
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
            var userId = (_orm.Ado.MasterPool as OdbcOracleConnectionPool)?.UserId;
 | 
					            var userId = (_orm.Ado.MasterPool as OdbcOracleConnectionPool)?.UserId;
 | 
				
			||||||
            if (string.IsNullOrEmpty(userId))
 | 
					            if (string.IsNullOrEmpty(userId))
 | 
				
			||||||
@@ -83,7 +83,7 @@ namespace FreeSql.Odbc.Oracle
 | 
				
			|||||||
                {
 | 
					                {
 | 
				
			||||||
                    userId = OdbcOracleConnectionPool.GetUserId(conn.Value.ConnectionString);
 | 
					                    userId = OdbcOracleConnectionPool.GetUserId(conn.Value.ConnectionString);
 | 
				
			||||||
                }
 | 
					                }
 | 
				
			||||||
            var seqcols = new List<(ColumnInfo, string[], bool)>(); //序列:列,表,自增
 | 
					            var seqcols = new List<NaviteTuple<ColumnInfo, string[], bool>>(); //序列:列,表,自增
 | 
				
			||||||
            var seqnameDel = new List<string>(); //要删除的序列+触发器
 | 
					            var seqnameDel = new List<string>(); //要删除的序列+触发器
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            var sb = new StringBuilder();
 | 
					            var sb = new StringBuilder();
 | 
				
			||||||
@@ -134,7 +134,7 @@ namespace FreeSql.Odbc.Oracle
 | 
				
			|||||||
                        foreach (var tbcol in tb.ColumnsByPosition)
 | 
					                        foreach (var tbcol in tb.ColumnsByPosition)
 | 
				
			||||||
                        {
 | 
					                        {
 | 
				
			||||||
                            sb.Append(" \r\n  ").Append(_commonUtils.QuoteSqlName(tbcol.Attribute.Name)).Append(" ").Append(tbcol.Attribute.DbType).Append(",");
 | 
					                            sb.Append(" \r\n  ").Append(_commonUtils.QuoteSqlName(tbcol.Attribute.Name)).Append(" ").Append(tbcol.Attribute.DbType).Append(",");
 | 
				
			||||||
                            if (tbcol.Attribute.IsIdentity == true) seqcols.Add((tbcol, tbname, true));
 | 
					                            if (tbcol.Attribute.IsIdentity == true) seqcols.Add(NaviteTuple.Create(tbcol, tbname, true));
 | 
				
			||||||
                        }
 | 
					                        }
 | 
				
			||||||
                        if (tb.Primarys.Any())
 | 
					                        if (tb.Primarys.Any())
 | 
				
			||||||
                        {
 | 
					                        {
 | 
				
			||||||
@@ -234,10 +234,10 @@ where a.owner={{0}} and a.table_name={{1}}", tboldname ?? tbname);
 | 
				
			|||||||
                                //修改列名
 | 
					                                //修改列名
 | 
				
			||||||
                                sbalter.Append("execute immediate 'ALTER TABLE ").Append(_commonUtils.QuoteSqlName($"{tbname[0]}.{tbname[1]}")).Append(" RENAME COLUMN ").Append(_commonUtils.QuoteSqlName(tbstructcol.column)).Append(" TO ").Append(_commonUtils.QuoteSqlName(tbcol.Attribute.Name)).Append("';\r\n");
 | 
					                                sbalter.Append("execute immediate 'ALTER TABLE ").Append(_commonUtils.QuoteSqlName($"{tbname[0]}.{tbname[1]}")).Append(" RENAME COLUMN ").Append(_commonUtils.QuoteSqlName(tbstructcol.column)).Append(" TO ").Append(_commonUtils.QuoteSqlName(tbcol.Attribute.Name)).Append("';\r\n");
 | 
				
			||||||
                                if (tbcol.Attribute.IsIdentity)
 | 
					                                if (tbcol.Attribute.IsIdentity)
 | 
				
			||||||
                                    seqcols.Add((tbcol, tbname, tbcol.Attribute.IsIdentity == true));
 | 
					                                    seqcols.Add(NaviteTuple.Create(tbcol, tbname, tbcol.Attribute.IsIdentity == true));
 | 
				
			||||||
                            }
 | 
					                            }
 | 
				
			||||||
                            else if (tbcol.Attribute.IsIdentity != tbstructcol.is_identity)
 | 
					                            else if (tbcol.Attribute.IsIdentity != tbstructcol.is_identity)
 | 
				
			||||||
                                seqcols.Add((tbcol, tbname, tbcol.Attribute.IsIdentity == true));
 | 
					                                seqcols.Add(NaviteTuple.Create(tbcol, tbname, tbcol.Attribute.IsIdentity == true));
 | 
				
			||||||
                            if (isCommentChanged)
 | 
					                            if (isCommentChanged)
 | 
				
			||||||
                                sbalter.Append("execute immediate 'COMMENT ON COLUMN ").Append(_commonUtils.QuoteSqlName($"{tbname[0]}.{tbname[1]}.{tbcol.Attribute.Name}")).Append(" IS ").Append(_commonUtils.FormatSql("{0}", tbcol.Comment ?? "").Replace("'", "''")).Append("';\r\n");
 | 
					                                sbalter.Append("execute immediate 'COMMENT ON COLUMN ").Append(_commonUtils.QuoteSqlName($"{tbname[0]}.{tbname[1]}.{tbcol.Attribute.Name}")).Append(" IS ").Append(_commonUtils.FormatSql("{0}", tbcol.Comment ?? "").Replace("'", "''")).Append("';\r\n");
 | 
				
			||||||
                            continue;
 | 
					                            continue;
 | 
				
			||||||
@@ -249,7 +249,7 @@ where a.owner={{0}} and a.table_name={{1}}", tboldname ?? tbname);
 | 
				
			|||||||
                            sbalter.Append("execute immediate 'UPDATE ").Append(_commonUtils.QuoteSqlName($"{tbname[0]}.{tbname[1]}")).Append(" SET ").Append(_commonUtils.QuoteSqlName(tbcol.Attribute.Name)).Append(" = ").Append(tbcol.DbDefaultValue.Replace("'", "''")).Append("';\r\n");
 | 
					                            sbalter.Append("execute immediate 'UPDATE ").Append(_commonUtils.QuoteSqlName($"{tbname[0]}.{tbname[1]}")).Append(" SET ").Append(_commonUtils.QuoteSqlName(tbcol.Attribute.Name)).Append(" = ").Append(tbcol.DbDefaultValue.Replace("'", "''")).Append("';\r\n");
 | 
				
			||||||
                            sbalter.Append("execute immediate 'ALTER TABLE ").Append(_commonUtils.QuoteSqlName($"{tbname[0]}.{tbname[1]}")).Append(" MODIFY ").Append(_commonUtils.QuoteSqlName(tbcol.Attribute.Name)).Append(" NOT NULL';\r\n");
 | 
					                            sbalter.Append("execute immediate 'ALTER TABLE ").Append(_commonUtils.QuoteSqlName($"{tbname[0]}.{tbname[1]}")).Append(" MODIFY ").Append(_commonUtils.QuoteSqlName(tbcol.Attribute.Name)).Append(" NOT NULL';\r\n");
 | 
				
			||||||
                        }
 | 
					                        }
 | 
				
			||||||
                        if (tbcol.Attribute.IsIdentity == true) seqcols.Add((tbcol, tbname, tbcol.Attribute.IsIdentity == true));
 | 
					                        if (tbcol.Attribute.IsIdentity == true) seqcols.Add(NaviteTuple.Create(tbcol, tbname, tbcol.Attribute.IsIdentity == true));
 | 
				
			||||||
                        if (string.IsNullOrEmpty(tbcol.Comment) == false) sbalter.Append("execute immediate 'COMMENT ON COLUMN ").Append(_commonUtils.QuoteSqlName($"{tbname[0]}.{tbname[1]}.{tbcol.Attribute.Name}")).Append(" IS ").Append(_commonUtils.FormatSql("{0}", tbcol.Comment ?? "").Replace("'", "''")).Append("';\r\n");
 | 
					                        if (string.IsNullOrEmpty(tbcol.Comment) == false) sbalter.Append("execute immediate 'COMMENT ON COLUMN ").Append(_commonUtils.QuoteSqlName($"{tbname[0]}.{tbname[1]}.{tbcol.Attribute.Name}")).Append(" IS ").Append(_commonUtils.FormatSql("{0}", tbcol.Comment ?? "").Replace("'", "''")).Append("';\r\n");
 | 
				
			||||||
                    }
 | 
					                    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -305,7 +305,7 @@ and not exists(select 1 from all_constraints where constraint_name = a.index_nam
 | 
				
			|||||||
                foreach (var tbcol in tb.ColumnsByPosition)
 | 
					                foreach (var tbcol in tb.ColumnsByPosition)
 | 
				
			||||||
                {
 | 
					                {
 | 
				
			||||||
                    sb.Append(" \r\n  ").Append(_commonUtils.QuoteSqlName(tbcol.Attribute.Name)).Append(" ").Append(tbcol.Attribute.DbType).Append(",");
 | 
					                    sb.Append(" \r\n  ").Append(_commonUtils.QuoteSqlName(tbcol.Attribute.Name)).Append(" ").Append(tbcol.Attribute.DbType).Append(",");
 | 
				
			||||||
                    if (tbcol.Attribute.IsIdentity == true) seqcols.Add((tbcol, tbname, true));
 | 
					                    if (tbcol.Attribute.IsIdentity == true) seqcols.Add(NaviteTuple.Create(tbcol, tbname, true));
 | 
				
			||||||
                }
 | 
					                }
 | 
				
			||||||
                if (tb.Primarys.Any())
 | 
					                if (tb.Primarys.Any())
 | 
				
			||||||
                {
 | 
					                {
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,5 +1,6 @@
 | 
				
			|||||||
using FreeSql.DatabaseModel;
 | 
					using FreeSql.DatabaseModel;
 | 
				
			||||||
using FreeSql.Internal;
 | 
					using FreeSql.Internal;
 | 
				
			||||||
 | 
					using FreeSql.Internal.Model;
 | 
				
			||||||
using System;
 | 
					using System;
 | 
				
			||||||
using System.Collections.Concurrent;
 | 
					using System.Collections.Concurrent;
 | 
				
			||||||
using System.Collections.Generic;
 | 
					using System.Collections.Generic;
 | 
				
			||||||
@@ -115,35 +116,35 @@ namespace FreeSql.Odbc.Oracle
 | 
				
			|||||||
            throw new NotImplementedException($"未实现 {column.DbTypeTextFull} 类型映射");
 | 
					            throw new NotImplementedException($"未实现 {column.DbTypeTextFull} 类型映射");
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        static ConcurrentDictionary<string, (string csConvert, string csParse, string csStringify, string csType, Type csTypeInfo, Type csNullableTypeInfo, string csTypeValue, string dataReaderMethod)> _dicDbToCs = new ConcurrentDictionary<string, (string csConvert, string csParse, string csStringify, string csType, Type csTypeInfo, Type csNullableTypeInfo, string csTypeValue, string dataReaderMethod)>(StringComparer.CurrentCultureIgnoreCase);
 | 
					        static ConcurrentDictionary<string, DbToCs> _dicDbToCs = new ConcurrentDictionary<string, DbToCs>(StringComparer.CurrentCultureIgnoreCase);
 | 
				
			||||||
        static OdbcOracleDbFirst()
 | 
					        static OdbcOracleDbFirst()
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
            var defaultDbToCs = new Dictionary<string, (string csConvert, string csParse, string csStringify, string csType, Type csTypeInfo, Type csNullableTypeInfo, string csTypeValue, string dataReaderMethod)>() {
 | 
					            var defaultDbToCs = new Dictionary<string, DbToCs>() {
 | 
				
			||||||
                { "number(1)", ("(bool?)", "{0} == \"1\"", "{0} == true ? \"1\" : \"0\"", "bool?", typeof(bool), typeof(bool?), "{0}.Value", "GetBoolean") },
 | 
					                { "number(1)", new DbToCs("(bool?)", "{0} == \"1\"", "{0} == true ? \"1\" : \"0\"", "bool?", typeof(bool), typeof(bool?), "{0}.Value", "GetBoolean") },
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                { "number(4)", ("(sbyte?)", "sbyte.Parse({0})", "{0}.ToString()", "sbyte?", typeof(sbyte), typeof(sbyte?), "{0}.Value", "GetInt16") },
 | 
					                { "number(4)", new DbToCs("(sbyte?)", "sbyte.Parse({0})", "{0}.ToString()", "sbyte?", typeof(sbyte), typeof(sbyte?), "{0}.Value", "GetInt16") },
 | 
				
			||||||
                { "number(6)", ("(short?)", "short.Parse({0})", "{0}.ToString()", "short?", typeof(short), typeof(short?), "{0}.Value", "GetInt16") },
 | 
					                { "number(6)", new DbToCs("(short?)", "short.Parse({0})", "{0}.ToString()", "short?", typeof(short), typeof(short?), "{0}.Value", "GetInt16") },
 | 
				
			||||||
                { "number(11)", ("(int?)", "int.Parse({0})", "{0}.ToString()", "int?", typeof(int), typeof(int?), "{0}.Value", "GetInt32") },
 | 
					                { "number(11)", new DbToCs("(int?)", "int.Parse({0})", "{0}.ToString()", "int?", typeof(int), typeof(int?), "{0}.Value", "GetInt32") },
 | 
				
			||||||
                { "number(21)", ("(long?)", "long.Parse({0})", "{0}.ToString()", "long?", typeof(long), typeof(long?), "{0}.Value", "GetInt64") },
 | 
					                { "number(21)", new DbToCs("(long?)", "long.Parse({0})", "{0}.ToString()", "long?", typeof(long), typeof(long?), "{0}.Value", "GetInt64") },
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                { "number(3)", ("(byte?)", "byte.Parse({0})", "{0}.ToString()", "byte?", typeof(byte), typeof(byte?), "{0}.Value", "GetByte") },
 | 
					                { "number(3)", new DbToCs("(byte?)", "byte.Parse({0})", "{0}.ToString()", "byte?", typeof(byte), typeof(byte?), "{0}.Value", "GetByte") },
 | 
				
			||||||
                { "number(5)", ("(ushort?)", "ushort.Parse({0})", "{0}.ToString()", "ushort?", typeof(ushort), typeof(ushort?), "{0}.Value", "GetInt32") },
 | 
					                { "number(5)", new DbToCs("(ushort?)", "ushort.Parse({0})", "{0}.ToString()", "ushort?", typeof(ushort), typeof(ushort?), "{0}.Value", "GetInt32") },
 | 
				
			||||||
                { "number(10)", ("(uint?)", "uint.Parse({0})", "{0}.ToString()", "uint?", typeof(uint), typeof(uint?), "{0}.Value", "GetInt64") },
 | 
					                { "number(10)", new DbToCs("(uint?)", "uint.Parse({0})", "{0}.ToString()", "uint?", typeof(uint), typeof(uint?), "{0}.Value", "GetInt64") },
 | 
				
			||||||
                { "number(20)", ("(ulong?)", "ulong.Parse({0})", "{0}.ToString()", "ulong?", typeof(ulong), typeof(ulong?), "{0}.Value", "GetDecimal") },
 | 
					                { "number(20)", new DbToCs("(ulong?)", "ulong.Parse({0})", "{0}.ToString()", "ulong?", typeof(ulong), typeof(ulong?), "{0}.Value", "GetDecimal") },
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                { "float(126)", ("(double?)", "double.Parse({0})", "{0}.ToString()", "double?", typeof(double), typeof(double?), "{0}.Value", "GetDouble") },
 | 
					                { "float(126)", new DbToCs("(double?)", "double.Parse({0})", "{0}.ToString()", "double?", typeof(double), typeof(double?), "{0}.Value", "GetDouble") },
 | 
				
			||||||
                { "float(63)", ("(float?)", "float.Parse({0})", "{0}.ToString()", "float?", typeof(float), typeof(float?), "{0}.Value", "GetFloat") },
 | 
					                { "float(63)", new DbToCs("(float?)", "float.Parse({0})", "{0}.ToString()", "float?", typeof(float), typeof(float?), "{0}.Value", "GetFloat") },
 | 
				
			||||||
                { "number(10,2)", ("(decimal?)", "decimal.Parse({0})", "{0}.ToString()", "decimal?", typeof(decimal), typeof(decimal?), "{0}.Value", "GetDecimal") },
 | 
					                { "number(10,2)", new DbToCs("(decimal?)", "decimal.Parse({0})", "{0}.ToString()", "decimal?", typeof(decimal), typeof(decimal?), "{0}.Value", "GetDecimal") },
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                { "interval day(2) to second(6)", ("(TimeSpan?)", "TimeSpan.Parse(double.Parse({0}))", "{0}.Ticks.ToString()", "TimeSpan?", typeof(TimeSpan), typeof(TimeSpan?), "{0}.Value", "GetValue") },
 | 
					                { "interval day(2) to second(6)", new DbToCs("(TimeSpan?)", "TimeSpan.Parse(double.Parse({0}))", "{0}.Ticks.ToString()", "TimeSpan?", typeof(TimeSpan), typeof(TimeSpan?), "{0}.Value", "GetValue") },
 | 
				
			||||||
                { "date(7)", ("(DateTime?)", "new DateTime(long.Parse({0}))", "{0}.Ticks.ToString()", "DateTime?", typeof(DateTime), typeof(DateTime?), "{0}.Value", "GetValue") },
 | 
					                { "date(7)", new DbToCs("(DateTime?)", "new DateTime(long.Parse({0}))", "{0}.Ticks.ToString()", "DateTime?", typeof(DateTime), typeof(DateTime?), "{0}.Value", "GetValue") },
 | 
				
			||||||
                { "timestamp(6)", ("(DateTime?)", "new DateTime(long.Parse({0}))", "{0}.Ticks.ToString()", "DateTime?", typeof(DateTime), typeof(DateTime?), "{0}.Value", "GetValue") },
 | 
					                { "timestamp(6)", new DbToCs("(DateTime?)", "new DateTime(long.Parse({0}))", "{0}.Ticks.ToString()", "DateTime?", typeof(DateTime), typeof(DateTime?), "{0}.Value", "GetValue") },
 | 
				
			||||||
                { "timestamp(6) with local time zone", ("(DateTime?)", "new DateTime(long.Parse({0}))", "{0}.Ticks.ToString()", "DateTime?", typeof(DateTime), typeof(DateTime?), "{0}.Value", "GetValue") },
 | 
					                { "timestamp(6) with local time zone", new DbToCs("(DateTime?)", "new DateTime(long.Parse({0}))", "{0}.Ticks.ToString()", "DateTime?", typeof(DateTime), typeof(DateTime?), "{0}.Value", "GetValue") },
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                { "blob", ("(byte[])", "Convert.FromBase64String({0})", "Convert.ToBase64String({0})", "byte[]", typeof(byte[]), typeof(byte[]), "{0}", "GetValue") },
 | 
					                { "blob", new DbToCs("(byte[])", "Convert.FromBase64String({0})", "Convert.ToBase64String({0})", "byte[]", typeof(byte[]), typeof(byte[]), "{0}", "GetValue") },
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                { "nvarchar2(255)", ("", "{0}.Replace(StringifySplit, \"|\")", "{0}.Replace(\"|\", StringifySplit)", "string", typeof(string), typeof(string), "{0}", "GetString") },
 | 
					                { "nvarchar2(255)", new DbToCs("", "{0}.Replace(StringifySplit, \"|\")", "{0}.Replace(\"|\", StringifySplit)", "string", typeof(string), typeof(string), "{0}", "GetString") },
 | 
				
			||||||
                { "char(36 char)", ("(Guid?)", "Guid.Parse({0})", "{0}.ToString()", "Guid?", typeof(Guid), typeof(Guid?), "{0}.Value", "GetGuid") },
 | 
					                { "char(36 char)", new DbToCs("(Guid?)", "Guid.Parse({0})", "{0}.ToString()", "Guid?", typeof(Guid), typeof(Guid?), "{0}.Value", "GetGuid") },
 | 
				
			||||||
            };
 | 
					            };
 | 
				
			||||||
            foreach (var kv in defaultDbToCs)
 | 
					            foreach (var kv in defaultDbToCs)
 | 
				
			||||||
                _dicDbToCs.TryAdd(kv.Key, kv.Value);
 | 
					                _dicDbToCs.TryAdd(kv.Key, kv.Value);
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -16,44 +16,44 @@ namespace FreeSql.Odbc.PostgreSQL
 | 
				
			|||||||
        public OdbcPostgreSQLCodeFirst(IFreeSql orm, CommonUtils commonUtils, CommonExpression commonExpression) : base(orm, commonUtils, commonExpression) { }
 | 
					        public OdbcPostgreSQLCodeFirst(IFreeSql orm, CommonUtils commonUtils, CommonExpression commonExpression) : base(orm, commonUtils, commonExpression) { }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        static object _dicCsToDbLock = new object();
 | 
					        static object _dicCsToDbLock = new object();
 | 
				
			||||||
        static Dictionary<string, (OdbcType type, string dbtype, string dbtypeFull, bool? isUnsigned, bool? isnullable, object defaultValue)> _dicCsToDb = new Dictionary<string, (OdbcType type, string dbtype, string dbtypeFull, bool? isUnsigned, bool? isnullable, object defaultValue)>() {
 | 
					        static Dictionary<string, CsToDb<OdbcType>> _dicCsToDb = new Dictionary<string, CsToDb<OdbcType>>() {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                { typeof(sbyte).FullName,  (OdbcType.SmallInt, "int2","int2 NOT NULL", false, false, 0) },{ typeof(sbyte?).FullName,  (OdbcType.SmallInt, "int2", "int2", false, true, null) },
 | 
					                { typeof(sbyte).FullName, CsToDb.New(OdbcType.SmallInt, "int2","int2 NOT NULL", false, false, 0) },{ typeof(sbyte?).FullName, CsToDb.New(OdbcType.SmallInt, "int2", "int2", false, true, null) },
 | 
				
			||||||
                { typeof(short).FullName,  (OdbcType.SmallInt, "int2","int2 NOT NULL", false, false, 0) },{ typeof(short?).FullName,  (OdbcType.SmallInt, "int2", "int2", false, true, null) },
 | 
					                { typeof(short).FullName, CsToDb.New(OdbcType.SmallInt, "int2","int2 NOT NULL", false, false, 0) },{ typeof(short?).FullName, CsToDb.New(OdbcType.SmallInt, "int2", "int2", false, true, null) },
 | 
				
			||||||
                { typeof(int).FullName,  (OdbcType.Int, "int4","int4 NOT NULL", false, false, 0) },{ typeof(int?).FullName,  (OdbcType.Int, "int4", "int4", false, true, null) },
 | 
					                { typeof(int).FullName, CsToDb.New(OdbcType.Int, "int4","int4 NOT NULL", false, false, 0) },{ typeof(int?).FullName, CsToDb.New(OdbcType.Int, "int4", "int4", false, true, null) },
 | 
				
			||||||
                { typeof(long).FullName,  (OdbcType.BigInt, "int8","int8 NOT NULL", false, false, 0) },{ typeof(long?).FullName,  (OdbcType.BigInt, "int8", "int8", false, true, null) },
 | 
					                { typeof(long).FullName, CsToDb.New(OdbcType.BigInt, "int8","int8 NOT NULL", false, false, 0) },{ typeof(long?).FullName, CsToDb.New(OdbcType.BigInt, "int8", "int8", false, true, null) },
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                { typeof(byte).FullName,  (OdbcType.SmallInt, "int2","int2 NOT NULL", false, false, 0) },{ typeof(byte?).FullName,  (OdbcType.SmallInt, "int2", "int2", false, true, null) },
 | 
					                { typeof(byte).FullName, CsToDb.New(OdbcType.SmallInt, "int2","int2 NOT NULL", false, false, 0) },{ typeof(byte?).FullName, CsToDb.New(OdbcType.SmallInt, "int2", "int2", false, true, null) },
 | 
				
			||||||
                { typeof(ushort).FullName,  (OdbcType.Int, "int4","int4 NOT NULL", false, false, 0) },{ typeof(ushort?).FullName,  (OdbcType.Int, "int4", "int4", false, true, null) },
 | 
					                { typeof(ushort).FullName, CsToDb.New(OdbcType.Int, "int4","int4 NOT NULL", false, false, 0) },{ typeof(ushort?).FullName, CsToDb.New(OdbcType.Int, "int4", "int4", false, true, null) },
 | 
				
			||||||
                { typeof(uint).FullName,  (OdbcType.BigInt, "int8","int8 NOT NULL", false, false, 0) },{ typeof(uint?).FullName,  (OdbcType.BigInt, "int8", "int8", false, true, null) },
 | 
					                { typeof(uint).FullName, CsToDb.New(OdbcType.BigInt, "int8","int8 NOT NULL", false, false, 0) },{ typeof(uint?).FullName, CsToDb.New(OdbcType.BigInt, "int8", "int8", false, true, null) },
 | 
				
			||||||
                { typeof(ulong).FullName,  (OdbcType.Numeric, "numeric","numeric(20,0) NOT NULL", false, false, 0) },{ typeof(ulong?).FullName,  (OdbcType.Numeric, "numeric", "numeric(20,0)", false, true, null) },
 | 
					                { typeof(ulong).FullName, CsToDb.New(OdbcType.Numeric, "numeric","numeric(20,0) NOT NULL", false, false, 0) },{ typeof(ulong?).FullName, CsToDb.New(OdbcType.Numeric, "numeric", "numeric(20,0)", false, true, null) },
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                { typeof(float).FullName,  (OdbcType.Real, "float4","float4 NOT NULL", false, false, 0) },{ typeof(float?).FullName,  (OdbcType.Real, "float4", "float4", false, true, null) },
 | 
					                { typeof(float).FullName, CsToDb.New(OdbcType.Real, "float4","float4 NOT NULL", false, false, 0) },{ typeof(float?).FullName, CsToDb.New(OdbcType.Real, "float4", "float4", false, true, null) },
 | 
				
			||||||
                { typeof(double).FullName,  (OdbcType.Double, "float8","float8 NOT NULL", false, false, 0) },{ typeof(double?).FullName,  (OdbcType.Double, "float8", "float8", false, true, null) },
 | 
					                { typeof(double).FullName, CsToDb.New(OdbcType.Double, "float8","float8 NOT NULL", false, false, 0) },{ typeof(double?).FullName, CsToDb.New(OdbcType.Double, "float8", "float8", false, true, null) },
 | 
				
			||||||
                { typeof(decimal).FullName,  (OdbcType.Numeric, "numeric", "numeric(10,2) NOT NULL", false, false, 0) },{ typeof(decimal?).FullName,  (OdbcType.Numeric, "numeric", "numeric(10,2)", false, true, null) },
 | 
					                { typeof(decimal).FullName, CsToDb.New(OdbcType.Numeric, "numeric", "numeric(10,2) NOT NULL", false, false, 0) },{ typeof(decimal?).FullName, CsToDb.New(OdbcType.Numeric, "numeric", "numeric(10,2)", false, true, null) },
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                { typeof(string).FullName,  (OdbcType.VarChar, "varchar", "varchar(255)", false, null, "") },
 | 
					                { typeof(string).FullName, CsToDb.New(OdbcType.VarChar, "varchar", "varchar(255)", false, null, "") },
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                { typeof(TimeSpan).FullName,  (OdbcType.Time, "time","time NOT NULL", false, false, 0) },{ typeof(TimeSpan?).FullName,  (OdbcType.Time, "time", "time",false, true, null) },
 | 
					                { typeof(TimeSpan).FullName, CsToDb.New(OdbcType.Time, "time","time NOT NULL", false, false, 0) },{ typeof(TimeSpan?).FullName, CsToDb.New(OdbcType.Time, "time", "time",false, true, null) },
 | 
				
			||||||
                { typeof(DateTime).FullName,  (OdbcType.DateTime, "timestamp", "timestamp NOT NULL", false, false, new DateTime(1970,1,1)) },{ typeof(DateTime?).FullName,  (OdbcType.DateTime, "timestamp", "timestamp", false, true, null) },
 | 
					                { typeof(DateTime).FullName, CsToDb.New(OdbcType.DateTime, "timestamp", "timestamp NOT NULL", false, false, new DateTime(1970,1,1)) },{ typeof(DateTime?).FullName, CsToDb.New(OdbcType.DateTime, "timestamp", "timestamp", false, true, null) },
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                { typeof(bool).FullName,  (OdbcType.Bit, "bool","bool NOT NULL", null, false, false) },{ typeof(bool?).FullName,  (OdbcType.Bit, "bool","bool", null, true, null) },
 | 
					                { typeof(bool).FullName, CsToDb.New(OdbcType.Bit, "bool","bool NOT NULL", null, false, false) },{ typeof(bool?).FullName, CsToDb.New(OdbcType.Bit, "bool","bool", null, true, null) },
 | 
				
			||||||
                { typeof(Byte[]).FullName,  (OdbcType.VarBinary, "bytea", "bytea", false, null, new byte[0]) },
 | 
					                { typeof(Byte[]).FullName, CsToDb.New(OdbcType.VarBinary, "bytea", "bytea", false, null, new byte[0]) },
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                { typeof(Guid).FullName,  (OdbcType.UniqueIdentifier, "uuid", "uuid NOT NULL", false, false, Guid.Empty) },{ typeof(Guid?).FullName,  (OdbcType.UniqueIdentifier, "uuid", "uuid", false, true, null) },
 | 
					                { typeof(Guid).FullName, CsToDb.New(OdbcType.UniqueIdentifier, "uuid", "uuid NOT NULL", false, false, Guid.Empty) },{ typeof(Guid?).FullName, CsToDb.New(OdbcType.UniqueIdentifier, "uuid", "uuid", false, true, null) },
 | 
				
			||||||
            };
 | 
					            };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        public override (int type, string dbtype, string dbtypeFull, bool? isnullable, object defaultValue)? GetDbInfo(Type type)
 | 
					        public override DbInfoResult GetDbInfo(Type type)
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
            var isarray = type.FullName != "System.Byte[]" && type.IsArray;
 | 
					            var isarray = type.FullName != "System.Byte[]" && type.IsArray;
 | 
				
			||||||
            var elementType = isarray ? type.GetElementType() : type;
 | 
					            var elementType = isarray ? type.GetElementType() : type;
 | 
				
			||||||
            var info = GetDbInfoNoneArray(elementType);
 | 
					            var info = GetDbInfoNoneArray(elementType);
 | 
				
			||||||
            if (info == null) return null;
 | 
					            if (info == null) return null;
 | 
				
			||||||
            return ((int)info.Value.type, info.Value.dbtype, info.Value.dbtypeFull, info.Value.isnullable, info.Value.defaultValue);
 | 
					            return new DbInfoResult((int)info.type, info.dbtype, info.dbtypeFull, info.isnullable, info.defaultValue);
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
        (OdbcType type, string dbtype, string dbtypeFull, bool? isnullable, object defaultValue)? GetDbInfoNoneArray(Type type)
 | 
					        CsToDb<OdbcType> GetDbInfoNoneArray(Type type)
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
            if (_dicCsToDb.TryGetValue(type.FullName, out var trydc)) return new (OdbcType, string, string, bool?, object)?((trydc.type, trydc.dbtype, trydc.dbtypeFull, trydc.isnullable, trydc.defaultValue));
 | 
					            if (_dicCsToDb.TryGetValue(type.FullName, out var trydc)) return trydc;
 | 
				
			||||||
            if (type.IsArray) return null;
 | 
					            if (type.IsArray) return null;
 | 
				
			||||||
            var enumType = type.IsEnum ? type : null;
 | 
					            var enumType = type.IsEnum ? type : null;
 | 
				
			||||||
            if (enumType == null && type.IsNullableType())
 | 
					            if (enumType == null && type.IsNullableType())
 | 
				
			||||||
@@ -64,8 +64,8 @@ namespace FreeSql.Odbc.PostgreSQL
 | 
				
			|||||||
            if (enumType != null)
 | 
					            if (enumType != null)
 | 
				
			||||||
            {
 | 
					            {
 | 
				
			||||||
                var newItem = enumType.GetCustomAttributes(typeof(FlagsAttribute), false).Any() ?
 | 
					                var newItem = enumType.GetCustomAttributes(typeof(FlagsAttribute), false).Any() ?
 | 
				
			||||||
                    (OdbcType.Int, "int8", $"int8{(type.IsEnum ? " NOT NULL" : "")}", false, type.IsEnum ? false : true, Enum.GetValues(enumType).GetValue(0)) :
 | 
					                    CsToDb.New(OdbcType.Int, "int8", $"int8{(type.IsEnum ? " NOT NULL" : "")}", false, type.IsEnum ? false : true, Enum.GetValues(enumType).GetValue(0)) :
 | 
				
			||||||
                    (OdbcType.BigInt, "int4", $"int4{(type.IsEnum ? " NOT NULL" : "")}", false, type.IsEnum ? false : true, Enum.GetValues(enumType).GetValue(0));
 | 
					                    CsToDb.New(OdbcType.BigInt, "int4", $"int4{(type.IsEnum ? " NOT NULL" : "")}", false, type.IsEnum ? false : true, Enum.GetValues(enumType).GetValue(0));
 | 
				
			||||||
                if (_dicCsToDb.ContainsKey(type.FullName) == false)
 | 
					                if (_dicCsToDb.ContainsKey(type.FullName) == false)
 | 
				
			||||||
                {
 | 
					                {
 | 
				
			||||||
                    lock (_dicCsToDbLock)
 | 
					                    lock (_dicCsToDbLock)
 | 
				
			||||||
@@ -74,15 +74,15 @@ namespace FreeSql.Odbc.PostgreSQL
 | 
				
			|||||||
                            _dicCsToDb.Add(type.FullName, newItem);
 | 
					                            _dicCsToDb.Add(type.FullName, newItem);
 | 
				
			||||||
                    }
 | 
					                    }
 | 
				
			||||||
                }
 | 
					                }
 | 
				
			||||||
                return (newItem.Item1, newItem.Item2, newItem.Item3, newItem.Item5, newItem.Item6);
 | 
					                return newItem;
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
            return null;
 | 
					            return null;
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        protected override string GetComparisonDDLStatements(params (Type entityType, string tableName)[] objects)
 | 
					        protected override string GetComparisonDDLStatements(params TypeAndName[] objects)
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
            var sb = new StringBuilder();
 | 
					            var sb = new StringBuilder();
 | 
				
			||||||
            var seqcols = new List<(ColumnInfo, string[], bool)>(); //序列
 | 
					            var seqcols = new List<NaviteTuple<ColumnInfo, string[], bool>>(); //序列
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            foreach (var obj in objects)
 | 
					            foreach (var obj in objects)
 | 
				
			||||||
            {
 | 
					            {
 | 
				
			||||||
@@ -128,7 +128,7 @@ namespace FreeSql.Odbc.PostgreSQL
 | 
				
			|||||||
                        foreach (var tbcol in tb.ColumnsByPosition)
 | 
					                        foreach (var tbcol in tb.ColumnsByPosition)
 | 
				
			||||||
                        {
 | 
					                        {
 | 
				
			||||||
                            sb.Append(" \r\n  ").Append(_commonUtils.QuoteSqlName(tbcol.Attribute.Name)).Append(" ").Append(tbcol.Attribute.DbType).Append(",");
 | 
					                            sb.Append(" \r\n  ").Append(_commonUtils.QuoteSqlName(tbcol.Attribute.Name)).Append(" ").Append(tbcol.Attribute.DbType).Append(",");
 | 
				
			||||||
                            if (tbcol.Attribute.IsIdentity == true) seqcols.Add((tbcol, tbname, true));
 | 
					                            if (tbcol.Attribute.IsIdentity == true) seqcols.Add(NaviteTuple.Create(tbcol, tbname, true));
 | 
				
			||||||
                        }
 | 
					                        }
 | 
				
			||||||
                        if (tb.Primarys.Any())
 | 
					                        if (tb.Primarys.Any())
 | 
				
			||||||
                        {
 | 
					                        {
 | 
				
			||||||
@@ -244,7 +244,7 @@ where ns.nspname = {0} and c.relname = {1}", tboldname ?? tbname);
 | 
				
			|||||||
                                }
 | 
					                                }
 | 
				
			||||||
                            }
 | 
					                            }
 | 
				
			||||||
                            if (tbcol.Attribute.IsIdentity != tbstructcol.is_identity)
 | 
					                            if (tbcol.Attribute.IsIdentity != tbstructcol.is_identity)
 | 
				
			||||||
                                seqcols.Add((tbcol, tbname, tbcol.Attribute.IsIdentity == true));
 | 
					                                seqcols.Add(NaviteTuple.Create(tbcol, tbname, tbcol.Attribute.IsIdentity == true));
 | 
				
			||||||
                            if (string.Compare(tbstructcol.column, tbcol.Attribute.OldName, true) == 0)
 | 
					                            if (string.Compare(tbstructcol.column, tbcol.Attribute.OldName, true) == 0)
 | 
				
			||||||
                                //修改列名
 | 
					                                //修改列名
 | 
				
			||||||
                                sbalter.Append("ALTER TABLE ").Append(_commonUtils.QuoteSqlName($"{tbname[0]}.{tbname[1]}")).Append(" RENAME COLUMN ").Append(_commonUtils.QuoteSqlName(tbstructcol.column)).Append(" TO ").Append(_commonUtils.QuoteSqlName(tbcol.Attribute.Name)).Append(";\r\n");
 | 
					                                sbalter.Append("ALTER TABLE ").Append(_commonUtils.QuoteSqlName($"{tbname[0]}.{tbname[1]}")).Append(" RENAME COLUMN ").Append(_commonUtils.QuoteSqlName(tbstructcol.column)).Append(" TO ").Append(_commonUtils.QuoteSqlName(tbcol.Attribute.Name)).Append(";\r\n");
 | 
				
			||||||
@@ -256,7 +256,7 @@ where ns.nspname = {0} and c.relname = {1}", tboldname ?? tbname);
 | 
				
			|||||||
                        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("ALTER TABLE ").Append(_commonUtils.QuoteSqlName($"{tbname[0]}.{tbname[1]}")).Append(" ADD COLUMN ").Append(_commonUtils.QuoteSqlName(tbcol.Attribute.Name)).Append(" ").Append(tbcol.Attribute.DbType.Split(' ').First()).Append(";\r\n");
 | 
				
			||||||
                        sbalter.Append("UPDATE ").Append(_commonUtils.QuoteSqlName($"{tbname[0]}.{tbname[1]}")).Append(" SET ").Append(_commonUtils.QuoteSqlName(tbcol.Attribute.Name)).Append(" = ").Append(tbcol.DbDefaultValue).Append(";\r\n");
 | 
					                        sbalter.Append("UPDATE ").Append(_commonUtils.QuoteSqlName($"{tbname[0]}.{tbname[1]}")).Append(" SET ").Append(_commonUtils.QuoteSqlName(tbcol.Attribute.Name)).Append(" = ").Append(tbcol.DbDefaultValue).Append(";\r\n");
 | 
				
			||||||
                        if (tbcol.Attribute.IsNullable == false) sbalter.Append("ALTER TABLE ").Append(_commonUtils.QuoteSqlName($"{tbname[0]}.{tbname[1]}")).Append(" ALTER COLUMN ").Append(_commonUtils.QuoteSqlName(tbcol.Attribute.Name)).Append(" SET NOT NULL;\r\n");
 | 
					                        if (tbcol.Attribute.IsNullable == false) sbalter.Append("ALTER TABLE ").Append(_commonUtils.QuoteSqlName($"{tbname[0]}.{tbname[1]}")).Append(" ALTER COLUMN ").Append(_commonUtils.QuoteSqlName(tbcol.Attribute.Name)).Append(" SET NOT NULL;\r\n");
 | 
				
			||||||
                        if (tbcol.Attribute.IsIdentity == true) seqcols.Add((tbcol, tbname, tbcol.Attribute.IsIdentity == true));
 | 
					                        if (tbcol.Attribute.IsIdentity == true) seqcols.Add(NaviteTuple.Create(tbcol, tbname, tbcol.Attribute.IsIdentity == true));
 | 
				
			||||||
                        if (string.IsNullOrEmpty(tbcol.Comment) == false) sbalter.Append("COMMENT ON COLUMN ").Append(_commonUtils.QuoteSqlName($"{tbname[0]}.{tbname[1]}.{tbcol.Attribute.Name}")).Append(" IS ").Append(_commonUtils.FormatSql("{0}", tbcol.Comment)).Append(";\r\n");
 | 
					                        if (string.IsNullOrEmpty(tbcol.Comment) == false) sbalter.Append("COMMENT ON COLUMN ").Append(_commonUtils.QuoteSqlName($"{tbname[0]}.{tbname[1]}.{tbcol.Attribute.Name}")).Append(" IS ").Append(_commonUtils.FormatSql("{0}", tbcol.Comment)).Append(";\r\n");
 | 
				
			||||||
                    }
 | 
					                    }
 | 
				
			||||||
                    var dsuksql = _commonUtils.FormatSql(@"
 | 
					                    var dsuksql = _commonUtils.FormatSql(@"
 | 
				
			||||||
@@ -313,7 +313,7 @@ where pg_namespace.nspname={0} and pg_class.relname={1} and pg_constraint.contyp
 | 
				
			|||||||
                foreach (var tbcol in tb.ColumnsByPosition)
 | 
					                foreach (var tbcol in tb.ColumnsByPosition)
 | 
				
			||||||
                {
 | 
					                {
 | 
				
			||||||
                    sb.Append(" \r\n  ").Append(_commonUtils.QuoteSqlName(tbcol.Attribute.Name)).Append(" ").Append(tbcol.Attribute.DbType).Append(",");
 | 
					                    sb.Append(" \r\n  ").Append(_commonUtils.QuoteSqlName(tbcol.Attribute.Name)).Append(" ").Append(tbcol.Attribute.DbType).Append(",");
 | 
				
			||||||
                    if (tbcol.Attribute.IsIdentity == true) seqcols.Add((tbcol, tbname, true));
 | 
					                    if (tbcol.Attribute.IsIdentity == true) seqcols.Add(NaviteTuple.Create(tbcol, tbname, true));
 | 
				
			||||||
                }
 | 
					                }
 | 
				
			||||||
                if (tb.Primarys.Any())
 | 
					                if (tb.Primarys.Any())
 | 
				
			||||||
                {
 | 
					                {
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,5 +1,6 @@
 | 
				
			|||||||
using FreeSql.DatabaseModel;
 | 
					using FreeSql.DatabaseModel;
 | 
				
			||||||
using FreeSql.Internal;
 | 
					using FreeSql.Internal;
 | 
				
			||||||
 | 
					using FreeSql.Internal.Model;
 | 
				
			||||||
using System;
 | 
					using System;
 | 
				
			||||||
using System.Collections.Generic;
 | 
					using System.Collections.Generic;
 | 
				
			||||||
using System.Data;
 | 
					using System.Data;
 | 
				
			||||||
@@ -62,26 +63,26 @@ namespace FreeSql.Odbc.PostgreSQL
 | 
				
			|||||||
            return ret;
 | 
					            return 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, DbToCs> _dicDbToCs = new Dictionary<int, DbToCs>() {
 | 
				
			||||||
                { (int)OdbcType.SmallInt, ("(short?)", "short.Parse({0})", "{0}.ToString()", "short?", typeof(short), typeof(short?), "{0}.Value", "GetInt16") },
 | 
					                { (int)OdbcType.SmallInt, new DbToCs("(short?)", "short.Parse({0})", "{0}.ToString()", "short?", typeof(short), typeof(short?), "{0}.Value", "GetInt16") },
 | 
				
			||||||
                { (int)OdbcType.Int, ("(int?)", "int.Parse({0})", "{0}.ToString()", "int?", typeof(int), typeof(int?), "{0}.Value", "GetInt32") },
 | 
					                { (int)OdbcType.Int, new DbToCs("(int?)", "int.Parse({0})", "{0}.ToString()", "int?", typeof(int), typeof(int?), "{0}.Value", "GetInt32") },
 | 
				
			||||||
                { (int)OdbcType.BigInt, ("(long?)", "long.Parse({0})", "{0}.ToString()", "long?", typeof(long), typeof(long?), "{0}.Value", "GetInt64") },
 | 
					                { (int)OdbcType.BigInt, new DbToCs("(long?)", "long.Parse({0})", "{0}.ToString()", "long?", typeof(long), typeof(long?), "{0}.Value", "GetInt64") },
 | 
				
			||||||
                { (int)OdbcType.Numeric, ("(decimal?)", "decimal.Parse({0})", "{0}.ToString()", "decimal?", typeof(decimal), typeof(decimal?), "{0}.Value", "GetDecimal") },
 | 
					                { (int)OdbcType.Numeric, new DbToCs("(decimal?)", "decimal.Parse({0})", "{0}.ToString()", "decimal?", typeof(decimal), typeof(decimal?), "{0}.Value", "GetDecimal") },
 | 
				
			||||||
                { (int)OdbcType.Real, ("(float?)", "float.Parse({0})", "{0}.ToString()", "float?", typeof(float), typeof(float?), "{0}.Value", "GetFloat") },
 | 
					                { (int)OdbcType.Real, new DbToCs("(float?)", "float.Parse({0})", "{0}.ToString()", "float?", typeof(float), typeof(float?), "{0}.Value", "GetFloat") },
 | 
				
			||||||
                { (int)OdbcType.Double, ("(double?)", "double.Parse({0})", "{0}.ToString()", "double?", typeof(double), typeof(double?), "{0}.Value", "GetDouble") },
 | 
					                { (int)OdbcType.Double, new DbToCs("(double?)", "double.Parse({0})", "{0}.ToString()", "double?", typeof(double), typeof(double?), "{0}.Value", "GetDouble") },
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                { (int)OdbcType.Char, ("", "{0}.Replace(StringifySplit, \"|\")", "{0}.Replace(\"|\", StringifySplit)", "string", typeof(string), typeof(string), "{0}", "GetString") },
 | 
					                { (int)OdbcType.Char, new DbToCs("", "{0}.Replace(StringifySplit, \"|\")", "{0}.Replace(\"|\", StringifySplit)", "string", typeof(string), typeof(string), "{0}", "GetString") },
 | 
				
			||||||
                { (int)OdbcType.VarChar, ("", "{0}.Replace(StringifySplit, \"|\")", "{0}.Replace(\"|\", StringifySplit)", "string", typeof(string), typeof(string), "{0}", "GetString") },
 | 
					                { (int)OdbcType.VarChar, new DbToCs("", "{0}.Replace(StringifySplit, \"|\")", "{0}.Replace(\"|\", StringifySplit)", "string", typeof(string), typeof(string), "{0}", "GetString") },
 | 
				
			||||||
                { (int)OdbcType.Text, ("", "{0}.Replace(StringifySplit, \"|\")", "{0}.Replace(\"|\", StringifySplit)", "string", typeof(string), typeof(string), "{0}", "GetString") },
 | 
					                { (int)OdbcType.Text, new DbToCs("", "{0}.Replace(StringifySplit, \"|\")", "{0}.Replace(\"|\", StringifySplit)", "string", typeof(string), typeof(string), "{0}", "GetString") },
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                { (int)OdbcType.DateTime,  ("(DateTime?)", "new DateTime(long.Parse({0}))", "{0}.Ticks.ToString()", "DateTime?", typeof(DateTime), typeof(DateTime?), "{0}.Value", "GetDateTime") },
 | 
					                { (int)OdbcType.DateTime, new DbToCs("(DateTime?)", "new DateTime(long.Parse({0}))", "{0}.Ticks.ToString()", "DateTime?", typeof(DateTime), typeof(DateTime?), "{0}.Value", "GetDateTime") },
 | 
				
			||||||
                { (int)OdbcType.Date,  ("(DateTime?)", "new DateTime(long.Parse({0}))", "{0}.Ticks.ToString()", "DateTime?", typeof(DateTime), typeof(DateTime?), "{0}.Value", "GetDateTime") },
 | 
					                { (int)OdbcType.Date, new DbToCs("(DateTime?)", "new DateTime(long.Parse({0}))", "{0}.Ticks.ToString()", "DateTime?", typeof(DateTime), typeof(DateTime?), "{0}.Value", "GetDateTime") },
 | 
				
			||||||
                { (int)OdbcType.Time, ("(TimeSpan?)", "TimeSpan.Parse(double.Parse({0}))", "{0}.Ticks.ToString()", "TimeSpan?", typeof(TimeSpan), typeof(TimeSpan?), "{0}.Value", "GetValue") },
 | 
					                { (int)OdbcType.Time, new DbToCs("(TimeSpan?)", "TimeSpan.Parse(double.Parse({0}))", "{0}.Ticks.ToString()", "TimeSpan?", typeof(TimeSpan), typeof(TimeSpan?), "{0}.Value", "GetValue") },
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                { (int)OdbcType.Bit, ("(bool?)", "{0} == \"1\"", "{0} == true ? \"1\" : \"0\"", "bool?", typeof(bool), typeof(bool?), "{0}.Value", "GetBoolean") },
 | 
					                { (int)OdbcType.Bit, new DbToCs("(bool?)", "{0} == \"1\"", "{0} == true ? \"1\" : \"0\"", "bool?", typeof(bool), typeof(bool?), "{0}.Value", "GetBoolean") },
 | 
				
			||||||
                { (int)OdbcType.VarBinary, ("(byte[])", "Convert.FromBase64String({0})", "Convert.ToBase64String({0})", "byte[]", typeof(byte[]), typeof(byte[]), "{0}", "GetValue") },
 | 
					                { (int)OdbcType.VarBinary, new DbToCs("(byte[])", "Convert.FromBase64String({0})", "Convert.ToBase64String({0})", "byte[]", typeof(byte[]), typeof(byte[]), "{0}", "GetValue") },
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                { (int)OdbcType.UniqueIdentifier, ("(Guid?)", "Guid.Parse({0})", "{0}.ToString()", "Guid", typeof(Guid), typeof(Guid?), "{0}", "GetString") },
 | 
					                { (int)OdbcType.UniqueIdentifier, new DbToCs("(Guid?)", "Guid.Parse({0})", "{0}.ToString()", "Guid", typeof(Guid), typeof(Guid?), "{0}", "GetString") },
 | 
				
			||||||
            };
 | 
					            };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        public string GetCsConvert(DbColumnInfo column) => _dicDbToCs.TryGetValue(column.DbType, out var trydc) ? (column.IsNullable ? trydc.csConvert : trydc.csConvert.Replace("?", "")) : null;
 | 
					        public string GetCsConvert(DbColumnInfo column) => _dicDbToCs.TryGetValue(column.DbType, out var trydc) ? (column.IsNullable ? trydc.csConvert : trydc.csConvert.Replace("?", "")) : null;
 | 
				
			||||||
@@ -454,13 +455,18 @@ where {loc8.ToString().Replace("a.table_name", "ns.nspname || '.' || b.relname")
 | 
				
			|||||||
            return tables;
 | 
					            return tables;
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        public class GetEnumsByDatabaseQueryInfo
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            public string name { get; set; }
 | 
				
			||||||
 | 
					            public string label { get; set; }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
        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, _commonUtils.FormatSql(@"
 | 
					            var drs = _orm.Ado.Query<GetEnumsByDatabaseQueryInfo>(CommandType.Text, _commonUtils.FormatSql(@"
 | 
				
			||||||
select
 | 
					select
 | 
				
			||||||
ns.nspname || '.' || a.typname,
 | 
					ns.nspname || '.' || a.typname AS name,
 | 
				
			||||||
b.enumlabel
 | 
					b.enumlabel AS label
 | 
				
			||||||
from pg_type a
 | 
					from pg_type a
 | 
				
			||||||
inner join pg_enum b on b.enumtypid = a.oid
 | 
					inner join pg_enum b on b.enumtypid = a.oid
 | 
				
			||||||
inner join pg_namespace ns on ns.oid = a.typnamespace
 | 
					inner join pg_namespace ns on ns.oid = a.typnamespace
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -147,7 +147,7 @@ namespace FreeSql.Odbc.PostgreSQL
 | 
				
			|||||||
                                if (objExp != null)
 | 
					                                if (objExp != null)
 | 
				
			||||||
                                {
 | 
					                                {
 | 
				
			||||||
                                    var dbinfo = _common._orm.CodeFirst.GetDbInfo(objExp.Type);
 | 
					                                    var dbinfo = _common._orm.CodeFirst.GetDbInfo(objExp.Type);
 | 
				
			||||||
                                    if (dbinfo.HasValue) args1 = $"{args1}::{dbinfo.Value.dbtype}";
 | 
					                                    if (dbinfo != null) args1 = $"{args1}::{dbinfo.dbtype}";
 | 
				
			||||||
                                }
 | 
					                                }
 | 
				
			||||||
                                return $"({left} @> {args1})";
 | 
					                                return $"({left} @> {args1})";
 | 
				
			||||||
                            case "Concat":
 | 
					                            case "Concat":
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -146,7 +146,7 @@ namespace FreeSql.Odbc.PostgreSQL
 | 
				
			|||||||
                }
 | 
					                }
 | 
				
			||||||
                sb.Append("]");
 | 
					                sb.Append("]");
 | 
				
			||||||
                var dbinfo = _orm.CodeFirst.GetDbInfo(type);
 | 
					                var dbinfo = _orm.CodeFirst.GetDbInfo(type);
 | 
				
			||||||
                if (dbinfo.HasValue) sb.Append("::").Append(dbinfo.Value.dbtype);
 | 
					                if (dbinfo != null) sb.Append("::").Append(dbinfo.dbtype);
 | 
				
			||||||
                return sb.ToString();
 | 
					                return sb.ToString();
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
            else if (dicGetParamterValue.ContainsKey(type2.FullName))
 | 
					            else if (dicGetParamterValue.ContainsKey(type2.FullName))
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -16,36 +16,36 @@ namespace FreeSql.Odbc.SqlServer
 | 
				
			|||||||
        public OdbcSqlServerCodeFirst(IFreeSql orm, CommonUtils commonUtils, CommonExpression commonExpression) : base(orm, commonUtils, commonExpression) { }
 | 
					        public OdbcSqlServerCodeFirst(IFreeSql orm, CommonUtils commonUtils, CommonExpression commonExpression) : base(orm, commonUtils, commonExpression) { }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        static object _dicCsToDbLock = new object();
 | 
					        static object _dicCsToDbLock = new object();
 | 
				
			||||||
        static Dictionary<string, (OdbcType type, string dbtype, string dbtypeFull, bool? isUnsigned, bool? isnullable, object defaultValue)> _dicCsToDb = new Dictionary<string, (OdbcType type, string dbtype, string dbtypeFull, bool? isUnsigned, bool? isnullable, object defaultValue)>() {
 | 
					        static Dictionary<string, CsToDb<OdbcType>> _dicCsToDb = new Dictionary<string, CsToDb<OdbcType>>() {
 | 
				
			||||||
                { typeof(bool).FullName,  (OdbcType.Bit, "bit","bit NOT NULL", null, false, false) },{ typeof(bool?).FullName,  (OdbcType.Bit, "bit","bit", null, true, null) },
 | 
					                { typeof(bool).FullName, CsToDb.New(OdbcType.Bit, "bit","bit NOT NULL", null, false, false) },{ typeof(bool?).FullName, CsToDb.New(OdbcType.Bit, "bit","bit", null, true, null) },
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                { typeof(sbyte).FullName,  (OdbcType.SmallInt, "smallint", "smallint NOT NULL", false, false, 0) },{ typeof(sbyte?).FullName,  (OdbcType.SmallInt, "smallint", "smallint", false, true, null) },
 | 
					                { typeof(sbyte).FullName, CsToDb.New(OdbcType.SmallInt, "smallint", "smallint NOT NULL", false, false, 0) },{ typeof(sbyte?).FullName, CsToDb.New(OdbcType.SmallInt, "smallint", "smallint", false, true, null) },
 | 
				
			||||||
                { typeof(short).FullName,  (OdbcType.SmallInt, "smallint","smallint NOT NULL", false, false, 0) },{ typeof(short?).FullName,  (OdbcType.SmallInt, "smallint", "smallint", false, true, null) },
 | 
					                { typeof(short).FullName, CsToDb.New(OdbcType.SmallInt, "smallint","smallint NOT NULL", false, false, 0) },{ typeof(short?).FullName, CsToDb.New(OdbcType.SmallInt, "smallint", "smallint", false, true, null) },
 | 
				
			||||||
                { typeof(int).FullName,  (OdbcType.Int, "int", "int NOT NULL", false, false, 0) },{ typeof(int?).FullName,  (OdbcType.Int, "int", "int", false, true, null) },
 | 
					                { typeof(int).FullName, CsToDb.New(OdbcType.Int, "int", "int NOT NULL", false, false, 0) },{ typeof(int?).FullName, CsToDb.New(OdbcType.Int, "int", "int", false, true, null) },
 | 
				
			||||||
                { typeof(long).FullName,  (OdbcType.BigInt, "bigint","bigint NOT NULL", false, false, 0) },{ typeof(long?).FullName,  (OdbcType.BigInt, "bigint","bigint", false, true, null) },
 | 
					                { typeof(long).FullName, CsToDb.New(OdbcType.BigInt, "bigint","bigint NOT NULL", false, false, 0) },{ typeof(long?).FullName, CsToDb.New(OdbcType.BigInt, "bigint","bigint", false, true, null) },
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                { typeof(byte).FullName,  (OdbcType.TinyInt, "tinyint","tinyint NOT NULL", true, false, 0) },{ typeof(byte?).FullName,  (OdbcType.TinyInt, "tinyint","tinyint", true, true, null) },
 | 
					                { typeof(byte).FullName, CsToDb.New(OdbcType.TinyInt, "tinyint","tinyint NOT NULL", true, false, 0) },{ typeof(byte?).FullName, CsToDb.New(OdbcType.TinyInt, "tinyint","tinyint", true, true, null) },
 | 
				
			||||||
                { typeof(ushort).FullName,  (OdbcType.Int, "int","int NOT NULL", true, false, 0) },{ typeof(ushort?).FullName,  (OdbcType.Int, "int", "int", true, true, null) },
 | 
					                { typeof(ushort).FullName, CsToDb.New(OdbcType.Int, "int","int NOT NULL", true, false, 0) },{ typeof(ushort?).FullName, CsToDb.New(OdbcType.Int, "int", "int", true, true, null) },
 | 
				
			||||||
                { typeof(uint).FullName,  (OdbcType.BigInt, "bigint", "bigint NOT NULL", true, false, 0) },{ typeof(uint?).FullName,  (OdbcType.BigInt, "bigint", "bigint", true, true, null) },
 | 
					                { typeof(uint).FullName, CsToDb.New(OdbcType.BigInt, "bigint", "bigint NOT NULL", true, false, 0) },{ typeof(uint?).FullName, CsToDb.New(OdbcType.BigInt, "bigint", "bigint", true, true, null) },
 | 
				
			||||||
                { typeof(ulong).FullName,  (OdbcType.Decimal, "decimal", "decimal(20,0) NOT NULL", true, false, 0) },{ typeof(ulong?).FullName,  (OdbcType.Decimal, "decimal", "decimal(20,0)", true, true, null) },
 | 
					                { typeof(ulong).FullName, CsToDb.New(OdbcType.Decimal, "decimal", "decimal(20,0) NOT NULL", true, false, 0) },{ typeof(ulong?).FullName, CsToDb.New(OdbcType.Decimal, "decimal", "decimal(20,0)", true, true, null) },
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                { typeof(double).FullName,  (OdbcType.Double, "float", "float NOT NULL", false, false, 0) },{ typeof(double?).FullName,  (OdbcType.Double, "float", "float", false, true, null) },
 | 
					                { typeof(double).FullName, CsToDb.New(OdbcType.Double, "float", "float NOT NULL", false, false, 0) },{ typeof(double?).FullName, CsToDb.New(OdbcType.Double, "float", "float", false, true, null) },
 | 
				
			||||||
                { typeof(float).FullName,  (OdbcType.Real, "real","real NOT NULL", false, false, 0) },{ typeof(float?).FullName,  (OdbcType.Real, "real","real", false, true, null) },
 | 
					                { typeof(float).FullName, CsToDb.New(OdbcType.Real, "real","real NOT NULL", false, false, 0) },{ typeof(float?).FullName, CsToDb.New(OdbcType.Real, "real","real", false, true, null) },
 | 
				
			||||||
                { typeof(decimal).FullName,  (OdbcType.Decimal, "decimal", "decimal(10,2) NOT NULL", false, false, 0) },{ typeof(decimal?).FullName,  (OdbcType.Decimal, "decimal", "decimal(10,2)", false, true, null) },
 | 
					                { typeof(decimal).FullName, CsToDb.New(OdbcType.Decimal, "decimal", "decimal(10,2) NOT NULL", false, false, 0) },{ typeof(decimal?).FullName, CsToDb.New(OdbcType.Decimal, "decimal", "decimal(10,2)", false, true, null) },
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                { typeof(TimeSpan).FullName,  (OdbcType.Time, "time","time NOT NULL", false, false, 0) },{ typeof(TimeSpan?).FullName,  (OdbcType.Time, "time", "time",false, true, null) },
 | 
					                { typeof(TimeSpan).FullName, CsToDb.New(OdbcType.Time, "time","time NOT NULL", false, false, 0) },{ typeof(TimeSpan?).FullName, CsToDb.New(OdbcType.Time, "time", "time",false, true, null) },
 | 
				
			||||||
                { typeof(DateTime).FullName,  (OdbcType.DateTime, "datetime", "datetime NOT NULL", false, false, new DateTime(1970,1,1)) },{ typeof(DateTime?).FullName,  (OdbcType.DateTime, "datetime", "datetime", false, true, null) },
 | 
					                { typeof(DateTime).FullName, CsToDb.New(OdbcType.DateTime, "datetime", "datetime NOT NULL", false, false, new DateTime(1970,1,1)) },{ typeof(DateTime?).FullName, CsToDb.New(OdbcType.DateTime, "datetime", "datetime", false, true, null) },
 | 
				
			||||||
                { typeof(DateTimeOffset).FullName,  (OdbcType.DateTime, "datetimeoffset", "datetimeoffset NOT NULL", false, false, new DateTimeOffset(new DateTime(1970,1,1), TimeSpan.Zero)) },{ typeof(DateTimeOffset?).FullName,  (OdbcType.DateTime, "datetimeoffset", "datetimeoffset", false, true, null) },
 | 
					                { typeof(DateTimeOffset).FullName, CsToDb.New(OdbcType.DateTime, "datetimeoffset", "datetimeoffset NOT NULL", false, false, new DateTimeOffset(new DateTime(1970,1,1), TimeSpan.Zero)) },{ typeof(DateTimeOffset?).FullName, CsToDb.New(OdbcType.DateTime, "datetimeoffset", "datetimeoffset", false, true, null) },
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                { typeof(byte[]).FullName,  (OdbcType.VarBinary, "varbinary", "varbinary(255)", false, null, new byte[0]) },
 | 
					                { typeof(byte[]).FullName, CsToDb.New(OdbcType.VarBinary, "varbinary", "varbinary(255)", false, null, new byte[0]) },
 | 
				
			||||||
                { typeof(string).FullName,  (OdbcType.NVarChar, "nvarchar", "nvarchar(255)", false, null, "") },
 | 
					                { typeof(string).FullName, CsToDb.New(OdbcType.NVarChar, "nvarchar", "nvarchar(255)", false, null, "") },
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                { typeof(Guid).FullName,  (OdbcType.UniqueIdentifier, "uniqueidentifier", "uniqueidentifier NOT NULL", false, false, Guid.Empty) },{ typeof(Guid?).FullName,  (OdbcType.UniqueIdentifier, "uniqueidentifier", "uniqueidentifier", false, true, null) },
 | 
					                { typeof(Guid).FullName, CsToDb.New(OdbcType.UniqueIdentifier, "uniqueidentifier", "uniqueidentifier NOT NULL", false, false, Guid.Empty) },{ typeof(Guid?).FullName, CsToDb.New(OdbcType.UniqueIdentifier, "uniqueidentifier", "uniqueidentifier", false, true, null) },
 | 
				
			||||||
            };
 | 
					            };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        public override (int type, string dbtype, string dbtypeFull, bool? isnullable, object defaultValue)? GetDbInfo(Type type)
 | 
					        public override DbInfoResult 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 (_dicCsToDb.TryGetValue(type.FullName, out var trydc)) return new DbInfoResult((int)trydc.type, trydc.dbtype, trydc.dbtypeFull, trydc.isnullable, trydc.defaultValue);
 | 
				
			||||||
            if (type.IsArray) return null;
 | 
					            if (type.IsArray) return null;
 | 
				
			||||||
            var enumType = type.IsEnum ? type : null;
 | 
					            var enumType = type.IsEnum ? type : null;
 | 
				
			||||||
            if (enumType == null && type.IsNullableType())
 | 
					            if (enumType == null && type.IsNullableType())
 | 
				
			||||||
@@ -56,8 +56,8 @@ namespace FreeSql.Odbc.SqlServer
 | 
				
			|||||||
            if (enumType != null)
 | 
					            if (enumType != null)
 | 
				
			||||||
            {
 | 
					            {
 | 
				
			||||||
                var newItem = enumType.GetCustomAttributes(typeof(FlagsAttribute), false).Any() ?
 | 
					                var newItem = enumType.GetCustomAttributes(typeof(FlagsAttribute), false).Any() ?
 | 
				
			||||||
                    (OdbcType.BigInt, "bigint", $"bigint{(type.IsEnum ? " NOT NULL" : "")}", false, type.IsEnum ? false : true, Enum.GetValues(enumType).GetValue(0)) :
 | 
					                    CsToDb.New(OdbcType.BigInt, "bigint", $"bigint{(type.IsEnum ? " NOT NULL" : "")}", false, type.IsEnum ? false : true, Enum.GetValues(enumType).GetValue(0)) :
 | 
				
			||||||
                    (OdbcType.Int, "int", $"int{(type.IsEnum ? " NOT NULL" : "")}", false, type.IsEnum ? false : true, Enum.GetValues(enumType).GetValue(0));
 | 
					                    CsToDb.New(OdbcType.Int, "int", $"int{(type.IsEnum ? " NOT NULL" : "")}", false, type.IsEnum ? false : true, Enum.GetValues(enumType).GetValue(0));
 | 
				
			||||||
                if (_dicCsToDb.ContainsKey(type.FullName) == false)
 | 
					                if (_dicCsToDb.ContainsKey(type.FullName) == false)
 | 
				
			||||||
                {
 | 
					                {
 | 
				
			||||||
                    lock (_dicCsToDbLock)
 | 
					                    lock (_dicCsToDbLock)
 | 
				
			||||||
@@ -66,7 +66,7 @@ namespace FreeSql.Odbc.SqlServer
 | 
				
			|||||||
                            _dicCsToDb.Add(type.FullName, newItem);
 | 
					                            _dicCsToDb.Add(type.FullName, newItem);
 | 
				
			||||||
                    }
 | 
					                    }
 | 
				
			||||||
                }
 | 
					                }
 | 
				
			||||||
                return ((int)newItem.Item1, newItem.Item2, newItem.Item3, newItem.Item5, newItem.Item6);
 | 
					                return new DbInfoResult((int)newItem.type, newItem.dbtype, newItem.dbtypeFull, newItem.isnullable, newItem.defaultValue);
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
            return null;
 | 
					            return null;
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
@@ -103,7 +103,7 @@ ELSE
 | 
				
			|||||||
    , @level2type = 'COLUMN', @level2name = N'{2}'
 | 
					    , @level2type = 'COLUMN', @level2name = N'{2}'
 | 
				
			||||||
", schema.Replace("'", "''"), table.Replace("'", "''"), column.Replace("'", "''"), comment?.Replace("'", "''") ?? "");
 | 
					", schema.Replace("'", "''"), table.Replace("'", "''"), column.Replace("'", "''"), comment?.Replace("'", "''") ?? "");
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
        protected override string GetComparisonDDLStatements(params (Type entityType, string tableName)[] objects)
 | 
					        protected override string GetComparisonDDLStatements(params TypeAndName[] objects)
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
            var conn = _orm.Ado.MasterPool.Get(TimeSpan.FromSeconds(5));
 | 
					            var conn = _orm.Ado.MasterPool.Get(TimeSpan.FromSeconds(5));
 | 
				
			||||||
            string database = null;
 | 
					            string database = null;
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,5 +1,6 @@
 | 
				
			|||||||
using FreeSql.DatabaseModel;
 | 
					using FreeSql.DatabaseModel;
 | 
				
			||||||
using FreeSql.Internal;
 | 
					using FreeSql.Internal;
 | 
				
			||||||
 | 
					using FreeSql.Internal.Model;
 | 
				
			||||||
using System;
 | 
					using System;
 | 
				
			||||||
using System.Collections.Generic;
 | 
					using System.Collections.Generic;
 | 
				
			||||||
using System.Data;
 | 
					using System.Data;
 | 
				
			||||||
@@ -59,36 +60,36 @@ namespace FreeSql.Odbc.SqlServer
 | 
				
			|||||||
            }
 | 
					            }
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        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, DbToCs> _dicDbToCs = new Dictionary<int, DbToCs>() {
 | 
				
			||||||
                { (int)OdbcType.Bit, ("(bool?)", "{0} == \"1\"", "{0} == true ? \"1\" : \"0\"", "bool?", typeof(bool), typeof(bool?), "{0}.Value", "GetBoolean") },
 | 
					                { (int)OdbcType.Bit, new DbToCs("(bool?)", "{0} == \"1\"", "{0} == true ? \"1\" : \"0\"", "bool?", typeof(bool), typeof(bool?), "{0}.Value", "GetBoolean") },
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                { (int)OdbcType.TinyInt, ("(byte?)", "byte.Parse({0})", "{0}.ToString()", "byte?", typeof(byte), typeof(byte?), "{0}.Value", "GetByte") },
 | 
					                { (int)OdbcType.TinyInt, new DbToCs("(byte?)", "byte.Parse({0})", "{0}.ToString()", "byte?", typeof(byte), typeof(byte?), "{0}.Value", "GetByte") },
 | 
				
			||||||
                { (int)OdbcType.SmallInt, ("(short?)", "short.Parse({0})", "{0}.ToString()", "short?", typeof(short), typeof(short?), "{0}.Value", "GetInt16") },
 | 
					                { (int)OdbcType.SmallInt, new DbToCs("(short?)", "short.Parse({0})", "{0}.ToString()", "short?", typeof(short), typeof(short?), "{0}.Value", "GetInt16") },
 | 
				
			||||||
                { (int)OdbcType.Int, ("(int?)", "int.Parse({0})", "{0}.ToString()", "int?", typeof(int), typeof(int?), "{0}.Value", "GetInt32") },
 | 
					                { (int)OdbcType.Int, new DbToCs("(int?)", "int.Parse({0})", "{0}.ToString()", "int?", typeof(int), typeof(int?), "{0}.Value", "GetInt32") },
 | 
				
			||||||
                { (int)OdbcType.BigInt, ("(long?)", "long.Parse({0})", "{0}.ToString()", "long?", typeof(long), typeof(long?), "{0}.Value", "GetInt64") },
 | 
					                { (int)OdbcType.BigInt, new DbToCs("(long?)", "long.Parse({0})", "{0}.ToString()", "long?", typeof(long), typeof(long?), "{0}.Value", "GetInt64") },
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                { (int)OdbcType.Decimal, ("(decimal?)", "decimal.Parse({0})", "{0}.ToString()", "decimal?", typeof(decimal), typeof(decimal?), "{0}.Value", "GetDecimal") },
 | 
					                { (int)OdbcType.Decimal, new DbToCs("(decimal?)", "decimal.Parse({0})", "{0}.ToString()", "decimal?", typeof(decimal), typeof(decimal?), "{0}.Value", "GetDecimal") },
 | 
				
			||||||
                { (int)OdbcType.Double, ("(double?)", "double.Parse({0})", "{0}.ToString()", "double?", typeof(double), typeof(double?), "{0}.Value", "GetDouble") },
 | 
					                { (int)OdbcType.Double, new DbToCs("(double?)", "double.Parse({0})", "{0}.ToString()", "double?", typeof(double), typeof(double?), "{0}.Value", "GetDouble") },
 | 
				
			||||||
                { (int)OdbcType.Real, ("(float?)", "float.Parse({0})", "{0}.ToString()", "float?", typeof(float), typeof(float?), "{0}.Value", "GetFloat") },
 | 
					                { (int)OdbcType.Real, new DbToCs("(float?)", "float.Parse({0})", "{0}.ToString()", "float?", typeof(float), typeof(float?), "{0}.Value", "GetFloat") },
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                { (int)OdbcType.Time, ("(TimeSpan?)", "TimeSpan.Parse(double.Parse({0}))", "{0}.Ticks.ToString()", "TimeSpan?", typeof(TimeSpan), typeof(TimeSpan?), "{0}.Value", "GetValue") },
 | 
					                { (int)OdbcType.Time, new DbToCs("(TimeSpan?)", "TimeSpan.Parse(double.Parse({0}))", "{0}.Ticks.ToString()", "TimeSpan?", typeof(TimeSpan), typeof(TimeSpan?), "{0}.Value", "GetValue") },
 | 
				
			||||||
                { (int)OdbcType.Date, ("(DateTime?)", "new DateTime(long.Parse({0}))", "{0}.Ticks.ToString()", "DateTime?", typeof(DateTime), typeof(DateTime?), "{0}.Value", "GetDateTime") },
 | 
					                { (int)OdbcType.Date, new DbToCs("(DateTime?)", "new DateTime(long.Parse({0}))", "{0}.Ticks.ToString()", "DateTime?", typeof(DateTime), typeof(DateTime?), "{0}.Value", "GetDateTime") },
 | 
				
			||||||
                { (int)OdbcType.DateTime, ("(DateTime?)", "new DateTime(long.Parse({0}))", "{0}.Ticks.ToString()", "DateTime?", typeof(DateTime), typeof(DateTime?), "{0}.Value", "GetDateTime") },
 | 
					                { (int)OdbcType.DateTime, new DbToCs("(DateTime?)", "new DateTime(long.Parse({0}))", "{0}.Ticks.ToString()", "DateTime?", typeof(DateTime), typeof(DateTime?), "{0}.Value", "GetDateTime") },
 | 
				
			||||||
                { (int)OdbcType.SmallDateTime, ("(DateTime?)", "new DateTime(long.Parse({0}))", "{0}.Ticks.ToString()", "DateTime?", typeof(DateTime), typeof(DateTime?), "{0}.Value", "GetDateTime") },
 | 
					                { (int)OdbcType.SmallDateTime, new DbToCs("(DateTime?)", "new DateTime(long.Parse({0}))", "{0}.Ticks.ToString()", "DateTime?", typeof(DateTime), typeof(DateTime?), "{0}.Value", "GetDateTime") },
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                { (int)OdbcType.Binary, ("(byte[])", "Convert.FromBase64String({0})", "Convert.ToBase64String({0})", "byte[]", typeof(byte[]), typeof(byte[]), "{0}", "GetValue") },
 | 
					                { (int)OdbcType.Binary, new DbToCs("(byte[])", "Convert.FromBase64String({0})", "Convert.ToBase64String({0})", "byte[]", typeof(byte[]), typeof(byte[]), "{0}", "GetValue") },
 | 
				
			||||||
                { (int)OdbcType.VarBinary, ("(byte[])", "Convert.FromBase64String({0})", "Convert.ToBase64String({0})", "byte[]", typeof(byte[]), typeof(byte[]), "{0}", "GetValue") },
 | 
					                { (int)OdbcType.VarBinary, new DbToCs("(byte[])", "Convert.FromBase64String({0})", "Convert.ToBase64String({0})", "byte[]", typeof(byte[]), typeof(byte[]), "{0}", "GetValue") },
 | 
				
			||||||
                { (int)OdbcType.Image, ("(byte[])", "Convert.FromBase64String({0})", "Convert.ToBase64String({0})", "byte[]", typeof(byte[]), typeof(byte[]), "{0}", "GetValue") },
 | 
					                { (int)OdbcType.Image, new DbToCs("(byte[])", "Convert.FromBase64String({0})", "Convert.ToBase64String({0})", "byte[]", typeof(byte[]), typeof(byte[]), "{0}", "GetValue") },
 | 
				
			||||||
                { (int)OdbcType.Timestamp, ("(byte[])", "Convert.FromBase64String({0})", "Convert.ToBase64String({0})", "byte[]", typeof(byte[]), typeof(byte[]), "{0}", "GetValue") },
 | 
					                { (int)OdbcType.Timestamp, new DbToCs("(byte[])", "Convert.FromBase64String({0})", "Convert.ToBase64String({0})", "byte[]", typeof(byte[]), typeof(byte[]), "{0}", "GetValue") },
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                { (int)OdbcType.Char, ("", "{0}.Replace(StringifySplit, \"|\")", "{0}.Replace(\"|\", StringifySplit)", "string", typeof(string), typeof(string), "{0}", "GetString") },
 | 
					                { (int)OdbcType.Char, new DbToCs("", "{0}.Replace(StringifySplit, \"|\")", "{0}.Replace(\"|\", StringifySplit)", "string", typeof(string), typeof(string), "{0}", "GetString") },
 | 
				
			||||||
                { (int)OdbcType.VarChar, ("", "{0}.Replace(StringifySplit, \"|\")", "{0}.Replace(\"|\", StringifySplit)", "string", typeof(string), typeof(string), "{0}", "GetString") },
 | 
					                { (int)OdbcType.VarChar, new DbToCs("", "{0}.Replace(StringifySplit, \"|\")", "{0}.Replace(\"|\", StringifySplit)", "string", typeof(string), typeof(string), "{0}", "GetString") },
 | 
				
			||||||
                { (int)OdbcType.Text, ("", "{0}.Replace(StringifySplit, \"|\")", "{0}.Replace(\"|\", StringifySplit)", "string", typeof(string), typeof(string), "{0}", "GetString") },
 | 
					                { (int)OdbcType.Text, new DbToCs("", "{0}.Replace(StringifySplit, \"|\")", "{0}.Replace(\"|\", StringifySplit)", "string", typeof(string), typeof(string), "{0}", "GetString") },
 | 
				
			||||||
                { (int)OdbcType.NChar, ("", "{0}.Replace(StringifySplit, \"|\")", "{0}.Replace(\"|\", StringifySplit)", "string", typeof(string), typeof(string), "{0}", "GetString") },
 | 
					                { (int)OdbcType.NChar, new DbToCs("", "{0}.Replace(StringifySplit, \"|\")", "{0}.Replace(\"|\", StringifySplit)", "string", typeof(string), typeof(string), "{0}", "GetString") },
 | 
				
			||||||
                { (int)OdbcType.NVarChar, ("", "{0}.Replace(StringifySplit, \"|\")", "{0}.Replace(\"|\", StringifySplit)", "string", typeof(string), typeof(string), "{0}", "GetString") },
 | 
					                { (int)OdbcType.NVarChar, new DbToCs("", "{0}.Replace(StringifySplit, \"|\")", "{0}.Replace(\"|\", StringifySplit)", "string", typeof(string), typeof(string), "{0}", "GetString") },
 | 
				
			||||||
                { (int)OdbcType.NText, ("", "{0}.Replace(StringifySplit, \"|\")", "{0}.Replace(\"|\", StringifySplit)", "string", typeof(string), typeof(string), "{0}", "GetString") },
 | 
					                { (int)OdbcType.NText, new DbToCs("", "{0}.Replace(StringifySplit, \"|\")", "{0}.Replace(\"|\", StringifySplit)", "string", typeof(string), typeof(string), "{0}", "GetString") },
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                { (int)OdbcType.UniqueIdentifier, ("(Guid?)", "Guid.Parse({0})", "{0}.ToString()", "Guid?", typeof(Guid), typeof(Guid?), "{0}.Value", "GetGuid") },
 | 
					                { (int)OdbcType.UniqueIdentifier, new DbToCs("(Guid?)", "Guid.Parse({0})", "{0}.ToString()", "Guid?", typeof(Guid), typeof(Guid?), "{0}.Value", "GetGuid") },
 | 
				
			||||||
            };
 | 
					            };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        public string GetCsConvert(DbColumnInfo column) => _dicDbToCs.TryGetValue(column.DbType, out var trydc) ? (column.IsNullable ? trydc.csConvert : trydc.csConvert.Replace("?", "")) : null;
 | 
					        public string GetCsConvert(DbColumnInfo column) => _dicDbToCs.TryGetValue(column.DbType, out var trydc) ? (column.IsNullable ? trydc.csConvert : trydc.csConvert.Replace("?", "")) : null;
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -21,36 +21,36 @@ namespace FreeSql.Oracle
 | 
				
			|||||||
        public OracleCodeFirst(IFreeSql orm, CommonUtils commonUtils, CommonExpression commonExpression) : base(orm, commonUtils, commonExpression) { }
 | 
					        public OracleCodeFirst(IFreeSql orm, CommonUtils commonUtils, CommonExpression commonExpression) : base(orm, commonUtils, commonExpression) { }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        static object _dicCsToDbLock = new object();
 | 
					        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)>() {
 | 
					        static Dictionary<string, CsToDb<OracleDbType>> _dicCsToDb = new Dictionary<string, CsToDb<OracleDbType>>() {
 | 
				
			||||||
                { 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(bool).FullName, CsToDb.New(OracleDbType.Boolean, "number","number(1) NOT NULL", null, false, false) },{ typeof(bool?).FullName, CsToDb.New(OracleDbType.Boolean, "number","number(1) NULL", null, true, null) },
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                { typeof(sbyte).FullName,  (OracleDbType.Decimal, "number", "number(4) NOT NULL", false, false, 0) },{ typeof(sbyte?).FullName,  (OracleDbType.Decimal, "number", "number(4) NULL", false, true, null) },
 | 
					                { typeof(sbyte).FullName, CsToDb.New(OracleDbType.Decimal, "number", "number(4) NOT NULL", false, false, 0) },{ typeof(sbyte?).FullName, CsToDb.New(OracleDbType.Decimal, "number", "number(4) NULL", false, true, null) },
 | 
				
			||||||
                { typeof(short).FullName,  (OracleDbType.Int16, "number","number(6) NOT NULL", false, false, 0) },{ typeof(short?).FullName,  (OracleDbType.Int16, "number", "number(6) NULL", false, true, null) },
 | 
					                { typeof(short).FullName, CsToDb.New(OracleDbType.Int16, "number","number(6) NOT NULL", false, false, 0) },{ typeof(short?).FullName, CsToDb.New(OracleDbType.Int16, "number", "number(6) NULL", false, true, null) },
 | 
				
			||||||
                { typeof(int).FullName,  (OracleDbType.Int32, "number", "number(11) NOT NULL", false, false, 0) },{ typeof(int?).FullName,  (OracleDbType.Int32, "number", "number(11) NULL", false, true, null) },
 | 
					                { typeof(int).FullName, CsToDb.New(OracleDbType.Int32, "number", "number(11) NOT NULL", false, false, 0) },{ typeof(int?).FullName, CsToDb.New(OracleDbType.Int32, "number", "number(11) NULL", false, true, null) },
 | 
				
			||||||
                { typeof(long).FullName,  (OracleDbType.Int64, "number","number(21) NOT NULL", false, false, 0) },{ typeof(long?).FullName,  (OracleDbType.Int64, "number","number(21) NULL", false, true, null) },
 | 
					                { typeof(long).FullName, CsToDb.New(OracleDbType.Int64, "number","number(21) NOT NULL", false, false, 0) },{ typeof(long?).FullName, CsToDb.New(OracleDbType.Int64, "number","number(21) NULL", false, true, null) },
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                { typeof(byte).FullName,  (OracleDbType.Byte, "number","number(3) NOT NULL", true, false, 0) },{ typeof(byte?).FullName,  (OracleDbType.Byte, "number","number(3) NULL", true, true, null) },
 | 
					                { typeof(byte).FullName, CsToDb.New(OracleDbType.Byte, "number","number(3) NOT NULL", true, false, 0) },{ typeof(byte?).FullName, CsToDb.New(OracleDbType.Byte, "number","number(3) NULL", true, true, null) },
 | 
				
			||||||
                { typeof(ushort).FullName,  (OracleDbType.Decimal, "number","number(5) NOT NULL", true, false, 0) },{ typeof(ushort?).FullName,  (OracleDbType.Decimal, "number", "number(5) NULL", true, true, null) },
 | 
					                { typeof(ushort).FullName, CsToDb.New(OracleDbType.Decimal, "number","number(5) NOT NULL", true, false, 0) },{ typeof(ushort?).FullName, CsToDb.New(OracleDbType.Decimal, "number", "number(5) NULL", true, true, null) },
 | 
				
			||||||
                { typeof(uint).FullName,  (OracleDbType.Decimal, "number", "number(10) NOT NULL", true, false, 0) },{ typeof(uint?).FullName,  (OracleDbType.Decimal, "number", "number(10) NULL", true, true, null) },
 | 
					                { typeof(uint).FullName, CsToDb.New(OracleDbType.Decimal, "number", "number(10) NOT NULL", true, false, 0) },{ typeof(uint?).FullName, CsToDb.New(OracleDbType.Decimal, "number", "number(10) NULL", true, true, null) },
 | 
				
			||||||
                { typeof(ulong).FullName,  (OracleDbType.Decimal, "number", "number(20) NOT NULL", true, false, 0) },{ typeof(ulong?).FullName,  (OracleDbType.Decimal, "number", "number(20) NULL", true, true, null) },
 | 
					                { typeof(ulong).FullName, CsToDb.New(OracleDbType.Decimal, "number", "number(20) NOT NULL", true, false, 0) },{ typeof(ulong?).FullName, CsToDb.New(OracleDbType.Decimal, "number", "number(20) NULL", true, true, null) },
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                { typeof(double).FullName,  (OracleDbType.Double, "float", "float(126) NOT NULL", false, false, 0) },{ typeof(double?).FullName,  (OracleDbType.Double, "float", "float(126) NULL", false, true, null) },
 | 
					                { typeof(double).FullName, CsToDb.New(OracleDbType.Double, "float", "float(126) NOT NULL", false, false, 0) },{ typeof(double?).FullName, CsToDb.New(OracleDbType.Double, "float", "float(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(float).FullName, CsToDb.New(OracleDbType.Single, "float","float(63) NOT NULL", false, false, 0) },{ typeof(float?).FullName, CsToDb.New(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(decimal).FullName, CsToDb.New(OracleDbType.Decimal, "number", "number(10,2) NOT NULL", false, false, 0) },{ typeof(decimal?).FullName, CsToDb.New(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(TimeSpan).FullName, CsToDb.New(OracleDbType.IntervalDS, "interval day to second","interval day(2) to second(6) NOT NULL", false, false, 0) },{ typeof(TimeSpan?).FullName, CsToDb.New(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(DateTime).FullName, CsToDb.New(OracleDbType.TimeStamp, "timestamp", "timestamp(6) NOT NULL", false, false, new DateTime(1970,1,1)) },{ typeof(DateTime?).FullName, CsToDb.New(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(DateTimeOffset?).FullName,  (OracleDbType.TimeStampLTZ, "timestamp with local time zone", "timestamp(6) with local time zone NULL", false, true, null) },
 | 
					                { typeof(DateTimeOffset).FullName, CsToDb.New(OracleDbType.TimeStampLTZ, "timestamp with local time zone", "timestamp(6) with local time zone NOT NULL", false, false, new DateTime(1970,1,1)) },{ typeof(DateTimeOffset?).FullName, CsToDb.New(OracleDbType.TimeStampLTZ, "timestamp with local time zone", "timestamp(6) with local time zone NULL", false, true, null) },
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                { typeof(byte[]).FullName,  (OracleDbType.Blob, "blob", "blob NULL", false, null, new byte[0]) },
 | 
					                { typeof(byte[]).FullName, CsToDb.New(OracleDbType.Blob, "blob", "blob NULL", false, null, new byte[0]) },
 | 
				
			||||||
                { typeof(string).FullName,  (OracleDbType.NVarchar2, "nvarchar2", "nvarchar2(255) NULL", false, null, "") },
 | 
					                { typeof(string).FullName, CsToDb.New(OracleDbType.NVarchar2, "nvarchar2", "nvarchar2(255) NULL", false, null, "") },
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                { typeof(Guid).FullName,  (OracleDbType.Char, "char", "char(36 CHAR) NOT NULL", false, false, Guid.Empty) },{ typeof(Guid?).FullName,  (OracleDbType.Char, "char", "char(36 CHAR) NULL", false, true, null) },
 | 
					                { typeof(Guid).FullName, CsToDb.New(OracleDbType.Char, "char", "char(36 CHAR) NOT NULL", false, false, Guid.Empty) },{ typeof(Guid?).FullName, CsToDb.New(OracleDbType.Char, "char", "char(36 CHAR) NULL", false, true, null) },
 | 
				
			||||||
            };
 | 
					            };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        public override (int type, string dbtype, string dbtypeFull, bool? isnullable, object defaultValue)? GetDbInfo(Type type)
 | 
					        public override DbInfoResult 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 (_dicCsToDb.TryGetValue(type.FullName, out var trydc)) return new DbInfoResult((int)trydc.type, trydc.dbtype, trydc.dbtypeFull, trydc.isnullable, trydc.defaultValue);
 | 
				
			||||||
            if (type.IsArray) return null;
 | 
					            if (type.IsArray) return null;
 | 
				
			||||||
            var enumType = type.IsEnum ? type : null;
 | 
					            var enumType = type.IsEnum ? type : null;
 | 
				
			||||||
            if (enumType == null && type.IsNullableType())
 | 
					            if (enumType == null && type.IsNullableType())
 | 
				
			||||||
@@ -61,8 +61,8 @@ namespace FreeSql.Oracle
 | 
				
			|||||||
            if (enumType != null)
 | 
					            if (enumType != null)
 | 
				
			||||||
            {
 | 
					            {
 | 
				
			||||||
                var newItem = enumType.GetCustomAttributes(typeof(FlagsAttribute), false).Any() ?
 | 
					                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)) :
 | 
					                    CsToDb.New(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));
 | 
					                    CsToDb.New(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)
 | 
					                if (_dicCsToDb.ContainsKey(type.FullName) == false)
 | 
				
			||||||
                {
 | 
					                {
 | 
				
			||||||
                    lock (_dicCsToDbLock)
 | 
					                    lock (_dicCsToDbLock)
 | 
				
			||||||
@@ -71,12 +71,12 @@ namespace FreeSql.Oracle
 | 
				
			|||||||
                            _dicCsToDb.Add(type.FullName, newItem);
 | 
					                            _dicCsToDb.Add(type.FullName, newItem);
 | 
				
			||||||
                    }
 | 
					                    }
 | 
				
			||||||
                }
 | 
					                }
 | 
				
			||||||
                return ((int)newItem.Item1, newItem.Item2, newItem.Item3, newItem.Item5, newItem.Item6);
 | 
					                return new DbInfoResult((int)newItem.type, newItem.dbtype, newItem.dbtypeFull, newItem.isnullable, newItem.defaultValue);
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
            return null;
 | 
					            return null;
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        protected override string GetComparisonDDLStatements(params (Type entityType, string tableName)[] objects)
 | 
					        protected override string GetComparisonDDLStatements(params TypeAndName[] objects)
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
            var userId = (_orm.Ado.MasterPool as OracleConnectionPool)?.UserId;
 | 
					            var userId = (_orm.Ado.MasterPool as OracleConnectionPool)?.UserId;
 | 
				
			||||||
            if (string.IsNullOrEmpty(userId))
 | 
					            if (string.IsNullOrEmpty(userId))
 | 
				
			||||||
@@ -84,7 +84,7 @@ namespace FreeSql.Oracle
 | 
				
			|||||||
                {
 | 
					                {
 | 
				
			||||||
                    userId = OracleConnectionPool.GetUserId(conn.Value.ConnectionString);
 | 
					                    userId = OracleConnectionPool.GetUserId(conn.Value.ConnectionString);
 | 
				
			||||||
                }
 | 
					                }
 | 
				
			||||||
            var seqcols = new List<(ColumnInfo, string[], bool)>(); //序列:列,表,自增
 | 
					            var seqcols = new List<NaviteTuple<ColumnInfo, string[], bool>>(); //序列:列,表,自增
 | 
				
			||||||
            var seqnameDel = new List<string>(); //要删除的序列+触发器
 | 
					            var seqnameDel = new List<string>(); //要删除的序列+触发器
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            var sb = new StringBuilder();
 | 
					            var sb = new StringBuilder();
 | 
				
			||||||
@@ -135,7 +135,7 @@ namespace FreeSql.Oracle
 | 
				
			|||||||
                        foreach (var tbcol in tb.ColumnsByPosition)
 | 
					                        foreach (var tbcol in tb.ColumnsByPosition)
 | 
				
			||||||
                        {
 | 
					                        {
 | 
				
			||||||
                            sb.Append(" \r\n  ").Append(_commonUtils.QuoteSqlName(tbcol.Attribute.Name)).Append(" ").Append(tbcol.Attribute.DbType).Append(",");
 | 
					                            sb.Append(" \r\n  ").Append(_commonUtils.QuoteSqlName(tbcol.Attribute.Name)).Append(" ").Append(tbcol.Attribute.DbType).Append(",");
 | 
				
			||||||
                            if (tbcol.Attribute.IsIdentity == true) seqcols.Add((tbcol, tbname, true));
 | 
					                            if (tbcol.Attribute.IsIdentity == true) seqcols.Add(NaviteTuple.Create(tbcol, tbname, true));
 | 
				
			||||||
                        }
 | 
					                        }
 | 
				
			||||||
                        if (tb.Primarys.Any())
 | 
					                        if (tb.Primarys.Any())
 | 
				
			||||||
                        {
 | 
					                        {
 | 
				
			||||||
@@ -235,10 +235,10 @@ where a.owner={{0}} and a.table_name={{1}}", tboldname ?? tbname);
 | 
				
			|||||||
                                //修改列名
 | 
					                                //修改列名
 | 
				
			||||||
                                sbalter.Append("execute immediate 'ALTER TABLE ").Append(_commonUtils.QuoteSqlName($"{tbname[0]}.{tbname[1]}")).Append(" RENAME COLUMN ").Append(_commonUtils.QuoteSqlName(tbstructcol.column)).Append(" TO ").Append(_commonUtils.QuoteSqlName(tbcol.Attribute.Name)).Append("';\r\n");
 | 
					                                sbalter.Append("execute immediate 'ALTER TABLE ").Append(_commonUtils.QuoteSqlName($"{tbname[0]}.{tbname[1]}")).Append(" RENAME COLUMN ").Append(_commonUtils.QuoteSqlName(tbstructcol.column)).Append(" TO ").Append(_commonUtils.QuoteSqlName(tbcol.Attribute.Name)).Append("';\r\n");
 | 
				
			||||||
                                if (tbcol.Attribute.IsIdentity)
 | 
					                                if (tbcol.Attribute.IsIdentity)
 | 
				
			||||||
                                    seqcols.Add((tbcol, tbname, tbcol.Attribute.IsIdentity == true));
 | 
					                                    seqcols.Add(NaviteTuple.Create(tbcol, tbname, tbcol.Attribute.IsIdentity == true));
 | 
				
			||||||
                            }
 | 
					                            }
 | 
				
			||||||
                            else if (tbcol.Attribute.IsIdentity != tbstructcol.is_identity)
 | 
					                            else if (tbcol.Attribute.IsIdentity != tbstructcol.is_identity)
 | 
				
			||||||
                                seqcols.Add((tbcol, tbname, tbcol.Attribute.IsIdentity == true));
 | 
					                                seqcols.Add(NaviteTuple.Create(tbcol, tbname, tbcol.Attribute.IsIdentity == true));
 | 
				
			||||||
                            if (isCommentChanged)
 | 
					                            if (isCommentChanged)
 | 
				
			||||||
                                sbalter.Append("execute immediate 'COMMENT ON COLUMN ").Append(_commonUtils.QuoteSqlName($"{tbname[0]}.{tbname[1]}.{tbcol.Attribute.Name}")).Append(" IS ").Append(_commonUtils.FormatSql("{0}", tbcol.Comment ?? "").Replace("'", "''")).Append("';\r\n");
 | 
					                                sbalter.Append("execute immediate 'COMMENT ON COLUMN ").Append(_commonUtils.QuoteSqlName($"{tbname[0]}.{tbname[1]}.{tbcol.Attribute.Name}")).Append(" IS ").Append(_commonUtils.FormatSql("{0}", tbcol.Comment ?? "").Replace("'", "''")).Append("';\r\n");
 | 
				
			||||||
                            continue;
 | 
					                            continue;
 | 
				
			||||||
@@ -250,7 +250,7 @@ where a.owner={{0}} and a.table_name={{1}}", tboldname ?? tbname);
 | 
				
			|||||||
                            sbalter.Append("execute immediate 'UPDATE ").Append(_commonUtils.QuoteSqlName($"{tbname[0]}.{tbname[1]}")).Append(" SET ").Append(_commonUtils.QuoteSqlName(tbcol.Attribute.Name)).Append(" = ").Append(tbcol.DbDefaultValue.Replace("'", "''")).Append("';\r\n");
 | 
					                            sbalter.Append("execute immediate 'UPDATE ").Append(_commonUtils.QuoteSqlName($"{tbname[0]}.{tbname[1]}")).Append(" SET ").Append(_commonUtils.QuoteSqlName(tbcol.Attribute.Name)).Append(" = ").Append(tbcol.DbDefaultValue.Replace("'", "''")).Append("';\r\n");
 | 
				
			||||||
                            sbalter.Append("execute immediate 'ALTER TABLE ").Append(_commonUtils.QuoteSqlName($"{tbname[0]}.{tbname[1]}")).Append(" MODIFY ").Append(_commonUtils.QuoteSqlName(tbcol.Attribute.Name)).Append(" NOT NULL';\r\n");
 | 
					                            sbalter.Append("execute immediate 'ALTER TABLE ").Append(_commonUtils.QuoteSqlName($"{tbname[0]}.{tbname[1]}")).Append(" MODIFY ").Append(_commonUtils.QuoteSqlName(tbcol.Attribute.Name)).Append(" NOT NULL';\r\n");
 | 
				
			||||||
                        }
 | 
					                        }
 | 
				
			||||||
                        if (tbcol.Attribute.IsIdentity == true) seqcols.Add((tbcol, tbname, tbcol.Attribute.IsIdentity == true));
 | 
					                        if (tbcol.Attribute.IsIdentity == true) seqcols.Add(NaviteTuple.Create(tbcol, tbname, tbcol.Attribute.IsIdentity == true));
 | 
				
			||||||
                        if (string.IsNullOrEmpty(tbcol.Comment) == false) sbalter.Append("execute immediate 'COMMENT ON COLUMN ").Append(_commonUtils.QuoteSqlName($"{tbname[0]}.{tbname[1]}.{tbcol.Attribute.Name}")).Append(" IS ").Append(_commonUtils.FormatSql("{0}", tbcol.Comment ?? "").Replace("'", "''")).Append("';\r\n");
 | 
					                        if (string.IsNullOrEmpty(tbcol.Comment) == false) sbalter.Append("execute immediate 'COMMENT ON COLUMN ").Append(_commonUtils.QuoteSqlName($"{tbname[0]}.{tbname[1]}.{tbcol.Attribute.Name}")).Append(" IS ").Append(_commonUtils.FormatSql("{0}", tbcol.Comment ?? "").Replace("'", "''")).Append("';\r\n");
 | 
				
			||||||
                    }
 | 
					                    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -306,7 +306,7 @@ and not exists(select 1 from all_constraints where constraint_name = a.index_nam
 | 
				
			|||||||
                foreach (var tbcol in tb.ColumnsByPosition)
 | 
					                foreach (var tbcol in tb.ColumnsByPosition)
 | 
				
			||||||
                {
 | 
					                {
 | 
				
			||||||
                    sb.Append(" \r\n  ").Append(_commonUtils.QuoteSqlName(tbcol.Attribute.Name)).Append(" ").Append(tbcol.Attribute.DbType).Append(",");
 | 
					                    sb.Append(" \r\n  ").Append(_commonUtils.QuoteSqlName(tbcol.Attribute.Name)).Append(" ").Append(tbcol.Attribute.DbType).Append(",");
 | 
				
			||||||
                    if (tbcol.Attribute.IsIdentity == true) seqcols.Add((tbcol, tbname, true));
 | 
					                    if (tbcol.Attribute.IsIdentity == true) seqcols.Add(NaviteTuple.Create(tbcol, tbname, true));
 | 
				
			||||||
                }
 | 
					                }
 | 
				
			||||||
                if (tb.Primarys.Any())
 | 
					                if (tb.Primarys.Any())
 | 
				
			||||||
                {
 | 
					                {
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,5 +1,6 @@
 | 
				
			|||||||
using FreeSql.DatabaseModel;
 | 
					using FreeSql.DatabaseModel;
 | 
				
			||||||
using FreeSql.Internal;
 | 
					using FreeSql.Internal;
 | 
				
			||||||
 | 
					using FreeSql.Internal.Model;
 | 
				
			||||||
using Oracle.ManagedDataAccess.Client;
 | 
					using Oracle.ManagedDataAccess.Client;
 | 
				
			||||||
using System;
 | 
					using System;
 | 
				
			||||||
using System.Collections.Concurrent;
 | 
					using System.Collections.Concurrent;
 | 
				
			||||||
@@ -115,35 +116,35 @@ namespace FreeSql.Oracle
 | 
				
			|||||||
            throw new NotImplementedException($"未实现 {column.DbTypeTextFull} 类型映射");
 | 
					            throw new NotImplementedException($"未实现 {column.DbTypeTextFull} 类型映射");
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        static ConcurrentDictionary<string, (string csConvert, string csParse, string csStringify, string csType, Type csTypeInfo, Type csNullableTypeInfo, string csTypeValue, string dataReaderMethod)> _dicDbToCs = new ConcurrentDictionary<string, (string csConvert, string csParse, string csStringify, string csType, Type csTypeInfo, Type csNullableTypeInfo, string csTypeValue, string dataReaderMethod)>(StringComparer.CurrentCultureIgnoreCase);
 | 
					        static ConcurrentDictionary<string, DbToCs> _dicDbToCs = new ConcurrentDictionary<string, DbToCs>(StringComparer.CurrentCultureIgnoreCase);
 | 
				
			||||||
        static OracleDbFirst()
 | 
					        static OracleDbFirst()
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
            var defaultDbToCs = new Dictionary<string, (string csConvert, string csParse, string csStringify, string csType, Type csTypeInfo, Type csNullableTypeInfo, string csTypeValue, string dataReaderMethod)>() {
 | 
					            var defaultDbToCs = new Dictionary<string, DbToCs>() {
 | 
				
			||||||
                { "number(1)", ("(bool?)", "{0} == \"1\"", "{0} == true ? \"1\" : \"0\"", "bool?", typeof(bool), typeof(bool?), "{0}.Value", "GetBoolean") },
 | 
					                { "number(1)", new DbToCs("(bool?)", "{0} == \"1\"", "{0} == true ? \"1\" : \"0\"", "bool?", typeof(bool), typeof(bool?), "{0}.Value", "GetBoolean") },
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                { "number(4)", ("(sbyte?)", "sbyte.Parse({0})", "{0}.ToString()", "sbyte?", typeof(sbyte), typeof(sbyte?), "{0}.Value", "GetInt16") },
 | 
					                { "number(4)", new DbToCs("(sbyte?)", "sbyte.Parse({0})", "{0}.ToString()", "sbyte?", typeof(sbyte), typeof(sbyte?), "{0}.Value", "GetInt16") },
 | 
				
			||||||
                { "number(6)", ("(short?)", "short.Parse({0})", "{0}.ToString()", "short?", typeof(short), typeof(short?), "{0}.Value", "GetInt16") },
 | 
					                { "number(6)", new DbToCs("(short?)", "short.Parse({0})", "{0}.ToString()", "short?", typeof(short), typeof(short?), "{0}.Value", "GetInt16") },
 | 
				
			||||||
                { "number(11)", ("(int?)", "int.Parse({0})", "{0}.ToString()", "int?", typeof(int), typeof(int?), "{0}.Value", "GetInt32") },
 | 
					                { "number(11)", new DbToCs("(int?)", "int.Parse({0})", "{0}.ToString()", "int?", typeof(int), typeof(int?), "{0}.Value", "GetInt32") },
 | 
				
			||||||
                { "number(21)", ("(long?)", "long.Parse({0})", "{0}.ToString()", "long?", typeof(long), typeof(long?), "{0}.Value", "GetInt64") },
 | 
					                { "number(21)", new DbToCs("(long?)", "long.Parse({0})", "{0}.ToString()", "long?", typeof(long), typeof(long?), "{0}.Value", "GetInt64") },
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                { "number(3)", ("(byte?)", "byte.Parse({0})", "{0}.ToString()", "byte?", typeof(byte), typeof(byte?), "{0}.Value", "GetByte") },
 | 
					                { "number(3)", new DbToCs("(byte?)", "byte.Parse({0})", "{0}.ToString()", "byte?", typeof(byte), typeof(byte?), "{0}.Value", "GetByte") },
 | 
				
			||||||
                { "number(5)", ("(ushort?)", "ushort.Parse({0})", "{0}.ToString()", "ushort?", typeof(ushort), typeof(ushort?), "{0}.Value", "GetInt32") },
 | 
					                { "number(5)", new DbToCs("(ushort?)", "ushort.Parse({0})", "{0}.ToString()", "ushort?", typeof(ushort), typeof(ushort?), "{0}.Value", "GetInt32") },
 | 
				
			||||||
                { "number(10)", ("(uint?)", "uint.Parse({0})", "{0}.ToString()", "uint?", typeof(uint), typeof(uint?), "{0}.Value", "GetInt64") },
 | 
					                { "number(10)", new DbToCs("(uint?)", "uint.Parse({0})", "{0}.ToString()", "uint?", typeof(uint), typeof(uint?), "{0}.Value", "GetInt64") },
 | 
				
			||||||
                { "number(20)", ("(ulong?)", "ulong.Parse({0})", "{0}.ToString()", "ulong?", typeof(ulong), typeof(ulong?), "{0}.Value", "GetDecimal") },
 | 
					                { "number(20)", new DbToCs("(ulong?)", "ulong.Parse({0})", "{0}.ToString()", "ulong?", typeof(ulong), typeof(ulong?), "{0}.Value", "GetDecimal") },
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                { "float(126)", ("(double?)", "double.Parse({0})", "{0}.ToString()", "double?", typeof(double), typeof(double?), "{0}.Value", "GetDouble") },
 | 
					                { "float(126)", new DbToCs("(double?)", "double.Parse({0})", "{0}.ToString()", "double?", typeof(double), typeof(double?), "{0}.Value", "GetDouble") },
 | 
				
			||||||
                { "float(63)", ("(float?)", "float.Parse({0})", "{0}.ToString()", "float?", typeof(float), typeof(float?), "{0}.Value", "GetFloat") },
 | 
					                { "float(63)", new DbToCs("(float?)", "float.Parse({0})", "{0}.ToString()", "float?", typeof(float), typeof(float?), "{0}.Value", "GetFloat") },
 | 
				
			||||||
                { "number(10,2)", ("(decimal?)", "decimal.Parse({0})", "{0}.ToString()", "decimal?", typeof(decimal), typeof(decimal?), "{0}.Value", "GetDecimal") },
 | 
					                { "number(10,2)", new DbToCs("(decimal?)", "decimal.Parse({0})", "{0}.ToString()", "decimal?", typeof(decimal), typeof(decimal?), "{0}.Value", "GetDecimal") },
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                { "interval day(2) to second(6)", ("(TimeSpan?)", "TimeSpan.Parse(double.Parse({0}))", "{0}.Ticks.ToString()", "TimeSpan?", typeof(TimeSpan), typeof(TimeSpan?), "{0}.Value", "GetValue") },
 | 
					                { "interval day(2) to second(6)", new DbToCs("(TimeSpan?)", "TimeSpan.Parse(double.Parse({0}))", "{0}.Ticks.ToString()", "TimeSpan?", typeof(TimeSpan), typeof(TimeSpan?), "{0}.Value", "GetValue") },
 | 
				
			||||||
                { "date(7)", ("(DateTime?)", "new DateTime(long.Parse({0}))", "{0}.Ticks.ToString()", "DateTime?", typeof(DateTime), typeof(DateTime?), "{0}.Value", "GetValue") },
 | 
					                { "date(7)", new DbToCs("(DateTime?)", "new DateTime(long.Parse({0}))", "{0}.Ticks.ToString()", "DateTime?", typeof(DateTime), typeof(DateTime?), "{0}.Value", "GetValue") },
 | 
				
			||||||
                { "timestamp(6)", ("(DateTime?)", "new DateTime(long.Parse({0}))", "{0}.Ticks.ToString()", "DateTime?", typeof(DateTime), typeof(DateTime?), "{0}.Value", "GetValue") },
 | 
					                { "timestamp(6)", new DbToCs("(DateTime?)", "new DateTime(long.Parse({0}))", "{0}.Ticks.ToString()", "DateTime?", typeof(DateTime), typeof(DateTime?), "{0}.Value", "GetValue") },
 | 
				
			||||||
                { "timestamp(6) with local time zone", ("(DateTime?)", "new DateTime(long.Parse({0}))", "{0}.Ticks.ToString()", "DateTime?", typeof(DateTime), typeof(DateTime?), "{0}.Value", "GetValue") },
 | 
					                { "timestamp(6) with local time zone", new DbToCs("(DateTime?)", "new DateTime(long.Parse({0}))", "{0}.Ticks.ToString()", "DateTime?", typeof(DateTime), typeof(DateTime?), "{0}.Value", "GetValue") },
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                { "blob", ("(byte[])", "Convert.FromBase64String({0})", "Convert.ToBase64String({0})", "byte[]", typeof(byte[]), typeof(byte[]), "{0}", "GetValue") },
 | 
					                { "blob", new DbToCs("(byte[])", "Convert.FromBase64String({0})", "Convert.ToBase64String({0})", "byte[]", typeof(byte[]), typeof(byte[]), "{0}", "GetValue") },
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                { "nvarchar2(255)", ("", "{0}.Replace(StringifySplit, \"|\")", "{0}.Replace(\"|\", StringifySplit)", "string", typeof(string), typeof(string), "{0}", "GetString") },
 | 
					                { "nvarchar2(255)", new DbToCs("", "{0}.Replace(StringifySplit, \"|\")", "{0}.Replace(\"|\", StringifySplit)", "string", typeof(string), typeof(string), "{0}", "GetString") },
 | 
				
			||||||
                { "char(36 char)", ("(Guid?)", "Guid.Parse({0})", "{0}.ToString()", "Guid?", typeof(Guid), typeof(Guid?), "{0}.Value", "GetGuid") },
 | 
					                { "char(36 char)", new DbToCs("(Guid?)", "Guid.Parse({0})", "{0}.ToString()", "Guid?", typeof(Guid), typeof(Guid?), "{0}.Value", "GetGuid") },
 | 
				
			||||||
            };
 | 
					            };
 | 
				
			||||||
            foreach (var kv in defaultDbToCs)
 | 
					            foreach (var kv in defaultDbToCs)
 | 
				
			||||||
                _dicDbToCs.TryAdd(kv.Key, kv.Value);
 | 
					                _dicDbToCs.TryAdd(kv.Key, kv.Value);
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -22,85 +22,85 @@ namespace FreeSql.PostgreSQL
 | 
				
			|||||||
        public PostgreSQLCodeFirst(IFreeSql orm, CommonUtils commonUtils, CommonExpression commonExpression) : base(orm, commonUtils, commonExpression) { }
 | 
					        public PostgreSQLCodeFirst(IFreeSql orm, CommonUtils commonUtils, CommonExpression commonExpression) : base(orm, commonUtils, commonExpression) { }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        static object _dicCsToDbLock = new object();
 | 
					        static object _dicCsToDbLock = new object();
 | 
				
			||||||
        static Dictionary<string, (NpgsqlDbType type, string dbtype, string dbtypeFull, bool? isUnsigned, bool? isnullable, object defaultValue)> _dicCsToDb = new Dictionary<string, (NpgsqlDbType type, string dbtype, string dbtypeFull, bool? isUnsigned, bool? isnullable, object defaultValue)>() {
 | 
					        static Dictionary<string, CsToDb<NpgsqlDbType>> _dicCsToDb = new Dictionary<string, CsToDb<NpgsqlDbType>>() {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                { typeof(sbyte).FullName,  (NpgsqlDbType.Smallint, "int2","int2 NOT NULL", false, false, 0) },{ typeof(sbyte?).FullName,  (NpgsqlDbType.Smallint, "int2", "int2", false, true, null) },
 | 
					                { typeof(sbyte).FullName, CsToDb.New(NpgsqlDbType.Smallint, "int2","int2 NOT NULL", false, false, 0) },{ typeof(sbyte?).FullName, CsToDb.New(NpgsqlDbType.Smallint, "int2", "int2", false, true, null) },
 | 
				
			||||||
                { typeof(short).FullName,  (NpgsqlDbType.Smallint, "int2","int2 NOT NULL", false, false, 0) },{ typeof(short?).FullName,  (NpgsqlDbType.Smallint, "int2", "int2", false, true, null) },
 | 
					                { typeof(short).FullName, CsToDb.New(NpgsqlDbType.Smallint, "int2","int2 NOT NULL", false, false, 0) },{ typeof(short?).FullName, CsToDb.New(NpgsqlDbType.Smallint, "int2", "int2", false, true, null) },
 | 
				
			||||||
                { typeof(int).FullName,  (NpgsqlDbType.Integer, "int4","int4 NOT NULL", false, false, 0) },{ typeof(int?).FullName,  (NpgsqlDbType.Integer, "int4", "int4", false, true, null) },
 | 
					                { typeof(int).FullName, CsToDb.New(NpgsqlDbType.Integer, "int4","int4 NOT NULL", false, false, 0) },{ typeof(int?).FullName, CsToDb.New(NpgsqlDbType.Integer, "int4", "int4", false, true, null) },
 | 
				
			||||||
                { typeof(long).FullName,  (NpgsqlDbType.Bigint, "int8","int8 NOT NULL", false, false, 0) },{ typeof(long?).FullName,  (NpgsqlDbType.Bigint, "int8", "int8", false, true, null) },
 | 
					                { typeof(long).FullName, CsToDb.New(NpgsqlDbType.Bigint, "int8","int8 NOT NULL", false, false, 0) },{ typeof(long?).FullName, CsToDb.New(NpgsqlDbType.Bigint, "int8", "int8", false, true, null) },
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                { typeof(byte).FullName,  (NpgsqlDbType.Smallint, "int2","int2 NOT NULL", false, false, 0) },{ typeof(byte?).FullName,  (NpgsqlDbType.Smallint, "int2", "int2", false, true, null) },
 | 
					                { typeof(byte).FullName, CsToDb.New(NpgsqlDbType.Smallint, "int2","int2 NOT NULL", false, false, 0) },{ typeof(byte?).FullName, CsToDb.New(NpgsqlDbType.Smallint, "int2", "int2", false, true, null) },
 | 
				
			||||||
                { typeof(ushort).FullName,  (NpgsqlDbType.Integer, "int4","int4 NOT NULL", false, false, 0) },{ typeof(ushort?).FullName,  (NpgsqlDbType.Integer, "int4", "int4", false, true, null) },
 | 
					                { typeof(ushort).FullName, CsToDb.New(NpgsqlDbType.Integer, "int4","int4 NOT NULL", false, false, 0) },{ typeof(ushort?).FullName, CsToDb.New(NpgsqlDbType.Integer, "int4", "int4", false, true, null) },
 | 
				
			||||||
                { typeof(uint).FullName,  (NpgsqlDbType.Bigint, "int8","int8 NOT NULL", false, false, 0) },{ typeof(uint?).FullName,  (NpgsqlDbType.Bigint, "int8", "int8", false, true, null) },
 | 
					                { typeof(uint).FullName, CsToDb.New(NpgsqlDbType.Bigint, "int8","int8 NOT NULL", false, false, 0) },{ typeof(uint?).FullName, CsToDb.New(NpgsqlDbType.Bigint, "int8", "int8", false, true, null) },
 | 
				
			||||||
                { typeof(ulong).FullName,  (NpgsqlDbType.Numeric, "numeric","numeric(20,0) NOT NULL", false, false, 0) },{ typeof(ulong?).FullName,  (NpgsqlDbType.Numeric, "numeric", "numeric(20,0)", false, true, null) },
 | 
					                { typeof(ulong).FullName, CsToDb.New(NpgsqlDbType.Numeric, "numeric","numeric(20,0) NOT NULL", false, false, 0) },{ typeof(ulong?).FullName, CsToDb.New(NpgsqlDbType.Numeric, "numeric", "numeric(20,0)", false, true, null) },
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                { typeof(float).FullName,  (NpgsqlDbType.Real, "float4","float4 NOT NULL", false, false, 0) },{ typeof(float?).FullName,  (NpgsqlDbType.Real, "float4", "float4", false, true, null) },
 | 
					                { typeof(float).FullName, CsToDb.New(NpgsqlDbType.Real, "float4","float4 NOT NULL", false, false, 0) },{ typeof(float?).FullName, CsToDb.New(NpgsqlDbType.Real, "float4", "float4", false, true, null) },
 | 
				
			||||||
                { typeof(double).FullName,  (NpgsqlDbType.Double, "float8","float8 NOT NULL", false, false, 0) },{ typeof(double?).FullName,  (NpgsqlDbType.Double, "float8", "float8", false, true, null) },
 | 
					                { typeof(double).FullName, CsToDb.New(NpgsqlDbType.Double, "float8","float8 NOT NULL", false, false, 0) },{ typeof(double?).FullName, CsToDb.New(NpgsqlDbType.Double, "float8", "float8", false, true, null) },
 | 
				
			||||||
                { typeof(decimal).FullName,  (NpgsqlDbType.Numeric, "numeric", "numeric(10,2) NOT NULL", false, false, 0) },{ typeof(decimal?).FullName,  (NpgsqlDbType.Numeric, "numeric", "numeric(10,2)", false, true, null) },
 | 
					                { typeof(decimal).FullName, CsToDb.New(NpgsqlDbType.Numeric, "numeric", "numeric(10,2) NOT NULL", false, false, 0) },{ typeof(decimal?).FullName, CsToDb.New(NpgsqlDbType.Numeric, "numeric", "numeric(10,2)", false, true, null) },
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                { typeof(string).FullName,  (NpgsqlDbType.Varchar, "varchar", "varchar(255)", false, null, "") },
 | 
					                { typeof(string).FullName, CsToDb.New(NpgsqlDbType.Varchar, "varchar", "varchar(255)", false, null, "") },
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                { typeof(TimeSpan).FullName,  (NpgsqlDbType.Time, "time","time NOT NULL", false, false, 0) },{ typeof(TimeSpan?).FullName,  (NpgsqlDbType.Time, "time", "time",false, true, null) },
 | 
					                { typeof(TimeSpan).FullName, CsToDb.New(NpgsqlDbType.Time, "time","time NOT NULL", false, false, 0) },{ typeof(TimeSpan?).FullName, CsToDb.New(NpgsqlDbType.Time, "time", "time",false, true, null) },
 | 
				
			||||||
                { typeof(DateTime).FullName,  (NpgsqlDbType.Timestamp, "timestamp", "timestamp NOT NULL", false, false, new DateTime(1970,1,1)) },{ typeof(DateTime?).FullName,  (NpgsqlDbType.Timestamp, "timestamp", "timestamp", false, true, null) },
 | 
					                { typeof(DateTime).FullName, CsToDb.New(NpgsqlDbType.Timestamp, "timestamp", "timestamp NOT NULL", false, false, new DateTime(1970,1,1)) },{ typeof(DateTime?).FullName, CsToDb.New(NpgsqlDbType.Timestamp, "timestamp", "timestamp", false, true, null) },
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                { typeof(bool).FullName,  (NpgsqlDbType.Boolean, "bool","bool NOT NULL", null, false, false) },{ typeof(bool?).FullName,  (NpgsqlDbType.Boolean, "bool","bool", null, true, null) },
 | 
					                { typeof(bool).FullName, CsToDb.New(NpgsqlDbType.Boolean, "bool","bool NOT NULL", null, false, false) },{ typeof(bool?).FullName, CsToDb.New(NpgsqlDbType.Boolean, "bool","bool", null, true, null) },
 | 
				
			||||||
                { typeof(Byte[]).FullName,  (NpgsqlDbType.Bytea, "bytea", "bytea", false, null, new byte[0]) },
 | 
					                { typeof(Byte[]).FullName, CsToDb.New(NpgsqlDbType.Bytea, "bytea", "bytea", false, null, new byte[0]) },
 | 
				
			||||||
                { typeof(BitArray).FullName,  (NpgsqlDbType.Varbit, "varbit", "varbit(64)", false, null, new BitArray(new byte[64])) },
 | 
					                { typeof(BitArray).FullName, CsToDb.New(NpgsqlDbType.Varbit, "varbit", "varbit(64)", false, null, new BitArray(new byte[64])) },
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                { typeof(NpgsqlPoint).FullName,  (NpgsqlDbType.Point, "point", "point NOT NULL", false, false, new NpgsqlPoint(0, 0)) },{ typeof(NpgsqlPoint?).FullName,  (NpgsqlDbType.Point, "point", "point", false, true, null) },
 | 
					                { typeof(NpgsqlPoint).FullName, CsToDb.New(NpgsqlDbType.Point, "point", "point NOT NULL", false, false, new NpgsqlPoint(0, 0)) },{ typeof(NpgsqlPoint?).FullName, CsToDb.New(NpgsqlDbType.Point, "point", "point", false, true, null) },
 | 
				
			||||||
                { typeof(NpgsqlLine).FullName,  (NpgsqlDbType.Line, "line", "line NOT NULL", false, false, new NpgsqlLine(0, 0, 1)) },{ typeof(NpgsqlLine?).FullName,  (NpgsqlDbType.Line, "line", "line", false, true, null) },
 | 
					                { typeof(NpgsqlLine).FullName, CsToDb.New(NpgsqlDbType.Line, "line", "line NOT NULL", false, false, new NpgsqlLine(0, 0, 1)) },{ typeof(NpgsqlLine?).FullName, CsToDb.New(NpgsqlDbType.Line, "line", "line", false, true, null) },
 | 
				
			||||||
                { typeof(NpgsqlLSeg).FullName,  (NpgsqlDbType.LSeg, "lseg", "lseg NOT NULL", false, false, new NpgsqlLSeg(0, 0, 0, 0)) },{ typeof(NpgsqlLSeg?).FullName,  (NpgsqlDbType.LSeg, "lseg", "lseg", false, true, null) },
 | 
					                { typeof(NpgsqlLSeg).FullName, CsToDb.New(NpgsqlDbType.LSeg, "lseg", "lseg NOT NULL", false, false, new NpgsqlLSeg(0, 0, 0, 0)) },{ typeof(NpgsqlLSeg?).FullName, CsToDb.New(NpgsqlDbType.LSeg, "lseg", "lseg", false, true, null) },
 | 
				
			||||||
                { typeof(NpgsqlBox).FullName,  (NpgsqlDbType.Box, "box", "box NOT NULL", false, false, new NpgsqlBox(0, 0, 0, 0)) },{ typeof(NpgsqlBox?).FullName,  (NpgsqlDbType.Box, "box", "box", false, true, null) },
 | 
					                { typeof(NpgsqlBox).FullName, CsToDb.New(NpgsqlDbType.Box, "box", "box NOT NULL", false, false, new NpgsqlBox(0, 0, 0, 0)) },{ typeof(NpgsqlBox?).FullName, CsToDb.New(NpgsqlDbType.Box, "box", "box", false, true, null) },
 | 
				
			||||||
                { typeof(NpgsqlPath).FullName,  (NpgsqlDbType.Path, "path", "path NOT NULL", false, false, new NpgsqlPath(new NpgsqlPoint(0, 0))) },{ typeof(NpgsqlPath?).FullName,  (NpgsqlDbType.Path, "path", "path", false, true, null) },
 | 
					                { typeof(NpgsqlPath).FullName, CsToDb.New(NpgsqlDbType.Path, "path", "path NOT NULL", false, false, new NpgsqlPath(new NpgsqlPoint(0, 0))) },{ typeof(NpgsqlPath?).FullName, CsToDb.New(NpgsqlDbType.Path, "path", "path", false, true, null) },
 | 
				
			||||||
                { typeof(NpgsqlPolygon).FullName,  (NpgsqlDbType.Polygon, "polygon", "polygon NOT NULL", false, false, new NpgsqlPolygon(new NpgsqlPoint(0, 0), new NpgsqlPoint(0, 0))) },{ typeof(NpgsqlPolygon?).FullName,  (NpgsqlDbType.Polygon, "polygon", "polygon", false, true, null) },
 | 
					                { typeof(NpgsqlPolygon).FullName, CsToDb.New(NpgsqlDbType.Polygon, "polygon", "polygon NOT NULL", false, false, new NpgsqlPolygon(new NpgsqlPoint(0, 0), new NpgsqlPoint(0, 0))) },{ typeof(NpgsqlPolygon?).FullName, CsToDb.New(NpgsqlDbType.Polygon, "polygon", "polygon", false, true, null) },
 | 
				
			||||||
                { typeof(NpgsqlCircle).FullName,  (NpgsqlDbType.Circle, "circle", "circle NOT NULL", false, false, new NpgsqlCircle(0, 0, 0)) },{ typeof(NpgsqlCircle?).FullName,  (NpgsqlDbType.Circle, "circle", "circle", false, true, null) },
 | 
					                { typeof(NpgsqlCircle).FullName, CsToDb.New(NpgsqlDbType.Circle, "circle", "circle NOT NULL", false, false, new NpgsqlCircle(0, 0, 0)) },{ typeof(NpgsqlCircle?).FullName, CsToDb.New(NpgsqlDbType.Circle, "circle", "circle", false, true, null) },
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                { typeof((IPAddress Address, int Subnet)).FullName,  (NpgsqlDbType.Cidr, "cidr", "cidr NOT NULL", false, false, (IPAddress.Any, 0)) },{ typeof((IPAddress Address, int Subnet)?).FullName,  (NpgsqlDbType.Cidr, "cidr", "cidr", false, true, null) },
 | 
					                { typeof((IPAddress Address, int Subnet)).FullName, CsToDb.New(NpgsqlDbType.Cidr, "cidr", "cidr NOT NULL", false, false, (IPAddress.Any, 0)) },{ typeof((IPAddress Address, int Subnet)?).FullName, CsToDb.New(NpgsqlDbType.Cidr, "cidr", "cidr", false, true, null) },
 | 
				
			||||||
                { typeof(IPAddress).FullName,  (NpgsqlDbType.Inet, "inet", "inet", false, null, IPAddress.Any) },
 | 
					                { typeof(IPAddress).FullName, CsToDb.New(NpgsqlDbType.Inet, "inet", "inet", false, null, IPAddress.Any) },
 | 
				
			||||||
                { typeof(PhysicalAddress).FullName,  (NpgsqlDbType.MacAddr, "macaddr", "macaddr", false, null, PhysicalAddress.None) },
 | 
					                { typeof(PhysicalAddress).FullName, CsToDb.New(NpgsqlDbType.MacAddr, "macaddr", "macaddr", false, null, PhysicalAddress.None) },
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                { typeof(JToken).FullName,  (NpgsqlDbType.Jsonb, "jsonb", "jsonb", false, null, JToken.Parse("{}")) },
 | 
					                { typeof(JToken).FullName, CsToDb.New(NpgsqlDbType.Jsonb, "jsonb", "jsonb", false, null, JToken.Parse("{}")) },
 | 
				
			||||||
                { typeof(JObject).FullName,  (NpgsqlDbType.Jsonb, "jsonb", "jsonb", false, null, JObject.Parse("{}")) },
 | 
					                { typeof(JObject).FullName, CsToDb.New(NpgsqlDbType.Jsonb, "jsonb", "jsonb", false, null, JObject.Parse("{}")) },
 | 
				
			||||||
                { typeof(JArray).FullName,  (NpgsqlDbType.Jsonb, "jsonb", "jsonb", false, null, JArray.Parse("[]")) },
 | 
					                { typeof(JArray).FullName, CsToDb.New(NpgsqlDbType.Jsonb, "jsonb", "jsonb", false, null, JArray.Parse("[]")) },
 | 
				
			||||||
                { typeof(Guid).FullName,  (NpgsqlDbType.Uuid, "uuid", "uuid NOT NULL", false, false, Guid.Empty) },{ typeof(Guid?).FullName,  (NpgsqlDbType.Uuid, "uuid", "uuid", false, true, null) },
 | 
					                { typeof(Guid).FullName, CsToDb.New(NpgsqlDbType.Uuid, "uuid", "uuid NOT NULL", false, false, Guid.Empty) },{ typeof(Guid?).FullName, CsToDb.New(NpgsqlDbType.Uuid, "uuid", "uuid", false, true, null) },
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                { typeof(NpgsqlRange<int>).FullName,  (NpgsqlDbType.Range | NpgsqlDbType.Integer, "int4range", "int4range NOT NULL", false, false, NpgsqlRange<int>.Empty) },{ typeof(NpgsqlRange<int>?).FullName,  (NpgsqlDbType.Range | NpgsqlDbType.Integer, "int4range", "int4range", false, true, null) },
 | 
					                { typeof(NpgsqlRange<int>).FullName, CsToDb.New(NpgsqlDbType.Range | NpgsqlDbType.Integer, "int4range", "int4range NOT NULL", false, false, NpgsqlRange<int>.Empty) },{ typeof(NpgsqlRange<int>?).FullName, CsToDb.New(NpgsqlDbType.Range | NpgsqlDbType.Integer, "int4range", "int4range", false, true, null) },
 | 
				
			||||||
                { typeof(NpgsqlRange<long>).FullName,  (NpgsqlDbType.Range | NpgsqlDbType.Bigint, "int8range", "int8range NOT NULL", false, false, NpgsqlRange<long>.Empty) },{ typeof(NpgsqlRange<long>?).FullName,  (NpgsqlDbType.Range | NpgsqlDbType.Bigint, "int8range", "int8range", false, true, null) },
 | 
					                { typeof(NpgsqlRange<long>).FullName, CsToDb.New(NpgsqlDbType.Range | NpgsqlDbType.Bigint, "int8range", "int8range NOT NULL", false, false, NpgsqlRange<long>.Empty) },{ typeof(NpgsqlRange<long>?).FullName, CsToDb.New(NpgsqlDbType.Range | NpgsqlDbType.Bigint, "int8range", "int8range", false, true, null) },
 | 
				
			||||||
                { typeof(NpgsqlRange<decimal>).FullName,  (NpgsqlDbType.Range | NpgsqlDbType.Numeric, "numrange", "numrange NOT NULL", false, false, NpgsqlRange<decimal>.Empty) },{ typeof(NpgsqlRange<decimal>?).FullName,  (NpgsqlDbType.Range | NpgsqlDbType.Numeric, "numrange", "numrange", false, true, null) },
 | 
					                { typeof(NpgsqlRange<decimal>).FullName, CsToDb.New(NpgsqlDbType.Range | NpgsqlDbType.Numeric, "numrange", "numrange NOT NULL", false, false, NpgsqlRange<decimal>.Empty) },{ typeof(NpgsqlRange<decimal>?).FullName, CsToDb.New(NpgsqlDbType.Range | NpgsqlDbType.Numeric, "numrange", "numrange", false, true, null) },
 | 
				
			||||||
                { typeof(NpgsqlRange<DateTime>).FullName,  (NpgsqlDbType.Range | NpgsqlDbType.Timestamp, "tsrange", "tsrange NOT NULL", false, false, NpgsqlRange<DateTime>.Empty) },{ typeof(NpgsqlRange<DateTime>?).FullName,  (NpgsqlDbType.Range | NpgsqlDbType.Timestamp, "tsrange", "tsrange", false, true, null) },
 | 
					                { typeof(NpgsqlRange<DateTime>).FullName, CsToDb.New(NpgsqlDbType.Range | NpgsqlDbType.Timestamp, "tsrange", "tsrange NOT NULL", false, false, NpgsqlRange<DateTime>.Empty) },{ typeof(NpgsqlRange<DateTime>?).FullName, CsToDb.New(NpgsqlDbType.Range | NpgsqlDbType.Timestamp, "tsrange", "tsrange", false, true, null) },
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                { typeof(Dictionary<string, string>).FullName,  (NpgsqlDbType.Hstore, "hstore", "hstore", false, null, new Dictionary<string, string>()) },
 | 
					                { typeof(Dictionary<string, string>).FullName, CsToDb.New(NpgsqlDbType.Hstore, "hstore", "hstore", false, null, new Dictionary<string, string>()) },
 | 
				
			||||||
                { typeof(PostgisPoint).FullName,  (NpgsqlDbType.Geometry, "geometry", "geometry", false, null, new PostgisPoint(0, 0)) },
 | 
					                { typeof(PostgisPoint).FullName, CsToDb.New(NpgsqlDbType.Geometry, "geometry", "geometry", false, null, new PostgisPoint(0, 0)) },
 | 
				
			||||||
                { typeof(PostgisLineString).FullName,  (NpgsqlDbType.Geometry, "geometry", "geometry", false, null, new PostgisLineString(new []{new Coordinate2D(0, 0),new Coordinate2D(0, 0) })) },
 | 
					                { typeof(PostgisLineString).FullName, CsToDb.New(NpgsqlDbType.Geometry, "geometry", "geometry", false, null, new PostgisLineString(new []{new Coordinate2D(0, 0),new Coordinate2D(0, 0) })) },
 | 
				
			||||||
                { typeof(PostgisPolygon).FullName,  (NpgsqlDbType.Geometry, "geometry", "geometry", false, null, new PostgisPolygon(new []{new []{new Coordinate2D(0, 0),new Coordinate2D(0, 0) }, new []{new Coordinate2D(0, 0),new Coordinate2D(0, 0) } })) },
 | 
					                { typeof(PostgisPolygon).FullName, CsToDb.New(NpgsqlDbType.Geometry, "geometry", "geometry", false, null, new PostgisPolygon(new []{new []{new Coordinate2D(0, 0),new Coordinate2D(0, 0) }, new []{new Coordinate2D(0, 0),new Coordinate2D(0, 0) } })) },
 | 
				
			||||||
                { typeof(PostgisMultiPoint).FullName,  (NpgsqlDbType.Geometry, "geometry", "geometry", false, null, new PostgisMultiPoint(new []{new Coordinate2D(0, 0),new Coordinate2D(0, 0) })) },
 | 
					                { typeof(PostgisMultiPoint).FullName, CsToDb.New(NpgsqlDbType.Geometry, "geometry", "geometry", false, null, new PostgisMultiPoint(new []{new Coordinate2D(0, 0),new Coordinate2D(0, 0) })) },
 | 
				
			||||||
                { typeof(PostgisMultiLineString).FullName,  (NpgsqlDbType.Geometry, "geometry", "geometry", false, null, new PostgisMultiLineString(new[]{new PostgisLineString(new []{new Coordinate2D(0, 0),new Coordinate2D(0, 0) }),new PostgisLineString(new []{new Coordinate2D(0, 0),new Coordinate2D(0, 0) }) })) },
 | 
					                { typeof(PostgisMultiLineString).FullName, CsToDb.New(NpgsqlDbType.Geometry, "geometry", "geometry", false, null, new PostgisMultiLineString(new[]{new PostgisLineString(new []{new Coordinate2D(0, 0),new Coordinate2D(0, 0) }),new PostgisLineString(new []{new Coordinate2D(0, 0),new Coordinate2D(0, 0) }) })) },
 | 
				
			||||||
                { typeof(PostgisMultiPolygon).FullName,  (NpgsqlDbType.Geometry, "geometry", "geometry", false, null, new PostgisMultiPolygon(new[]{new PostgisPolygon(new []{new []{new Coordinate2D(0, 0),new Coordinate2D(0, 0) }, new []{new Coordinate2D(0, 0),new Coordinate2D(0, 0) } }),new PostgisPolygon(new []{new []{new Coordinate2D(0, 0),new Coordinate2D(0, 0) }, new []{new Coordinate2D(0, 0),new Coordinate2D(0, 0) } }) })) },
 | 
					                { typeof(PostgisMultiPolygon).FullName, CsToDb.New(NpgsqlDbType.Geometry, "geometry", "geometry", false, null, new PostgisMultiPolygon(new[]{new PostgisPolygon(new []{new []{new Coordinate2D(0, 0),new Coordinate2D(0, 0) }, new []{new Coordinate2D(0, 0),new Coordinate2D(0, 0) } }),new PostgisPolygon(new []{new []{new Coordinate2D(0, 0),new Coordinate2D(0, 0) }, new []{new Coordinate2D(0, 0),new Coordinate2D(0, 0) } }) })) },
 | 
				
			||||||
                { typeof(PostgisGeometry).FullName,  (NpgsqlDbType.Geometry, "geometry", "geometry", false, null, new PostgisPoint(0, 0)) },
 | 
					                { typeof(PostgisGeometry).FullName, CsToDb.New(NpgsqlDbType.Geometry, "geometry", "geometry", false, null, new PostgisPoint(0, 0)) },
 | 
				
			||||||
                { typeof(PostgisGeometryCollection).FullName,  (NpgsqlDbType.Geometry, "geometry", "geometry", false, null, new PostgisGeometryCollection(new[]{new PostgisPoint(0, 0),new PostgisPoint(0, 0) })) },
 | 
					                { typeof(PostgisGeometryCollection).FullName, CsToDb.New(NpgsqlDbType.Geometry, "geometry", "geometry", false, null, new PostgisGeometryCollection(new[]{new PostgisPoint(0, 0),new PostgisPoint(0, 0) })) },
 | 
				
			||||||
            };
 | 
					            };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        public override (int type, string dbtype, string dbtypeFull, bool? isnullable, object defaultValue)? GetDbInfo(Type type)
 | 
					        public override DbInfoResult GetDbInfo(Type type)
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
            var isarray = type.FullName != "System.Byte[]" && type.IsArray;
 | 
					            var isarray = type.FullName != "System.Byte[]" && type.IsArray;
 | 
				
			||||||
            var elementType = isarray ? type.GetElementType() : type;
 | 
					            var elementType = isarray ? type.GetElementType() : type;
 | 
				
			||||||
            var info = GetDbInfoNoneArray(elementType);
 | 
					            var info = GetDbInfoNoneArray(elementType);
 | 
				
			||||||
            if (info == null) return null;
 | 
					            if (info == null) return null;
 | 
				
			||||||
            if (isarray == false) return ((int)info.Value.type, info.Value.dbtype, info.Value.dbtypeFull, info.Value.isnullable, info.Value.defaultValue);
 | 
					            if (isarray == false) return new DbInfoResult((int)info.type, info.dbtype, info.dbtypeFull, info.isnullable, info.defaultValue);
 | 
				
			||||||
            var dbtypefull = Regex.Replace(info.Value.dbtypeFull, $@"{info.Value.dbtype}(\s*\([^\)]+\))?", "$0[]").Replace(" NOT NULL", "");
 | 
					            var dbtypefull = Regex.Replace(info.dbtypeFull, $@"{info.dbtype}(\s*\([^\)]+\))?", "$0[]").Replace(" NOT NULL", "");
 | 
				
			||||||
            return ((int)(info.Value.type | NpgsqlDbType.Array), $"{info.Value.dbtype}[]", dbtypefull, null, Array.CreateInstance(elementType, 0));
 | 
					            return new DbInfoResult((int)(info.type | NpgsqlDbType.Array), $"{info.dbtype}[]", dbtypefull, null, Array.CreateInstance(elementType, 0));
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
        (NpgsqlDbType type, string dbtype, string dbtypeFull, bool? isnullable, object defaultValue)? GetDbInfoNoneArray(Type type)
 | 
					        CsToDb<NpgsqlDbType> GetDbInfoNoneArray(Type type)
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
            if (_dicCsToDb.TryGetValue(type.FullName, out var trydc)) return new (NpgsqlDbType, string, string, bool?, object)?((trydc.type, trydc.dbtype, trydc.dbtypeFull, trydc.isnullable, trydc.defaultValue));
 | 
					            if (_dicCsToDb.TryGetValue(type.FullName, out var trydc)) return trydc;
 | 
				
			||||||
            if (type.IsArray) return null;
 | 
					            if (type.IsArray) return null;
 | 
				
			||||||
            var enumType = type.IsEnum ? type : null;
 | 
					            var enumType = type.IsEnum ? type : null;
 | 
				
			||||||
            if (enumType == null && type.IsNullableType() && type.GenericTypeArguments.Length == 1 && type.GenericTypeArguments.First().IsEnum) enumType = type.GenericTypeArguments.First();
 | 
					            if (enumType == null && type.IsNullableType() && type.GenericTypeArguments.Length == 1 && type.GenericTypeArguments.First().IsEnum) enumType = type.GenericTypeArguments.First();
 | 
				
			||||||
            if (enumType != null)
 | 
					            if (enumType != null)
 | 
				
			||||||
            {
 | 
					            {
 | 
				
			||||||
                var newItem = enumType.GetCustomAttributes(typeof(FlagsAttribute), false).Any() ?
 | 
					                var newItem = enumType.GetCustomAttributes(typeof(FlagsAttribute), false).Any() ?
 | 
				
			||||||
                    (NpgsqlDbType.Bigint, "int8", $"int8{(type.IsEnum ? " NOT NULL" : "")}", false, type.IsEnum ? false : true, Enum.GetValues(enumType).GetValue(0)) :
 | 
					                    CsToDb.New(NpgsqlDbType.Bigint, "int8", $"int8{(type.IsEnum ? " NOT NULL" : "")}", false, type.IsEnum ? false : true, Enum.GetValues(enumType).GetValue(0)) :
 | 
				
			||||||
                    (NpgsqlDbType.Integer, "int4", $"int4{(type.IsEnum ? " NOT NULL" : "")}", false, type.IsEnum ? false : true, Enum.GetValues(enumType).GetValue(0));
 | 
					                    CsToDb.New(NpgsqlDbType.Integer, "int4", $"int4{(type.IsEnum ? " NOT NULL" : "")}", false, type.IsEnum ? false : true, Enum.GetValues(enumType).GetValue(0));
 | 
				
			||||||
                if (_dicCsToDb.ContainsKey(type.FullName) == false)
 | 
					                if (_dicCsToDb.ContainsKey(type.FullName) == false)
 | 
				
			||||||
                {
 | 
					                {
 | 
				
			||||||
                    lock (_dicCsToDbLock)
 | 
					                    lock (_dicCsToDbLock)
 | 
				
			||||||
@@ -109,12 +109,12 @@ namespace FreeSql.PostgreSQL
 | 
				
			|||||||
                            _dicCsToDb.Add(type.FullName, newItem);
 | 
					                            _dicCsToDb.Add(type.FullName, newItem);
 | 
				
			||||||
                    }
 | 
					                    }
 | 
				
			||||||
                }
 | 
					                }
 | 
				
			||||||
                return (newItem.Item1, newItem.Item2, newItem.Item3, newItem.Item5, newItem.Item6);
 | 
					                return newItem;
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
            return null;
 | 
					            return null;
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        protected override string GetComparisonDDLStatements(params (Type entityType, string tableName)[] objects)
 | 
					        protected override string GetComparisonDDLStatements(params TypeAndName[] objects)
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
            var sb = new StringBuilder();
 | 
					            var sb = new StringBuilder();
 | 
				
			||||||
            var seqcols = new List<(ColumnInfo, string[], bool)>(); //序列
 | 
					            var seqcols = new List<(ColumnInfo, string[], bool)>(); //序列
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -177,7 +177,7 @@ namespace FreeSql.PostgreSQL
 | 
				
			|||||||
                                if (objExp != null)
 | 
					                                if (objExp != null)
 | 
				
			||||||
                                {
 | 
					                                {
 | 
				
			||||||
                                    var dbinfo = _common._orm.CodeFirst.GetDbInfo(objExp.Type);
 | 
					                                    var dbinfo = _common._orm.CodeFirst.GetDbInfo(objExp.Type);
 | 
				
			||||||
                                    if (dbinfo.HasValue) args1 = $"{args1}::{dbinfo.Value.dbtype}";
 | 
					                                    if (dbinfo != null) args1 = $"{args1}::{dbinfo.dbtype}";
 | 
				
			||||||
                                }
 | 
					                                }
 | 
				
			||||||
                                return $"({left} @> {args1})";
 | 
					                                return $"({left} @> {args1})";
 | 
				
			||||||
                            case "Concat":
 | 
					                            case "Concat":
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -181,7 +181,7 @@ namespace FreeSql.PostgreSQL
 | 
				
			|||||||
                }
 | 
					                }
 | 
				
			||||||
                sb.Append("]");
 | 
					                sb.Append("]");
 | 
				
			||||||
                var dbinfo = _orm.CodeFirst.GetDbInfo(type);
 | 
					                var dbinfo = _orm.CodeFirst.GetDbInfo(type);
 | 
				
			||||||
                if (dbinfo.HasValue) sb.Append("::").Append(dbinfo.Value.dbtype);
 | 
					                if (dbinfo != null) sb.Append("::").Append(dbinfo.dbtype);
 | 
				
			||||||
                return sb.ToString();
 | 
					                return sb.ToString();
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
            else if (type2 == typeof(BitArray))
 | 
					            else if (type2 == typeof(BitArray))
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -15,36 +15,36 @@ namespace FreeSql.SqlServer
 | 
				
			|||||||
        public SqlServerCodeFirst(IFreeSql orm, CommonUtils commonUtils, CommonExpression commonExpression) : base(orm, commonUtils, commonExpression) { }
 | 
					        public SqlServerCodeFirst(IFreeSql orm, CommonUtils commonUtils, CommonExpression commonExpression) : base(orm, commonUtils, commonExpression) { }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        static object _dicCsToDbLock = new object();
 | 
					        static object _dicCsToDbLock = new object();
 | 
				
			||||||
        static Dictionary<string, (SqlDbType type, string dbtype, string dbtypeFull, bool? isUnsigned, bool? isnullable, object defaultValue)> _dicCsToDb = new Dictionary<string, (SqlDbType type, string dbtype, string dbtypeFull, bool? isUnsigned, bool? isnullable, object defaultValue)>() {
 | 
					        static Dictionary<string, CsToDb<SqlDbType>> _dicCsToDb = new Dictionary<string, CsToDb<SqlDbType>>() {
 | 
				
			||||||
                { typeof(bool).FullName,  (SqlDbType.Bit, "bit","bit NOT NULL", null, false, false) },{ typeof(bool?).FullName,  (SqlDbType.Bit, "bit","bit", null, true, null) },
 | 
					                { typeof(bool).FullName, CsToDb.New(SqlDbType.Bit, "bit","bit NOT NULL", null, false, false) },{ typeof(bool?).FullName, CsToDb.New(SqlDbType.Bit, "bit","bit", null, true, null) },
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                { typeof(sbyte).FullName,  (SqlDbType.SmallInt, "smallint", "smallint NOT NULL", false, false, 0) },{ typeof(sbyte?).FullName,  (SqlDbType.SmallInt, "smallint", "smallint", false, true, null) },
 | 
					                { typeof(sbyte).FullName, CsToDb.New(SqlDbType.SmallInt, "smallint", "smallint NOT NULL", false, false, 0) },{ typeof(sbyte?).FullName, CsToDb.New(SqlDbType.SmallInt, "smallint", "smallint", false, true, null) },
 | 
				
			||||||
                { typeof(short).FullName,  (SqlDbType.SmallInt, "smallint","smallint NOT NULL", false, false, 0) },{ typeof(short?).FullName,  (SqlDbType.SmallInt, "smallint", "smallint", false, true, null) },
 | 
					                { typeof(short).FullName, CsToDb.New(SqlDbType.SmallInt, "smallint","smallint NOT NULL", false, false, 0) },{ typeof(short?).FullName, CsToDb.New(SqlDbType.SmallInt, "smallint", "smallint", false, true, null) },
 | 
				
			||||||
                { typeof(int).FullName,  (SqlDbType.Int, "int", "int NOT NULL", false, false, 0) },{ typeof(int?).FullName,  (SqlDbType.Int, "int", "int", false, true, null) },
 | 
					                { typeof(int).FullName, CsToDb.New(SqlDbType.Int, "int", "int NOT NULL", false, false, 0) },{ typeof(int?).FullName, CsToDb.New(SqlDbType.Int, "int", "int", false, true, null) },
 | 
				
			||||||
                { typeof(long).FullName,  (SqlDbType.BigInt, "bigint","bigint NOT NULL", false, false, 0) },{ typeof(long?).FullName,  (SqlDbType.BigInt, "bigint","bigint", false, true, null) },
 | 
					                { typeof(long).FullName, CsToDb.New(SqlDbType.BigInt, "bigint","bigint NOT NULL", false, false, 0) },{ typeof(long?).FullName, CsToDb.New(SqlDbType.BigInt, "bigint","bigint", false, true, null) },
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                { typeof(byte).FullName,  (SqlDbType.TinyInt, "tinyint","tinyint NOT NULL", true, false, 0) },{ typeof(byte?).FullName,  (SqlDbType.TinyInt, "tinyint","tinyint", true, true, null) },
 | 
					                { typeof(byte).FullName, CsToDb.New(SqlDbType.TinyInt, "tinyint","tinyint NOT NULL", true, false, 0) },{ typeof(byte?).FullName, CsToDb.New(SqlDbType.TinyInt, "tinyint","tinyint", true, true, null) },
 | 
				
			||||||
                { typeof(ushort).FullName,  (SqlDbType.Int, "int","int NOT NULL", true, false, 0) },{ typeof(ushort?).FullName,  (SqlDbType.Int, "int", "int", true, true, null) },
 | 
					                { typeof(ushort).FullName, CsToDb.New(SqlDbType.Int, "int","int NOT NULL", true, false, 0) },{ typeof(ushort?).FullName, CsToDb.New(SqlDbType.Int, "int", "int", true, true, null) },
 | 
				
			||||||
                { typeof(uint).FullName,  (SqlDbType.BigInt, "bigint", "bigint NOT NULL", true, false, 0) },{ typeof(uint?).FullName,  (SqlDbType.BigInt, "bigint", "bigint", true, true, null) },
 | 
					                { typeof(uint).FullName, CsToDb.New(SqlDbType.BigInt, "bigint", "bigint NOT NULL", true, false, 0) },{ typeof(uint?).FullName, CsToDb.New(SqlDbType.BigInt, "bigint", "bigint", true, true, null) },
 | 
				
			||||||
                { typeof(ulong).FullName,  (SqlDbType.Decimal, "decimal", "decimal(20,0) NOT NULL", true, false, 0) },{ typeof(ulong?).FullName,  (SqlDbType.Decimal, "decimal", "decimal(20,0)", true, true, null) },
 | 
					                { typeof(ulong).FullName, CsToDb.New(SqlDbType.Decimal, "decimal", "decimal(20,0) NOT NULL", true, false, 0) },{ typeof(ulong?).FullName, CsToDb.New(SqlDbType.Decimal, "decimal", "decimal(20,0)", true, true, null) },
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                { typeof(double).FullName,  (SqlDbType.Float, "float", "float NOT NULL", false, false, 0) },{ typeof(double?).FullName,  (SqlDbType.Float, "float", "float", false, true, null) },
 | 
					                { typeof(double).FullName, CsToDb.New(SqlDbType.Float, "float", "float NOT NULL", false, false, 0) },{ typeof(double?).FullName, CsToDb.New(SqlDbType.Float, "float", "float", false, true, null) },
 | 
				
			||||||
                { typeof(float).FullName,  (SqlDbType.Real, "real","real NOT NULL", false, false, 0) },{ typeof(float?).FullName,  (SqlDbType.Real, "real","real", false, true, null) },
 | 
					                { typeof(float).FullName, CsToDb.New(SqlDbType.Real, "real","real NOT NULL", false, false, 0) },{ typeof(float?).FullName, CsToDb.New(SqlDbType.Real, "real","real", false, true, null) },
 | 
				
			||||||
                { typeof(decimal).FullName,  (SqlDbType.Decimal, "decimal", "decimal(10,2) NOT NULL", false, false, 0) },{ typeof(decimal?).FullName,  (SqlDbType.Decimal, "decimal", "decimal(10,2)", false, true, null) },
 | 
					                { typeof(decimal).FullName, CsToDb.New(SqlDbType.Decimal, "decimal", "decimal(10,2) NOT NULL", false, false, 0) },{ typeof(decimal?).FullName, CsToDb.New(SqlDbType.Decimal, "decimal", "decimal(10,2)", false, true, null) },
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                { typeof(TimeSpan).FullName,  (SqlDbType.Time, "time","time NOT NULL", false, false, 0) },{ typeof(TimeSpan?).FullName,  (SqlDbType.Time, "time", "time",false, true, null) },
 | 
					                { typeof(TimeSpan).FullName, CsToDb.New(SqlDbType.Time, "time","time NOT NULL", false, false, 0) },{ typeof(TimeSpan?).FullName, CsToDb.New(SqlDbType.Time, "time", "time",false, true, null) },
 | 
				
			||||||
                { typeof(DateTime).FullName,  (SqlDbType.DateTime, "datetime", "datetime NOT NULL", false, false, new DateTime(1970,1,1)) },{ typeof(DateTime?).FullName,  (SqlDbType.DateTime, "datetime", "datetime", false, true, null) },
 | 
					                { typeof(DateTime).FullName, CsToDb.New(SqlDbType.DateTime, "datetime", "datetime NOT NULL", false, false, new DateTime(1970,1,1)) },{ typeof(DateTime?).FullName, CsToDb.New(SqlDbType.DateTime, "datetime", "datetime", false, true, null) },
 | 
				
			||||||
                { typeof(DateTimeOffset).FullName,  (SqlDbType.DateTimeOffset, "datetimeoffset", "datetimeoffset NOT NULL", false, false, new DateTimeOffset(new DateTime(1970,1,1), TimeSpan.Zero)) },{ typeof(DateTimeOffset?).FullName,  (SqlDbType.DateTimeOffset, "datetimeoffset", "datetimeoffset", false, true, null) },
 | 
					                { typeof(DateTimeOffset).FullName, CsToDb.New(SqlDbType.DateTimeOffset, "datetimeoffset", "datetimeoffset NOT NULL", false, false, new DateTimeOffset(new DateTime(1970,1,1), TimeSpan.Zero)) },{ typeof(DateTimeOffset?).FullName, CsToDb.New(SqlDbType.DateTimeOffset, "datetimeoffset", "datetimeoffset", false, true, null) },
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                { typeof(byte[]).FullName,  (SqlDbType.VarBinary, "varbinary", "varbinary(255)", false, null, new byte[0]) },
 | 
					                { typeof(byte[]).FullName, CsToDb.New(SqlDbType.VarBinary, "varbinary", "varbinary(255)", false, null, new byte[0]) },
 | 
				
			||||||
                { typeof(string).FullName,  (SqlDbType.NVarChar, "nvarchar", "nvarchar(255)", false, null, "") },
 | 
					                { typeof(string).FullName, CsToDb.New(SqlDbType.NVarChar, "nvarchar", "nvarchar(255)", false, null, "") },
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                { typeof(Guid).FullName,  (SqlDbType.UniqueIdentifier, "uniqueidentifier", "uniqueidentifier NOT NULL", false, false, Guid.Empty) },{ typeof(Guid?).FullName,  (SqlDbType.UniqueIdentifier, "uniqueidentifier", "uniqueidentifier", false, true, null) },
 | 
					                { typeof(Guid).FullName, CsToDb.New(SqlDbType.UniqueIdentifier, "uniqueidentifier", "uniqueidentifier NOT NULL", false, false, Guid.Empty) },{ typeof(Guid?).FullName, CsToDb.New(SqlDbType.UniqueIdentifier, "uniqueidentifier", "uniqueidentifier", false, true, null) },
 | 
				
			||||||
            };
 | 
					            };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        public override (int type, string dbtype, string dbtypeFull, bool? isnullable, object defaultValue)? GetDbInfo(Type type)
 | 
					        public override DbInfoResult 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 (_dicCsToDb.TryGetValue(type.FullName, out var trydc)) return new DbInfoResult((int)trydc.type, trydc.dbtype, trydc.dbtypeFull, trydc.isnullable, trydc.defaultValue);
 | 
				
			||||||
            if (type.IsArray) return null;
 | 
					            if (type.IsArray) return null;
 | 
				
			||||||
            var enumType = type.IsEnum ? type : null;
 | 
					            var enumType = type.IsEnum ? type : null;
 | 
				
			||||||
            if (enumType == null && type.IsNullableType())
 | 
					            if (enumType == null && type.IsNullableType())
 | 
				
			||||||
@@ -55,8 +55,8 @@ namespace FreeSql.SqlServer
 | 
				
			|||||||
            if (enumType != null)
 | 
					            if (enumType != null)
 | 
				
			||||||
            {
 | 
					            {
 | 
				
			||||||
                var newItem = enumType.GetCustomAttributes(typeof(FlagsAttribute), false).Any() ?
 | 
					                var newItem = enumType.GetCustomAttributes(typeof(FlagsAttribute), false).Any() ?
 | 
				
			||||||
                    (SqlDbType.BigInt, "bigint", $"bigint{(type.IsEnum ? " NOT NULL" : "")}", false, type.IsEnum ? false : true, Enum.GetValues(enumType).GetValue(0)) :
 | 
					                    CsToDb.New(SqlDbType.BigInt, "bigint", $"bigint{(type.IsEnum ? " NOT NULL" : "")}", false, type.IsEnum ? false : true, Enum.GetValues(enumType).GetValue(0)) :
 | 
				
			||||||
                    (SqlDbType.Int, "int", $"int{(type.IsEnum ? " NOT NULL" : "")}", false, type.IsEnum ? false : true, Enum.GetValues(enumType).GetValue(0));
 | 
					                    CsToDb.New(SqlDbType.Int, "int", $"int{(type.IsEnum ? " NOT NULL" : "")}", false, type.IsEnum ? false : true, Enum.GetValues(enumType).GetValue(0));
 | 
				
			||||||
                if (_dicCsToDb.ContainsKey(type.FullName) == false)
 | 
					                if (_dicCsToDb.ContainsKey(type.FullName) == false)
 | 
				
			||||||
                {
 | 
					                {
 | 
				
			||||||
                    lock (_dicCsToDbLock)
 | 
					                    lock (_dicCsToDbLock)
 | 
				
			||||||
@@ -65,7 +65,7 @@ namespace FreeSql.SqlServer
 | 
				
			|||||||
                            _dicCsToDb.Add(type.FullName, newItem);
 | 
					                            _dicCsToDb.Add(type.FullName, newItem);
 | 
				
			||||||
                    }
 | 
					                    }
 | 
				
			||||||
                }
 | 
					                }
 | 
				
			||||||
                return ((int)newItem.Item1, newItem.Item2, newItem.Item3, newItem.Item5, newItem.Item6);
 | 
					                return new DbInfoResult((int)newItem.type, newItem.dbtype, newItem.dbtypeFull, newItem.isnullable, newItem.defaultValue);
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
            return null;
 | 
					            return null;
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
@@ -102,7 +102,7 @@ ELSE
 | 
				
			|||||||
    , @level2type = 'COLUMN', @level2name = N'{2}'
 | 
					    , @level2type = 'COLUMN', @level2name = N'{2}'
 | 
				
			||||||
", schema.Replace("'", "''"), table.Replace("'", "''"), column.Replace("'", "''"), comment?.Replace("'", "''") ?? "");
 | 
					", schema.Replace("'", "''"), table.Replace("'", "''"), column.Replace("'", "''"), comment?.Replace("'", "''") ?? "");
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
        protected override string GetComparisonDDLStatements(params (Type entityType, string tableName)[] objects)
 | 
					        protected override string GetComparisonDDLStatements(params TypeAndName[] objects)
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
            var conn = _orm.Ado.MasterPool.Get(TimeSpan.FromSeconds(5));
 | 
					            var conn = _orm.Ado.MasterPool.Get(TimeSpan.FromSeconds(5));
 | 
				
			||||||
            string database = null;
 | 
					            string database = null;
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,5 +1,6 @@
 | 
				
			|||||||
using FreeSql.DatabaseModel;
 | 
					using FreeSql.DatabaseModel;
 | 
				
			||||||
using FreeSql.Internal;
 | 
					using FreeSql.Internal;
 | 
				
			||||||
 | 
					using FreeSql.Internal.Model;
 | 
				
			||||||
using System;
 | 
					using System;
 | 
				
			||||||
using System.Collections.Generic;
 | 
					using System.Collections.Generic;
 | 
				
			||||||
using System.Data;
 | 
					using System.Data;
 | 
				
			||||||
@@ -58,40 +59,40 @@ namespace FreeSql.SqlServer
 | 
				
			|||||||
            }
 | 
					            }
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        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, DbToCs> _dicDbToCs = new Dictionary<int, DbToCs>() {
 | 
				
			||||||
                { (int)SqlDbType.Bit, ("(bool?)", "{0} == \"1\"", "{0} == true ? \"1\" : \"0\"", "bool?", typeof(bool), typeof(bool?), "{0}.Value", "GetBoolean") },
 | 
					                { (int)SqlDbType.Bit, new DbToCs("(bool?)", "{0} == \"1\"", "{0} == true ? \"1\" : \"0\"", "bool?", typeof(bool), typeof(bool?), "{0}.Value", "GetBoolean") },
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                { (int)SqlDbType.TinyInt, ("(byte?)", "byte.Parse({0})", "{0}.ToString()", "byte?", typeof(byte), typeof(byte?), "{0}.Value", "GetByte") },
 | 
					                { (int)SqlDbType.TinyInt, new DbToCs("(byte?)", "byte.Parse({0})", "{0}.ToString()", "byte?", typeof(byte), typeof(byte?), "{0}.Value", "GetByte") },
 | 
				
			||||||
                { (int)SqlDbType.SmallInt, ("(short?)", "short.Parse({0})", "{0}.ToString()", "short?", typeof(short), typeof(short?), "{0}.Value", "GetInt16") },
 | 
					                { (int)SqlDbType.SmallInt, new DbToCs("(short?)", "short.Parse({0})", "{0}.ToString()", "short?", typeof(short), typeof(short?), "{0}.Value", "GetInt16") },
 | 
				
			||||||
                { (int)SqlDbType.Int, ("(int?)", "int.Parse({0})", "{0}.ToString()", "int?", typeof(int), typeof(int?), "{0}.Value", "GetInt32") },
 | 
					                { (int)SqlDbType.Int, new DbToCs("(int?)", "int.Parse({0})", "{0}.ToString()", "int?", typeof(int), typeof(int?), "{0}.Value", "GetInt32") },
 | 
				
			||||||
                { (int)SqlDbType.BigInt, ("(long?)", "long.Parse({0})", "{0}.ToString()", "long?", typeof(long), typeof(long?), "{0}.Value", "GetInt64") },
 | 
					                { (int)SqlDbType.BigInt, new DbToCs("(long?)", "long.Parse({0})", "{0}.ToString()", "long?", typeof(long), typeof(long?), "{0}.Value", "GetInt64") },
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                { (int)SqlDbType.SmallMoney, ("(decimal?)", "decimal.Parse({0})", "{0}.ToString()", "decimal?", typeof(decimal), typeof(decimal?), "{0}.Value", "GetDecimal") },
 | 
					                { (int)SqlDbType.SmallMoney, new DbToCs("(decimal?)", "decimal.Parse({0})", "{0}.ToString()", "decimal?", typeof(decimal), typeof(decimal?), "{0}.Value", "GetDecimal") },
 | 
				
			||||||
                { (int)SqlDbType.Money, ("(decimal?)", "decimal.Parse({0})", "{0}.ToString()", "decimal?", typeof(decimal), typeof(decimal?), "{0}.Value", "GetDecimal") },
 | 
					                { (int)SqlDbType.Money, new DbToCs("(decimal?)", "decimal.Parse({0})", "{0}.ToString()", "decimal?", typeof(decimal), typeof(decimal?), "{0}.Value", "GetDecimal") },
 | 
				
			||||||
                { (int)SqlDbType.Decimal, ("(decimal?)", "decimal.Parse({0})", "{0}.ToString()", "decimal?", typeof(decimal), typeof(decimal?), "{0}.Value", "GetDecimal") },
 | 
					                { (int)SqlDbType.Decimal, new DbToCs("(decimal?)", "decimal.Parse({0})", "{0}.ToString()", "decimal?", typeof(decimal), typeof(decimal?), "{0}.Value", "GetDecimal") },
 | 
				
			||||||
                { (int)SqlDbType.Float, ("(double?)", "double.Parse({0})", "{0}.ToString()", "double?", typeof(double), typeof(double?), "{0}.Value", "GetDouble") },
 | 
					                { (int)SqlDbType.Float, new DbToCs("(double?)", "double.Parse({0})", "{0}.ToString()", "double?", typeof(double), typeof(double?), "{0}.Value", "GetDouble") },
 | 
				
			||||||
                { (int)SqlDbType.Real, ("(float?)", "float.Parse({0})", "{0}.ToString()", "float?", typeof(float), typeof(float?), "{0}.Value", "GetFloat") },
 | 
					                { (int)SqlDbType.Real, new DbToCs("(float?)", "float.Parse({0})", "{0}.ToString()", "float?", typeof(float), typeof(float?), "{0}.Value", "GetFloat") },
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                { (int)SqlDbType.Time, ("(TimeSpan?)", "TimeSpan.Parse(double.Parse({0}))", "{0}.Ticks.ToString()", "TimeSpan?", typeof(TimeSpan), typeof(TimeSpan?), "{0}.Value", "GetValue") },
 | 
					                { (int)SqlDbType.Time, new DbToCs("(TimeSpan?)", "TimeSpan.Parse(double.Parse({0}))", "{0}.Ticks.ToString()", "TimeSpan?", typeof(TimeSpan), typeof(TimeSpan?), "{0}.Value", "GetValue") },
 | 
				
			||||||
                { (int)SqlDbType.Date, ("(DateTime?)", "new DateTime(long.Parse({0}))", "{0}.Ticks.ToString()", "DateTime?", typeof(DateTime), typeof(DateTime?), "{0}.Value", "GetDateTime") },
 | 
					                { (int)SqlDbType.Date, new DbToCs("(DateTime?)", "new DateTime(long.Parse({0}))", "{0}.Ticks.ToString()", "DateTime?", typeof(DateTime), typeof(DateTime?), "{0}.Value", "GetDateTime") },
 | 
				
			||||||
                { (int)SqlDbType.DateTime, ("(DateTime?)", "new DateTime(long.Parse({0}))", "{0}.Ticks.ToString()", "DateTime?", typeof(DateTime), typeof(DateTime?), "{0}.Value", "GetDateTime") },
 | 
					                { (int)SqlDbType.DateTime, new DbToCs("(DateTime?)", "new DateTime(long.Parse({0}))", "{0}.Ticks.ToString()", "DateTime?", typeof(DateTime), typeof(DateTime?), "{0}.Value", "GetDateTime") },
 | 
				
			||||||
                { (int)SqlDbType.DateTime2, ("(DateTime?)", "new DateTime(long.Parse({0}))", "{0}.Ticks.ToString()", "DateTime?", typeof(DateTime), typeof(DateTime?), "{0}.Value", "GetDateTime") },
 | 
					                { (int)SqlDbType.DateTime2, new DbToCs("(DateTime?)", "new DateTime(long.Parse({0}))", "{0}.Ticks.ToString()", "DateTime?", typeof(DateTime), typeof(DateTime?), "{0}.Value", "GetDateTime") },
 | 
				
			||||||
                { (int)SqlDbType.SmallDateTime, ("(DateTime?)", "new DateTime(long.Parse({0}))", "{0}.Ticks.ToString()", "DateTime?", typeof(DateTime), typeof(DateTime?), "{0}.Value", "GetDateTime") },
 | 
					                { (int)SqlDbType.SmallDateTime, new DbToCs("(DateTime?)", "new DateTime(long.Parse({0}))", "{0}.Ticks.ToString()", "DateTime?", typeof(DateTime), typeof(DateTime?), "{0}.Value", "GetDateTime") },
 | 
				
			||||||
                { (int)SqlDbType.DateTimeOffset, ("(DateTimeOffset?)", "new DateTimeOffset(long.Parse({0}))", "{0}.Ticks.ToString()", "DateTime?", typeof(DateTimeOffset), typeof(DateTimeOffset?), "{0}.Value", "GetDateTimeOffset") },
 | 
					                { (int)SqlDbType.DateTimeOffset, new DbToCs("(DateTimeOffset?)", "new DateTimeOffset(long.Parse({0}))", "{0}.Ticks.ToString()", "DateTime?", typeof(DateTimeOffset), typeof(DateTimeOffset?), "{0}.Value", "GetDateTimeOffset") },
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                { (int)SqlDbType.Binary, ("(byte[])", "Convert.FromBase64String({0})", "Convert.ToBase64String({0})", "byte[]", typeof(byte[]), typeof(byte[]), "{0}", "GetValue") },
 | 
					                { (int)SqlDbType.Binary, new DbToCs("(byte[])", "Convert.FromBase64String({0})", "Convert.ToBase64String({0})", "byte[]", typeof(byte[]), typeof(byte[]), "{0}", "GetValue") },
 | 
				
			||||||
                { (int)SqlDbType.VarBinary, ("(byte[])", "Convert.FromBase64String({0})", "Convert.ToBase64String({0})", "byte[]", typeof(byte[]), typeof(byte[]), "{0}", "GetValue") },
 | 
					                { (int)SqlDbType.VarBinary, new DbToCs("(byte[])", "Convert.FromBase64String({0})", "Convert.ToBase64String({0})", "byte[]", typeof(byte[]), typeof(byte[]), "{0}", "GetValue") },
 | 
				
			||||||
                { (int)SqlDbType.Image, ("(byte[])", "Convert.FromBase64String({0})", "Convert.ToBase64String({0})", "byte[]", typeof(byte[]), typeof(byte[]), "{0}", "GetValue") },
 | 
					                { (int)SqlDbType.Image, new DbToCs("(byte[])", "Convert.FromBase64String({0})", "Convert.ToBase64String({0})", "byte[]", typeof(byte[]), typeof(byte[]), "{0}", "GetValue") },
 | 
				
			||||||
                { (int)SqlDbType.Timestamp, ("(byte[])", "Convert.FromBase64String({0})", "Convert.ToBase64String({0})", "byte[]", typeof(byte[]), typeof(byte[]), "{0}", "GetValue") },
 | 
					                { (int)SqlDbType.Timestamp, new DbToCs("(byte[])", "Convert.FromBase64String({0})", "Convert.ToBase64String({0})", "byte[]", typeof(byte[]), typeof(byte[]), "{0}", "GetValue") },
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                { (int)SqlDbType.Char, ("", "{0}.Replace(StringifySplit, \"|\")", "{0}.Replace(\"|\", StringifySplit)", "string", typeof(string), typeof(string), "{0}", "GetString") },
 | 
					                { (int)SqlDbType.Char, new DbToCs("", "{0}.Replace(StringifySplit, \"|\")", "{0}.Replace(\"|\", StringifySplit)", "string", typeof(string), typeof(string), "{0}", "GetString") },
 | 
				
			||||||
                { (int)SqlDbType.VarChar, ("", "{0}.Replace(StringifySplit, \"|\")", "{0}.Replace(\"|\", StringifySplit)", "string", typeof(string), typeof(string), "{0}", "GetString") },
 | 
					                { (int)SqlDbType.VarChar, new DbToCs("", "{0}.Replace(StringifySplit, \"|\")", "{0}.Replace(\"|\", StringifySplit)", "string", typeof(string), typeof(string), "{0}", "GetString") },
 | 
				
			||||||
                { (int)SqlDbType.Text, ("", "{0}.Replace(StringifySplit, \"|\")", "{0}.Replace(\"|\", StringifySplit)", "string", typeof(string), typeof(string), "{0}", "GetString") },
 | 
					                { (int)SqlDbType.Text, new DbToCs("", "{0}.Replace(StringifySplit, \"|\")", "{0}.Replace(\"|\", StringifySplit)", "string", typeof(string), typeof(string), "{0}", "GetString") },
 | 
				
			||||||
                { (int)SqlDbType.NChar, ("", "{0}.Replace(StringifySplit, \"|\")", "{0}.Replace(\"|\", StringifySplit)", "string", typeof(string), typeof(string), "{0}", "GetString") },
 | 
					                { (int)SqlDbType.NChar, new DbToCs("", "{0}.Replace(StringifySplit, \"|\")", "{0}.Replace(\"|\", StringifySplit)", "string", typeof(string), typeof(string), "{0}", "GetString") },
 | 
				
			||||||
                { (int)SqlDbType.NVarChar, ("", "{0}.Replace(StringifySplit, \"|\")", "{0}.Replace(\"|\", StringifySplit)", "string", typeof(string), typeof(string), "{0}", "GetString") },
 | 
					                { (int)SqlDbType.NVarChar, new DbToCs("", "{0}.Replace(StringifySplit, \"|\")", "{0}.Replace(\"|\", StringifySplit)", "string", typeof(string), typeof(string), "{0}", "GetString") },
 | 
				
			||||||
                { (int)SqlDbType.NText, ("", "{0}.Replace(StringifySplit, \"|\")", "{0}.Replace(\"|\", StringifySplit)", "string", typeof(string), typeof(string), "{0}", "GetString") },
 | 
					                { (int)SqlDbType.NText, new DbToCs("", "{0}.Replace(StringifySplit, \"|\")", "{0}.Replace(\"|\", StringifySplit)", "string", typeof(string), typeof(string), "{0}", "GetString") },
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                { (int)SqlDbType.UniqueIdentifier, ("(Guid?)", "Guid.Parse({0})", "{0}.ToString()", "Guid?", typeof(Guid), typeof(Guid?), "{0}.Value", "GetGuid") },
 | 
					                { (int)SqlDbType.UniqueIdentifier, new DbToCs("(Guid?)", "Guid.Parse({0})", "{0}.ToString()", "Guid?", typeof(Guid), typeof(Guid?), "{0}.Value", "GetGuid") },
 | 
				
			||||||
            };
 | 
					            };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        public string GetCsConvert(DbColumnInfo column) => _dicDbToCs.TryGetValue(column.DbType, out var trydc) ? (column.IsNullable ? trydc.csConvert : trydc.csConvert.Replace("?", "")) : null;
 | 
					        public string GetCsConvert(DbColumnInfo column) => _dicDbToCs.TryGetValue(column.DbType, out var trydc) ? (column.IsNullable ? trydc.csConvert : trydc.csConvert.Replace("?", "")) : null;
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,4 +1,5 @@
 | 
				
			|||||||
using FreeSql;
 | 
					using FreeSql;
 | 
				
			||||||
 | 
					using FreeSql.Internal.Model;
 | 
				
			||||||
using System;
 | 
					using System;
 | 
				
			||||||
using System.Collections.Concurrent;
 | 
					using System.Collections.Concurrent;
 | 
				
			||||||
using System.Collections.Generic;
 | 
					using System.Collections.Generic;
 | 
				
			||||||
@@ -37,11 +38,11 @@ public static partial class FreeSqlSqlServerGlobalExtensions
 | 
				
			|||||||
    /// <param name="options"></param>
 | 
					    /// <param name="options"></param>
 | 
				
			||||||
    public static IFreeSql SetGlobalSelectWithLock(this IFreeSql that, SqlServerLock lockType, Dictionary<Type, bool> rule)
 | 
					    public static IFreeSql SetGlobalSelectWithLock(this IFreeSql that, SqlServerLock lockType, Dictionary<Type, bool> rule)
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
        var value = (lockType, rule);
 | 
					        var value = NaviteTuple.Create(lockType, rule);
 | 
				
			||||||
        _dicSetGlobalSelectWithLock.AddOrUpdate(that, value, (_, __) => value);
 | 
					        _dicSetGlobalSelectWithLock.AddOrUpdate(that, value, (_, __) => value);
 | 
				
			||||||
        return that;
 | 
					        return that;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    internal static ConcurrentDictionary<IFreeSql, (SqlServerLock, Dictionary<Type, bool>)> _dicSetGlobalSelectWithLock = new ConcurrentDictionary<IFreeSql, (SqlServerLock, Dictionary<Type, bool>)>();
 | 
					    internal static ConcurrentDictionary<IFreeSql, NaviteTuple<SqlServerLock, Dictionary<Type, bool>>> _dicSetGlobalSelectWithLock = new ConcurrentDictionary<IFreeSql, NaviteTuple<SqlServerLock, Dictionary<Type, bool>>>();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    #region ExecuteSqlBulkCopy
 | 
					    #region ExecuteSqlBulkCopy
 | 
				
			||||||
    /// <summary>
 | 
					    /// <summary>
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,4 +1,5 @@
 | 
				
			|||||||
using FreeSql.Internal;
 | 
					using FreeSql.Internal;
 | 
				
			||||||
 | 
					using FreeSql.Internal.Model;
 | 
				
			||||||
using System;
 | 
					using System;
 | 
				
			||||||
using System.Collections.Generic;
 | 
					using System.Collections.Generic;
 | 
				
			||||||
using System.Data;
 | 
					using System.Data;
 | 
				
			||||||
@@ -15,35 +16,35 @@ namespace FreeSql.Sqlite
 | 
				
			|||||||
        public SqliteCodeFirst(IFreeSql orm, CommonUtils commonUtils, CommonExpression commonExpression) : base(orm, commonUtils, commonExpression) { }
 | 
					        public SqliteCodeFirst(IFreeSql orm, CommonUtils commonUtils, CommonExpression commonExpression) : base(orm, commonUtils, commonExpression) { }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        static object _dicCsToDbLock = new object();
 | 
					        static object _dicCsToDbLock = new object();
 | 
				
			||||||
        static Dictionary<string, (DbType type, string dbtype, string dbtypeFull, bool? isUnsigned, bool? isnullable, object defaultValue)> _dicCsToDb = new Dictionary<string, (DbType type, string dbtype, string dbtypeFull, bool? isUnsigned, bool? isnullable, object defaultValue)>() {
 | 
					        static Dictionary<string, CsToDb<DbType>> _dicCsToDb = new Dictionary<string, CsToDb<DbType>>() {
 | 
				
			||||||
                { typeof(bool).FullName,  (DbType.Boolean, "boolean","boolean NOT NULL", null, false, false) },{ typeof(bool?).FullName,  (DbType.Boolean, "boolean","boolean", null, true, null) },
 | 
					                { typeof(bool).FullName, CsToDb.New(DbType.Boolean, "boolean","boolean NOT NULL", null, false, false) },{ typeof(bool?).FullName, CsToDb.New(DbType.Boolean, "boolean","boolean", null, true, null) },
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                { typeof(sbyte).FullName,  (DbType.SByte, "smallint", "smallint NOT NULL", false, false, 0) },{ typeof(sbyte?).FullName,  (DbType.SByte, "smallint", "smallint", false, true, null) },
 | 
					                { typeof(sbyte).FullName, CsToDb.New(DbType.SByte, "smallint", "smallint NOT NULL", false, false, 0) },{ typeof(sbyte?).FullName, CsToDb.New(DbType.SByte, "smallint", "smallint", false, true, null) },
 | 
				
			||||||
                { typeof(short).FullName,  (DbType.Int16, "smallint","smallint NOT NULL", false, false, 0) },{ typeof(short?).FullName,  (DbType.Int16, "smallint", "smallint", false, true, null) },
 | 
					                { typeof(short).FullName, CsToDb.New(DbType.Int16, "smallint","smallint NOT NULL", false, false, 0) },{ typeof(short?).FullName, CsToDb.New(DbType.Int16, "smallint", "smallint", false, true, null) },
 | 
				
			||||||
                { typeof(int).FullName,  (DbType.Int32, "integer", "integer NOT NULL", false, false, 0) },{ typeof(int?).FullName,  (DbType.Int32, "integer", "integer", false, true, null) },
 | 
					                { typeof(int).FullName, CsToDb.New(DbType.Int32, "integer", "integer NOT NULL", false, false, 0) },{ typeof(int?).FullName, CsToDb.New(DbType.Int32, "integer", "integer", false, true, null) },
 | 
				
			||||||
                { typeof(long).FullName,  (DbType.Int64, "integer","integer NOT NULL", false, false, 0) },{ typeof(long?).FullName,  (DbType.Int64, "integer","integer", false, true, null) },
 | 
					                { typeof(long).FullName, CsToDb.New(DbType.Int64, "integer","integer NOT NULL", false, false, 0) },{ typeof(long?).FullName, CsToDb.New(DbType.Int64, "integer","integer", false, true, null) },
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                { typeof(byte).FullName,  (DbType.Byte, "int2","int2 NOT NULL", true, false, 0) },{ typeof(byte?).FullName,  (DbType.Byte, "int2","int2", true, true, null) },
 | 
					                { typeof(byte).FullName, CsToDb.New(DbType.Byte, "int2","int2 NOT NULL", true, false, 0) },{ typeof(byte?).FullName, CsToDb.New(DbType.Byte, "int2","int2", true, true, null) },
 | 
				
			||||||
                { typeof(ushort).FullName,  (DbType.UInt16, "unsigned","unsigned NOT NULL", true, false, 0) },{ typeof(ushort?).FullName,  (DbType.UInt16, "unsigned", "unsigned", true, true, null) },
 | 
					                { typeof(ushort).FullName, CsToDb.New(DbType.UInt16, "unsigned","unsigned NOT NULL", true, false, 0) },{ typeof(ushort?).FullName, CsToDb.New(DbType.UInt16, "unsigned", "unsigned", true, true, null) },
 | 
				
			||||||
                { typeof(uint).FullName,  (DbType.Decimal, "decimal(10,0)", "decimal(10,0) NOT NULL", true, false, 0) },{ typeof(uint?).FullName,  (DbType.Decimal, "decimal(10,0)", "decimal(10,0)", true, true, null) },
 | 
					                { typeof(uint).FullName, CsToDb.New(DbType.Decimal, "decimal(10,0)", "decimal(10,0) NOT NULL", true, false, 0) },{ typeof(uint?).FullName, CsToDb.New(DbType.Decimal, "decimal(10,0)", "decimal(10,0)", true, true, null) },
 | 
				
			||||||
                { typeof(ulong).FullName,  (DbType.Decimal, "decimal(21,0)", "decimal(21,0) NOT NULL", true, false, 0) },{ typeof(ulong?).FullName,  (DbType.Decimal, "decimal(21,0)", "decimal(21,0)", true, true, null) },
 | 
					                { typeof(ulong).FullName, CsToDb.New(DbType.Decimal, "decimal(21,0)", "decimal(21,0) NOT NULL", true, false, 0) },{ typeof(ulong?).FullName, CsToDb.New(DbType.Decimal, "decimal(21,0)", "decimal(21,0)", true, true, null) },
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                { typeof(double).FullName,  (DbType.Double, "double", "double NOT NULL", false, false, 0) },{ typeof(double?).FullName,  (DbType.Double, "double", "double", false, true, null) },
 | 
					                { typeof(double).FullName, CsToDb.New(DbType.Double, "double", "double NOT NULL", false, false, 0) },{ typeof(double?).FullName, CsToDb.New(DbType.Double, "double", "double", false, true, null) },
 | 
				
			||||||
                { typeof(float).FullName,  (DbType.Single, "float","float NOT NULL", false, false, 0) },{ typeof(float?).FullName,  (DbType.Single, "float","float", false, true, null) },
 | 
					                { typeof(float).FullName, CsToDb.New(DbType.Single, "float","float NOT NULL", false, false, 0) },{ typeof(float?).FullName, CsToDb.New(DbType.Single, "float","float", false, true, null) },
 | 
				
			||||||
                { typeof(decimal).FullName,  (DbType.Decimal, "decimal", "decimal(10,2) NOT NULL", false, false, 0) },{ typeof(decimal?).FullName,  (DbType.Decimal, "decimal", "decimal(10,2)", false, true, null) },
 | 
					                { typeof(decimal).FullName, CsToDb.New(DbType.Decimal, "decimal", "decimal(10,2) NOT NULL", false, false, 0) },{ typeof(decimal?).FullName, CsToDb.New(DbType.Decimal, "decimal", "decimal(10,2)", false, true, null) },
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                { typeof(TimeSpan).FullName,  (DbType.Time, "bigint","bigint NOT NULL", false, false, 0) },{ typeof(TimeSpan?).FullName,  (DbType.Time, "bigint", "bigint",false, true, null) },
 | 
					                { typeof(TimeSpan).FullName, CsToDb.New(DbType.Time, "bigint","bigint NOT NULL", false, false, 0) },{ typeof(TimeSpan?).FullName, CsToDb.New(DbType.Time, "bigint", "bigint",false, true, null) },
 | 
				
			||||||
                { typeof(DateTime).FullName,  (DbType.DateTime, "datetime", "datetime NOT NULL", false, false, new DateTime(1970,1,1)) },{ typeof(DateTime?).FullName,  (DbType.DateTime, "datetime", "datetime", false, true, null) },
 | 
					                { typeof(DateTime).FullName, CsToDb.New(DbType.DateTime, "datetime", "datetime NOT NULL", false, false, new DateTime(1970,1,1)) },{ typeof(DateTime?).FullName, CsToDb.New(DbType.DateTime, "datetime", "datetime", false, true, null) },
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                { typeof(byte[]).FullName,  (DbType.Binary, "blob", "blob", false, null, new byte[0]) },
 | 
					                { typeof(byte[]).FullName, CsToDb.New(DbType.Binary, "blob", "blob", false, null, new byte[0]) },
 | 
				
			||||||
                { typeof(string).FullName,  (DbType.String, "nvarchar", "nvarchar(255)", false, null, "") },
 | 
					                { typeof(string).FullName, CsToDb.New(DbType.String, "nvarchar", "nvarchar(255)", false, null, "") },
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                { typeof(Guid).FullName,  (DbType.Guid, "character", "character(36) NOT NULL", false, false, Guid.Empty) },{ typeof(Guid?).FullName,  (DbType.Guid, "character", "character(36)", false, true, null) },
 | 
					                { typeof(Guid).FullName, CsToDb.New(DbType.Guid, "character", "character(36) NOT NULL", false, false, Guid.Empty) },{ typeof(Guid?).FullName, CsToDb.New(DbType.Guid, "character", "character(36)", false, true, null) },
 | 
				
			||||||
            };
 | 
					            };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        public override (int type, string dbtype, string dbtypeFull, bool? isnullable, object defaultValue)? GetDbInfo(Type type)
 | 
					        public override DbInfoResult 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 (_dicCsToDb.TryGetValue(type.FullName, out var trydc)) return new DbInfoResult((int)trydc.type, trydc.dbtype, trydc.dbtypeFull, trydc.isnullable, trydc.defaultValue);
 | 
				
			||||||
            if (type.IsArray) return null;
 | 
					            if (type.IsArray) return null;
 | 
				
			||||||
            var enumType = type.IsEnum ? type : null;
 | 
					            var enumType = type.IsEnum ? type : null;
 | 
				
			||||||
            if (enumType == null && type.IsNullableType())
 | 
					            if (enumType == null && type.IsNullableType())
 | 
				
			||||||
@@ -54,8 +55,8 @@ namespace FreeSql.Sqlite
 | 
				
			|||||||
            if (enumType != null)
 | 
					            if (enumType != null)
 | 
				
			||||||
            {
 | 
					            {
 | 
				
			||||||
                var newItem = enumType.GetCustomAttributes(typeof(FlagsAttribute), false).Any() ?
 | 
					                var newItem = enumType.GetCustomAttributes(typeof(FlagsAttribute), false).Any() ?
 | 
				
			||||||
                    (DbType.Int64, "bigint", $"bigint{(type.IsEnum ? " NOT NULL" : "")}", false, type.IsEnum ? false : true, Enum.GetValues(enumType).GetValue(0)) :
 | 
					                    CsToDb.New(DbType.Int64, "bigint", $"bigint{(type.IsEnum ? " NOT NULL" : "")}", false, type.IsEnum ? false : true, Enum.GetValues(enumType).GetValue(0)) :
 | 
				
			||||||
                    (DbType.Int32, "mediumint", $"mediumint{(type.IsEnum ? " NOT NULL" : "")}", false, type.IsEnum ? false : true, Enum.GetValues(enumType).GetValue(0));
 | 
					                    CsToDb.New(DbType.Int32, "mediumint", $"mediumint{(type.IsEnum ? " NOT NULL" : "")}", false, type.IsEnum ? false : true, Enum.GetValues(enumType).GetValue(0));
 | 
				
			||||||
                if (_dicCsToDb.ContainsKey(type.FullName) == false)
 | 
					                if (_dicCsToDb.ContainsKey(type.FullName) == false)
 | 
				
			||||||
                {
 | 
					                {
 | 
				
			||||||
                    lock (_dicCsToDbLock)
 | 
					                    lock (_dicCsToDbLock)
 | 
				
			||||||
@@ -64,12 +65,12 @@ namespace FreeSql.Sqlite
 | 
				
			|||||||
                            _dicCsToDb.Add(type.FullName, newItem);
 | 
					                            _dicCsToDb.Add(type.FullName, newItem);
 | 
				
			||||||
                    }
 | 
					                    }
 | 
				
			||||||
                }
 | 
					                }
 | 
				
			||||||
                return ((int)newItem.Item1, newItem.Item2, newItem.Item3, newItem.Item5, newItem.Item6);
 | 
					                return new DbInfoResult((int)newItem.type, newItem.dbtype, newItem.dbtypeFull, newItem.isnullable, newItem.defaultValue);
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
            return null;
 | 
					            return null;
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        protected override string GetComparisonDDLStatements(params (Type entityType, string tableName)[] objects)
 | 
					        protected override string GetComparisonDDLStatements(params TypeAndName[] objects)
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
            var sb = new StringBuilder();
 | 
					            var sb = new StringBuilder();
 | 
				
			||||||
            var sbDeclare = new StringBuilder();
 | 
					            var sbDeclare = new StringBuilder();
 | 
				
			||||||
 
 | 
				
			|||||||
		Reference in New Issue
	
	Block a user