mirror of
https://github.com/nsnail/FreeSql.git
synced 2025-04-22 18:52:50 +08:00
- 修复 Oracle Dbfirst 字段可空的判断 bug;
This commit is contained in:
parent
cb074e7f0d
commit
76b613709e
@ -110,6 +110,13 @@
|
|||||||
清空状态数据
|
清空状态数据
|
||||||
</summary>
|
</summary>
|
||||||
</member>
|
</member>
|
||||||
|
<member name="M:FreeSql.DbSet`1.RemoveAsync(System.Linq.Expressions.Expression{System.Func{`0,System.Boolean}})">
|
||||||
|
<summary>
|
||||||
|
根据 lambda 条件删除数据
|
||||||
|
</summary>
|
||||||
|
<param name="predicate"></param>
|
||||||
|
<returns></returns>
|
||||||
|
</member>
|
||||||
<member name="M:FreeSql.DbSet`1.Add(`0)">
|
<member name="M:FreeSql.DbSet`1.Add(`0)">
|
||||||
<summary>
|
<summary>
|
||||||
添加
|
添加
|
||||||
|
@ -245,6 +245,8 @@ namespace FreeSql.Tests
|
|||||||
[Fact]
|
[Fact]
|
||||||
public void Test02()
|
public void Test02()
|
||||||
{
|
{
|
||||||
|
g.sqlite.Update<TestIgnoreDefaultValue>(Guid.Empty).Set(a => a.ct1 == a.ct2).ExecuteAffrows();
|
||||||
|
|
||||||
g.sqlite.Insert(new otot1 { name = "otot1_name1" }).ExecuteAffrows();
|
g.sqlite.Insert(new otot1 { name = "otot1_name1" }).ExecuteAffrows();
|
||||||
|
|
||||||
var otolst1 = g.sqlite.Select<otot1>()
|
var otolst1 = g.sqlite.Select<otot1>()
|
||||||
|
@ -2267,124 +2267,103 @@
|
|||||||
<member name="P:FreeSql.IAop.SyncStructureAfter">
|
<member name="P:FreeSql.IAop.SyncStructureAfter">
|
||||||
<summary>
|
<summary>
|
||||||
CodeFirst迁移,执行完成触发
|
CodeFirst迁移,执行完成触发
|
||||||
</summary>
|
</sum"P:FreeSql.ICodeFirst.IsNoneCommandParameter">
|
||||||
</member>
|
|
||||||
<member name="P:FreeSql.IAop.AuditValue">
|
|
||||||
<summary>
|
<summary>
|
||||||
Insert/Update自动值处理
|
不使用命令参数化执行,针对 Insert/Update
|
||||||
</summary>
|
</summary>
|
||||||
</member>
|
</member>
|
||||||
<member name="P:FreeSql.Aop.ParseExpressionEventArgs.FreeParse">
|
<member name="P:FreeSql.ICodeFirst.IsGenerateCommandParameterWithLambda">
|
||||||
<summary>
|
<summary>
|
||||||
内置解析功能,可辅助您进行解析
|
是否生成命令参数化执行,针对 lambda 表达式解析
|
||||||
</summary>
|
</summary>
|
||||||
</member>
|
</member>
|
||||||
<member name="P:FreeSql.Aop.ParseExpressionEventArgs.Expression">
|
<member name="P:FreeSql.ICodeFirst.IsLazyLoading">
|
||||||
<summary>
|
<summary>
|
||||||
需要您解析的表达式
|
延时加载导航属性对象,导航属性需要声明 virtual
|
||||||
</summary>
|
</summary>
|
||||||
</member>
|
</member>
|
||||||
<member name="P:FreeSql.Aop.ParseExpressionEventArgs.Result">
|
<member name="M:FreeSql.ICodeFirst.GetComparisonDDLStatements``1">
|
||||||
<summary>
|
<summary>
|
||||||
解析后的内容
|
将实体类型与数据库对比,返回DDL语句
|
||||||
</summary>
|
</summary>
|
||||||
|
<typeparam name="TEntity"></typeparam>
|
||||||
|
<returns></returns>
|
||||||
</member>
|
</member>
|
||||||
<member name="P:FreeSql.Aop.ConfigEntityEventArgs.EntityType">
|
<member name="M:FreeSql.ICodeFirst.GetComparisonDDLStatements(System.Type[])">
|
||||||
<summary>
|
<summary>
|
||||||
实体类型
|
将实体类型集合与数据库对比,返回DDL语句
|
||||||
</summary>
|
</summary>
|
||||||
|
<param name="entityTypes">实体类型</param>
|
||||||
|
<returns></returns>
|
||||||
</member>
|
</member>
|
||||||
<member name="P:FreeSql.Aop.ConfigEntityEventArgs.ModifyResult">
|
<member name="M:FreeSql.ICodeFirst.GetComparisonDDLStatements(System.Type,System.String)">
|
||||||
<summary>
|
<summary>
|
||||||
实体配置
|
将实体类型与数据库对比,返回DDL语句(指定表名)
|
||||||
</summary>
|
</summary>
|
||||||
|
<param name="entityType">实体类型</param>
|
||||||
|
<param name="tableName">指定表名对比</param>
|
||||||
|
<returns></returns>
|
||||||
</member>
|
</member>
|
||||||
<member name="P:FreeSql.Aop.ConfigEntityEventArgs.ModifyIndexResult">
|
<member name="M:FreeSql.ICodeFirst.SyncStructure``1">
|
||||||
<summary>
|
<summary>
|
||||||
索引配置
|
同步实体类型到数据库
|
||||||
</summary>
|
</summary>
|
||||||
|
<typeparam name="TEntity"></typeparam>
|
||||||
|
<returns></returns>
|
||||||
</member>
|
</member>
|
||||||
<member name="P:FreeSql.Aop.ConfigEntityPropertyEventArgs.EntityType">
|
<member name="M:FreeSql.ICodeFirst.SyncStructure(System.Type[])">
|
||||||
<summary>
|
<summary>
|
||||||
实体类型
|
同步实体类型集合到数据库
|
||||||
</summary>
|
</summary>
|
||||||
|
<param name="entityTypes"></param>
|
||||||
|
<returns></returns>
|
||||||
</member>
|
</member>
|
||||||
<member name="P:FreeSql.Aop.ConfigEntityPropertyEventArgs.Property">
|
<member name="M:FreeSql.ICodeFirst.SyncStructure(System.Type,System.String)">
|
||||||
<summary>
|
<summary>
|
||||||
实体的属性
|
同步实体类型到数据库(指定表名)
|
||||||
</summary>
|
</summary>
|
||||||
|
<param name="entityType">实体类型</param>
|
||||||
|
<param name="tableName">指定表名对比</param>
|
||||||
|
<returns></returns>
|
||||||
</member>
|
</member>
|
||||||
<member name="P:FreeSql.Aop.ConfigEntityPropertyEventArgs.ModifyResult">
|
<member name="M:FreeSql.ICodeFirst.GetDbInfo(System.Type)">
|
||||||
<summary>
|
<summary>
|
||||||
实体的属性配置
|
根据 System.Type 获取数据库信息
|
||||||
</summary>
|
</summary>
|
||||||
|
<param name="type"></param>
|
||||||
|
<returns></returns>
|
||||||
</member>
|
</member>
|
||||||
<member name="P:FreeSql.Aop.CurdBeforeEventArgs.Identifier">
|
<member name="M:FreeSql.ICodeFirst.ConfigEntity``1(System.Action{FreeSql.DataAnnotations.TableFluent{``0}})">
|
||||||
<summary>
|
<summary>
|
||||||
标识符,可将 CurdBefore 与 CurdAfter 进行匹配
|
在外部配置实体的特性
|
||||||
</summary>
|
</summary>
|
||||||
|
<typeparam name="T"></typeparam>
|
||||||
|
<param name="entity"></param>
|
||||||
|
<returns></returns>
|
||||||
</member>
|
</member>
|
||||||
<member name="P:FreeSql.Aop.CurdBeforeEventArgs.CurdType">
|
<member name="M:FreeSql.ICodeFirst.ConfigEntity(System.Type,System.Action{FreeSql.DataAnnotations.TableFluent})">
|
||||||
<summary>
|
<summary>
|
||||||
操作类型
|
在外部配置实体的特性
|
||||||
</summary>
|
</summary>
|
||||||
|
<param name="type"></param>
|
||||||
|
<param name="entity"></param>
|
||||||
|
<returns></returns>
|
||||||
</member>
|
</member>
|
||||||
<member name="P:FreeSql.Aop.CurdBeforeEventArgs.EntityType">
|
<member name="M:FreeSql.ICodeFirst.GetConfigEntity(System.Type)">
|
||||||
<summary>
|
<summary>
|
||||||
实体类型
|
获取在外部配置实体的特性
|
||||||
</summary>
|
</summary>
|
||||||
|
<param name="type"></param>
|
||||||
|
<returns>未使用ConfigEntity配置时,返回null</returns>
|
||||||
</member>
|
</member>
|
||||||
<member name="P:FreeSql.Aop.CurdBeforeEventArgs.Table">
|
<member name="M:FreeSql.ICodeFirst.GetTableByEntity(System.Type)">
|
||||||
<summary>
|
<summary>
|
||||||
实体类型的元数据
|
获取实体类核心配置
|
||||||
</summary>
|
</summary>
|
||||||
|
<param name="type"></param>
|
||||||
|
<returns></returns>
|
||||||
</member>
|
</member>
|
||||||
<member name="P:FreeSql.Aop.CurdBeforeEventArgs.Sql">
|
<member name="M:FreeSql.IDbFirst.GetDatabases">
|
||||||
<summary>
|
|
||||||
执行的 SQL
|
|
||||||
</summary>
|
|
||||||
</member>
|
|
||||||
<member name="P:FreeSql.Aop.CurdBeforeEventArgs.DbParms">
|
|
||||||
<summary>
|
|
||||||
参数化命令
|
|
||||||
</summary>
|
|
||||||
</member>
|
|
||||||
<member name="P:FreeSql.Aop.CurdAfterEventArgs.Exception">
|
|
||||||
<summary>
|
|
||||||
发生的错误
|
|
||||||
</summary>
|
|
||||||
</member>
|
|
||||||
<member name="P:FreeSql.Aop.CurdAfterEventArgs.ExecuteResult">
|
|
||||||
<summary>
|
|
||||||
执行SQL命令,返回的结果
|
|
||||||
</summary>
|
|
||||||
</member>
|
|
||||||
<member name="P:FreeSql.Aop.CurdAfterEventArgs.ElapsedTicks">
|
|
||||||
<summary>
|
|
||||||
耗时(单位:Ticks)
|
|
||||||
</summary>
|
|
||||||
</member>
|
|
||||||
<member name="P:FreeSql.Aop.CurdAfterEventArgs.ElapsedMilliseconds">
|
|
||||||
<summary>
|
|
||||||
耗时(单位:毫秒)
|
|
||||||
</summary>
|
|
||||||
</member>
|
|
||||||
<member name="P:FreeSql.Aop.SyncStructureBeforeEventArgs.Identifier">
|
|
||||||
<summary>
|
|
||||||
标识符,可将 SyncStructureBeforeEventArgs 与 SyncStructureAfterEventArgs 进行匹配
|
|
||||||
</summary>
|
|
||||||
</member>
|
|
||||||
<member name="P:FreeSql.Aop.SyncStructureBeforeEventArgs.EntityTypes">
|
|
||||||
<summary>
|
|
||||||
实体类型
|
|
||||||
</summary>
|
|
||||||
</member>
|
|
||||||
<member name="P:FreeSql.Aop.SyncStructureAfterEventArgs.Sql">
|
|
||||||
<summary>
|
|
||||||
执行的 SQL
|
|
||||||
</summary>
|
|
||||||
</member>
|
|
||||||
<member namerst.GetDatabases">
|
|
||||||
<summary>
|
<summary>
|
||||||
获取所有数据库
|
获取所有数据库
|
||||||
</summary>
|
</summary>
|
||||||
@ -2577,158 +2556,6 @@
|
|||||||
<param name="exp2"></param>
|
<param name="exp2"></param>
|
||||||
<returns></returns>
|
<returns></returns>
|
||||||
</member>
|
</member>
|
||||||
<member name="M:FreeSqlGlobalExpressionCall.Contains``3(System.C <member name="M:FreeSql.IDbFirst.GetCsTypeInfo(FreeSql.DatabaseModel.DbColumnInfo)">
|
|
||||||
<summary>
|
|
||||||
获取c#类型对象
|
|
||||||
</summary>
|
|
||||||
<param name="column"></param>
|
|
||||||
<returns></returns>
|
|
||||||
</member>
|
|
||||||
<member name="M:FreeSql.IDbFirst.GetDataReaderMethod(FreeSql.DatabaseModel.DbColumnInfo)">
|
|
||||||
<summary>
|
|
||||||
获取ado.net读取方法, GetBoolean、GetInt64
|
|
||||||
</summary>
|
|
||||||
<param name="column"></param>
|
|
||||||
<returns></returns>
|
|
||||||
</member>
|
|
||||||
<member name="M:FreeSql.IDbFirst.GetCsStringify(FreeSql.DatabaseModel.DbColumnInfo)">
|
|
||||||
<summary>
|
|
||||||
序列化
|
|
||||||
</summary>
|
|
||||||
<param name="column"></param>
|
|
||||||
<returns></returns>
|
|
||||||
</member>
|
|
||||||
<member name="M:FreeSql.IDbFirst.GetCsParse(FreeSql.DatabaseModel.DbColumnInfo)">
|
|
||||||
<summary>
|
|
||||||
反序列化
|
|
||||||
</summary>
|
|
||||||
<param name="column"></param>
|
|
||||||
<returns></returns>
|
|
||||||
</member>
|
|
||||||
<member name="M:FreeSql.IDbFirst.GetEnumsByDatabase(System.String[])">
|
|
||||||
<summary>
|
|
||||||
获取数据库枚举类型,适用 PostgreSQL
|
|
||||||
</summary>
|
|
||||||
<param name="database"></param>
|
|
||||||
<returns></returns>
|
|
||||||
</member>
|
|
||||||
<member name="M:FreeSql.Internal.CommonProvider.InsertProvider`1.IgnoreCanInsert">
|
|
||||||
<summary>
|
|
||||||
AsType, Ctor, ClearData 三处地方需要重新加载
|
|
||||||
</summary>
|
|
||||||
</member>
|
|
||||||
<member name="M:FreeSql.Internal.CommonProvider.UpdateProvider`1.IgnoreCanUpdate">
|
|
||||||
<summary>
|
|
||||||
AsType, Ctor, ClearData 三处地方需要重新加载
|
|
||||||
</summary>
|
|
||||||
</member>
|
|
||||||
<member name="M:FreeSql.Internal.CommonUtils.GetProperyCommentBySummary(System.Type)">
|
|
||||||
<summary>
|
|
||||||
通过属性的注释文本,通过 xml 读取
|
|
||||||
</summary>
|
|
||||||
<param name="type"></param>
|
|
||||||
<returns>Dict:key=属性名,value=注释</returns>
|
|
||||||
</member>
|
|
||||||
<member name="M:FreeSql.Internal.GlobalFilter.Apply``1(System.String,System.Linq.Expressions.Expression{System.Func{``0,System.Boolean}})">
|
|
||||||
<summary>
|
|
||||||
创建一个过滤器
|
|
||||||
</summary>
|
|
||||||
<typeparam name="TEntity"></typeparam>
|
|
||||||
<param name="name">名字</param>
|
|
||||||
<param name="where">表达式</param>
|
|
||||||
<returns></returns>
|
|
||||||
</member>
|
|
||||||
<member name="P:FreeSql.Internal.Model.TableRef.RefMiddleEntityType">
|
|
||||||
<summary>
|
|
||||||
中间表,多对多
|
|
||||||
</summary>
|
|
||||||
</member>
|
|
||||||
<member name="F:FreeSql.Internal.StringConvertType.None">
|
|
||||||
<summary>
|
|
||||||
不进行任何处理
|
|
||||||
</summary>
|
|
||||||
</member>
|
|
||||||
<member name="F:FreeSql.Internal.StringConvertType.PascalCaseToUnderscore">
|
|
||||||
<summary>
|
|
||||||
将帕斯卡命名字符串转换为下划线分隔字符串
|
|
||||||
<para></para>
|
|
||||||
BigApple -> Big_Apple
|
|
||||||
</summary>
|
|
||||||
</member>
|
|
||||||
<member name="F:FreeSql.Internal.StringConvertType.PascalCaseToUnderscoreWithUpper">
|
|
||||||
<summary>
|
|
||||||
将帕斯卡命名字符串转换为下划线分隔字符串,且转换为全大写
|
|
||||||
<para></para>
|
|
||||||
BigApple -> BIG_APPLE
|
|
||||||
</summary>
|
|
||||||
</member>
|
|
||||||
<member name="F:FreeSql.Internal.StringConvertType.PascalCaseToUnderscoreWithLower">
|
|
||||||
<summary>
|
|
||||||
将帕斯卡命名字符串转换为下划线分隔字符串,且转换为全小写
|
|
||||||
<para></para>
|
|
||||||
BigApple -> big_apple
|
|
||||||
</summary>
|
|
||||||
</member>
|
|
||||||
<member name="F:FreeSql.Internal.StringConvertType.Upper">
|
|
||||||
<summary>
|
|
||||||
将字符串转换为大写
|
|
||||||
<para></para>
|
|
||||||
BigApple -> BIGAPPLE
|
|
||||||
</summary>
|
|
||||||
</member>
|
|
||||||
<member name="F:FreeSql.Internal.StringConvertType.Lower">
|
|
||||||
<summary>
|
|
||||||
将字符串转换为小写
|
|
||||||
<para></para>
|
|
||||||
BigApple -> bigapple
|
|
||||||
</summary>
|
|
||||||
</member>
|
|
||||||
<member name="M:FreeSql.Internal.StringUtils.PascalCaseToUnderScore(System.String)">
|
|
||||||
<summary>
|
|
||||||
将帕斯卡命名字符串转换为下划线分隔字符串
|
|
||||||
<para></para>
|
|
||||||
BigApple -> Big_Apple
|
|
||||||
</summary>
|
|
||||||
<param name="str"></param>
|
|
||||||
<returns></returns>
|
|
||||||
</member>
|
|
||||||
<member name="M:FreeSqlGlobalExpressionCall.Between(System.DateTime,System.DateTime,System.DateTime)">
|
|
||||||
<summary>
|
|
||||||
C#: that >= between && that <= and<para></para>
|
|
||||||
SQL: that BETWEEN between AND and
|
|
||||||
</summary>
|
|
||||||
<param name="that"></param>
|
|
||||||
<param name="between"></param>
|
|
||||||
<param name="and"></param>
|
|
||||||
<returns></returns>
|
|
||||||
</member>
|
|
||||||
<member name="M:FreeSqlGlobalExpressionCall.BetweenEnd(System.DateTime,System.DateTime,System.DateTime)">
|
|
||||||
<summary>
|
|
||||||
注意:这个方法和 Between 有细微区别<para></para>
|
|
||||||
C#: that >= start && that < end<para></para>
|
|
||||||
SQL: that >= start and that < end
|
|
||||||
</summary>
|
|
||||||
<param name="that"></param>
|
|
||||||
<param name="start"></param>
|
|
||||||
<param name="end"></param>
|
|
||||||
<returns></returns>
|
|
||||||
</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)">
|
<member name="M:FreeSqlGlobalExpressionCall.Contains``3(System.Collections.Generic.IEnumerable{System.ValueTuple{``0,``1,``2}},``0,``1,``2)">
|
||||||
<summary>
|
<summary>
|
||||||
C#:从元组集合中查找 exp1, exp2, exp2 是否存在<para></para>
|
C#:从元组集合中查找 exp1, exp2, exp2 是否存在<para></para>
|
||||||
@ -2991,6 +2818,160 @@
|
|||||||
CodeFirst 模式开发相关方法
|
CodeFirst 模式开发相关方法
|
||||||
</summary>
|
</summary>
|
||||||
</member>
|
</member>
|
||||||
|
<member name="P:IFreeSql.DbFirst">
|
||||||
|
<summary>
|
||||||
|
DbFirst 模式开发相关方法
|
||||||
|
</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.Action,System.TimeSpan)">
|
||||||
|
<summary>
|
||||||
|
开启事务(不支持异步)
|
||||||
|
</summary>
|
||||||
|
<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">
|
<member name="P:IFreeSql.DbFirst">
|
||||||
<summary>
|
<summary>
|
||||||
DbFirst 模式开发相关方法
|
DbFirst 模式开发相关方法
|
||||||
|
@ -62,7 +62,7 @@ namespace FreeSql.Odbc.Dameng
|
|||||||
{
|
{
|
||||||
|
|
||||||
internal OdbcDamengConnectionPool _pool;
|
internal OdbcDamengConnectionPool _pool;
|
||||||
public string Name { get; set; } = "Oracle OdbcConnection 对象池";
|
public string Name { get; set; } = "Dameng OdbcConnection 对象池";
|
||||||
public int PoolSize { get; set; } = 100;
|
public int PoolSize { get; set; } = 100;
|
||||||
public TimeSpan SyncGetTimeout { get; set; } = TimeSpan.FromSeconds(10);
|
public TimeSpan SyncGetTimeout { get; set; } = TimeSpan.FromSeconds(10);
|
||||||
public TimeSpan IdleTimeout { get; set; } = TimeSpan.Zero;
|
public TimeSpan IdleTimeout { get; set; } = TimeSpan.Zero;
|
||||||
|
@ -0,0 +1,31 @@
|
|||||||
|
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
|
||||||
|
}
|
||||||
|
}
|
176
Providers/FreeSql.Provider.Odbc/GBase/Curd/OdbcGBaseSelect.cs
Normal file
176
Providers/FreeSql.Provider.Odbc/GBase/Curd/OdbcGBaseSelect.cs
Normal file
@ -0,0 +1,176 @@
|
|||||||
|
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, 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.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, _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, _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, _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, _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, _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, _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, _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, _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, _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, _whereCascadeExpression, _orm);
|
||||||
|
}
|
||||||
|
}
|
149
Providers/FreeSql.Provider.Odbc/GBase/Curd/__OdbcGBaseInsert.cs
Normal file
149
Providers/FreeSql.Provider.Odbc/GBase/Curd/__OdbcGBaseInsert.cs
Normal file
@ -0,0 +1,149 @@
|
|||||||
|
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(5000, 3000);
|
||||||
|
public override long ExecuteIdentity() => base.SplitExecuteIdentity(5000, 3000);
|
||||||
|
public override List<T1> ExecuteInserted() => base.SplitExecuteInserted(5000, 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.CurdBefore?.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.CurdAfter?.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.CurdBefore?.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.CurdAfter?.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.CurdBefore?.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.CurdAfter?.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.CurdBefore?.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.CurdAfter?.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
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,85 @@
|
|||||||
|
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(500, 3000);
|
||||||
|
public override List<T1> ExecuteUpdated() => base.SplitExecuteUpdated(500, 3000);
|
||||||
|
|
||||||
|
protected override List<T1> RawExecuteUpdated()
|
||||||
|
{
|
||||||
|
throw new NotImplementedException();
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override void ToSqlCase(StringBuilder caseWhen, ColumnInfo[] primarys)
|
||||||
|
{
|
||||||
|
if (_table.Primarys.Length == 1)
|
||||||
|
{
|
||||||
|
caseWhen.Append(_commonUtils.QuoteReadColumn(_table.Primarys.First().Attribute.MapType, _commonUtils.QuoteSqlName(_table.Primarys.First().Attribute.Name)));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
caseWhen.Append("(");
|
||||||
|
var pkidx = 0;
|
||||||
|
foreach (var pk in _table.Primarys)
|
||||||
|
{
|
||||||
|
if (pkidx > 0) caseWhen.Append(" || ");
|
||||||
|
caseWhen.Append(_commonUtils.QuoteReadColumn(pk.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
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,248 @@
|
|||||||
|
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;
|
||||||
|
|
||||||
|
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)
|
||||||
|
{
|
||||||
|
var policy = new OdbcPostgreSQLConnectionPoolPolicy
|
||||||
|
{
|
||||||
|
_pool = this,
|
||||||
|
Name = name
|
||||||
|
};
|
||||||
|
this.Policy = policy;
|
||||||
|
policy.ConnectionString = connectionString;
|
||||||
|
|
||||||
|
this.availableHandler = availableHandler;
|
||||||
|
this.unavailableHandler = unavailableHandler;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Return(Object<DbConnection> obj, Exception exception, bool isRecreate = false)
|
||||||
|
{
|
||||||
|
if (exception != null && exception is 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.Zero;
|
||||||
|
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) => 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
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,68 @@
|
|||||||
|
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) : base(DataType.PostgreSQL)
|
||||||
|
{
|
||||||
|
base._util = util;
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static DateTime dt1970 = new DateTime(1970, 1, 1);
|
||||||
|
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 || mapType.IsArrayOrList()))
|
||||||
|
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 IEnumerable)
|
||||||
|
return AddslashesIEnumerable(param, mapType, mapColumn);
|
||||||
|
|
||||||
|
return string.Concat("'", param.ToString().Replace("'", "''"), "'");
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override DbCommand CreateCommand()
|
||||||
|
{
|
||||||
|
return new OdbcCommand();
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override void ReturnConnection(ObjectPool<DbConnection> pool, Object<DbConnection> conn, Exception ex)
|
||||||
|
{
|
||||||
|
(pool as OdbcGBaseConnectionPool).Return(conn, ex);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override DbParameter[] GetDbParamtersByObject(string sql, object obj) => _util.GetDbParamtersByObject(sql, obj);
|
||||||
|
}
|
||||||
|
}
|
61
Providers/FreeSql.Provider.Odbc/GBase/OdbcGBaseProvider.cs
Normal file
61
Providers/FreeSql.Provider.Odbc/GBase/OdbcGBaseProvider.cs
Normal file
@ -0,0 +1,61 @@
|
|||||||
|
using FreeSql.Internal;
|
||||||
|
using FreeSql.Internal.CommonProvider;
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
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)
|
||||||
|
{
|
||||||
|
this.InternalCommonUtils = new OdbcGBaseUtils(this);
|
||||||
|
this.InternalCommonExpression = new OdbcGBaseExpression(this.InternalCommonUtils);
|
||||||
|
|
||||||
|
this.Ado = new OdbcGBaseAdo(this.InternalCommonUtils, masterConnectionString, slaveConnectionString);
|
||||||
|
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(Action handler, TimeSpan timeout) => Ado.Transaction(handler, timeout);
|
||||||
|
|
||||||
|
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();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
387
Providers/FreeSql.Provider.Odbc/GBase/__OdbcGBaseCodeFirst.cs
Normal file
387
Providers/FreeSql.Provider.Odbc/GBase/__OdbcGBaseCodeFirst.cs
Normal file
@ -0,0 +1,387 @@
|
|||||||
|
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, "int8","int8 NOT NULL", false, false, 0) },{ typeof(uint?).FullName, (OdbcType.BigInt, "int8", "int8", 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 = tb.DbName.Split(new[] { '.' }, 2);
|
||||||
|
if (tbname?.Length == 1) tbname = new[] { "public", tbname[0] };
|
||||||
|
|
||||||
|
var tboldname = tb.DbOldName?.Split(new[] { '.' }, 2); //旧表名
|
||||||
|
if (tboldname?.Length == 1) tboldname = new[] { "public", tboldname[0] };
|
||||||
|
if (string.IsNullOrEmpty(obj.tableName) == false)
|
||||||
|
{
|
||||||
|
var tbtmpname = obj.tableName.Split(new[] { '.' }, 2);
|
||||||
|
if (tbtmpname?.Length == 1) tbtmpname = new[] { "public", tbtmpname[0] };
|
||||||
|
if (tbname[0] != tbtmpname[0] || tbname[1] != tbtmpname[1])
|
||||||
|
{
|
||||||
|
tbname = tbtmpname;
|
||||||
|
tboldname = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
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();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
480
Providers/FreeSql.Provider.Odbc/GBase/__OdbcGBaseDbFirst.cs
Normal file
480
Providers/FreeSql.Provider.Odbc/GBase/__OdbcGBaseDbFirst.cs
Normal file
@ -0,0 +1,480 @@
|
|||||||
|
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")} and a.indisprimary = 'f'
|
||||||
|
";
|
||||||
|
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();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
554
Providers/FreeSql.Provider.Odbc/GBase/__OdbcGBaseExpression.cs
Normal file
554
Providers/FreeSql.Provider.Odbc/GBase/__OdbcGBaseExpression.cs
Normal file
@ -0,0 +1,554 @@
|
|||||||
|
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)})::int2";
|
||||||
|
case "System.Char": return $"substr(({getExp(operandExp)})::char, 1, 1)";
|
||||||
|
case "System.DateTime": return $"({getExp(operandExp)})::timestamp";
|
||||||
|
case "System.Decimal": return $"({getExp(operandExp)})::numeric";
|
||||||
|
case "System.Double": return $"({getExp(operandExp)})::float8";
|
||||||
|
case "System.Int16": return $"({getExp(operandExp)})::int2";
|
||||||
|
case "System.Int32": return $"({getExp(operandExp)})::int4";
|
||||||
|
case "System.Int64": return $"({getExp(operandExp)})::int8";
|
||||||
|
case "System.SByte": return $"({getExp(operandExp)})::int2";
|
||||||
|
case "System.Single": return $"({getExp(operandExp)})::float4";
|
||||||
|
case "System.String": return $"({getExp(operandExp)})::varchar";
|
||||||
|
case "System.UInt16": return $"({getExp(operandExp)})::int2";
|
||||||
|
case "System.UInt32": return $"({getExp(operandExp)})::int4";
|
||||||
|
case "System.UInt64": return $"({getExp(operandExp)})::int8";
|
||||||
|
case "System.Guid": return $"({getExp(operandExp)})::uuid";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case ExpressionType.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])})::int2";
|
||||||
|
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])})::numeric";
|
||||||
|
case "System.Double": return $"({getExp(callExp.Arguments[0])})::float8";
|
||||||
|
case "System.Int16": return $"({getExp(callExp.Arguments[0])})::int2";
|
||||||
|
case "System.Int32": return $"({getExp(callExp.Arguments[0])})::int4";
|
||||||
|
case "System.Int64": return $"({getExp(callExp.Arguments[0])})::int8";
|
||||||
|
case "System.SByte": return $"({getExp(callExp.Arguments[0])})::int2";
|
||||||
|
case "System.Single": return $"({getExp(callExp.Arguments[0])})::float4";
|
||||||
|
case "System.UInt16": return $"({getExp(callExp.Arguments[0])})::int2";
|
||||||
|
case "System.UInt32": return $"({getExp(callExp.Arguments[0])})::int4";
|
||||||
|
case "System.UInt64": return $"({getExp(callExp.Arguments[0])})::int8";
|
||||||
|
case "System.Guid": return $"({getExp(callExp.Arguments[0])})::uuid";
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case "NewGuid":
|
||||||
|
return null;
|
||||||
|
case "Next":
|
||||||
|
if (callExp.Object?.Type == typeof(Random)) return "(random()*1000000000)::int4";
|
||||||
|
return null;
|
||||||
|
case "NextDouble":
|
||||||
|
if (callExp.Object?.Type == typeof(Random)) return "random()";
|
||||||
|
return null;
|
||||||
|
case "Random":
|
||||||
|
if (callExp.Method.DeclaringType.IsNumberType()) return "random()";
|
||||||
|
return null;
|
||||||
|
case "ToString":
|
||||||
|
if (callExp.Object != null) return callExp.Arguments.Count == 0 ? $"({getExp(callExp.Object)})::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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
167
Providers/FreeSql.Provider.Odbc/GBase/__OdbcGBaseUtils.cs
Normal file
167
Providers/FreeSql.Provider.Odbc/GBase/__OdbcGBaseUtils.cs
Normal file
@ -0,0 +1,167 @@
|
|||||||
|
using FreeSql.Internal;
|
||||||
|
using System;
|
||||||
|
using System.Collections;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Collections.Concurrent;
|
||||||
|
using System.Data.Common;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Net;
|
||||||
|
using System.Text;
|
||||||
|
using System.Linq.Expressions;
|
||||||
|
using System.Reflection;
|
||||||
|
using System.Data.Odbc;
|
||||||
|
using FreeSql.Internal.Model;
|
||||||
|
|
||||||
|
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(string name)
|
||||||
|
{
|
||||||
|
var nametrim = name.Trim();
|
||||||
|
if (nametrim.StartsWith("(") && nametrim.EndsWith(")"))
|
||||||
|
return nametrim; //原生SQL
|
||||||
|
return $"\"{nametrim.Trim('"').Replace(".", "\".\"")}\"";
|
||||||
|
}
|
||||||
|
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 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, 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[]))
|
||||||
|
{
|
||||||
|
var bytes = value as byte[];
|
||||||
|
var sb = new StringBuilder().Append("'\\x");
|
||||||
|
foreach (var vc in bytes)
|
||||||
|
{
|
||||||
|
if (vc < 10) sb.Append("0");
|
||||||
|
sb.Append(vc.ToString("X"));
|
||||||
|
}
|
||||||
|
return sb.Append("'").ToString(); //val = Encoding.UTF8.GetString(val as byte[]);
|
||||||
|
}
|
||||||
|
else 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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -182,7 +182,7 @@ a.data_length,
|
|||||||
a.data_precision,
|
a.data_precision,
|
||||||
a.data_scale,
|
a.data_scale,
|
||||||
a.char_used,
|
a.char_used,
|
||||||
case when a.nullable = 'Y' then 1 else 0 end,
|
case when a.nullable = 'N' then 0 else 1 end,
|
||||||
nvl((select 1 from user_sequences where sequence_name='{Utils.GetCsName((tboldname ?? tbname).Last())}_seq_'||a.column_name), 0),
|
nvl((select 1 from user_sequences where sequence_name='{Utils.GetCsName((tboldname ?? tbname).Last())}_seq_'||a.column_name), 0),
|
||||||
nvl((select 1 from user_triggers where trigger_name='{Utils.GetCsName((tboldname ?? tbname).Last())}_seq_'||a.column_name||'TI'), 0),
|
nvl((select 1 from user_triggers where trigger_name='{Utils.GetCsName((tboldname ?? tbname).Last())}_seq_'||a.column_name||'TI'), 0),
|
||||||
b.comments
|
b.comments
|
||||||
|
@ -258,7 +258,7 @@ a.data_length,
|
|||||||
a.data_precision,
|
a.data_precision,
|
||||||
a.data_scale,
|
a.data_scale,
|
||||||
a.char_used,
|
a.char_used,
|
||||||
case when a.nullable = 'Y' then 1 else 0 end,
|
case when a.nullable = 'N' then 0 else 1 end,
|
||||||
nvl((select 1 from user_sequences where upper(sequence_name)=upper(a.table_name||'_seq_'||a.column_name)), 0),
|
nvl((select 1 from user_sequences where upper(sequence_name)=upper(a.table_name||'_seq_'||a.column_name)), 0),
|
||||||
b.comments
|
b.comments
|
||||||
from all_tab_cols a
|
from all_tab_cols a
|
||||||
|
@ -57,7 +57,7 @@ namespace FreeSql.Odbc.PostgreSQL
|
|||||||
{
|
{
|
||||||
|
|
||||||
internal OdbcPostgreSQLConnectionPool _pool;
|
internal OdbcPostgreSQLConnectionPool _pool;
|
||||||
public string Name { get; set; } = "PostgreSQL NpgsqlConnection 对象池";
|
public string Name { get; set; } = "PostgreSQL OdbcConnection 对象池";
|
||||||
public int PoolSize { get; set; } = 50;
|
public int PoolSize { get; set; } = 50;
|
||||||
public TimeSpan SyncGetTimeout { get; set; } = TimeSpan.FromSeconds(10);
|
public TimeSpan SyncGetTimeout { get; set; } = TimeSpan.FromSeconds(10);
|
||||||
public TimeSpan IdleTimeout { get; set; } = TimeSpan.Zero;
|
public TimeSpan IdleTimeout { get; set; } = TimeSpan.Zero;
|
||||||
|
@ -183,7 +183,7 @@ a.data_length,
|
|||||||
a.data_precision,
|
a.data_precision,
|
||||||
a.data_scale,
|
a.data_scale,
|
||||||
a.char_used,
|
a.char_used,
|
||||||
case when a.nullable = 'Y' then 1 else 0 end,
|
case when a.nullable = 'N' then 0 else 1 end,
|
||||||
nvl((select 1 from user_sequences where sequence_name='{Utils.GetCsName((tboldname ?? tbname).Last())}_seq_'||a.column_name), 0),
|
nvl((select 1 from user_sequences where sequence_name='{Utils.GetCsName((tboldname ?? tbname).Last())}_seq_'||a.column_name), 0),
|
||||||
nvl((select 1 from user_triggers where trigger_name='{Utils.GetCsName((tboldname ?? tbname).Last())}_seq_'||a.column_name||'TI'), 0),
|
nvl((select 1 from user_triggers where trigger_name='{Utils.GetCsName((tboldname ?? tbname).Last())}_seq_'||a.column_name||'TI'), 0),
|
||||||
b.comments
|
b.comments
|
||||||
|
@ -258,7 +258,7 @@ a.data_length,
|
|||||||
a.data_precision,
|
a.data_precision,
|
||||||
a.data_scale,
|
a.data_scale,
|
||||||
a.char_used,
|
a.char_used,
|
||||||
case when a.nullable = 'Y' then 1 else 0 end,
|
case when a.nullable = 'N' then 0 else 1 end,
|
||||||
nvl((select 1 from user_sequences where upper(sequence_name)=upper(a.table_name||'_seq_'||a.column_name)), 0),
|
nvl((select 1 from user_sequences where upper(sequence_name)=upper(a.table_name||'_seq_'||a.column_name)), 0),
|
||||||
b.comments
|
b.comments
|
||||||
from all_tab_cols a
|
from all_tab_cols a
|
||||||
|
Loading…
x
Reference in New Issue
Block a user