mirror of
https://github.com/nsnail/FreeSql.git
synced 2025-04-22 02:32:50 +08:00
增加虚谷支持,基础版本
This commit is contained in:
parent
68bb3400cf
commit
f60acc0741
@ -0,0 +1,29 @@
|
|||||||
|
<Project Sdk="Microsoft.NET.Sdk">
|
||||||
|
|
||||||
|
<PropertyGroup>
|
||||||
|
<TargetFramework>net6.0</TargetFramework>
|
||||||
|
<ImplicitUsings>enable</ImplicitUsings>
|
||||||
|
<Nullable>enable</Nullable>
|
||||||
|
|
||||||
|
<IsPackable>false</IsPackable>
|
||||||
|
</PropertyGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.3.2" />
|
||||||
|
<PackageReference Include="xunit" Version="2.4.2" />
|
||||||
|
<PackageReference Include="xunit.runner.visualstudio" Version="2.4.5">
|
||||||
|
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
||||||
|
<PrivateAssets>all</PrivateAssets>
|
||||||
|
</PackageReference>
|
||||||
|
<PackageReference Include="coverlet.collector" Version="3.1.2">
|
||||||
|
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
||||||
|
<PrivateAssets>all</PrivateAssets>
|
||||||
|
</PackageReference>
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<ProjectReference Include="..\..\FreeSql\FreeSql.csproj" />
|
||||||
|
<ProjectReference Include="..\..\Providers\FreeSql.Provider.Xugu\FreeSql.Provider.Xugu.csproj" />
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
|
</Project>
|
44
FreeSql.Tests/FreeSql.Tests.Provider.Xugu/UnitDbFirst.cs
Normal file
44
FreeSql.Tests/FreeSql.Tests.Provider.Xugu/UnitDbFirst.cs
Normal file
@ -0,0 +1,44 @@
|
|||||||
|
|
||||||
|
namespace FreeSql.Tests.Provider.Xugu
|
||||||
|
{
|
||||||
|
public class UnitDbFirst
|
||||||
|
{
|
||||||
|
[Fact]
|
||||||
|
public void GetDatabases()
|
||||||
|
{
|
||||||
|
var t1 = g.xugu.DbFirst.GetDatabases();
|
||||||
|
|
||||||
|
Assert.True(t1.Count > 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void GetTablesByDatabase()
|
||||||
|
{
|
||||||
|
var t2 = g.xugu.DbFirst.GetTablesByDatabase();
|
||||||
|
Assert.True(t2.Count > 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void GetTableByName()
|
||||||
|
{
|
||||||
|
var fsql = g.xugu;
|
||||||
|
var t1 = fsql.DbFirst.GetTableByName("GENERAL.system_log");
|
||||||
|
Assert.NotNull(t1);
|
||||||
|
Assert.True(t1.Columns.Count > 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void ExistsTable()
|
||||||
|
{
|
||||||
|
var fsql = g.xugu;
|
||||||
|
Assert.False(fsql.DbFirst.ExistsTable("GENERAL.system_log"));
|
||||||
|
fsql.CodeFirst.SyncStructure(typeof(test_existstb01));
|
||||||
|
Assert.True(fsql.DbFirst.ExistsTable("test_existstb01"));
|
||||||
|
fsql.Ado.ExecuteNonQuery("drop table test_existstb01");
|
||||||
|
}
|
||||||
|
class test_existstb01
|
||||||
|
{
|
||||||
|
public long id { get; set; }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
1
FreeSql.Tests/FreeSql.Tests.Provider.Xugu/Usings.cs
Normal file
1
FreeSql.Tests/FreeSql.Tests.Provider.Xugu/Usings.cs
Normal file
@ -0,0 +1 @@
|
|||||||
|
global using Xunit;
|
28
FreeSql.Tests/FreeSql.Tests.Provider.Xugu/g.cs
Normal file
28
FreeSql.Tests/FreeSql.Tests.Provider.Xugu/g.cs
Normal file
@ -0,0 +1,28 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Diagnostics;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
namespace FreeSql.Tests.Provider.Xugu
|
||||||
|
{
|
||||||
|
public class g
|
||||||
|
{
|
||||||
|
|
||||||
|
static Lazy<IFreeSql> xuguLazy = new Lazy<IFreeSql>(() => new FreeSql.FreeSqlBuilder()
|
||||||
|
.UseConnectionString(FreeSql.DataType.Xugu, "IP=127.0.0.1;DB=SYSTEM;User=SYSDBA;PWD=SYSDBA;Port=5138;AUTO_COMMIT=on;CHAR_SET=UTF8")
|
||||||
|
//.UseAutoSyncStructure(true)
|
||||||
|
//.UseGenerateCommandParameterWithLambda(true)
|
||||||
|
.UseLazyLoading(true)
|
||||||
|
//.UseNameConvert(FreeSql.Internal.NameConvertType.ToUpper)
|
||||||
|
//.UseNoneCommandParameter(true)
|
||||||
|
|
||||||
|
.UseMonitorCommand(
|
||||||
|
cmd => Trace.WriteLine("\r\n线程" + Thread.CurrentThread.ManagedThreadId + ": " + cmd.CommandText) //监听SQL命令对象,在执行前
|
||||||
|
//, (cmd, traceLog) => Console.WriteLine(traceLog)
|
||||||
|
)
|
||||||
|
.Build());
|
||||||
|
public static IFreeSql xugu => xuguLazy.Value;
|
||||||
|
}
|
||||||
|
}
|
19
FreeSql.sln
19
FreeSql.sln
@ -121,6 +121,8 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "FreeSql.Provider.QuestDb",
|
|||||||
EndProject
|
EndProject
|
||||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "FreeSql.Extensions.AggregateRoot", "Extensions\FreeSql.Extensions.AggregateRoot\FreeSql.Extensions.AggregateRoot.csproj", "{71A6F937-D11B-4AE4-9933-BB6B4D925665}"
|
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "FreeSql.Extensions.AggregateRoot", "Extensions\FreeSql.Extensions.AggregateRoot\FreeSql.Extensions.AggregateRoot.csproj", "{71A6F937-D11B-4AE4-9933-BB6B4D925665}"
|
||||||
EndProject
|
EndProject
|
||||||
|
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "FreeSql.Provider.Xugu", "Providers\FreeSql.Provider.Xugu\FreeSql.Provider.Xugu.csproj", "{8064870C-22EA-4A58-972D-DBD57D096D91}"
|
||||||
|
EndProject
|
||||||
Global
|
Global
|
||||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||||
Debug|Any CPU = Debug|Any CPU
|
Debug|Any CPU = Debug|Any CPU
|
||||||
@ -719,6 +721,18 @@ Global
|
|||||||
{71A6F937-D11B-4AE4-9933-BB6B4D925665}.Release|x64.Build.0 = Release|Any CPU
|
{71A6F937-D11B-4AE4-9933-BB6B4D925665}.Release|x64.Build.0 = Release|Any CPU
|
||||||
{71A6F937-D11B-4AE4-9933-BB6B4D925665}.Release|x86.ActiveCfg = Release|Any CPU
|
{71A6F937-D11B-4AE4-9933-BB6B4D925665}.Release|x86.ActiveCfg = Release|Any CPU
|
||||||
{71A6F937-D11B-4AE4-9933-BB6B4D925665}.Release|x86.Build.0 = Release|Any CPU
|
{71A6F937-D11B-4AE4-9933-BB6B4D925665}.Release|x86.Build.0 = Release|Any CPU
|
||||||
|
{8064870C-22EA-4A58-972D-DBD57D096D91}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||||
|
{8064870C-22EA-4A58-972D-DBD57D096D91}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||||
|
{8064870C-22EA-4A58-972D-DBD57D096D91}.Debug|x64.ActiveCfg = Debug|Any CPU
|
||||||
|
{8064870C-22EA-4A58-972D-DBD57D096D91}.Debug|x64.Build.0 = Debug|Any CPU
|
||||||
|
{8064870C-22EA-4A58-972D-DBD57D096D91}.Debug|x86.ActiveCfg = Debug|Any CPU
|
||||||
|
{8064870C-22EA-4A58-972D-DBD57D096D91}.Debug|x86.Build.0 = Debug|Any CPU
|
||||||
|
{8064870C-22EA-4A58-972D-DBD57D096D91}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||||
|
{8064870C-22EA-4A58-972D-DBD57D096D91}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||||
|
{8064870C-22EA-4A58-972D-DBD57D096D91}.Release|x64.ActiveCfg = Release|Any CPU
|
||||||
|
{8064870C-22EA-4A58-972D-DBD57D096D91}.Release|x64.Build.0 = Release|Any CPU
|
||||||
|
{8064870C-22EA-4A58-972D-DBD57D096D91}.Release|x86.ActiveCfg = Release|Any CPU
|
||||||
|
{8064870C-22EA-4A58-972D-DBD57D096D91}.Release|x86.Build.0 = Release|Any CPU
|
||||||
EndGlobalSection
|
EndGlobalSection
|
||||||
GlobalSection(SolutionProperties) = preSolution
|
GlobalSection(SolutionProperties) = preSolution
|
||||||
HideSolutionNode = FALSE
|
HideSolutionNode = FALSE
|
||||||
@ -758,10 +772,11 @@ Global
|
|||||||
{ECF7FC70-A7FC-4FC3-9BF7-462EA0A65F9C} = {2A381C57-2697-427B-9F10-55DA11FD02E4}
|
{ECF7FC70-A7FC-4FC3-9BF7-462EA0A65F9C} = {2A381C57-2697-427B-9F10-55DA11FD02E4}
|
||||||
{8A06B18A-A8BF-4AEA-AFE4-0F573C2DBFEE} = {2A381C57-2697-427B-9F10-55DA11FD02E4}
|
{8A06B18A-A8BF-4AEA-AFE4-0F573C2DBFEE} = {2A381C57-2697-427B-9F10-55DA11FD02E4}
|
||||||
{71A6F937-D11B-4AE4-9933-BB6B4D925665} = {4A92E8A6-9A6D-41A1-9CDA-DE10899648AA}
|
{71A6F937-D11B-4AE4-9933-BB6B4D925665} = {4A92E8A6-9A6D-41A1-9CDA-DE10899648AA}
|
||||||
|
{8064870C-22EA-4A58-972D-DBD57D096D91} = {2A381C57-2697-427B-9F10-55DA11FD02E4}
|
||||||
EndGlobalSection
|
EndGlobalSection
|
||||||
GlobalSection(ExtensibilityGlobals) = postSolution
|
GlobalSection(ExtensibilityGlobals) = postSolution
|
||||||
RESX_NeutralResourcesLanguage = en-US
|
|
||||||
RESX_PrefixTranslations = True
|
|
||||||
SolutionGuid = {089687FD-5D25-40AB-BA8A-A10D1E137F98}
|
SolutionGuid = {089687FD-5D25-40AB-BA8A-A10D1E137F98}
|
||||||
|
RESX_PrefixTranslations = True
|
||||||
|
RESX_NeutralResourcesLanguage = en-US
|
||||||
EndGlobalSection
|
EndGlobalSection
|
||||||
EndGlobal
|
EndGlobal
|
||||||
|
121
Providers/FreeSql.Provider.Xugu/Curd/XuguDelete.cs
Normal file
121
Providers/FreeSql.Provider.Xugu/Curd/XuguDelete.cs
Normal file
@ -0,0 +1,121 @@
|
|||||||
|
using FreeSql.Internal;
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Data;
|
||||||
|
using System.Data.Common;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
namespace FreeSql.Xugu.Curd
|
||||||
|
{
|
||||||
|
|
||||||
|
class XuguDelete<T1> : Internal.CommonProvider.DeleteProvider<T1>
|
||||||
|
{
|
||||||
|
public XuguDelete(IFreeSql orm, CommonUtils commonUtils, CommonExpression commonExpression, object dywhere)
|
||||||
|
: base(orm, commonUtils, commonExpression, dywhere)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
public override List<T1> ExecuteDeleted()
|
||||||
|
{
|
||||||
|
var ret = new List<T1>();
|
||||||
|
DbParameter[] dbParms = null;
|
||||||
|
StringBuilder sbret = null;
|
||||||
|
ToSqlFetch(sb =>
|
||||||
|
{
|
||||||
|
if (dbParms == null)
|
||||||
|
{
|
||||||
|
dbParms = _params.ToArray();
|
||||||
|
sbret = new StringBuilder();
|
||||||
|
sbret.Append(" RETURNING ");
|
||||||
|
|
||||||
|
var colidx = 0;
|
||||||
|
foreach (var col in _table.Columns.Values)
|
||||||
|
{
|
||||||
|
if (colidx > 0) sbret.Append(", ");
|
||||||
|
sbret.Append(_commonUtils.RereadColumn(col, _commonUtils.QuoteSqlName(col.Attribute.Name))).Append(" as ").Append(_commonUtils.QuoteSqlName(col.CsName));
|
||||||
|
++colidx;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
var sql = sb.Append(sbret).ToString();
|
||||||
|
var before = new Aop.CurdBeforeEventArgs(_table.Type, _table, Aop.CurdType.Delete, sql, dbParms);
|
||||||
|
_orm.Aop.CurdBeforeHandler?.Invoke(this, before);
|
||||||
|
|
||||||
|
Exception exception = null;
|
||||||
|
try
|
||||||
|
{
|
||||||
|
ret.AddRange(_orm.Ado.Query<T1>(_table.TypeLazy ?? _table.Type, _connection, _transaction, CommandType.Text, sql, _commandTimeout, dbParms));
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
exception = ex;
|
||||||
|
throw ex;
|
||||||
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
var after = new Aop.CurdAfterEventArgs(before, exception, ret);
|
||||||
|
_orm.Aop.CurdAfterHandler?.Invoke(this, after);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
if (dbParms != null)
|
||||||
|
{
|
||||||
|
this.ClearData();
|
||||||
|
sbret.Clear();
|
||||||
|
}
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
#if net40
|
||||||
|
#else
|
||||||
|
async public override Task<List<T1>> ExecuteDeletedAsync(CancellationToken cancellationToken = default)
|
||||||
|
{
|
||||||
|
var ret = new List<T1>();
|
||||||
|
DbParameter[] dbParms = null;
|
||||||
|
StringBuilder sbret = null;
|
||||||
|
await ToSqlFetchAsync(async sb =>
|
||||||
|
{
|
||||||
|
if (dbParms == null)
|
||||||
|
{
|
||||||
|
dbParms = _params.ToArray();
|
||||||
|
sbret = new StringBuilder();
|
||||||
|
sbret.Append(" RETURNING ");
|
||||||
|
|
||||||
|
var colidx = 0;
|
||||||
|
foreach (var col in _table.Columns.Values)
|
||||||
|
{
|
||||||
|
if (colidx > 0) sbret.Append(", ");
|
||||||
|
sbret.Append(_commonUtils.RereadColumn(col, _commonUtils.QuoteSqlName(col.Attribute.Name))).Append(" as ").Append(_commonUtils.QuoteSqlName(col.CsName));
|
||||||
|
++colidx;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
var sql = sb.Append(sbret).ToString();
|
||||||
|
var before = new Aop.CurdBeforeEventArgs(_table.Type, _table, Aop.CurdType.Delete, sql, dbParms);
|
||||||
|
_orm.Aop.CurdBeforeHandler?.Invoke(this, before);
|
||||||
|
|
||||||
|
Exception exception = null;
|
||||||
|
try
|
||||||
|
{
|
||||||
|
ret.AddRange(await _orm.Ado.QueryAsync<T1>(_table.TypeLazy ?? _table.Type, _connection, _transaction, CommandType.Text, sql, _commandTimeout, dbParms, cancellationToken));
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
exception = ex;
|
||||||
|
throw ex;
|
||||||
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
var after = new Aop.CurdAfterEventArgs(before, exception, ret);
|
||||||
|
_orm.Aop.CurdAfterHandler?.Invoke(this, after);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
if (dbParms != null)
|
||||||
|
{
|
||||||
|
this.ClearData();
|
||||||
|
sbret.Clear();
|
||||||
|
}
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
}
|
242
Providers/FreeSql.Provider.Xugu/Curd/XuguInsert.cs
Normal file
242
Providers/FreeSql.Provider.Xugu/Curd/XuguInsert.cs
Normal file
@ -0,0 +1,242 @@
|
|||||||
|
using FreeSql.Internal;
|
||||||
|
using FreeSql.Internal.Model;
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Data;
|
||||||
|
using System.Data.Common;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using XuguClient;
|
||||||
|
|
||||||
|
namespace FreeSql.Xugu.Curd
|
||||||
|
{
|
||||||
|
|
||||||
|
class XuguInsert<T1> : Internal.CommonProvider.InsertProvider<T1> where T1 : class
|
||||||
|
{
|
||||||
|
public XuguInsert(IFreeSql orm, CommonUtils commonUtils, CommonExpression commonExpression)
|
||||||
|
: base(orm, commonUtils, commonExpression)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
internal IFreeSql InternalOrm => _orm;
|
||||||
|
internal TableInfo InternalTable => _table;
|
||||||
|
internal DbParameter[] InternalParams => _params;
|
||||||
|
internal DbConnection InternalConnection => _connection;
|
||||||
|
internal DbTransaction InternalTransaction => _transaction;
|
||||||
|
internal CommonUtils InternalCommonUtils => _commonUtils;
|
||||||
|
internal CommonExpression InternalCommonExpression => _commonExpression;
|
||||||
|
internal List<T1> InternalSource => _source;
|
||||||
|
internal Dictionary<string, bool> InternalIgnore => _ignore;
|
||||||
|
internal void InternalClearData() => ClearData();
|
||||||
|
|
||||||
|
public override int ExecuteAffrows() => base.SplitExecuteAffrows(_batchValuesLimit > 0 ? _batchValuesLimit : 5000, _batchParameterLimit > 0 ? _batchParameterLimit : 3000);
|
||||||
|
public override long ExecuteIdentity() => base.SplitExecuteIdentity(_batchValuesLimit > 0 ? _batchValuesLimit : 5000, _batchParameterLimit > 0 ? _batchParameterLimit : 3000);
|
||||||
|
public override List<T1> ExecuteInserted() => base.SplitExecuteInserted(_batchValuesLimit > 0 ? _batchValuesLimit : 5000, _batchParameterLimit > 0 ? _batchParameterLimit : 3000);
|
||||||
|
|
||||||
|
protected override long RawExecuteIdentity()
|
||||||
|
{
|
||||||
|
var sql = this.ToSql();
|
||||||
|
if (string.IsNullOrEmpty(sql)) return 0;
|
||||||
|
|
||||||
|
long ret = 0;
|
||||||
|
Aop.CurdBeforeEventArgs before = new Aop.CurdBeforeEventArgs(_table.Type, _table, Aop.CurdType.Insert, sql, _params);
|
||||||
|
_orm.Aop.CurdBeforeHandler?.Invoke(this, before);
|
||||||
|
Exception exception = null;
|
||||||
|
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var identCols = _table.Columns.Where(a => a.Value.Attribute.IsIdentity == true);
|
||||||
|
if (identCols.Any() == false)
|
||||||
|
{
|
||||||
|
//var ex = new Exception("对没有自增主键的表执行插入操作时不能要求返回自增主键");
|
||||||
|
//exception = ex;
|
||||||
|
_orm.Ado.ExecuteNonQuery(_connection, _transaction, CommandType.Text, sql, _commandTimeout, _params);
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
}
|
||||||
|
_orm.Ado.ExecuteNonQuery(_connection, _transaction, CommandType.Text, sql, _commandTimeout, cmd =>
|
||||||
|
{
|
||||||
|
var rowid = (cmd as XGCommand).get_insert_rowid();
|
||||||
|
|
||||||
|
//using (var command = cmd.Connection.CreateCommand()) {
|
||||||
|
//command.CommandType = CommandType.Text;
|
||||||
|
var sqlIdentity = $"SELECT {_commonUtils.QuoteSqlName(identCols.First().Value.Attribute.Name)} FROM {_table.DbName} WHERE \"ROWID\"='{rowid}'";
|
||||||
|
|
||||||
|
|
||||||
|
//command.CommandText = sql;
|
||||||
|
if (!long.TryParse(_orm.Ado.ExecuteScalar(CommandType.Text, sqlIdentity, _params).ToString(), out ret))
|
||||||
|
{
|
||||||
|
|
||||||
|
};
|
||||||
|
// command.Dispose();
|
||||||
|
//}
|
||||||
|
|
||||||
|
}, _params);
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
exception = ex;
|
||||||
|
throw;
|
||||||
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
var after = new Aop.CurdAfterEventArgs(before, exception, ret);
|
||||||
|
_orm.Aop.CurdAfterHandler?.Invoke(this, after);
|
||||||
|
}
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override List<T1> RawExecuteInserted()
|
||||||
|
{
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
var sql = this.ToSql();
|
||||||
|
if (string.IsNullOrEmpty(sql)) return null;
|
||||||
|
|
||||||
|
Aop.CurdBeforeEventArgs before = new Aop.CurdBeforeEventArgs(_table.Type, _table, Aop.CurdType.Insert, sql, _params);
|
||||||
|
_orm.Aop.CurdBeforeHandler?.Invoke(this, before);
|
||||||
|
Exception exception = null;
|
||||||
|
|
||||||
|
var ret = new List<T1>();
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var sbColumn = new StringBuilder();
|
||||||
|
var colidx = 0;
|
||||||
|
foreach (var col in _table.Columns.Values)
|
||||||
|
{
|
||||||
|
if (colidx > 0) sbColumn.Append(", ");
|
||||||
|
sbColumn.Append(_commonUtils.RereadColumn(col, _commonUtils.QuoteSqlName(col.Attribute.Name))).Append(" as ").Append(_commonUtils.QuoteSqlName(col.CsName));
|
||||||
|
++colidx;
|
||||||
|
}
|
||||||
|
|
||||||
|
_orm.Ado.ExecuteNonQuery(_connection, _transaction, CommandType.Text, sql, _commandTimeout, cmd =>
|
||||||
|
{
|
||||||
|
var rowid = (cmd as XGCommand).get_insert_rowid();
|
||||||
|
|
||||||
|
var sqlIdentity = $"SELECT {sbColumn} FROM {_table.DbName} WHERE \"ROWID\"='{rowid}'";
|
||||||
|
|
||||||
|
ret = _orm.Ado.Query<T1>(_table.TypeLazy ?? _table.Type, _connection, _transaction, CommandType.Text, sqlIdentity, _commandTimeout, _params);
|
||||||
|
|
||||||
|
}, _params);
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
exception = ex;
|
||||||
|
throw;
|
||||||
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
var after = new Aop.CurdAfterEventArgs(before, exception, ret);
|
||||||
|
_orm.Aop.CurdAfterHandler?.Invoke(this, after);
|
||||||
|
}
|
||||||
|
return ret;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
#if net40
|
||||||
|
#else
|
||||||
|
public override Task<int> ExecuteAffrowsAsync(CancellationToken cancellationToken = default) => base.SplitExecuteAffrowsAsync(_batchValuesLimit > 0 ? _batchValuesLimit : 5000, _batchParameterLimit > 0 ? _batchParameterLimit : 3000, cancellationToken);
|
||||||
|
public override Task<long> ExecuteIdentityAsync(CancellationToken cancellationToken = default) => base.SplitExecuteIdentityAsync(_batchValuesLimit > 0 ? _batchValuesLimit : 5000, _batchParameterLimit > 0 ? _batchParameterLimit : 3000, cancellationToken);
|
||||||
|
public override Task<List<T1>> ExecuteInsertedAsync(CancellationToken cancellationToken = default) => base.SplitExecuteInsertedAsync(_batchValuesLimit > 0 ? _batchValuesLimit : 5000, _batchParameterLimit > 0 ? _batchParameterLimit : 3000, cancellationToken);
|
||||||
|
|
||||||
|
async protected override Task<long> RawExecuteIdentityAsync(CancellationToken cancellationToken = default)
|
||||||
|
{
|
||||||
|
|
||||||
|
|
||||||
|
var sql = this.ToSql();
|
||||||
|
if (string.IsNullOrEmpty(sql)) return 0;
|
||||||
|
|
||||||
|
var before = new Aop.CurdBeforeEventArgs(_table.Type, _table, Aop.CurdType.Insert, sql, _params);
|
||||||
|
_orm.Aop.CurdBeforeHandler?.Invoke(this, before);
|
||||||
|
long ret = 0;
|
||||||
|
Exception exception = null;
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var identCols = _table.Columns.Where(a => a.Value.Attribute.IsIdentity == true);
|
||||||
|
if (identCols.Any() == false)
|
||||||
|
{
|
||||||
|
//var ex = new Exception("对没有自增主键的表执行插入操作时不能要求返回自增主键");
|
||||||
|
//exception = ex;
|
||||||
|
_orm.Ado.ExecuteNonQuery(_connection, _transaction, CommandType.Text, sql, _commandTimeout, _params);
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
}
|
||||||
|
await _orm.Ado.ExecuteNonQueryAsync(_connection, _transaction, CommandType.Text, sql, _commandTimeout, cmd =>
|
||||||
|
{
|
||||||
|
var rowid = (cmd as XGCommand).get_insert_rowid();
|
||||||
|
var sqlIdentity = $"SELECT {_commonUtils.QuoteSqlName(identCols.First().Value.Attribute.Name)} FROM {_table.DbName} WHERE \"ROWID\"='{rowid}'";
|
||||||
|
if (!long.TryParse(_orm.Ado.ExecuteScalar(CommandType.Text, sqlIdentity, _params).ToString(), out ret))
|
||||||
|
{
|
||||||
|
|
||||||
|
};
|
||||||
|
return Task.CompletedTask;
|
||||||
|
}, _params, cancellationToken);
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
exception = ex;
|
||||||
|
throw;
|
||||||
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
var after = new Aop.CurdAfterEventArgs(before, exception, ret);
|
||||||
|
_orm.Aop.CurdAfterHandler?.Invoke(this, after);
|
||||||
|
}
|
||||||
|
return ret;
|
||||||
|
|
||||||
|
}
|
||||||
|
async protected override Task<List<T1>> RawExecuteInsertedAsync(CancellationToken cancellationToken = default)
|
||||||
|
{
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
var sql = this.ToSql();
|
||||||
|
if (string.IsNullOrEmpty(sql)) return null;
|
||||||
|
|
||||||
|
var before = new Aop.CurdBeforeEventArgs(_table.Type, _table, Aop.CurdType.Insert, sql, _params);
|
||||||
|
_orm.Aop.CurdBeforeHandler?.Invoke(this, before);
|
||||||
|
var ret = new List<T1>();
|
||||||
|
Exception exception = null;
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var sbColumn = new StringBuilder();
|
||||||
|
var colidx = 0;
|
||||||
|
foreach (var col in _table.Columns.Values)
|
||||||
|
{
|
||||||
|
if (colidx > 0) sbColumn.Append(", ");
|
||||||
|
sbColumn.Append(_commonUtils.RereadColumn(col, _commonUtils.QuoteSqlName(col.Attribute.Name))).Append(" as ").Append(_commonUtils.QuoteSqlName(col.CsName));
|
||||||
|
++colidx;
|
||||||
|
}
|
||||||
|
await _orm.Ado.ExecuteNonQueryAsync(_connection, _transaction, CommandType.Text, sql, _commandTimeout, cmd =>
|
||||||
|
{
|
||||||
|
var rowid = (cmd as XGCommand).get_insert_rowid();
|
||||||
|
|
||||||
|
var sqlIdentity = $"SELECT {sbColumn} FROM {_table.DbName} WHERE \"ROWID\"='{rowid}'";
|
||||||
|
|
||||||
|
ret = _orm.Ado.Query<T1>(_table.TypeLazy ?? _table.Type, _connection, _transaction, CommandType.Text, sqlIdentity, _commandTimeout, _params);
|
||||||
|
return Task.CompletedTask;
|
||||||
|
}, _params, cancellationToken);
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
exception = ex;
|
||||||
|
throw;
|
||||||
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
var after = new Aop.CurdAfterEventArgs(before, exception, ret);
|
||||||
|
_orm.Aop.CurdAfterHandler?.Invoke(this, after);
|
||||||
|
}
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
}
|
89
Providers/FreeSql.Provider.Xugu/Curd/XuguInsertOrUpdate.cs
Normal file
89
Providers/FreeSql.Provider.Xugu/Curd/XuguInsertOrUpdate.cs
Normal file
@ -0,0 +1,89 @@
|
|||||||
|
using FreeSql.Internal;
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Data.Common;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
|
||||||
|
namespace FreeSql.Xugu.Curd
|
||||||
|
{
|
||||||
|
|
||||||
|
class XuguInsertOrUpdate<T1> : Internal.CommonProvider.InsertOrUpdateProvider<T1> where T1 : class
|
||||||
|
{
|
||||||
|
public XuguInsertOrUpdate(IFreeSql orm, CommonUtils commonUtils, CommonExpression commonExpression)
|
||||||
|
: base(orm, commonUtils, commonExpression)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
public override string ToSql()
|
||||||
|
{
|
||||||
|
|
||||||
|
var dbParams = new List<DbParameter>();
|
||||||
|
if (_sourceSql != null) return getMergeSql(null);
|
||||||
|
if (_source?.Any() != true) return null;
|
||||||
|
|
||||||
|
var sqls = new string[2];
|
||||||
|
// 如果实体类有自增属性,分成两个 List,有值的Item1 merge,无值的Item2 insert
|
||||||
|
var ds = SplitSourceByIdentityValueIsNull(_source);
|
||||||
|
if (ds.Item1.Any()) sqls[0] = string.Join("\r\n\r\n;\r\n\r\n", ds.Item1.Select(a => getMergeSql(a)));
|
||||||
|
if (ds.Item2.Any()) sqls[1] = string.Join("\r\n\r\n;\r\n\r\n", ds.Item2.Select(a => getInsertSql(a)));
|
||||||
|
_params = dbParams.ToArray();
|
||||||
|
if (ds.Item2.Any() == false) return sqls[0];
|
||||||
|
if (ds.Item1.Any() == false) return sqls[1];
|
||||||
|
return string.Join("\r\n\r\n;\r\n\r\n", sqls);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
string getMergeSql(List<T1> data)
|
||||||
|
{
|
||||||
|
if (_tempPrimarys.Any() == false) throw new Exception(CoreStrings.InsertOrUpdate_Must_Primary_Key(_table.CsName));
|
||||||
|
|
||||||
|
var tempPrimaryIsIdentity = _tempPrimarys.Any(b => b.Attribute.IsIdentity);
|
||||||
|
var sb = new StringBuilder().Append("MERGE INTO ").Append(_commonUtils.QuoteSqlName(TableRuleInvoke())).Append(" t1 \r\nUSING (");
|
||||||
|
WriteSourceSelectUnionAll(data, sb, dbParams);
|
||||||
|
sb.Append(" ) t2 ON (").Append(string.Join(" AND ", _tempPrimarys.Select(a => $"t1.{_commonUtils.QuoteSqlName(a.Attribute.Name)} = t2.{_commonUtils.QuoteSqlName(a.Attribute.Name)}"))).Append(") \r\n");
|
||||||
|
|
||||||
|
var cols = _table.Columns.Values.Where(a => _tempPrimarys.Contains(a) == false && a.Attribute.CanUpdate == true && a.Attribute.IsIdentity == false && _updateIgnore.ContainsKey(a.Attribute.Name) == false);
|
||||||
|
if (_doNothing == false && cols.Any())
|
||||||
|
sb.Append("WHEN MATCHED THEN \r\n")
|
||||||
|
.Append(" update set ").Append(string.Join(", ", cols.Select(a =>
|
||||||
|
a.Attribute.IsVersion && a.Attribute.MapType != typeof(byte[]) ?
|
||||||
|
$"{_commonUtils.QuoteSqlName(a.Attribute.Name)} = t1.{_commonUtils.QuoteSqlName(a.Attribute.Name)} + 1" :
|
||||||
|
$"{_commonUtils.QuoteSqlName(a.Attribute.Name)} = t2.{_commonUtils.QuoteSqlName(a.Attribute.Name)}"
|
||||||
|
))).Append(" \r\n");
|
||||||
|
|
||||||
|
cols = _table.Columns.Values.Where(a => a.Attribute.CanInsert == true);
|
||||||
|
if (tempPrimaryIsIdentity == false) cols = cols.Where(a => a.Attribute.IsIdentity == false || string.IsNullOrEmpty(a.DbInsertValue) == false);
|
||||||
|
if (cols.Any())
|
||||||
|
sb.Append("WHEN NOT MATCHED THEN \r\n")
|
||||||
|
.Append(" insert (").Append(string.Join(", ", cols.Select(a => _commonUtils.QuoteSqlName(a.Attribute.Name)))).Append(") \r\n")
|
||||||
|
.Append(" values (").Append(string.Join(", ", cols.Select(a =>
|
||||||
|
{
|
||||||
|
//InsertValueSql = "seq.nextval"
|
||||||
|
if (tempPrimaryIsIdentity == false && a.Attribute.IsIdentity && string.IsNullOrEmpty(a.DbInsertValue) == false) return a.DbInsertValue;
|
||||||
|
return $"t2.{_commonUtils.QuoteSqlName(a.Attribute.Name)}";
|
||||||
|
}))).Append(")");
|
||||||
|
|
||||||
|
return sb.ToString();
|
||||||
|
}
|
||||||
|
string getInsertSql(List<T1> data)
|
||||||
|
{
|
||||||
|
var insert = _orm.Insert<T1>()
|
||||||
|
.AsTable(_tableRule).AsType(_table.Type)
|
||||||
|
.WithConnection(_connection)
|
||||||
|
.WithTransaction(_transaction)
|
||||||
|
.NoneParameter(true) as Internal.CommonProvider.InsertProvider<T1>;
|
||||||
|
insert._source = data;
|
||||||
|
insert._table = _table;
|
||||||
|
var sql = insert.ToSql();
|
||||||
|
if (string.IsNullOrEmpty(sql)) return null;
|
||||||
|
if (insert._params?.Any() == true) dbParams.AddRange(insert._params);
|
||||||
|
return sql;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
216
Providers/FreeSql.Provider.Xugu/Curd/XuguSelect.cs
Normal file
216
Providers/FreeSql.Provider.Xugu/Curd/XuguSelect.cs
Normal file
@ -0,0 +1,216 @@
|
|||||||
|
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.Xugu.Curd
|
||||||
|
{
|
||||||
|
|
||||||
|
class XuguSelect<T1> : FreeSql.Internal.CommonProvider.Select1Provider<T1>
|
||||||
|
{
|
||||||
|
|
||||||
|
internal static string ToSqlStatic(CommonUtils _commonUtils, CommonExpression _commonExpression, string _select, bool _distinct, string field, StringBuilder _join, StringBuilder _where, string _groupby, string _having, string _orderby, int _skip, int _limit, List<SelectTableInfo> _tables, List<Dictionary<Type, string>> tbUnions, Func<Type, string, string> _aliasRule, string _tosqlAppendContent, List<GlobalFilter.Item> _whereGlobalFilter, IFreeSql _orm)
|
||||||
|
{
|
||||||
|
if (_orm.CodeFirst.IsAutoSyncStructure)
|
||||||
|
_orm.CodeFirst.SyncStructure(_tables.Select(a => a.Table.Type).ToArray());
|
||||||
|
|
||||||
|
if (_whereGlobalFilter.Any())
|
||||||
|
foreach (var tb in _tables.Where(a => a.Type != SelectTableInfoType.Parent))
|
||||||
|
tb.Cascade = _commonExpression.GetWhereCascadeSql(tb, _whereGlobalFilter, true);
|
||||||
|
|
||||||
|
var sb = new StringBuilder();
|
||||||
|
var tbUnionsGt0 = tbUnions.Count > 1;
|
||||||
|
for (var tbUnionsIdx = 0; tbUnionsIdx < tbUnions.Count; tbUnionsIdx++)
|
||||||
|
{
|
||||||
|
if (tbUnionsIdx > 0) sb.Append("\r\n \r\nUNION ALL\r\n \r\n");
|
||||||
|
if (tbUnionsGt0) sb.Append(_select).Append(" * from (");
|
||||||
|
var tbUnion = tbUnions[tbUnionsIdx];
|
||||||
|
|
||||||
|
var sbnav = new StringBuilder();
|
||||||
|
sb.Append(_select);
|
||||||
|
if (_distinct) sb.Append("DISTINCT ");
|
||||||
|
sb.Append(field).Append(" \r\nFROM ");
|
||||||
|
var tbsjoin = _tables.Where(a => a.Type != SelectTableInfoType.From).ToArray();
|
||||||
|
var tbsfrom = _tables.Where(a => a.Type == SelectTableInfoType.From).ToArray();
|
||||||
|
for (var a = 0; a < tbsfrom.Length; a++)
|
||||||
|
{
|
||||||
|
sb.Append(_commonUtils.QuoteSqlName(tbUnion[tbsfrom[a].Table.Type])).Append(" ").Append(_aliasRule?.Invoke(tbsfrom[a].Table.Type, tbsfrom[a].Alias) ?? tbsfrom[a].Alias);
|
||||||
|
if (tbsjoin.Length > 0)
|
||||||
|
{
|
||||||
|
//如果存在 join 查询,则处理 from t1, t2 改为 from t1 inner join t2 on 1 = 1
|
||||||
|
for (var b = 1; b < tbsfrom.Length; b++)
|
||||||
|
{
|
||||||
|
sb.Append(" \r\nLEFT JOIN ").Append(_commonUtils.QuoteSqlName(tbUnion[tbsfrom[b].Table.Type])).Append(" ").Append(_aliasRule?.Invoke(tbsfrom[b].Table.Type, tbsfrom[b].Alias) ?? tbsfrom[b].Alias);
|
||||||
|
|
||||||
|
if (string.IsNullOrEmpty(tbsfrom[b].NavigateCondition) && string.IsNullOrEmpty(tbsfrom[b].On) && string.IsNullOrEmpty(tbsfrom[b].Cascade)) sb.Append(" ON 1 = 1");
|
||||||
|
else
|
||||||
|
{
|
||||||
|
var onSql = tbsfrom[b].NavigateCondition ?? tbsfrom[b].On;
|
||||||
|
sb.Append(" ON ").Append(onSql);
|
||||||
|
if (string.IsNullOrEmpty(tbsfrom[b].Cascade) == false)
|
||||||
|
{
|
||||||
|
if (string.IsNullOrEmpty(onSql)) sb.Append(tbsfrom[b].Cascade);
|
||||||
|
else sb.Append(" AND ").Append(tbsfrom[b].Cascade);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (!string.IsNullOrEmpty(tbsfrom[a].NavigateCondition)) sbnav.Append(" AND (").Append(tbsfrom[a].NavigateCondition).Append(")");
|
||||||
|
if (!string.IsNullOrEmpty(tbsfrom[a].On)) sbnav.Append(" AND (").Append(tbsfrom[a].On).Append(")");
|
||||||
|
if (a > 0 && !string.IsNullOrEmpty(tbsfrom[a].Cascade)) sbnav.Append(" AND ").Append(tbsfrom[a].Cascade);
|
||||||
|
}
|
||||||
|
if (a < tbsfrom.Length - 1) sb.Append(", ");
|
||||||
|
}
|
||||||
|
foreach (var tb in tbsjoin)
|
||||||
|
{
|
||||||
|
switch (tb.Type)
|
||||||
|
{
|
||||||
|
case SelectTableInfoType.Parent:
|
||||||
|
case SelectTableInfoType.RawJoin:
|
||||||
|
continue;
|
||||||
|
case SelectTableInfoType.LeftJoin:
|
||||||
|
sb.Append(" \r\nLEFT JOIN ");
|
||||||
|
break;
|
||||||
|
case SelectTableInfoType.InnerJoin:
|
||||||
|
sb.Append(" \r\nINNER JOIN ");
|
||||||
|
break;
|
||||||
|
case SelectTableInfoType.RightJoin:
|
||||||
|
sb.Append(" \r\nRIGHT JOIN ");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
sb.Append(_commonUtils.QuoteSqlName(tbUnion[tb.Table.Type])).Append(" ").Append(_aliasRule?.Invoke(tb.Table.Type, tb.Alias) ?? tb.Alias).Append(" ON ").Append(tb.On ?? tb.NavigateCondition);
|
||||||
|
if (!string.IsNullOrEmpty(tb.Cascade)) sb.Append(" AND ").Append(tb.Cascade);
|
||||||
|
if (!string.IsNullOrEmpty(tb.On) && !string.IsNullOrEmpty(tb.NavigateCondition)) sbnav.Append(" AND (").Append(tb.NavigateCondition).Append(")");
|
||||||
|
}
|
||||||
|
if (_join.Length > 0) sb.Append(_join);
|
||||||
|
|
||||||
|
sbnav.Append(_where);
|
||||||
|
if (!string.IsNullOrEmpty(_tables[0].Cascade))
|
||||||
|
sbnav.Append(" AND ").Append(_tables[0].Cascade);
|
||||||
|
|
||||||
|
if (sbnav.Length > 0)
|
||||||
|
{
|
||||||
|
sb.Append(" \r\nWHERE ").Append(sbnav.Remove(0, 5));
|
||||||
|
}
|
||||||
|
if (string.IsNullOrEmpty(_groupby) == false)
|
||||||
|
{
|
||||||
|
sb.Append(_groupby);
|
||||||
|
if (string.IsNullOrEmpty(_having) == false)
|
||||||
|
sb.Append(" \r\nHAVING ").Append(_having.Substring(5));
|
||||||
|
}
|
||||||
|
sb.Append(_orderby);
|
||||||
|
if (_limit > 0) {
|
||||||
|
sb.Append(" \r\nlimit ").Append(_limit);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (_skip > 0)
|
||||||
|
sb.Append(" \r\noffset ").Append(_skip);
|
||||||
|
|
||||||
|
sbnav.Clear();
|
||||||
|
if (tbUnionsGt0) sb.Append(") ftb");
|
||||||
|
}
|
||||||
|
return sb.Append(_tosqlAppendContent).ToString();
|
||||||
|
}
|
||||||
|
|
||||||
|
public XuguSelect(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 PostgreSQLSelect<T1, T2>(_orm, _commonUtils, _commonExpression, null); XuguSelect<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 PostgreSQLSelect<T1, T2, T3>(_orm, _commonUtils, _commonExpression, null); XuguSelect<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 PostgreSQLSelect<T1, T2, T3, T4>(_orm, _commonUtils, _commonExpression, null); XuguSelect<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 PostgreSQLSelect<T1, T2, T3, T4, T5>(_orm, _commonUtils, _commonExpression, null); XuguSelect<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 PostgreSQLSelect<T1, T2, T3, T4, T5, T6>(_orm, _commonUtils, _commonExpression, null); XuguSelect<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 PostgreSQLSelect<T1, T2, T3, T4, T5, T6, T7>(_orm, _commonUtils, _commonExpression, null); XuguSelect<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 PostgreSQLSelect<T1, T2, T3, T4, T5, T6, T7, T8>(_orm, _commonUtils, _commonExpression, null); XuguSelect<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 PostgreSQLSelect<T1, T2, T3, T4, T5, T6, T7, T8, T9>(_orm, _commonUtils, _commonExpression, null); XuguSelect<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 PostgreSQLSelect<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10>(_orm, _commonUtils, _commonExpression, null); XuguSelect<T1>.CopyData(this, ret, exp?.Parameters); return ret; }
|
||||||
|
|
||||||
|
public override ISelect<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11> From<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11>(Expression<Func<ISelectFromExpression<T1>, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, ISelectFromExpression<T1>>> exp) { this.InternalFrom(exp); var ret = new PostgreSQLSelect<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11>(_orm, _commonUtils, _commonExpression, null); XuguSelect<T1>.CopyData(this, ret, exp?.Parameters); return ret; }
|
||||||
|
public override ISelect<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12> From<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12>(Expression<Func<ISelectFromExpression<T1>, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, ISelectFromExpression<T1>>> exp) { this.InternalFrom(exp); var ret = new PostgreSQLSelect<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12>(_orm, _commonUtils, _commonExpression, null); XuguSelect<T1>.CopyData(this, ret, exp?.Parameters); return ret; }
|
||||||
|
public override ISelect<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13> From<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13>(Expression<Func<ISelectFromExpression<T1>, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, ISelectFromExpression<T1>>> exp) { this.InternalFrom(exp); var ret = new PostgreSQLSelect<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13>(_orm, _commonUtils, _commonExpression, null); XuguSelect<T1>.CopyData(this, ret, exp?.Parameters); return ret; }
|
||||||
|
public override ISelect<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14> From<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14>(Expression<Func<ISelectFromExpression<T1>, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, ISelectFromExpression<T1>>> exp) { this.InternalFrom(exp); var ret = new PostgreSQLSelect<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14>(_orm, _commonUtils, _commonExpression, null); XuguSelect<T1>.CopyData(this, ret, exp?.Parameters); return ret; }
|
||||||
|
public override ISelect<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15> From<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15>(Expression<Func<ISelectFromExpression<T1>, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15, ISelectFromExpression<T1>>> exp) { this.InternalFrom(exp); var ret = new PostgreSQLSelect<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15>(_orm, _commonUtils, _commonExpression, null); XuguSelect<T1>.CopyData(this, ret, exp?.Parameters); return ret; }
|
||||||
|
public override ISelect<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15, T16> From<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15, T16>(Expression<Func<ISelectFromExpression<T1>, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15, T16, ISelectFromExpression<T1>>> exp) { this.InternalFrom(exp); var ret = new PostgreSQLSelect<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15, T16>(_orm, _commonUtils, _commonExpression, null); XuguSelect<T1>.CopyData(this, ret, exp?.Parameters); return ret; }
|
||||||
|
public override string ToSql(string field = null) => ToSqlStatic(_commonUtils, _commonExpression, _select, _distinct, field ?? this.GetAllFieldExpressionTreeLevel2().Field, _join, _where, _groupby, _having, _orderby, _skip, _limit, _tables, this.GetTableRuleUnions(), _aliasRule, _tosqlAppendContent, _whereGlobalFilter, _orm);
|
||||||
|
}
|
||||||
|
class PostgreSQLSelect<T1, T2> : FreeSql.Internal.CommonProvider.Select2Provider<T1, T2> where T2 : class
|
||||||
|
{
|
||||||
|
public PostgreSQLSelect(IFreeSql orm, CommonUtils commonUtils, CommonExpression commonExpression, object dywhere) : base(orm, commonUtils, commonExpression, dywhere) { }
|
||||||
|
public override string ToSql(string field = null) => XuguSelect<T1>.ToSqlStatic(_commonUtils, _commonExpression, _select, _distinct, field ?? this.GetAllFieldExpressionTreeLevel2().Field, _join, _where, _groupby, _having, _orderby, _skip, _limit, _tables, this.GetTableRuleUnions(), _aliasRule, _tosqlAppendContent, _whereGlobalFilter, _orm);
|
||||||
|
}
|
||||||
|
class PostgreSQLSelect<T1, T2, T3> : FreeSql.Internal.CommonProvider.Select3Provider<T1, T2, T3> where T2 : class where T3 : class
|
||||||
|
{
|
||||||
|
public PostgreSQLSelect(IFreeSql orm, CommonUtils commonUtils, CommonExpression commonExpression, object dywhere) : base(orm, commonUtils, commonExpression, dywhere) { }
|
||||||
|
public override string ToSql(string field = null) => XuguSelect<T1>.ToSqlStatic(_commonUtils, _commonExpression, _select, _distinct, field ?? this.GetAllFieldExpressionTreeLevel2().Field, _join, _where, _groupby, _having, _orderby, _skip, _limit, _tables, this.GetTableRuleUnions(), _aliasRule, _tosqlAppendContent, _whereGlobalFilter, _orm);
|
||||||
|
}
|
||||||
|
class PostgreSQLSelect<T1, T2, T3, T4> : FreeSql.Internal.CommonProvider.Select4Provider<T1, T2, T3, T4> where T2 : class where T3 : class where T4 : class
|
||||||
|
{
|
||||||
|
public PostgreSQLSelect(IFreeSql orm, CommonUtils commonUtils, CommonExpression commonExpression, object dywhere) : base(orm, commonUtils, commonExpression, dywhere) { }
|
||||||
|
public override string ToSql(string field = null) => XuguSelect<T1>.ToSqlStatic(_commonUtils, _commonExpression, _select, _distinct, field ?? this.GetAllFieldExpressionTreeLevel2().Field, _join, _where, _groupby, _having, _orderby, _skip, _limit, _tables, this.GetTableRuleUnions(), _aliasRule, _tosqlAppendContent, _whereGlobalFilter, _orm);
|
||||||
|
}
|
||||||
|
class PostgreSQLSelect<T1, T2, T3, T4, T5> : FreeSql.Internal.CommonProvider.Select5Provider<T1, T2, T3, T4, T5> where T2 : class where T3 : class where T4 : class where T5 : class
|
||||||
|
{
|
||||||
|
public PostgreSQLSelect(IFreeSql orm, CommonUtils commonUtils, CommonExpression commonExpression, object dywhere) : base(orm, commonUtils, commonExpression, dywhere) { }
|
||||||
|
public override string ToSql(string field = null) => XuguSelect<T1>.ToSqlStatic(_commonUtils, _commonExpression, _select, _distinct, field ?? this.GetAllFieldExpressionTreeLevel2().Field, _join, _where, _groupby, _having, _orderby, _skip, _limit, _tables, this.GetTableRuleUnions(), _aliasRule, _tosqlAppendContent, _whereGlobalFilter, _orm);
|
||||||
|
}
|
||||||
|
class PostgreSQLSelect<T1, T2, T3, T4, T5, T6> : FreeSql.Internal.CommonProvider.Select6Provider<T1, T2, T3, T4, T5, T6> where T2 : class where T3 : class where T4 : class where T5 : class where T6 : class
|
||||||
|
{
|
||||||
|
public PostgreSQLSelect(IFreeSql orm, CommonUtils commonUtils, CommonExpression commonExpression, object dywhere) : base(orm, commonUtils, commonExpression, dywhere) { }
|
||||||
|
public override string ToSql(string field = null) => XuguSelect<T1>.ToSqlStatic(_commonUtils, _commonExpression, _select, _distinct, field ?? this.GetAllFieldExpressionTreeLevel2().Field, _join, _where, _groupby, _having, _orderby, _skip, _limit, _tables, this.GetTableRuleUnions(), _aliasRule, _tosqlAppendContent, _whereGlobalFilter, _orm);
|
||||||
|
}
|
||||||
|
class PostgreSQLSelect<T1, T2, T3, T4, T5, T6, T7> : FreeSql.Internal.CommonProvider.Select7Provider<T1, T2, T3, T4, T5, T6, T7> where T2 : class where T3 : class where T4 : class where T5 : class where T6 : class where T7 : class
|
||||||
|
{
|
||||||
|
public PostgreSQLSelect(IFreeSql orm, CommonUtils commonUtils, CommonExpression commonExpression, object dywhere) : base(orm, commonUtils, commonExpression, dywhere) { }
|
||||||
|
public override string ToSql(string field = null) => XuguSelect<T1>.ToSqlStatic(_commonUtils, _commonExpression, _select, _distinct, field ?? this.GetAllFieldExpressionTreeLevel2().Field, _join, _where, _groupby, _having, _orderby, _skip, _limit, _tables, this.GetTableRuleUnions(), _aliasRule, _tosqlAppendContent, _whereGlobalFilter, _orm);
|
||||||
|
}
|
||||||
|
class PostgreSQLSelect<T1, T2, T3, T4, T5, T6, T7, T8> : FreeSql.Internal.CommonProvider.Select8Provider<T1, T2, T3, T4, T5, T6, T7, T8> where T2 : class where T3 : class where T4 : class where T5 : class where T6 : class where T7 : class where T8 : class
|
||||||
|
{
|
||||||
|
public PostgreSQLSelect(IFreeSql orm, CommonUtils commonUtils, CommonExpression commonExpression, object dywhere) : base(orm, commonUtils, commonExpression, dywhere) { }
|
||||||
|
public override string ToSql(string field = null) => XuguSelect<T1>.ToSqlStatic(_commonUtils, _commonExpression, _select, _distinct, field ?? this.GetAllFieldExpressionTreeLevel2().Field, _join, _where, _groupby, _having, _orderby, _skip, _limit, _tables, this.GetTableRuleUnions(), _aliasRule, _tosqlAppendContent, _whereGlobalFilter, _orm);
|
||||||
|
}
|
||||||
|
class PostgreSQLSelect<T1, T2, T3, T4, T5, T6, T7, T8, T9> : FreeSql.Internal.CommonProvider.Select9Provider<T1, T2, T3, T4, T5, T6, T7, T8, T9> where T2 : class where T3 : class where T4 : class where T5 : class where T6 : class where T7 : class where T8 : class where T9 : class
|
||||||
|
{
|
||||||
|
public PostgreSQLSelect(IFreeSql orm, CommonUtils commonUtils, CommonExpression commonExpression, object dywhere) : base(orm, commonUtils, commonExpression, dywhere) { }
|
||||||
|
public override string ToSql(string field = null) => XuguSelect<T1>.ToSqlStatic(_commonUtils, _commonExpression, _select, _distinct, field ?? this.GetAllFieldExpressionTreeLevel2().Field, _join, _where, _groupby, _having, _orderby, _skip, _limit, _tables, this.GetTableRuleUnions(), _aliasRule, _tosqlAppendContent, _whereGlobalFilter, _orm);
|
||||||
|
}
|
||||||
|
class PostgreSQLSelect<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10> : FreeSql.Internal.CommonProvider.Select10Provider<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10> where T2 : class where T3 : class where T4 : class where T5 : class where T6 : class where T7 : class where T8 : class where T9 : class where T10 : class
|
||||||
|
{
|
||||||
|
public PostgreSQLSelect(IFreeSql orm, CommonUtils commonUtils, CommonExpression commonExpression, object dywhere) : base(orm, commonUtils, commonExpression, dywhere) { }
|
||||||
|
public override string ToSql(string field = null) => XuguSelect<T1>.ToSqlStatic(_commonUtils, _commonExpression, _select, _distinct, field ?? this.GetAllFieldExpressionTreeLevel2().Field, _join, _where, _groupby, _having, _orderby, _skip, _limit, _tables, this.GetTableRuleUnions(), _aliasRule, _tosqlAppendContent, _whereGlobalFilter, _orm);
|
||||||
|
}
|
||||||
|
|
||||||
|
class PostgreSQLSelect<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11> : FreeSql.Internal.CommonProvider.Select11Provider<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11> where T2 : class where T3 : class where T4 : class where T5 : class where T6 : class where T7 : class where T8 : class where T9 : class where T10 : class where T11 : class
|
||||||
|
{
|
||||||
|
public PostgreSQLSelect(IFreeSql orm, CommonUtils commonUtils, CommonExpression commonExpression, object dywhere) : base(orm, commonUtils, commonExpression, dywhere) { }
|
||||||
|
public override string ToSql(string field = null) => XuguSelect<T1>.ToSqlStatic(_commonUtils, _commonExpression, _select, _distinct, field ?? this.GetAllFieldExpressionTreeLevel2().Field, _join, _where, _groupby, _having, _orderby, _skip, _limit, _tables, this.GetTableRuleUnions(), _aliasRule, _tosqlAppendContent, _whereGlobalFilter, _orm);
|
||||||
|
}
|
||||||
|
class PostgreSQLSelect<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12> : FreeSql.Internal.CommonProvider.Select12Provider<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12> where T2 : class where T3 : class where T4 : class where T5 : class where T6 : class where T7 : class where T8 : class where T9 : class where T10 : class where T11 : class where T12 : class
|
||||||
|
{
|
||||||
|
public PostgreSQLSelect(IFreeSql orm, CommonUtils commonUtils, CommonExpression commonExpression, object dywhere) : base(orm, commonUtils, commonExpression, dywhere) { }
|
||||||
|
public override string ToSql(string field = null) => XuguSelect<T1>.ToSqlStatic(_commonUtils, _commonExpression, _select, _distinct, field ?? this.GetAllFieldExpressionTreeLevel2().Field, _join, _where, _groupby, _having, _orderby, _skip, _limit, _tables, this.GetTableRuleUnions(), _aliasRule, _tosqlAppendContent, _whereGlobalFilter, _orm);
|
||||||
|
}
|
||||||
|
class PostgreSQLSelect<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13> : FreeSql.Internal.CommonProvider.Select13Provider<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13> where T2 : class where T3 : class where T4 : class where T5 : class where T6 : class where T7 : class where T8 : class where T9 : class where T10 : class where T11 : class where T12 : class where T13 : class
|
||||||
|
{
|
||||||
|
public PostgreSQLSelect(IFreeSql orm, CommonUtils commonUtils, CommonExpression commonExpression, object dywhere) : base(orm, commonUtils, commonExpression, dywhere) { }
|
||||||
|
public override string ToSql(string field = null) => XuguSelect<T1>.ToSqlStatic(_commonUtils, _commonExpression, _select, _distinct, field ?? this.GetAllFieldExpressionTreeLevel2().Field, _join, _where, _groupby, _having, _orderby, _skip, _limit, _tables, this.GetTableRuleUnions(), _aliasRule, _tosqlAppendContent, _whereGlobalFilter, _orm);
|
||||||
|
}
|
||||||
|
class PostgreSQLSelect<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14> : FreeSql.Internal.CommonProvider.Select14Provider<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14> where T2 : class where T3 : class where T4 : class where T5 : class where T6 : class where T7 : class where T8 : class where T9 : class where T10 : class where T11 : class where T12 : class where T13 : class where T14 : class
|
||||||
|
{
|
||||||
|
public PostgreSQLSelect(IFreeSql orm, CommonUtils commonUtils, CommonExpression commonExpression, object dywhere) : base(orm, commonUtils, commonExpression, dywhere) { }
|
||||||
|
public override string ToSql(string field = null) => XuguSelect<T1>.ToSqlStatic(_commonUtils, _commonExpression, _select, _distinct, field ?? this.GetAllFieldExpressionTreeLevel2().Field, _join, _where, _groupby, _having, _orderby, _skip, _limit, _tables, this.GetTableRuleUnions(), _aliasRule, _tosqlAppendContent, _whereGlobalFilter, _orm);
|
||||||
|
}
|
||||||
|
class PostgreSQLSelect<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15> : FreeSql.Internal.CommonProvider.Select15Provider<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15> where T2 : class where T3 : class where T4 : class where T5 : class where T6 : class where T7 : class where T8 : class where T9 : class where T10 : class where T11 : class where T12 : class where T13 : class where T14 : class where T15 : class
|
||||||
|
{
|
||||||
|
public PostgreSQLSelect(IFreeSql orm, CommonUtils commonUtils, CommonExpression commonExpression, object dywhere) : base(orm, commonUtils, commonExpression, dywhere) { }
|
||||||
|
public override string ToSql(string field = null) => XuguSelect<T1>.ToSqlStatic(_commonUtils, _commonExpression, _select, _distinct, field ?? this.GetAllFieldExpressionTreeLevel2().Field, _join, _where, _groupby, _having, _orderby, _skip, _limit, _tables, this.GetTableRuleUnions(), _aliasRule, _tosqlAppendContent, _whereGlobalFilter, _orm);
|
||||||
|
}
|
||||||
|
class PostgreSQLSelect<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15, T16> : FreeSql.Internal.CommonProvider.Select16Provider<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15, T16> where T2 : class where T3 : class where T4 : class where T5 : class where T6 : class where T7 : class where T8 : class where T9 : class where T10 : class where T11 : class where T12 : class where T13 : class where T14 : class where T15 : class where T16 : class
|
||||||
|
{
|
||||||
|
public PostgreSQLSelect(IFreeSql orm, CommonUtils commonUtils, CommonExpression commonExpression, object dywhere) : base(orm, commonUtils, commonExpression, dywhere) { }
|
||||||
|
public override string ToSql(string field = null) => XuguSelect<T1>.ToSqlStatic(_commonUtils, _commonExpression, _select, _distinct, field ?? this.GetAllFieldExpressionTreeLevel2().Field, _join, _where, _groupby, _having, _orderby, _skip, _limit, _tables, this.GetTableRuleUnions(), _aliasRule, _tosqlAppendContent, _whereGlobalFilter, _orm);
|
||||||
|
}
|
||||||
|
}
|
187
Providers/FreeSql.Provider.Xugu/Curd/XuguUpdate.cs
Normal file
187
Providers/FreeSql.Provider.Xugu/Curd/XuguUpdate.cs
Normal file
@ -0,0 +1,187 @@
|
|||||||
|
using FreeSql.Internal;
|
||||||
|
using FreeSql.Internal.Model;
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Data;
|
||||||
|
using System.Data.Common;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
namespace FreeSql.Xugu.Curd
|
||||||
|
{
|
||||||
|
|
||||||
|
class XuguUpdate<T1> : Internal.CommonProvider.UpdateProvider<T1>
|
||||||
|
{
|
||||||
|
|
||||||
|
public XuguUpdate(IFreeSql orm, CommonUtils commonUtils, CommonExpression commonExpression, object dywhere)
|
||||||
|
: base(orm, commonUtils, commonExpression, dywhere)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
internal string InternalTableAlias { get; set; }
|
||||||
|
internal StringBuilder InternalSbSet => _set;
|
||||||
|
internal StringBuilder InternalSbSetIncr => _setIncr;
|
||||||
|
internal Dictionary<string, bool> InternalIgnore => _ignore;
|
||||||
|
internal void InternalResetSource(List<T1> source) => _source = source;
|
||||||
|
internal string InternalWhereCaseSource(string CsName, Func<string, string> thenValue) => WhereCaseSource(CsName, thenValue);
|
||||||
|
internal void InternalToSqlCaseWhenEnd(StringBuilder sb, ColumnInfo col) => ToSqlCaseWhenEnd(sb, col);
|
||||||
|
|
||||||
|
public override int ExecuteAffrows() => base.SplitExecuteAffrows(_batchRowsLimit > 0 ? _batchRowsLimit : 500, _batchParameterLimit > 0 ? _batchParameterLimit : 3000);
|
||||||
|
public override List<T1> ExecuteUpdated() => base.SplitExecuteUpdated(_batchRowsLimit > 0 ? _batchRowsLimit : 500, _batchParameterLimit > 0 ? _batchParameterLimit : 3000);
|
||||||
|
|
||||||
|
protected override List<T1> RawExecuteUpdated()
|
||||||
|
{
|
||||||
|
var ret = new List<T1>();
|
||||||
|
DbParameter[] dbParms = null;
|
||||||
|
StringBuilder sbret = null;
|
||||||
|
ToSqlFetch(sb =>
|
||||||
|
{
|
||||||
|
if (dbParms == null)
|
||||||
|
{
|
||||||
|
dbParms = _params.Concat(_paramsSource).ToArray();
|
||||||
|
sbret = new StringBuilder();
|
||||||
|
sbret.Append(" RETURNING ");
|
||||||
|
|
||||||
|
var colidx = 0;
|
||||||
|
foreach (var col in _table.Columns.Values)
|
||||||
|
{
|
||||||
|
if (colidx > 0) sbret.Append(", ");
|
||||||
|
sbret.Append(_commonUtils.RereadColumn(col, _commonUtils.QuoteSqlName(col.Attribute.Name))).Append(" as ").Append(_commonUtils.QuoteSqlName(col.CsName));
|
||||||
|
++colidx;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
var sql = sb.Append(sbret).ToString();
|
||||||
|
var before = new Aop.CurdBeforeEventArgs(_table.Type, _table, Aop.CurdType.Update, sql, dbParms);
|
||||||
|
_orm.Aop.CurdBeforeHandler?.Invoke(this, before);
|
||||||
|
|
||||||
|
Exception exception = null;
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var rettmp = _orm.Ado.Query<T1>(_table.TypeLazy ?? _table.Type, _connection, _transaction, CommandType.Text, sql, _commandTimeout, dbParms);
|
||||||
|
ValidateVersionAndThrow(rettmp.Count, sql, dbParms);
|
||||||
|
ret.AddRange(rettmp);
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
exception = ex;
|
||||||
|
throw;
|
||||||
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
var after = new Aop.CurdAfterEventArgs(before, exception, ret);
|
||||||
|
_orm.Aop.CurdAfterHandler?.Invoke(this, after);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
sbret?.Clear();
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override void ToSqlCase(StringBuilder caseWhen, ColumnInfo[] primarys)
|
||||||
|
{
|
||||||
|
if (primarys.Length == 1)
|
||||||
|
{
|
||||||
|
var pk = primarys.First();
|
||||||
|
if (string.IsNullOrEmpty(InternalTableAlias) == false) caseWhen.Append(InternalTableAlias).Append(".");
|
||||||
|
caseWhen.Append(_commonUtils.RereadColumn(pk, _commonUtils.QuoteSqlName(pk.Attribute.Name)));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
caseWhen.Append("(");
|
||||||
|
var pkidx = 0;
|
||||||
|
foreach (var pk in primarys)
|
||||||
|
{
|
||||||
|
if (pkidx > 0) caseWhen.Append(" || '+' || ");
|
||||||
|
if (string.IsNullOrEmpty(InternalTableAlias) == false) caseWhen.Append(InternalTableAlias).Append(".");
|
||||||
|
caseWhen.Append(_commonUtils.RereadColumn(pk, _commonUtils.QuoteSqlName(pk.Attribute.Name))).Append("::text");
|
||||||
|
++pkidx;
|
||||||
|
}
|
||||||
|
caseWhen.Append(")");
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override void ToSqlWhen(StringBuilder sb, ColumnInfo[] primarys, object d)
|
||||||
|
{
|
||||||
|
if (primarys.Length == 1)
|
||||||
|
{
|
||||||
|
sb.Append(_commonUtils.FormatSql("{0}", primarys[0].GetDbValue(d)));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
sb.Append("(");
|
||||||
|
var pkidx = 0;
|
||||||
|
foreach (var pk in primarys)
|
||||||
|
{
|
||||||
|
if (pkidx > 0) sb.Append(" || '+' || ");
|
||||||
|
sb.Append(_commonUtils.FormatSql("{0}", pk.GetDbValue(d))).Append("::text");
|
||||||
|
++pkidx;
|
||||||
|
}
|
||||||
|
sb.Append(")");
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override void ToSqlCaseWhenEnd(StringBuilder sb, ColumnInfo col)
|
||||||
|
{
|
||||||
|
if (_noneParameter == false) return;
|
||||||
|
if (col.Attribute.MapType == typeof(string))
|
||||||
|
{
|
||||||
|
sb.Append("::text");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
var dbtype = _commonUtils.CodeFirst.GetDbInfo(col.Attribute.MapType)?.dbtype;
|
||||||
|
if (dbtype == null) return;
|
||||||
|
|
||||||
|
sb.Append("::").Append(dbtype);
|
||||||
|
}
|
||||||
|
|
||||||
|
#if net40
|
||||||
|
#else
|
||||||
|
public override Task<int> ExecuteAffrowsAsync(CancellationToken cancellationToken = default) => base.SplitExecuteAffrowsAsync(_batchRowsLimit > 0 ? _batchRowsLimit : 500, _batchParameterLimit > 0 ? _batchParameterLimit : 3000, cancellationToken);
|
||||||
|
public override Task<List<T1>> ExecuteUpdatedAsync(CancellationToken cancellationToken = default) => base.SplitExecuteUpdatedAsync(_batchRowsLimit > 0 ? _batchRowsLimit : 500, _batchParameterLimit > 0 ? _batchParameterLimit : 3000, cancellationToken);
|
||||||
|
|
||||||
|
async protected override Task<List<T1>> RawExecuteUpdatedAsync(CancellationToken cancellationToken = default)
|
||||||
|
{
|
||||||
|
var ret = new List<T1>();
|
||||||
|
DbParameter[] dbParms = null;
|
||||||
|
StringBuilder sbret = null;
|
||||||
|
await ToSqlFetchAsync(async sb =>
|
||||||
|
{
|
||||||
|
if (dbParms == null)
|
||||||
|
{
|
||||||
|
dbParms = _params.Concat(_paramsSource).ToArray();
|
||||||
|
sbret = new StringBuilder();
|
||||||
|
sbret.Append(" RETURNING ");
|
||||||
|
|
||||||
|
var colidx = 0;
|
||||||
|
foreach (var col in _table.Columns.Values)
|
||||||
|
{
|
||||||
|
if (colidx > 0) sbret.Append(", ");
|
||||||
|
sbret.Append(_commonUtils.RereadColumn(col, _commonUtils.QuoteSqlName(col.Attribute.Name))).Append(" as ").Append(_commonUtils.QuoteSqlName(col.CsName));
|
||||||
|
++colidx;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
var sql = sb.Append(sbret).ToString();
|
||||||
|
var before = new Aop.CurdBeforeEventArgs(_table.Type, _table, Aop.CurdType.Update, sql, dbParms);
|
||||||
|
_orm.Aop.CurdBeforeHandler?.Invoke(this, before);
|
||||||
|
|
||||||
|
Exception exception = null;
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var rettmp = await _orm.Ado.QueryAsync<T1>(_table.TypeLazy ?? _table.Type, _connection, _transaction, CommandType.Text, sql, _commandTimeout, dbParms, cancellationToken);
|
||||||
|
ValidateVersionAndThrow(rettmp.Count, sql, dbParms);
|
||||||
|
ret.AddRange(rettmp);
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
exception = ex;
|
||||||
|
throw;
|
||||||
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
var after = new Aop.CurdAfterEventArgs(before, exception, ret);
|
||||||
|
_orm.Aop.CurdAfterHandler?.Invoke(this, after);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
sbret?.Clear();
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
}
|
Binary file not shown.
File diff suppressed because it is too large
Load Diff
Binary file not shown.
File diff suppressed because it is too large
Load Diff
107
Providers/FreeSql.Provider.Xugu/XuguAdo/XuguAdo.cs
Normal file
107
Providers/FreeSql.Provider.Xugu/XuguAdo/XuguAdo.cs
Normal file
@ -0,0 +1,107 @@
|
|||||||
|
using FreeSql.Internal;
|
||||||
|
using FreeSql.Internal.Model;
|
||||||
|
using FreeSql.Internal.ObjectPool;
|
||||||
|
using Newtonsoft.Json.Linq;
|
||||||
|
using System;
|
||||||
|
using System.Collections;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Data.Common;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading;
|
||||||
|
using XuguClient;
|
||||||
|
|
||||||
|
namespace FreeSql.Xugu
|
||||||
|
{
|
||||||
|
class XuguAdo : FreeSql.Internal.CommonProvider.AdoProvider
|
||||||
|
{
|
||||||
|
public XuguAdo() : base(DataType.PostgreSQL, null, null) { }
|
||||||
|
public XuguAdo(CommonUtils util, string masterConnectionString, string[] slaveConnectionStrings, Func<DbConnection> connectionFactory) : base(DataType.PostgreSQL, masterConnectionString, slaveConnectionStrings)
|
||||||
|
{
|
||||||
|
base._util = util;
|
||||||
|
if (connectionFactory != null)
|
||||||
|
{
|
||||||
|
MasterPool = new FreeSql.Internal.CommonProvider.DbConnectionPool(DataType.PostgreSQL, connectionFactory);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (!string.IsNullOrEmpty(masterConnectionString))
|
||||||
|
MasterPool = new XuguConnectionPool(CoreStrings.S_MasterDatabase, masterConnectionString, null, null);
|
||||||
|
if (slaveConnectionStrings != null)
|
||||||
|
{
|
||||||
|
foreach (var slaveConnectionString in slaveConnectionStrings)
|
||||||
|
{
|
||||||
|
var slavePool = new XuguConnectionPool($"{CoreStrings.S_SlaveDatabase}{SlavePools.Count + 1}", slaveConnectionString, () => Interlocked.Decrement(ref slaveUnavailables), () => Interlocked.Increment(ref slaveUnavailables));
|
||||||
|
SlavePools.Add(slavePool);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public override object AddslashesProcessParam(object param, Type mapType, ColumnInfo mapColumn)
|
||||||
|
{
|
||||||
|
if (param == null) return "NULL";
|
||||||
|
if (mapType != null && mapType != param.GetType() && (param is IEnumerable == false || param is JToken || param is JObject || param is JArray))
|
||||||
|
param = Utils.GetDataReaderValue(mapType, param);
|
||||||
|
|
||||||
|
bool isdic;
|
||||||
|
if (param is bool || param is bool?)
|
||||||
|
return (bool)param ? "'t'" : "'f'";
|
||||||
|
else if (param is string)
|
||||||
|
return string.Concat("'", param.ToString().Replace("'", "''"), "'");
|
||||||
|
else if (param is char)
|
||||||
|
return string.Concat("'", param.ToString().Replace("'", "''").Replace('\0', ' '), "'");
|
||||||
|
else if (param is Enum)
|
||||||
|
return ((Enum)param).ToInt64();
|
||||||
|
else if (decimal.TryParse(string.Concat(param), out var trydec))
|
||||||
|
return param;
|
||||||
|
else if (param is DateTime || param is DateTime?)
|
||||||
|
return string.Concat("'", ((DateTime)param).ToString("yyyy-MM-dd HH:mm:ss.ffffff"), "'");
|
||||||
|
else if (param is TimeSpan || param is TimeSpan?)
|
||||||
|
return ((TimeSpan)param).Ticks / 10;
|
||||||
|
else if (param is byte[])
|
||||||
|
return $"'\\x{CommonUtils.BytesSqlRaw(param as byte[])}'";
|
||||||
|
else if (param is JToken || param is JObject || param is JArray)
|
||||||
|
return string.Concat("'", param.ToString().Replace("'", "''"), "'::jsonb");
|
||||||
|
else if ((isdic = param is Dictionary<string, string>) ||
|
||||||
|
param is IEnumerable<KeyValuePair<string, string>>)
|
||||||
|
{
|
||||||
|
var pgdics = isdic ? param as Dictionary<string, string> :
|
||||||
|
param as IEnumerable<KeyValuePair<string, string>>;
|
||||||
|
|
||||||
|
var pghstore = new StringBuilder("'");
|
||||||
|
var pairs = pgdics.ToArray();
|
||||||
|
|
||||||
|
for (var i = 0; i < pairs.Length; i++)
|
||||||
|
{
|
||||||
|
if (i != 0) pghstore.Append(",");
|
||||||
|
|
||||||
|
pghstore.AppendFormat("\"{0}\"=>", pairs[i].Key.Replace("'", "''"));
|
||||||
|
|
||||||
|
if (pairs[i].Value == null)
|
||||||
|
pghstore.Append("NULL");
|
||||||
|
else
|
||||||
|
pghstore.AppendFormat("\"{0}\"", pairs[i].Value.Replace("'", "''"));
|
||||||
|
}
|
||||||
|
|
||||||
|
return pghstore.Append("'::hstore");
|
||||||
|
}
|
||||||
|
else if (param is IEnumerable)
|
||||||
|
return AddslashesIEnumerable(param, mapType, mapColumn);
|
||||||
|
|
||||||
|
return string.Concat("'", param.ToString().Replace("'", "''"), "'");
|
||||||
|
}
|
||||||
|
|
||||||
|
public override DbCommand CreateCommand()
|
||||||
|
{
|
||||||
|
return new XGCommand();
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void ReturnConnection(IObjectPool<DbConnection> pool, Object<DbConnection> conn, Exception ex)
|
||||||
|
{
|
||||||
|
var rawPool = pool as XuguConnectionPool;
|
||||||
|
if (rawPool != null) rawPool.Return(conn, ex);
|
||||||
|
else pool.Return(conn);
|
||||||
|
}
|
||||||
|
|
||||||
|
public override DbParameter[] GetDbParamtersByObject(string sql, object obj) => _util.GetDbParamtersByObject(sql, obj);
|
||||||
|
}
|
||||||
|
}
|
239
Providers/FreeSql.Provider.Xugu/XuguAdo/XuguConnectionPool.cs
Normal file
239
Providers/FreeSql.Provider.Xugu/XuguAdo/XuguConnectionPool.cs
Normal file
@ -0,0 +1,239 @@
|
|||||||
|
using FreeSql.Internal.ObjectPool;
|
||||||
|
using System;
|
||||||
|
using System.Collections.Concurrent;
|
||||||
|
using System.Data;
|
||||||
|
using System.Data.Common;
|
||||||
|
using System.Text.RegularExpressions;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
namespace FreeSql.Xugu
|
||||||
|
{
|
||||||
|
|
||||||
|
class XuguConnectionPool : ObjectPool<DbConnection>
|
||||||
|
{
|
||||||
|
|
||||||
|
internal Action availableHandler;
|
||||||
|
internal Action unavailableHandler;
|
||||||
|
|
||||||
|
public XuguConnectionPool(string name, string connectionString, Action availableHandler, Action unavailableHandler) : base(null)
|
||||||
|
{
|
||||||
|
this.availableHandler = availableHandler;
|
||||||
|
this.unavailableHandler = unavailableHandler;
|
||||||
|
var policy = new XuguConnectionPoolPolicy
|
||||||
|
{
|
||||||
|
_pool = this,
|
||||||
|
Name = name
|
||||||
|
};
|
||||||
|
this.Policy = policy;
|
||||||
|
policy.ConnectionString = connectionString;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Return(Object<DbConnection> obj, Exception exception, bool isRecreate = false)
|
||||||
|
{
|
||||||
|
//if (exception != null && exception is NpgsqlException)
|
||||||
|
//{
|
||||||
|
// if (obj.Value.Ping() == false)
|
||||||
|
// base.SetUnavailable(exception, obj.LastGetTimeCopy);
|
||||||
|
//}
|
||||||
|
base.Return(obj, isRecreate);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class XuguConnectionPoolPolicy : IPolicy<DbConnection>
|
||||||
|
{
|
||||||
|
|
||||||
|
internal XuguConnectionPool _pool;
|
||||||
|
public string Name { get; set; } = $"Xugu XuguConnection {CoreStrings.S_ObjectPool}";
|
||||||
|
public int PoolSize { get; set; } = 50;
|
||||||
|
public TimeSpan SyncGetTimeout { get; set; } = TimeSpan.FromSeconds(10);
|
||||||
|
public TimeSpan IdleTimeout { get; set; } = TimeSpan.FromSeconds(20);
|
||||||
|
public int AsyncGetCapacity { get; set; } = 10000;
|
||||||
|
public bool IsThrowGetTimeoutException { get; set; } = true;
|
||||||
|
public bool IsAutoDisposeWithSystem { get; set; } = true;
|
||||||
|
public int CheckAvailableInterval { get; set; } = 2;
|
||||||
|
public int Weight { get; set; } = 1;
|
||||||
|
|
||||||
|
static ConcurrentDictionary<string, int> dicConnStrIncr = new ConcurrentDictionary<string, int>(StringComparer.CurrentCultureIgnoreCase);
|
||||||
|
private string _connectionString;
|
||||||
|
public string ConnectionString
|
||||||
|
{
|
||||||
|
get => _connectionString;
|
||||||
|
set
|
||||||
|
{
|
||||||
|
_connectionString = value ?? "";
|
||||||
|
|
||||||
|
var minPoolSize = 0;
|
||||||
|
var pattern = @"Min(imum)?\s*pool\s*size\s*=\s*(\d+)";
|
||||||
|
var m = Regex.Match(_connectionString, pattern, RegexOptions.IgnoreCase);
|
||||||
|
if (m.Success)
|
||||||
|
{
|
||||||
|
minPoolSize = int.Parse(m.Groups[2].Value);
|
||||||
|
_connectionString = Regex.Replace(_connectionString, pattern, "", RegexOptions.IgnoreCase);
|
||||||
|
}
|
||||||
|
|
||||||
|
pattern = @"Max(imum)?\s*pool\s*size\s*=\s*(\d+)";
|
||||||
|
m = Regex.Match(_connectionString, pattern, RegexOptions.IgnoreCase);
|
||||||
|
if (m.Success == false || int.TryParse(m.Groups[2].Value, out var poolsize) == false || poolsize <= 0) poolsize = Math.Max(50, minPoolSize);
|
||||||
|
var connStrIncr = dicConnStrIncr.AddOrUpdate(_connectionString, 1, (oldkey, oldval) => Math.Min(5, oldval + 1));
|
||||||
|
PoolSize = poolsize + connStrIncr;
|
||||||
|
_connectionString = m.Success ?
|
||||||
|
Regex.Replace(_connectionString, pattern, $"Maximum pool size={PoolSize}", RegexOptions.IgnoreCase) :
|
||||||
|
$"{_connectionString};Maximum 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);
|
||||||
|
}
|
||||||
|
|
||||||
|
FreeSql.Internal.CommonUtils.PrevReheatConnectionPool(_pool, minPoolSize);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool OnCheckAvailable(Object<DbConnection> obj)
|
||||||
|
{
|
||||||
|
if (obj.Value == null) return false;
|
||||||
|
if (obj.Value.State == ConnectionState.Closed) obj.Value.Open();
|
||||||
|
return obj.Value.Ping(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
public DbConnection OnCreate()
|
||||||
|
{
|
||||||
|
var conn = new XuguClient.XGConnection(_connectionString);
|
||||||
|
return conn;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void OnDestroy(DbConnection obj)
|
||||||
|
{
|
||||||
|
try { if (obj.State != ConnectionState.Closed) obj.Close(); } catch { }
|
||||||
|
|
||||||
|
//try { XuguClient.XGConnection.ClearPool(obj as XuguClient.XGConnection); } catch { }
|
||||||
|
obj.Dispose();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void OnGet(Object<DbConnection> obj)
|
||||||
|
{
|
||||||
|
|
||||||
|
if (_pool.IsAvailable)
|
||||||
|
{
|
||||||
|
if (obj.Value == null)
|
||||||
|
{
|
||||||
|
_pool.SetUnavailable(new Exception(CoreStrings.S_ConnectionStringError), obj.LastGetTimeCopy);
|
||||||
|
throw new Exception(CoreStrings.S_ConnectionStringError_Check(this.Name));
|
||||||
|
}
|
||||||
|
|
||||||
|
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, obj.LastGetTimeCopy) == true)
|
||||||
|
throw new Exception($"【{this.Name}】Block access and wait for recovery: {ex.Message}");
|
||||||
|
throw ex;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#if net40
|
||||||
|
#else
|
||||||
|
async public Task OnGetAsync(Object<DbConnection> obj)
|
||||||
|
{
|
||||||
|
|
||||||
|
if (_pool.IsAvailable)
|
||||||
|
{
|
||||||
|
if (obj.Value == null)
|
||||||
|
{
|
||||||
|
_pool.SetUnavailable(new Exception(CoreStrings.S_ConnectionStringError), obj.LastGetTimeCopy);
|
||||||
|
throw new Exception(CoreStrings.S_ConnectionStringError_Check(this.Name));
|
||||||
|
}
|
||||||
|
|
||||||
|
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, obj.LastGetTimeCopy) == true)
|
||||||
|
throw new Exception($"【{this.Name}】Block access and wait for recovery: {ex.Message}");
|
||||||
|
throw ex;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
public void OnGetTimeout()
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public void OnReturn(Object<DbConnection> obj)
|
||||||
|
{
|
||||||
|
//if (obj?.Value != null && obj.Value.State != ConnectionState.Closed) try { obj.Value.Close(); } catch { }
|
||||||
|
}
|
||||||
|
|
||||||
|
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
|
||||||
|
}
|
||||||
|
}
|
155
Providers/FreeSql.Provider.Xugu/XuguAdo/XuguTypesConverter.cs
Normal file
155
Providers/FreeSql.Provider.Xugu/XuguAdo/XuguTypesConverter.cs
Normal file
@ -0,0 +1,155 @@
|
|||||||
|
using Newtonsoft.Json.Linq;
|
||||||
|
using System;
|
||||||
|
using System.Collections;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Net;
|
||||||
|
using System.Net.NetworkInformation;
|
||||||
|
|
||||||
|
namespace Newtonsoft.Json
|
||||||
|
{
|
||||||
|
public class XuguTypesConverter : JsonConverter
|
||||||
|
{
|
||||||
|
private static readonly Type typeof_BitArray = typeof(BitArray);
|
||||||
|
|
||||||
|
//private static readonly Type typeof_NpgsqlPoint = typeof(NpgsqlPoint);
|
||||||
|
//private static readonly Type typeof_NpgsqlLine = typeof(NpgsqlLine);
|
||||||
|
//private static readonly Type typeof_NpgsqlLSeg = typeof(NpgsqlLSeg);
|
||||||
|
//private static readonly Type typeof_NpgsqlBox = typeof(NpgsqlBox);
|
||||||
|
//private static readonly Type typeof_NpgsqlPath = typeof(NpgsqlPath);
|
||||||
|
//private static readonly Type typeof_NpgsqlPolygon = typeof(NpgsqlPolygon);
|
||||||
|
//private static readonly Type typeof_NpgsqlCircle = typeof(NpgsqlCircle);
|
||||||
|
|
||||||
|
//private static readonly Type typeof_Cidr = typeof((IPAddress, int));
|
||||||
|
//private static readonly Type typeof_IPAddress = typeof(IPAddress);
|
||||||
|
//private static readonly Type typeof_PhysicalAddress = typeof(PhysicalAddress);
|
||||||
|
|
||||||
|
private static readonly Type typeof_String = typeof(string);
|
||||||
|
|
||||||
|
//private static readonly Type typeof_NpgsqlRange_int = typeof(NpgsqlRange<int>);
|
||||||
|
//private static readonly Type typeof_NpgsqlRange_long = typeof(NpgsqlRange<long>);
|
||||||
|
//private static readonly Type typeof_NpgsqlRange_decimal = typeof(NpgsqlRange<decimal>);
|
||||||
|
//private static readonly Type typeof_NpgsqlRange_DateTime = typeof(NpgsqlRange<DateTime>);
|
||||||
|
public override bool CanConvert(Type objectType)
|
||||||
|
{
|
||||||
|
Type ctype = objectType.IsArray ? objectType.GetElementType() : objectType;
|
||||||
|
var ctypeGenericType1 = ctype.GenericTypeArguments.FirstOrDefault();
|
||||||
|
|
||||||
|
if (ctype == typeof_BitArray) return true;
|
||||||
|
|
||||||
|
//if (ctype == typeof_NpgsqlPoint || ctypeGenericType1 == typeof_NpgsqlPoint) return true;
|
||||||
|
//if (ctype == typeof_NpgsqlLine || ctypeGenericType1 == typeof_NpgsqlLine) return true;
|
||||||
|
//if (ctype == typeof_NpgsqlLSeg || ctypeGenericType1 == typeof_NpgsqlLSeg) return true;
|
||||||
|
//if (ctype == typeof_NpgsqlBox || ctypeGenericType1 == typeof_NpgsqlBox) return true;
|
||||||
|
//if (ctype == typeof_NpgsqlPath || ctypeGenericType1 == typeof_NpgsqlPath) return true;
|
||||||
|
//if (ctype == typeof_NpgsqlPolygon || ctypeGenericType1 == typeof_NpgsqlPolygon) return true;
|
||||||
|
//if (ctype == typeof_NpgsqlCircle || ctypeGenericType1 == typeof_NpgsqlCircle) return true;
|
||||||
|
|
||||||
|
//if (ctype == typeof_Cidr || ctypeGenericType1 == typeof_Cidr) return true;
|
||||||
|
//if (ctype == typeof_IPAddress) return true;
|
||||||
|
//if (ctype == typeof_PhysicalAddress) return true;
|
||||||
|
|
||||||
|
//if (ctype == typeof_NpgsqlRange_int || ctypeGenericType1 == typeof_NpgsqlRange_int) return true;
|
||||||
|
//if (ctype == typeof_NpgsqlRange_long || ctypeGenericType1 == typeof_NpgsqlRange_long) return true;
|
||||||
|
//if (ctype == typeof_NpgsqlRange_decimal || ctypeGenericType1 == typeof_NpgsqlRange_decimal) return true;
|
||||||
|
//if (ctype == typeof_NpgsqlRange_DateTime || ctypeGenericType1 == typeof_NpgsqlRange_DateTime) return true;
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
private object YieldJToken(Type ctype, JToken jt, int rank)
|
||||||
|
{
|
||||||
|
if (jt.Type == JTokenType.Null) return null;
|
||||||
|
if (rank == 0)
|
||||||
|
{
|
||||||
|
var ctypeGenericType1 = ctype.GenericTypeArguments.FirstOrDefault();//ctype.Namespace == "System" && ctype.Name.StartsWith("Nullable`") ? ctype.GenericTypeArguments.FirstOrDefault() : null;
|
||||||
|
if (ctype == typeof_BitArray) return jt.ToString().ToBitArray();
|
||||||
|
|
||||||
|
//if (ctype == typeof_NpgsqlPoint || ctypeGenericType1 == typeof_NpgsqlPoint) return NpgsqlPoint.Parse(jt.ToString());
|
||||||
|
//if (ctype == typeof_NpgsqlLine || ctypeGenericType1 == typeof_NpgsqlLine) return NpgsqlLine.Parse(jt.ToString());
|
||||||
|
//if (ctype == typeof_NpgsqlLSeg || ctypeGenericType1 == typeof_NpgsqlLSeg) return NpgsqlLSeg.Parse(jt.ToString());
|
||||||
|
//if (ctype == typeof_NpgsqlBox || ctypeGenericType1 == typeof_NpgsqlBox) return NpgsqlBox.Parse(jt.ToString());
|
||||||
|
//if (ctype == typeof_NpgsqlPath || ctypeGenericType1 == typeof_NpgsqlPath) return NpgsqlPath.Parse(jt.ToString());
|
||||||
|
//if (ctype == typeof_NpgsqlPolygon || ctypeGenericType1 == typeof_NpgsqlPolygon) return NpgsqlPolygon.Parse(jt.ToString());
|
||||||
|
//if (ctype == typeof_NpgsqlCircle || ctypeGenericType1 == typeof_NpgsqlCircle) return NpgsqlCircle.Parse(jt.ToString());
|
||||||
|
|
||||||
|
//if (ctype == typeof_Cidr || ctypeGenericType1 == typeof_Cidr)
|
||||||
|
//{
|
||||||
|
// var cidrArgs = jt.ToString().Split(new[] { '/' }, 2);
|
||||||
|
// return (IPAddress.Parse(cidrArgs.First()), cidrArgs.Length >= 2 ? int.TryParse(cidrArgs[1], out var tryCdirSubnet) ? tryCdirSubnet : 0 : 0);
|
||||||
|
//}
|
||||||
|
//if (ctype == typeof_IPAddress) return IPAddress.Parse(jt.ToString());
|
||||||
|
//if (ctype == typeof_PhysicalAddress) return PhysicalAddress.Parse(jt.ToString());
|
||||||
|
|
||||||
|
//if (ctype == typeof_NpgsqlRange_int || ctypeGenericType1 == typeof_NpgsqlRange_int) return jt.ToString().ToNpgsqlRange<int>();
|
||||||
|
//if (ctype == typeof_NpgsqlRange_long || ctypeGenericType1 == typeof_NpgsqlRange_long) return jt.ToString().ToNpgsqlRange<long>();
|
||||||
|
//if (ctype == typeof_NpgsqlRange_decimal || ctypeGenericType1 == typeof_NpgsqlRange_decimal) return jt.ToString().ToNpgsqlRange<decimal>();
|
||||||
|
//if (ctype == typeof_NpgsqlRange_DateTime || ctypeGenericType1 == typeof_NpgsqlRange_DateTime) return jt.ToString().ToNpgsqlRange<DateTime>();
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
var jtarr = jt.ToArray();
|
||||||
|
var ret = Array.CreateInstance(ctype, jtarr.Length);
|
||||||
|
var jtarrIdx = 0;
|
||||||
|
foreach (var a in jtarr)
|
||||||
|
{
|
||||||
|
var t2 = YieldJToken(ctype, a, rank - 1);
|
||||||
|
ret.SetValue(t2, jtarrIdx++);
|
||||||
|
}
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
|
||||||
|
{
|
||||||
|
int rank = objectType.IsArray ? objectType.GetArrayRank() : 0;
|
||||||
|
Type ctype = objectType.IsArray ? objectType.GetElementType() : objectType;
|
||||||
|
|
||||||
|
var ret = YieldJToken(ctype, JToken.Load(reader), rank);
|
||||||
|
if (ret != null && rank > 0) return ret;
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
|
||||||
|
{
|
||||||
|
Type objectType = value.GetType();
|
||||||
|
if (objectType.IsArray)
|
||||||
|
{
|
||||||
|
int rank = objectType.GetArrayRank();
|
||||||
|
int[] indices = new int[rank];
|
||||||
|
GetJObject(value as Array, indices, 0).WriteTo(writer);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
GetJObject(value).WriteTo(writer);
|
||||||
|
}
|
||||||
|
public static JToken GetJObject(object value)
|
||||||
|
{
|
||||||
|
if (value is BitArray) return JToken.FromObject((value as BitArray)?.To1010());
|
||||||
|
if (value is IPAddress) return JToken.FromObject((value as IPAddress)?.ToString());
|
||||||
|
if (value is ValueTuple<IPAddress, int> || value is ValueTuple<IPAddress, int>?)
|
||||||
|
{
|
||||||
|
ValueTuple<IPAddress, int>? cidrValue = (ValueTuple<IPAddress, int>?)value;
|
||||||
|
return JToken.FromObject(cidrValue == null ? null : $"{cidrValue.Value.Item1.ToString()}/{cidrValue.Value.Item2.ToString()}");
|
||||||
|
}
|
||||||
|
return JToken.FromObject(value?.ToString());
|
||||||
|
}
|
||||||
|
public static JToken GetJObject(Array value, int[] indices, int idx)
|
||||||
|
{
|
||||||
|
if (idx == indices.Length)
|
||||||
|
{
|
||||||
|
return GetJObject(value.GetValue(indices));
|
||||||
|
}
|
||||||
|
JArray ja = new JArray();
|
||||||
|
if (indices.Length == 1)
|
||||||
|
{
|
||||||
|
foreach (object a in value)
|
||||||
|
ja.Add(GetJObject(a));
|
||||||
|
return ja;
|
||||||
|
}
|
||||||
|
int lb = value.GetLowerBound(idx);
|
||||||
|
int ub = value.GetUpperBound(idx);
|
||||||
|
for (int b = lb; b <= ub; b++)
|
||||||
|
{
|
||||||
|
indices[idx] = b;
|
||||||
|
ja.Add(GetJObject(value, indices, idx + 1));
|
||||||
|
}
|
||||||
|
return ja;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,25 @@
|
|||||||
|
using System.Collections;
|
||||||
|
|
||||||
|
public static partial class XuguTypesExtensions
|
||||||
|
{
|
||||||
|
|
||||||
|
public static string To1010(this BitArray ba)
|
||||||
|
{
|
||||||
|
char[] ret = new char[ba.Length];
|
||||||
|
for (int a = 0; a < ba.Length; a++) ret[a] = ba[a] ? '1' : '0';
|
||||||
|
return new string(ret);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 将 1010101010 这样的二进制字符串转换成 BitArray
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="_1010Str">1010101010</param>
|
||||||
|
/// <returns></returns>
|
||||||
|
public static BitArray ToBitArray(this string _1010Str)
|
||||||
|
{
|
||||||
|
if (_1010Str == null) return null;
|
||||||
|
BitArray ret = new BitArray(_1010Str.Length);
|
||||||
|
for (int a = 0; a < _1010Str.Length; a++) ret[a] = _1010Str[a] == '1';
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
}
|
511
Providers/FreeSql.Provider.Xugu/XuguCodeFirst.cs
Normal file
511
Providers/FreeSql.Provider.Xugu/XuguCodeFirst.cs
Normal file
@ -0,0 +1,511 @@
|
|||||||
|
using FreeSql.Internal;
|
||||||
|
using FreeSql.Internal.Model;
|
||||||
|
using System;
|
||||||
|
using System.Collections;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Data;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Net;
|
||||||
|
using System.Net.NetworkInformation;
|
||||||
|
using System.Numerics;
|
||||||
|
using System.Text;
|
||||||
|
using System.Text.RegularExpressions;
|
||||||
|
using XuguClient;
|
||||||
|
|
||||||
|
namespace FreeSql.Xugu
|
||||||
|
{
|
||||||
|
|
||||||
|
class XuguCodeFirst : Internal.CommonProvider.CodeFirstProvider
|
||||||
|
{
|
||||||
|
public readonly string DefaultSchema = "SYSDBA";//默认模式
|
||||||
|
public XuguCodeFirst(IFreeSql orm, CommonUtils commonUtils, CommonExpression commonExpression) : base(orm, commonUtils, commonExpression) {
|
||||||
|
}
|
||||||
|
|
||||||
|
static object _dicCsToDbLock = new object();
|
||||||
|
static Dictionary<string, CsToDb<XGDbType>> _dicCsToDb = new Dictionary<string, CsToDb<XGDbType>>() {
|
||||||
|
|
||||||
|
{
|
||||||
|
typeof(byte).FullName,
|
||||||
|
CsToDb.New(XGDbType.SmallInt, "TINYINT","TINYINT NOT NULL", false, false, 0)
|
||||||
|
},
|
||||||
|
|
||||||
|
{ typeof(byte?).FullName, CsToDb.New(XGDbType.SmallInt, "TINYINT", "TINYINT", false, true, null) },
|
||||||
|
{ typeof(short).FullName, CsToDb.New(XGDbType.SmallInt, "SMALLINT","SMALLINT NOT NULL", false, false, 0) },{ typeof(short?).FullName, CsToDb.New(XGDbType.SmallInt, "SMALLINT", "SMALLINT", false, true, null) },
|
||||||
|
{ typeof(int).FullName, CsToDb.New(XGDbType.Int, "INTEGER","INTEGER NOT NULL", false, false, 0) },{ typeof(int?).FullName, CsToDb.New(XGDbType.Int, "INTEGER", "INTEGER", false, true, null) },
|
||||||
|
{ typeof(long).FullName, CsToDb.New(XGDbType.BigInt, "BIGINT","BIGINT NOT NULL", false, false, 0) },{ typeof(long?).FullName, CsToDb.New(XGDbType.BigInt, "BIGINT", "BIGINT", false, true, null) },
|
||||||
|
|
||||||
|
|
||||||
|
{ typeof(ushort).FullName, CsToDb.New(XGDbType.Int, "INT","INT NOT NULL", false, false, 0) },{ typeof(ushort?).FullName, CsToDb.New(XGDbType.Int, "INT", "INT", false, true, null) },
|
||||||
|
{ typeof(uint).FullName, CsToDb.New(XGDbType.BigInt, "BIGINT","BIGINT NOT NULL", false, false, 0) },{ typeof(uint?).FullName, CsToDb.New(XGDbType.BigInt, "BIGINT", "BIGINT", false, true, null) },
|
||||||
|
{ typeof(ulong).FullName, CsToDb.New(XGDbType.Numeric, "NUMERIC","NUMERIC(20,0) NOT NULL", false, false, 0) },{ typeof(ulong?).FullName, CsToDb.New(XGDbType.Numeric, "NUMERIC", "NUMERIC(20,0)", false, true, null) },
|
||||||
|
|
||||||
|
{ typeof(float).FullName, CsToDb.New(XGDbType.Real, "FLOAT","FLOAT NOT NULL", false, false, 0) },{ typeof(float?).FullName, CsToDb.New(XGDbType.Real, "FLOAT", "FLOAT", false, true, null) },
|
||||||
|
{ typeof(double).FullName, CsToDb.New(XGDbType.Double, "DOUBLE","DOUBLE NOT NULL", false, false, 0) },{ typeof(double?).FullName, CsToDb.New(XGDbType.Double, "DOUBLE", "DOUBLE", false, true, null) },
|
||||||
|
{ typeof(decimal).FullName, CsToDb.New(XGDbType.Numeric, "NUMERIC", "NUMERIC(10,2) NOT NULL", false, false, 0) },{ typeof(decimal?).FullName, CsToDb.New(XGDbType.Numeric, "NUMERIC", "NUMERIC(10,2)", false, true, null) },
|
||||||
|
|
||||||
|
{ typeof(string).FullName, CsToDb.New(XGDbType.VarChar, "VARCHAR", "VARCHAR(255)", false, null, "") },
|
||||||
|
|
||||||
|
{ typeof(char).FullName, CsToDb.New(XGDbType.Char, "CHAR", "CHAR(1)", false, null, '\0') },
|
||||||
|
|
||||||
|
//{ typeof(TimeSpan).FullName, CsToDb.New(XGDbType.Time, "time","time NOT NULL", false, false, 0) },{ typeof(TimeSpan?).FullName, CsToDb.New(XGDbType.Time, "time", "time",false, true, null) },
|
||||||
|
{ typeof(DateTime).FullName, CsToDb.New(XGDbType.DateTime, "DATETIME", "DATETIME NOT NULL", false, false, new DateTime(1970,1,1)) },
|
||||||
|
{ typeof(DateTime?).FullName, CsToDb.New(XGDbType.DateTime, "DATETIME", "DATETIME", false, true, null) },
|
||||||
|
|
||||||
|
{ typeof(bool).FullName, CsToDb.New(XGDbType.Bool, "BOOLEAN","BOOLEAN NOT NULL", null, false, false) },{ typeof(bool?).FullName, CsToDb.New(XGDbType.Bool, "BOOLEAN","BOOLEAN", null, true, null) },
|
||||||
|
|
||||||
|
{ typeof(byte[]).FullName, CsToDb.New(XGDbType.VarBinary, "blob", "blob NULL", false, null, new byte[0]) },
|
||||||
|
{ typeof(Guid).FullName, CsToDb.New(XGDbType.Char, "char", "char(36) NOT NULL", false, false, Guid.Empty) },{ typeof(Guid?).FullName, CsToDb.New(XGDbType.Char, "char", "char(36) NULL", false, true, null) },
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
//{ typeof(Dictionary<string, string>).FullName, CsToDb.New(XGDbType.Hstore, "hstore", "hstore", false, null, new Dictionary<string, string>()) },
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
public override DbInfoResult GetDbInfo(Type type)
|
||||||
|
{
|
||||||
|
_dicCsToDb.TryGetValue(type.FullName, out var info);
|
||||||
|
if (info == null) return null;
|
||||||
|
return new DbInfoResult((int)info.type, info.dbtype, info.dbtypeFull, info.isnullable, info.defaultValue);
|
||||||
|
}
|
||||||
|
internal static string GetXuguSqlTypeFullName(object[] row)
|
||||||
|
{
|
||||||
|
var a = row;
|
||||||
|
var sqlType = string.Concat(a[1]).ToUpper();
|
||||||
|
var data_length = long.Parse(string.Concat(a[2]));
|
||||||
|
var char_used = string.Concat(a[5]);
|
||||||
|
bool.TryParse(a[9]?.ToString(), out var isVar);
|
||||||
|
if (sqlType == "CHAR" && isVar)
|
||||||
|
{
|
||||||
|
sqlType = "VARCHAR";
|
||||||
|
}
|
||||||
|
|
||||||
|
if (data_length <= 0)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
else if (sqlType.StartsWith("TIMESTAMP", StringComparison.CurrentCultureIgnoreCase))
|
||||||
|
{
|
||||||
|
}
|
||||||
|
else if (sqlType.StartsWith("DATETIME", StringComparison.CurrentCultureIgnoreCase))
|
||||||
|
{
|
||||||
|
}
|
||||||
|
else if (sqlType.StartsWith("BLOB"))
|
||||||
|
{
|
||||||
|
}
|
||||||
|
else if (sqlType.StartsWith("CLOB"))
|
||||||
|
{
|
||||||
|
}
|
||||||
|
else if (sqlType.ToUpper()== "NUMERIC")
|
||||||
|
{
|
||||||
|
//data_length=655362
|
||||||
|
//实际类型是 NUMRIC(10,2) 计算得到的是 NUMRIC(10,12)
|
||||||
|
//标度计算错误
|
||||||
|
|
||||||
|
var data_precision= data_length % 65536;
|
||||||
|
var data_scale = data_length / 65536;
|
||||||
|
sqlType += $"({data_scale},{data_precision})";
|
||||||
|
}
|
||||||
|
else if (sqlType.ToLower() == "float")
|
||||||
|
{ }
|
||||||
|
else
|
||||||
|
sqlType += $"({data_length})";
|
||||||
|
return sqlType;
|
||||||
|
}
|
||||||
|
protected override string GetComparisonDDLStatements(params TypeAndName[] objects)
|
||||||
|
{
|
||||||
|
var sb = new StringBuilder();
|
||||||
|
var seqcols = new List<NativeTuple<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(CoreStrings.S_Type_IsNot_Migrable(obj.entityType.FullName));
|
||||||
|
if (tb.Columns.Any() == false) throw new Exception(CoreStrings.S_Type_IsNot_Migrable_0Attributes(obj.entityType.FullName));
|
||||||
|
var tbname = _commonUtils.SplitTableName(tb.DbName);
|
||||||
|
if (tbname?.Length == 1) tbname = new[] { DefaultSchema, tbname[0] };
|
||||||
|
|
||||||
|
var tboldname = _commonUtils.SplitTableName(tb.DbOldName); //旧表名
|
||||||
|
|
||||||
|
if (tboldname?.Length == 1) tboldname = new[] { DefaultSchema, tboldname[0] };
|
||||||
|
if (string.IsNullOrEmpty(obj.tableName) == false)
|
||||||
|
{
|
||||||
|
var tbtmpname = _commonUtils.SplitTableName(obj.tableName);
|
||||||
|
if (tbtmpname?.Length == 1) tbtmpname = new[] { DefaultSchema, tbtmpname[0] };
|
||||||
|
if (tbname[0] != tbtmpname[0] || tbname[1] != tbtmpname[1])
|
||||||
|
{
|
||||||
|
tbname = tbtmpname;
|
||||||
|
tboldname = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
//codefirst 不支持表名、模式名、数据库名中带 .
|
||||||
|
|
||||||
|
if (_orm.Ado.ExecuteScalar(CommandType.Text, _commonUtils.FormatSql(" select 1 from all_schemas where schema_name={0}", tbname[0])) == null) //创建模式
|
||||||
|
throw new Exception($"模式“{tbname[0]}”不存在,请手动创建");
|
||||||
|
//sb.Append($"CREATE SCHEMA {tbname[0]};\r\n");
|
||||||
|
//sb.Append("CREATE SCHEMA IF NOT EXISTS ").Append(tbname[0]).Append(";\r\n");
|
||||||
|
|
||||||
|
var sbalter = new StringBuilder();
|
||||||
|
var istmpatler = false; //创建临时表,导入数据,删除旧表,修改
|
||||||
|
|
||||||
|
//虚谷
|
||||||
|
var sql0 = string.Format("select 1 from all_tables a inner join all_schemas b on b.schema_id = a.schema_id where b.schema_name || '.' || a.table_name = '{0}.{1}'", tbname);
|
||||||
|
|
||||||
|
|
||||||
|
//判断表是否存在
|
||||||
|
if (_orm.Ado.ExecuteScalar(CommandType.Text, sql0) == null)
|
||||||
|
{
|
||||||
|
//表不存在
|
||||||
|
if (tboldname != null)
|
||||||
|
{
|
||||||
|
if (_orm.Ado.ExecuteScalar(CommandType.Text, string.Format(" select 1 from all_tables a inner join all_schemas b on b.schema_id = a.schema_id where b.schema_name || '.' || a.table_name = '{0}.{1}'", tboldname)) == null)
|
||||||
|
//旧表不存在
|
||||||
|
tboldname = null;
|
||||||
|
}
|
||||||
|
if (tboldname == null)
|
||||||
|
{
|
||||||
|
//创建表
|
||||||
|
var createTableName = _commonUtils.QuoteSqlName($"{tbname[0]}.{tbname[1]}");
|
||||||
|
sb.Append("CREATE TABLE ").Append(createTableName).Append(" ( ");
|
||||||
|
foreach (var tbcol in tb.ColumnsByPosition)
|
||||||
|
{
|
||||||
|
sb.Append(" \r\n ").Append(_commonUtils.QuoteSqlName(tbcol.Attribute.Name)).Append(" ");
|
||||||
|
if (tbcol.Attribute.IsIdentity == true)
|
||||||
|
{
|
||||||
|
sb.Append(tbcol.Attribute.DbType.Replace("NOT NULL",""));
|
||||||
|
sb.Append(" identity(1,1)");
|
||||||
|
//seqcols.Add(NativeTuple.Create(tbcol, tbname, true));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
sb.Append(tbcol.Attribute.DbType.Replace("NTEXT", "CLOB").Replace("TEXT", "CLOB"));
|
||||||
|
}
|
||||||
|
sb.Append(",");
|
||||||
|
}
|
||||||
|
if (tb.Primarys.Any())
|
||||||
|
{
|
||||||
|
var pkname = $"{tbname[0]}_{tbname[1]}_pkey";
|
||||||
|
sb.Append(" \r\n CONSTRAINT ").Append(_commonUtils.QuoteSqlName(pkname)).Append(" PRIMARY KEY (");
|
||||||
|
foreach (var tbcol in tb.Primarys) sb.Append(_commonUtils.QuoteSqlName(tbcol.Attribute.Name)).Append(", ");
|
||||||
|
sb.Remove(sb.Length - 2, 2).Append("),");
|
||||||
|
}
|
||||||
|
sb.Remove(sb.Length - 1, 1);
|
||||||
|
sb.Append("\r\n);\r\n");
|
||||||
|
|
||||||
|
//创建表的索引
|
||||||
|
foreach (var uk in tb.Indexes)
|
||||||
|
{
|
||||||
|
sb.Append("CREATE ");
|
||||||
|
if (uk.IsUnique) sb.Append("UNIQUE ");
|
||||||
|
sb.Append("INDEX ").Append(_commonUtils.QuoteSqlName(ReplaceIndexName(uk.Name, tbname[1]))).Append(" ON ").Append(createTableName).Append("(");
|
||||||
|
foreach (var tbcol in uk.Columns)
|
||||||
|
{
|
||||||
|
sb.Append(_commonUtils.QuoteSqlName(tbcol.Column.Attribute.Name));
|
||||||
|
if (tbcol.IsDesc) sb.Append(" DESC");
|
||||||
|
sb.Append(", ");
|
||||||
|
}
|
||||||
|
sb.Remove(sb.Length - 2, 2).Append(");\r\n");
|
||||||
|
}
|
||||||
|
//备注
|
||||||
|
foreach (var tbcol in tb.ColumnsByPosition)
|
||||||
|
{
|
||||||
|
if (string.IsNullOrEmpty(tbcol.Comment) == false)
|
||||||
|
sb.Append("COMMENT ON COLUMN ").Append(_commonUtils.QuoteSqlName($"{tbname[0]}.{tbname[1]}.{tbcol.Attribute.Name}")).Append(" IS ").Append(_commonUtils.FormatSql("{0}", tbcol.Comment)).Append(";\r\n");
|
||||||
|
}
|
||||||
|
if (string.IsNullOrEmpty(tb.Comment) == false)
|
||||||
|
sb.Append("COMMENT ON TABLE ").Append(_commonUtils.QuoteSqlName($"{tbname[0]}.{tbname[1]}")).Append(" IS ").Append(_commonUtils.FormatSql("{0}", tb.Comment)).Append(";\r\n");
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
//如果新表,旧表在一个数据库和模式下,直接修改表名
|
||||||
|
if (string.Compare(tbname[0], tboldname[0], true) == 0)
|
||||||
|
sbalter.Append("ALTER TABLE ").Append(_commonUtils.QuoteSqlName($"{tboldname[0]}.{tboldname[1]}")).Append(" RENAME TO ").Append(_commonUtils.QuoteSqlName($"{tbname[1]}")).Append(";\r\n");
|
||||||
|
else
|
||||||
|
{
|
||||||
|
//如果新表,旧表不在一起,创建新表,导入数据,删除旧表
|
||||||
|
istmpatler = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
tboldname = null; //如果新表已经存在,不走改表名逻辑
|
||||||
|
|
||||||
|
|
||||||
|
var sql = _commonUtils.FormatSql($@"
|
||||||
|
select
|
||||||
|
a.COL_NAME,
|
||||||
|
a.TYPE_NAME,
|
||||||
|
a.SCALE,
|
||||||
|
case when a.NOT_NULL then '0' else '1' end as is_nullable,
|
||||||
|
seq.SEQ_ID,
|
||||||
|
seq.IS_SYS,
|
||||||
|
a.COMMENTS,
|
||||||
|
tb.table_name,
|
||||||
|
ns.schema_id,
|
||||||
|
a.`VARYING`
|
||||||
|
from all_columns as a
|
||||||
|
left join all_tables tb on a.table_id=tb.table_id
|
||||||
|
left join all_schemas ns on tb.schema_id = ns.schema_id
|
||||||
|
left join all_sequences seq on seq.SEQ_ID=a.Serial_ID
|
||||||
|
WHERE ns.SCHEMA_NAME={{0}} and tb.TABLE_NAME={{1}}
|
||||||
|
|
||||||
|
", tboldname ?? tbname);
|
||||||
|
var ds = _orm.Ado.ExecuteArray(CommandType.Text, sql);
|
||||||
|
//从系统表读取的现有字段的基本信息
|
||||||
|
var tbstruct = ds.ToDictionary(a => string.Concat(a[0]), a =>
|
||||||
|
{
|
||||||
|
var sqlType = GetXuguSqlTypeFullName(a);
|
||||||
|
var max_length = long.Parse(string.Concat(a[2]));
|
||||||
|
//long SEQ_ID = 0;
|
||||||
|
long.TryParse(a[4]?.ToString() ?? "0", out long SEQ_ID);
|
||||||
|
var SEQ_IS_SYS = (a[5]?.ToString() ?? "false")?.ToLower();
|
||||||
|
try
|
||||||
|
{
|
||||||
|
return new
|
||||||
|
{
|
||||||
|
column = string.Concat(a[0]),
|
||||||
|
sqlType = string.Concat(sqlType),
|
||||||
|
max_length = long.Parse(string.Concat(a[2]) ?? "0"),
|
||||||
|
is_nullable = string.Concat(a[3]) == "1",
|
||||||
|
is_identity = (SEQ_ID > 0 && SEQ_IS_SYS == "true"),
|
||||||
|
comment = string.Concat(a[6])
|
||||||
|
};
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
|
||||||
|
throw ex;
|
||||||
|
}
|
||||||
|
|
||||||
|
}, StringComparer.CurrentCultureIgnoreCase);
|
||||||
|
|
||||||
|
if (istmpatler == false)
|
||||||
|
{
|
||||||
|
//基本信息对比 比如名称 添加列 数据类型 Identity
|
||||||
|
foreach (var tbcol in tb.ColumnsByPosition)
|
||||||
|
{
|
||||||
|
//对别数据库中列和C#中的信息是否一致
|
||||||
|
if (tbstruct.TryGetValue(tbcol.Attribute.Name, out var tbstructcol) ||
|
||||||
|
string.IsNullOrEmpty(tbcol.Attribute.OldName) == false && tbstruct.TryGetValue(tbcol.Attribute.OldName, out tbstructcol))
|
||||||
|
{
|
||||||
|
var isCommentChanged = tbstructcol.comment != (tbcol.Comment ?? "");
|
||||||
|
var sqlTypeSize = tbstructcol.sqlType;
|
||||||
|
//如果数据中是CHAR或VARCHAR 要加上C#中定义的长度
|
||||||
|
if (sqlTypeSize.Contains("(") == false)
|
||||||
|
{
|
||||||
|
switch (sqlTypeSize)
|
||||||
|
{
|
||||||
|
case "char":
|
||||||
|
case "varchar":
|
||||||
|
sqlTypeSize = $"{sqlTypeSize}({tbstructcol.max_length})"; break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var dbType = tbcol.Attribute.DbType.Replace("NTEXT", "CLOB").Replace("TEXT", "CLOB");
|
||||||
|
if (dbType.StartsWith(sqlTypeSize, StringComparison.CurrentCultureIgnoreCase) == false)
|
||||||
|
sbalter.Append("ALTER TABLE ").Append(_commonUtils.QuoteSqlName($"{tbname[0]}.{tbname[1]}")).Append(" ALTER COLUMN ").Append(_commonUtils.QuoteSqlName(tbstructcol.column)).Append(" ").Append(tbcol.Attribute.DbType.Split(' ').First().Replace("NTEXT", "CLOB").Replace("TEXT", "CLOB")).Append(";\r\n");//为了适应FreeSQL的长文本规则采用Replace
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
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)
|
||||||
|
{
|
||||||
|
//sbalter.Append(" identity(1,1)");
|
||||||
|
seqcols.Add(NativeTuple.Create(tbcol, tbname, tbcol.Attribute.IsIdentity == true));
|
||||||
|
}
|
||||||
|
if (string.Compare(tbstructcol.column, tbcol.Attribute.OldName, true) == 0)
|
||||||
|
//修改列名
|
||||||
|
sbalter.Append("ALTER TABLE ").Append(_commonUtils.QuoteSqlName($"{tbname[0]}.{tbname[1]}")).Append(" RENAME COLUMN ").Append(_commonUtils.QuoteSqlName(tbstructcol.column)).Append(" TO ").Append(_commonUtils.QuoteSqlName(tbcol.Attribute.Name)).Append(";\r\n");
|
||||||
|
|
||||||
|
if (isCommentChanged)
|
||||||
|
sbalter.Append("COMMENT ON COLUMN ").Append(_commonUtils.QuoteSqlName($"{tbname[0]}.{tbname[1]}.{tbcol.Attribute.Name}")).Append(" IS ").Append(_commonUtils.FormatSql("{0}", tbcol.Comment)).Append(";\r\n");
|
||||||
|
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
//添加列
|
||||||
|
sbalter.Append("ALTER TABLE ").Append(_commonUtils.QuoteSqlName($"{tbname[0]}.{tbname[1]}")).Append(" ADD COLUMN ").Append(_commonUtils.QuoteSqlName(tbcol.Attribute.Name)).Append(" ").Append(tbcol.Attribute.DbType.Split(' ').First()).Append(";\r\n");
|
||||||
|
sbalter.Append("UPDATE ").Append(_commonUtils.QuoteSqlName($"{tbname[0]}.{tbname[1]}")).Append(" SET ").Append(_commonUtils.QuoteSqlName(tbcol.Attribute.Name)).Append(" = ").Append(tbcol.DbDefaultValue).Append(";\r\n");
|
||||||
|
if (tbcol.Attribute.IsNullable == false) sbalter.Append("ALTER TABLE ").Append(_commonUtils.QuoteSqlName($"{tbname[0]}.{tbname[1]}")).Append(" ALTER COLUMN ").Append(_commonUtils.QuoteSqlName(tbcol.Attribute.Name)).Append(" SET NOT NULL;\r\n");
|
||||||
|
if (tbcol.Attribute.IsIdentity == true)
|
||||||
|
{
|
||||||
|
seqcols.Add(NativeTuple.Create(tbcol, tbname, tbcol.Attribute.IsIdentity == true));
|
||||||
|
}
|
||||||
|
if (string.IsNullOrEmpty(tbcol.Comment) == false) sbalter.Append("COMMENT ON COLUMN ").Append(_commonUtils.QuoteSqlName($"{tbname[0]}.{tbname[1]}.{tbcol.Attribute.Name}")).Append(" IS ").Append(_commonUtils.FormatSql("{0}", tbcol.Comment)).Append(";\r\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
var dsuksql = _commonUtils.FormatSql($@"
|
||||||
|
select
|
||||||
|
keys,
|
||||||
|
a.index_name,
|
||||||
|
case when a.IS_UNIQUE then 1 else 0 end as IsUnique,
|
||||||
|
t.table_name,
|
||||||
|
ns.SCHEMA_NAME,
|
||||||
|
a.IS_SYS
|
||||||
|
from all_INDEXES a
|
||||||
|
left join all_tables t on a.TABLE_ID=t.TABLE_ID
|
||||||
|
left join all_schemas ns on t.SCHEMA_ID=ns.SCHEMA_ID
|
||||||
|
WHERE a.IS_Primary = false and t.table_name={{1}} and schema_name={{0}}",
|
||||||
|
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]), string.Concat(a[4]) }).ToList();
|
||||||
|
foreach (var uk in tb.Indexes)
|
||||||
|
{
|
||||||
|
if (string.IsNullOrEmpty(uk.Name) || uk.Columns.Any() == false) continue;
|
||||||
|
//获取C#中定义的索引名称
|
||||||
|
var ukname = ReplaceIndexName(uk.Name, tbname[1]);
|
||||||
|
//数据库和C#定义名称一致的
|
||||||
|
var dsukfind1 = dsuk.FirstOrDefault(a => string.Compare(a[1], ukname, true) == 0);
|
||||||
|
|
||||||
|
if (dsukfind1==null || //没有找到一致的索引,表示新定义的
|
||||||
|
dsukfind1[0].Split(',').Length!=uk.Columns.Length ||
|
||||||
|
uk.Columns.Any(x=>dsukfind1[0].ToLower().IndexOf( x.Column.Attribute.Name.ToLower())==-1) ||
|
||||||
|
uk.IsUnique != (dsukfind1[2]== "1")
|
||||||
|
)
|
||||||
|
{
|
||||||
|
if (dsukfind1 != null) sbalter.Append("DROP INDEX ").Append($"\"{dsukfind1[4]}\".\"{dsukfind1[3]}\".\"{ukname}\"").Append(";\r\n");
|
||||||
|
sbalter.Append("CREATE ");
|
||||||
|
if (uk.IsUnique) sbalter.Append("UNIQUE ");
|
||||||
|
sbalter.Append("INDEX ").Append(_commonUtils.QuoteSqlName(ukname)).Append(" ON ").Append(_commonUtils.QuoteSqlName($"{tbname[0]}.{tbname[1]}")).Append("(");
|
||||||
|
foreach (var tbcol in uk.Columns)
|
||||||
|
{
|
||||||
|
sbalter.Append(_commonUtils.QuoteSqlName(tbcol.Column.Attribute.Name));
|
||||||
|
//if (tbcol.IsDesc) sbalter.Append(" DESC");
|
||||||
|
sbalter.Append(", ");
|
||||||
|
}
|
||||||
|
sbalter.Remove(sbalter.Length - 2, 2).Append(");\r\n");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (istmpatler == false)
|
||||||
|
{
|
||||||
|
//描述
|
||||||
|
var dbcomment = string.Concat(_orm.Ado.ExecuteScalar(CommandType.Text, _commonUtils.FormatSql($@"
|
||||||
|
select COMMENTS,TABLE_NAME,SCHEMA_NAME from all_tables as a
|
||||||
|
left join all_schemas as b on a.SCHEMA_ID=b.SCHEMA_ID
|
||||||
|
WHERE a.Table_Name={{1}} and b.SCHEMA_NAME={{0}}
|
||||||
|
",tbname)));
|
||||||
|
if ((dbcomment??"") != (tb.Comment ?? ""))
|
||||||
|
sbalter.Append("COMMENT ON TABLE ").Append(_commonUtils.QuoteSqlName($"{tbname[0]}.{tbname[1]}")).Append(" IS ").Append(_commonUtils.FormatSql("{0}", tb.Comment)).Append(";\r\n");
|
||||||
|
|
||||||
|
sb.Append(sbalter);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
//约束primary key
|
||||||
|
|
||||||
|
var oldpk = _orm.Ado.ExecuteScalar(CommandType.Text, _commonUtils.FormatSql(@"
|
||||||
|
select cons_name from all_constraints as a
|
||||||
|
left join all_tables as b on a.Table_ID=b.Table_ID
|
||||||
|
left Join all_SCHEMAS AS c on b.SCHEMA_ID=c.SCHEMA_ID
|
||||||
|
where b.TABLE_NAME={0} and c.SCHEMA_NAME={1} and a.cons_TYPE='P'
|
||||||
|
", tbname))?.ToString();
|
||||||
|
if (string.IsNullOrEmpty(oldpk) == false)
|
||||||
|
sb.Append("ALTER TABLE ").Append(_commonUtils.QuoteSqlName($"{tbname[0]}.{tbname[1]}")).Append(" DROP CONSTRAINT ").Append(oldpk).Append(";\r\n");
|
||||||
|
|
||||||
|
//创建临时表,数据导进临时表,然后删除原表,将临时表改名为原表名
|
||||||
|
var tablename = tboldname == null ? _commonUtils.QuoteSqlName($"{tbname[0]}.{tbname[1]}") : _commonUtils.QuoteSqlName($"{tboldname[0]}.{tboldname[1]}");
|
||||||
|
|
||||||
|
//创建临时表
|
||||||
|
var tmptablename = _commonUtils.QuoteSqlName($"{tbname[0]}.FreeSqlTmp_{tbname[1]}");
|
||||||
|
sb.Append("CREATE TABLE IF NOT EXISTS ").Append(tmptablename).Append(" ( ");
|
||||||
|
foreach (var tbcol in tb.ColumnsByPosition)
|
||||||
|
{
|
||||||
|
sb.Append(" \r\n ").Append(_commonUtils.QuoteSqlName(tbcol.Attribute.Name)).Append(" ").Append(tbcol.Attribute.DbType);
|
||||||
|
if (tbcol.Attribute.IsIdentity == true)
|
||||||
|
{
|
||||||
|
//sb.Append(" identity(1,1)");
|
||||||
|
seqcols.Add(NativeTuple.Create(tbcol, tbname, true));
|
||||||
|
}
|
||||||
|
sb.Append(",");
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
if (tb.Primarys.Any())
|
||||||
|
{
|
||||||
|
var pkname = $"{tbname[0]}_{tbname[1]}_pkey";
|
||||||
|
sb.Append(" \r\n CONSTRAINT ").Append(_commonUtils.QuoteSqlName(pkname)).Append(" PRIMARY KEY (");
|
||||||
|
foreach (var tbcol in tb.Primarys) sb.Append(_commonUtils.QuoteSqlName(tbcol.Attribute.Name)).Append(", ");
|
||||||
|
sb.Remove(sb.Length - 2, 2).Append("),");
|
||||||
|
}
|
||||||
|
sb.Remove(sb.Length - 1, 1);
|
||||||
|
sb.Append("\r\n);\r\n");
|
||||||
|
//备注
|
||||||
|
foreach (var tbcol in tb.ColumnsByPosition)
|
||||||
|
{
|
||||||
|
if (string.IsNullOrEmpty(tbcol.Comment) == false)
|
||||||
|
sb.Append("COMMENT ON COLUMN ").Append(_commonUtils.QuoteSqlName($"{tbname[0]}.FreeSqlTmp_{tbname[1]}.{tbcol.Attribute.Name}")).Append(" IS ").Append(_commonUtils.FormatSql("{0}", tbcol.Comment)).Append(";\r\n");
|
||||||
|
}
|
||||||
|
if (string.IsNullOrEmpty(tb.Comment) == false)
|
||||||
|
sb.Append("COMMENT ON TABLE ").Append(_commonUtils.QuoteSqlName($"{tbname[0]}.FreeSqlTmp_{tbname[1]}")).Append(" IS ").Append(_commonUtils.FormatSql("{0}", tb.Comment)).Append(";\r\n");
|
||||||
|
|
||||||
|
sb.Append("INSERT INTO ").Append(tmptablename).Append(" (");
|
||||||
|
foreach (var tbcol in tb.ColumnsByPosition)
|
||||||
|
sb.Append(_commonUtils.QuoteSqlName(tbcol.Attribute.Name)).Append(", ");
|
||||||
|
sb.Remove(sb.Length - 2, 2).Append(")\r\nSELECT ");
|
||||||
|
foreach (var tbcol in tb.ColumnsByPosition)
|
||||||
|
{
|
||||||
|
var insertvalue = "NULL";
|
||||||
|
if (tbstruct.TryGetValue(tbcol.Attribute.Name, out var tbstructcol) ||
|
||||||
|
string.IsNullOrEmpty(tbcol.Attribute.OldName) == false && tbstruct.TryGetValue(tbcol.Attribute.OldName, out tbstructcol))
|
||||||
|
{
|
||||||
|
insertvalue = _commonUtils.QuoteSqlName(tbstructcol.column);
|
||||||
|
if (tbcol.Attribute.DbType.StartsWith(tbstructcol.sqlType, StringComparison.CurrentCultureIgnoreCase) == false)
|
||||||
|
insertvalue = $"cast({insertvalue} as {tbcol.Attribute.DbType.Split(' ').First()})";
|
||||||
|
if (tbcol.Attribute.IsNullable != tbstructcol.is_nullable)
|
||||||
|
insertvalue = $"coalesce({insertvalue},{tbcol.DbDefaultValue})";
|
||||||
|
}
|
||||||
|
else if (tbcol.Attribute.IsNullable == false)
|
||||||
|
insertvalue = tbcol.DbDefaultValue;
|
||||||
|
sb.Append(insertvalue).Append(", ");
|
||||||
|
}
|
||||||
|
sb.Remove(sb.Length - 2, 2).Append(" FROM ").Append(tablename).Append(";\r\n");
|
||||||
|
sb.Append("DROP TABLE ").Append(tablename).Append(";\r\n");
|
||||||
|
sb.Append("ALTER TABLE ").Append(tmptablename).Append(" RENAME TO ").Append(_commonUtils.QuoteSqlName(tbname[1])).Append(";\r\n");
|
||||||
|
//创建表的索引
|
||||||
|
foreach (var uk in tb.Indexes)
|
||||||
|
{
|
||||||
|
sb.Append("CREATE ");
|
||||||
|
if (uk.IsUnique) sb.Append("UNIQUE ");
|
||||||
|
sb.Append("INDEX ").Append(_commonUtils.QuoteSqlName(ReplaceIndexName(uk.Name, tbname[1]))).Append(" ON ").Append(tablename).Append("(");
|
||||||
|
foreach (var tbcol in uk.Columns)
|
||||||
|
{
|
||||||
|
sb.Append(_commonUtils.QuoteSqlName(tbcol.Column.Attribute.Name));
|
||||||
|
if (tbcol.IsDesc) sb.Append(" DESC");
|
||||||
|
sb.Append(", ");
|
||||||
|
}
|
||||||
|
sb.Remove(sb.Length - 2, 2).Append(");\r\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//foreach (var seqcol in seqcols)
|
||||||
|
//{
|
||||||
|
// var tbname = seqcol.Item2;
|
||||||
|
// var seqname = Utils.GetCsName($"{tbname[0]}.{tbname[1]}_{seqcol.Item1.Attribute.Name}_sequence_name").ToLower();
|
||||||
|
// var tbname2 = _commonUtils.QuoteSqlName($"{tbname[0]}.{tbname[1]}");
|
||||||
|
// var colname2 = _commonUtils.QuoteSqlName(seqcol.Item1.Attribute.Name);
|
||||||
|
// sb.Append("ALTER TABLE ").Append(tbname2).Append(" ALTER COLUMN ").Append(colname2).Append(" SET DEFAULT null;\r\n");
|
||||||
|
// sb.Append("DROP SEQUENCE IF EXISTS ").Append(seqname).Append(";\r\n");
|
||||||
|
// if (seqcol.Item3)
|
||||||
|
// {
|
||||||
|
// sb.Append("CREATE SEQUENCE ").Append(seqname).Append(";\r\n");
|
||||||
|
// sb.Append("ALTER TABLE ").Append(tbname2).Append(" ALTER COLUMN ").Append(colname2).Append(" SET DEFAULT nextval('").Append(seqname).Append("'::regclass);\r\n");
|
||||||
|
// sb.Append(" SELECT case when max(").Append(colname2).Append(") is null then 0 else setval('").Append(seqname).Append("', max(").Append(colname2).Append(")) end FROM ").Append(tbname2).Append(";\r\n");
|
||||||
|
// }
|
||||||
|
//}
|
||||||
|
Console.Write(sb.ToString());
|
||||||
|
//throw new Exception(sb.ToString());
|
||||||
|
return sb.Length == 0 ? null : sb.ToString();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
543
Providers/FreeSql.Provider.Xugu/XuguDbFirst.cs
Normal file
543
Providers/FreeSql.Provider.Xugu/XuguDbFirst.cs
Normal file
@ -0,0 +1,543 @@
|
|||||||
|
using FreeSql.DatabaseModel;
|
||||||
|
using FreeSql.Internal;
|
||||||
|
using System;
|
||||||
|
using System.Collections;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Data;
|
||||||
|
using System.Data.SqlTypes;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Net;
|
||||||
|
using System.Net.NetworkInformation;
|
||||||
|
using System.Text;
|
||||||
|
using System.Text.RegularExpressions;
|
||||||
|
using XuguClient;
|
||||||
|
|
||||||
|
namespace FreeSql.Xugu
|
||||||
|
{
|
||||||
|
class XuguDbFirst : IDbFirst
|
||||||
|
{
|
||||||
|
public readonly string DefaultSchema = "SYSDBA";//默认模式
|
||||||
|
IFreeSql _orm;
|
||||||
|
protected CommonUtils _commonUtils;
|
||||||
|
protected CommonExpression _commonExpression;
|
||||||
|
public XuguDbFirst(IFreeSql orm, CommonUtils commonUtils, CommonExpression commonExpression)
|
||||||
|
{
|
||||||
|
_orm = orm;
|
||||||
|
_commonUtils = commonUtils;
|
||||||
|
_commonExpression = commonExpression;
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool IsPg10 => ServerVersion >= 10;
|
||||||
|
public int ServerVersion
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
if (_ServerVersionValue == 0 && _orm.Ado.MasterPool != null)
|
||||||
|
using (var conn = _orm.Ado.MasterPool.Get())
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
_ServerVersionValue = int.Parse(conn.Value.ServerVersion.Split('.')[0]);
|
||||||
|
}
|
||||||
|
catch
|
||||||
|
{
|
||||||
|
_ServerVersionValue = 9;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return _ServerVersionValue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
int _ServerVersionValue = 0;
|
||||||
|
|
||||||
|
public int GetDbType(DbColumnInfo column) => (int)GetXGDbType(column);
|
||||||
|
XGDbType GetXGDbType(DbColumnInfo column)
|
||||||
|
{
|
||||||
|
var dbtype = column.DbTypeText;
|
||||||
|
var isarray = dbtype?.EndsWith("[]") == true;
|
||||||
|
if (isarray) dbtype = dbtype.Remove(dbtype.Length - 2);
|
||||||
|
XGDbType ret = XGDbType.LongVarChar;
|
||||||
|
switch (dbtype?.ToUpper().TrimStart('_'))
|
||||||
|
{
|
||||||
|
case "SMALLINT": ret = XGDbType.SmallInt; break;
|
||||||
|
case "INTEGER": ret = XGDbType.Int; break;
|
||||||
|
case "BIGINT": ret = XGDbType.BigInt; break;
|
||||||
|
case "NUMERIC": ret = XGDbType.Numeric; break;
|
||||||
|
case "FLOAT": ret = XGDbType.Real; break;
|
||||||
|
case "DOUBLE": ret = XGDbType.Double; break;
|
||||||
|
//case "money": ret = XGDbType.; break;
|
||||||
|
|
||||||
|
case "CHAR": ret = XGDbType.Char; break;
|
||||||
|
case "VARCHAR": ret = XGDbType.VarChar; break;
|
||||||
|
case "CLOB": ret = XGDbType.LongVarChar; break;
|
||||||
|
|
||||||
|
//case "timestamp": ret = XGDbType.DateTime; break;
|
||||||
|
//case "timestamptz": ret = XGDbType.DateTime; break;
|
||||||
|
//case "date": ret = XGDbType.Date; break;
|
||||||
|
//case "time": ret = XGDbType.Time; break;
|
||||||
|
//case "timetz": ret = XGDbType.TimeTz; break;
|
||||||
|
//case "interval": ret = XGDbType.Interval; break;
|
||||||
|
|
||||||
|
case "BOOLEAN": ret = XGDbType.Bool; break;
|
||||||
|
//case "bytea": ret = XGDbType.Bytea; break;
|
||||||
|
//case "bit": ret = XGDbType.Bool; break;
|
||||||
|
//case "varbit": ret = XGDbType.Varbit; break;
|
||||||
|
|
||||||
|
//case "point": ret = XGDbType.Point; break;
|
||||||
|
//case "line": ret = XGDbType.Line; break;
|
||||||
|
//case "lseg": ret = XGDbType.LSeg; break;
|
||||||
|
//case "box": ret = XGDbType.Box; break;
|
||||||
|
//case "path": ret = XGDbType.Path; break;
|
||||||
|
//case "polygon": ret = XGDbType.Polygon; break;
|
||||||
|
//case "circle": ret = XGDbType.Circle; break;
|
||||||
|
|
||||||
|
//case "cidr": ret = XGDbType.Cidr; break;
|
||||||
|
//case "inet": ret = XGDbType.Inet; break;
|
||||||
|
//case "macaddr": ret = XGDbType.MacAddr; break;
|
||||||
|
|
||||||
|
//case "json": ret = XGDbType.Json; break;
|
||||||
|
//case "jsonb": ret = XGDbType.Jsonb; break;
|
||||||
|
//case "uuid": ret = XGDbType.Uuid; break;
|
||||||
|
|
||||||
|
//case "int4range": ret = XGDbType.Range | XGDbType.Integer; break;
|
||||||
|
//case "int8range": ret = XGDbType.Range | XGDbType.Bigint; break;
|
||||||
|
//case "numrange": ret = XGDbType.Range | XGDbType.Numeric; break;
|
||||||
|
//case "tsrange": ret = XGDbType.Range | XGDbType.Timestamp; break;
|
||||||
|
//case "tstzrange": ret = XGDbType.Range | XGDbType.TimestampTz; break;
|
||||||
|
//case "daterange": ret = XGDbType.Range | XGDbType.Date; break;
|
||||||
|
|
||||||
|
//case "hstore": ret = XGDbType.Hstore; break;
|
||||||
|
//case "geometry": ret = XGDbType.Geometry; break;
|
||||||
|
}
|
||||||
|
return ret ;
|
||||||
|
//return isarray ? (ret | XGDbType.Array) : ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
static readonly Dictionary<int, (string csConvert, string csParse, string csStringify, string csType, Type csTypeInfo, Type csNullableTypeInfo, string csTypeValue, string dataReaderMethod)> _dicDbToCs = new Dictionary<int, (string csConvert, string csParse, string csStringify, string csType, Type csTypeInfo, Type csNullableTypeInfo, string csTypeValue, string dataReaderMethod)>() {
|
||||||
|
{ (int)XGDbType.SmallInt, ("(short?)", "short.Parse({0})", "{0}.ToString()", "short?", typeof(short), typeof(short?), "{0}.Value", "GetInt16") },
|
||||||
|
{ (int)XGDbType.Int, ("(int?)", "int.Parse({0})", "{0}.ToString()", "int?", typeof(int), typeof(int?), "{0}.Value", "GetInt32") },
|
||||||
|
{ (int)XGDbType.BigInt, ("(long?)", "long.Parse({0})", "{0}.ToString()", "long?", typeof(long), typeof(long?), "{0}.Value", "GetInt64") },
|
||||||
|
{ (int)XGDbType.Numeric, ("(decimal?)", "decimal.Parse({0})", "{0}.ToString()", "decimal?", typeof(decimal), typeof(decimal?), "{0}.Value", "GetDecimal") },
|
||||||
|
{ (int)XGDbType.Real, ("(float?)", "float.Parse({0})", "{0}.ToString()", "float?", typeof(float), typeof(float?), "{0}.Value", "GetFloat") },
|
||||||
|
{ (int)XGDbType.Double, ("(double?)", "double.Parse({0})", "{0}.ToString()", "double?", typeof(double), typeof(double?), "{0}.Value", "GetDouble") },
|
||||||
|
|
||||||
|
{ (int)XGDbType.Char, ("", "{0}.Replace(StringifySplit, \"|\")", "{0}.Replace(\"|\", StringifySplit)", "string", typeof(string), typeof(string), "{0}", "GetString") },
|
||||||
|
{ (int)XGDbType.VarChar, ("", "{0}.Replace(StringifySplit, \"|\")", "{0}.Replace(\"|\", StringifySplit)", "string", typeof(string), typeof(string), "{0}", "GetString") },
|
||||||
|
{ (int)XGDbType.LongVarChar, ("", "{0}.Replace(StringifySplit, \"|\")", "{0}.Replace(\"|\", StringifySplit)", "string", typeof(string), typeof(string), "{0}", "GetString") },
|
||||||
|
|
||||||
|
|
||||||
|
{ (int)XGDbType.DateTime, ("(DateTime?)", "new DateTime({0})", "{0}.ToString()", "DateTime?", typeof(DateTime), typeof(DateTime?), "{0}.Value", "GetValue") },
|
||||||
|
|
||||||
|
|
||||||
|
{ (int)XGDbType.Bool, ("(bool?)", "{0} == \"1\"", "{0} == true ? \"1\" : \"0\"", "bool?", typeof(bool), typeof(bool?), "{0}.Value", "GetBoolean") },
|
||||||
|
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
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 DB_NAME from all_databases where DROPED=FALSE AND USER_ID>0";
|
||||||
|
var ds = _orm.Ado.ExecuteArray(CommandType.Text, sql);
|
||||||
|
return ds.Select(a => a.FirstOrDefault()?.ToString()).ToList();
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool ExistsTable(string name, bool ignoreCase)
|
||||||
|
{
|
||||||
|
if (string.IsNullOrEmpty(name)) return false;
|
||||||
|
var tbname = _commonUtils.SplitTableName(name);
|
||||||
|
if (tbname?.Length == 1) tbname = new[] { DefaultSchema, tbname[0] };
|
||||||
|
var sql = string.Format("select 1 from all_tables a inner join all_schemas b on b.schema_id = a.schema_id where b.schema_name || '.' || a.table_name = '{0}.{1}'", tbname);
|
||||||
|
|
||||||
|
return string.Concat(_orm.Ado.ExecuteScalar(CommandType.Text, sql)) == "1";
|
||||||
|
}
|
||||||
|
|
||||||
|
public DbTableInfo GetTableByName(string name, bool ignoreCase = true) => GetTables(null, name, ignoreCase)?.FirstOrDefault();
|
||||||
|
public List<DbTableInfo> GetTablesByDatabase(params string[] database) => GetTables(database, null,false);
|
||||||
|
|
||||||
|
public List<DbTableInfo> GetTables(string[] database, string tablename, bool ignoreCase)
|
||||||
|
{
|
||||||
|
var olddatabase = "";
|
||||||
|
using (var conn = _orm.Ado.MasterPool.Get(TimeSpan.FromSeconds(5)))
|
||||||
|
{
|
||||||
|
olddatabase = conn.Value.Database;
|
||||||
|
}
|
||||||
|
string[] tbname = null;
|
||||||
|
string[] dbs = database == null || database.Any() == false ? new[] { olddatabase } : database;
|
||||||
|
if (string.IsNullOrEmpty(tablename) == false)
|
||||||
|
{
|
||||||
|
tbname = _commonUtils.SplitTableName(tablename);
|
||||||
|
if (tbname?.Length == 1) tbname = new[] { DefaultSchema, tbname[0] };
|
||||||
|
dbs = new[] { olddatabase };
|
||||||
|
}
|
||||||
|
var tables = new List<DbTableInfo>();
|
||||||
|
|
||||||
|
foreach (var db in dbs)
|
||||||
|
{
|
||||||
|
if (string.IsNullOrEmpty(db) || string.Compare(db, olddatabase, true) != 0) continue;
|
||||||
|
|
||||||
|
var loc1 = new List<DbTableInfo>();
|
||||||
|
var loc2 = new Dictionary<string, DbTableInfo>();
|
||||||
|
var loc3 = new Dictionary<string, Dictionary<string, DbColumnInfo>>();
|
||||||
|
|
||||||
|
var sql = $@"
|
||||||
|
{(tbname == null ? "" : $"select * from (")}select b.schema_name || '.' || a.table_name as ns,
|
||||||
|
b.schema_name,
|
||||||
|
a.table_name,
|
||||||
|
a.comments,
|
||||||
|
'TABLE' AS type
|
||||||
|
from all_tables a
|
||||||
|
inner join all_schemas b on b.schema_id = a.schema_id
|
||||||
|
where a.IS_SYS=FALSE
|
||||||
|
|
||||||
|
union all
|
||||||
|
|
||||||
|
select b.schema_name || '.' || a.view_name as ns,
|
||||||
|
b.schema_name,
|
||||||
|
a.view_name,
|
||||||
|
a.comments,
|
||||||
|
'VIEW' AS type
|
||||||
|
from all_views a
|
||||||
|
inner join all_schemas b on b.schema_id = a.schema_id
|
||||||
|
where a.IS_SYS=FALSE
|
||||||
|
{(tbname == null ? "" : $") ft_dbf where schema_name ={_commonUtils.FormatSql("{0}", tbname[0])} and ft_dbf.Table_Name={_commonUtils.FormatSql("{0}", tbname[1])}")}";
|
||||||
|
var ds = _orm.Ado.ExecuteArray(CommandType.Text, sql);
|
||||||
|
if (ds == null) return loc1;
|
||||||
|
|
||||||
|
var loc6 = new List<string[]>();
|
||||||
|
var loc66 = new List<string[]>();
|
||||||
|
var loc6_1000 = new List<string>();
|
||||||
|
var loc66_1000 = new List<string>();
|
||||||
|
foreach (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.schema_name || '.' || tb.table_name as id,
|
||||||
|
a.COL_NAME,
|
||||||
|
a.TYPE_NAME,
|
||||||
|
a.SCALE,
|
||||||
|
case when a.NOT_NULL then '0' else '1' end as is_nullable,
|
||||||
|
seq.SEQ_ID,
|
||||||
|
seq.IS_SYS,
|
||||||
|
seq.MIN_VAL,
|
||||||
|
seq.STEP_VAL,
|
||||||
|
a.COMMENTS,
|
||||||
|
tb.table_name,
|
||||||
|
a.def_val,
|
||||||
|
ns.schema_id,
|
||||||
|
a.`VARYING`
|
||||||
|
from all_columns as a
|
||||||
|
left join all_tables tb on a.table_id=tb.table_id
|
||||||
|
left join all_schemas ns on tb.schema_id = ns.schema_id
|
||||||
|
left join all_sequences seq on seq.SEQ_ID=a.Serial_ID
|
||||||
|
where {loc8.ToString().Replace("a.table_name", "ns.schema_name || '.' || tb.table_name")}";
|
||||||
|
|
||||||
|
ds = _orm.Ado.ExecuteArray(CommandType.Text, sql);
|
||||||
|
if (ds == null) return loc1;
|
||||||
|
var position = 1;
|
||||||
|
foreach (object[] row in ds)
|
||||||
|
{
|
||||||
|
var object_id = string.Concat(row[0]);
|
||||||
|
var column = string.Concat(row[1]);
|
||||||
|
var type = string.Concat(row[2]);
|
||||||
|
var max_length = int.Parse(string.Concat(row[3]));
|
||||||
|
//var sqlType = string.Concat(row[4]);
|
||||||
|
var is_nullable = string.Concat(row[5]) == "1";
|
||||||
|
|
||||||
|
long.TryParse(row[5]?.ToString() ?? "0", out long SEQ_ID);
|
||||||
|
var SEQ_IS_SYS = (row[6]?.ToString() ?? "false")?.ToLower();
|
||||||
|
|
||||||
|
var is_identity = (SEQ_ID > 0 && SEQ_IS_SYS == "true");
|
||||||
|
var comment = string.Concat(row[9]);
|
||||||
|
|
||||||
|
|
||||||
|
var defaultValue = string.Concat(row[11]);
|
||||||
|
//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++;
|
||||||
|
//}
|
||||||
|
var sqlType = type;
|
||||||
|
if (max_length > 0)
|
||||||
|
{
|
||||||
|
switch (type.ToUpper())
|
||||||
|
{
|
||||||
|
//case "numeric": sqlType += $"({max_length})"; break;
|
||||||
|
|
||||||
|
case "NUMERIC":
|
||||||
|
{
|
||||||
|
var data_precision = max_length % 65536;
|
||||||
|
var data_scale = max_length / 65536;
|
||||||
|
sqlType += $"({data_scale},{data_precision})"; break;
|
||||||
|
}
|
||||||
|
|
||||||
|
//case "DATETIME":
|
||||||
|
// break;
|
||||||
|
default:
|
||||||
|
sqlType += $"({max_length})"; break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
//if (attndims > 0) type += "[]";
|
||||||
|
|
||||||
|
loc3[object_id].Add(column, new DbColumnInfo
|
||||||
|
{
|
||||||
|
Name = column,
|
||||||
|
MaxLength = max_length,
|
||||||
|
IsIdentity = is_identity,
|
||||||
|
IsNullable = is_nullable,
|
||||||
|
IsPrimary = false,
|
||||||
|
DbTypeText = type,
|
||||||
|
DbTypeTextFull = sqlType,
|
||||||
|
Table = loc2[object_id],
|
||||||
|
Comment = comment,
|
||||||
|
DefaultValue = defaultValue,
|
||||||
|
Position = position
|
||||||
|
});
|
||||||
|
loc3[object_id][column].DbType = this.GetDbType(loc3[object_id][column]);
|
||||||
|
loc3[object_id][column].CsType = this.GetCsTypeInfo(loc3[object_id][column]);
|
||||||
|
position++;
|
||||||
|
}
|
||||||
|
|
||||||
|
sql = $@"
|
||||||
|
select
|
||||||
|
ns.SCHEMA_NAME || '.' || t.table_name as table_id,
|
||||||
|
keys,
|
||||||
|
a.index_name,
|
||||||
|
case when a.IS_UNIQUE then 1 else 0 end as IsUnique,
|
||||||
|
case when a.IS_Primary then 1 else 0 end as IsPrimary,
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
t.table_name,
|
||||||
|
ns.SCHEMA_NAME,
|
||||||
|
a.IS_SYS
|
||||||
|
from all_INDEXES a
|
||||||
|
left join all_tables t on a.TABLE_ID=t.TABLE_ID
|
||||||
|
left join all_schemas ns on t.SCHEMA_ID=ns.SCHEMA_ID
|
||||||
|
where IS_SYS=false and {loc8.ToString().Replace("a.table_name", "ns.SCHEMA_NAME || '.' || t.table_name")}
|
||||||
|
";
|
||||||
|
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 = false;//= string.Concat(row[5]) == "1";
|
||||||
|
var is_desc = false;//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) //bug: https://github.com/2881099/FreeSql.Wiki.VuePress/issues/9
|
||||||
|
//{
|
||||||
|
// if (loc3[object_id][tc].DbTypeText.EndsWith("[]"))
|
||||||
|
// {
|
||||||
|
// column = tc;
|
||||||
|
// break;
|
||||||
|
// }
|
||||||
|
//}
|
||||||
|
if (loc3.ContainsKey(object_id) == false || loc3[object_id].ContainsKey(column) == false) continue;
|
||||||
|
var loc9 = loc3[object_id][column];
|
||||||
|
if (loc9.IsPrimary == false && is_primary_key) loc9.IsPrimary = is_primary_key;
|
||||||
|
|
||||||
|
Dictionary<string, DbIndexInfo> loc10 = null;
|
||||||
|
DbIndexInfo loc11 = null;
|
||||||
|
if (!indexColumns.TryGetValue(object_id, out loc10))
|
||||||
|
indexColumns.Add(object_id, loc10 = new Dictionary<string, DbIndexInfo>());
|
||||||
|
if (!loc10.TryGetValue(index_id, out loc11))
|
||||||
|
loc10.Add(index_id, loc11 = new DbIndexInfo());
|
||||||
|
loc11.Columns.Add(new DbIndexColumnInfo { Column = loc9, IsDesc = is_desc });
|
||||||
|
if (is_unique && !is_primary_key)
|
||||||
|
{
|
||||||
|
if (!uniqueColumns.TryGetValue(object_id, out loc10))
|
||||||
|
uniqueColumns.Add(object_id, loc10 = new Dictionary<string, DbIndexInfo>());
|
||||||
|
if (!loc10.TryGetValue(index_id, out loc11))
|
||||||
|
loc10.Add(index_id, loc11 = new DbIndexInfo());
|
||||||
|
loc11.Columns.Add(new DbIndexColumnInfo { Column = loc9, IsDesc = is_desc });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
foreach (var object_id in indexColumns.Keys)
|
||||||
|
{
|
||||||
|
foreach (var column in indexColumns[object_id])
|
||||||
|
loc2[object_id].IndexesDict.Add(column.Key, column.Value);
|
||||||
|
}
|
||||||
|
foreach (var object_id in uniqueColumns.Keys)
|
||||||
|
{
|
||||||
|
foreach (var column in uniqueColumns[object_id])
|
||||||
|
{
|
||||||
|
column.Value.Columns.Sort((c1, c2) => c1.Column.Name.CompareTo(c2.Column.Name));
|
||||||
|
loc2[object_id].UniquesDict.Add(column.Key, column.Value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (tbname == null)
|
||||||
|
{
|
||||||
|
sql = $@"
|
||||||
|
select
|
||||||
|
schema_name || '.' || b.table_name as table_id,
|
||||||
|
cons_name as FKId,
|
||||||
|
cons_type,
|
||||||
|
define
|
||||||
|
from all_constraints as a
|
||||||
|
left join all_tables as b on a.Table_ID=b.Table_ID
|
||||||
|
left Join all_SCHEMAS AS c on b.SCHEMA_ID=c.SCHEMA_ID
|
||||||
|
where IS_SYS=false AND {loc8.ToString().Replace("a.table_name", "schema_name || '.' || b.table_name")}
|
||||||
|
";
|
||||||
|
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[3] as string[];
|
||||||
|
var fk_id = string.Concat(row[1]);
|
||||||
|
var ref_table_id = string.Concat(row[0]);
|
||||||
|
var is_foreign_key = string.Concat(row[2]) == "F";
|
||||||
|
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)
|
||||||
|
{
|
||||||
|
return new List<DbEnumInfo>();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
689
Providers/FreeSql.Provider.Xugu/XuguExpression.cs
Normal file
689
Providers/FreeSql.Provider.Xugu/XuguExpression.cs
Normal file
@ -0,0 +1,689 @@
|
|||||||
|
using FreeSql.Internal;
|
||||||
|
using Newtonsoft.Json.Linq;
|
||||||
|
using System;
|
||||||
|
using System.Collections;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Linq.Expressions;
|
||||||
|
using System.Text;
|
||||||
|
using System.Text.RegularExpressions;
|
||||||
|
|
||||||
|
namespace FreeSql.Xugu
|
||||||
|
{
|
||||||
|
class XuguExpression : CommonExpression
|
||||||
|
{
|
||||||
|
|
||||||
|
public XuguExpression(CommonUtils common) : base(common) { }
|
||||||
|
|
||||||
|
public override string ExpressionLambdaToSqlOther(Expression exp, ExpTSC tsc)
|
||||||
|
{
|
||||||
|
Func<Expression, string> getExp = exparg => ExpressionLambdaToSql(exparg, tsc);
|
||||||
|
switch (exp.NodeType)
|
||||||
|
{
|
||||||
|
case ExpressionType.ArrayLength:
|
||||||
|
var arrOper = (exp as UnaryExpression)?.Operand;
|
||||||
|
var arrOperExp = getExp(arrOper);
|
||||||
|
if (arrOperExp.StartsWith("(") || arrOperExp.EndsWith(")")) return $"array_length(array[{arrOperExp.TrimStart('(').TrimEnd(')')}],1)";
|
||||||
|
if (arrOper.Type == typeof(byte[])) return $"octet_length({getExp(arrOper)})";
|
||||||
|
return $"case when {arrOperExp} is null then 0 else array_length({arrOperExp},1) end";
|
||||||
|
case ExpressionType.Convert:
|
||||||
|
var operandExp = (exp as UnaryExpression)?.Operand;
|
||||||
|
var gentype = exp.Type.NullableTypeOrThis();
|
||||||
|
if (gentype != operandExp.Type.NullableTypeOrThis())
|
||||||
|
{
|
||||||
|
switch (exp.Type.NullableTypeOrThis().ToString())
|
||||||
|
{
|
||||||
|
case "System.Boolean": return $"(({getExp(operandExp)})::varchar not in ('0','false','f','no'))";
|
||||||
|
case "System.Byte": return $"({getExp(operandExp)})::int2";
|
||||||
|
case "System.Char": return $"substr(({getExp(operandExp)})::char, 1, 1)";
|
||||||
|
case "System.DateTime": return ExpressionConstDateTime(operandExp) ?? $"({getExp(operandExp)})::timestamp";
|
||||||
|
case "System.Decimal": return $"({getExp(operandExp)})::numeric";
|
||||||
|
case "System.Double": return $"({getExp(operandExp)})::float8";
|
||||||
|
case "System.Int16": return $"({getExp(operandExp)})::int2";
|
||||||
|
case "System.Int32": return $"({getExp(operandExp)})::int4";
|
||||||
|
case "System.Int64": return $"({getExp(operandExp)})::int8";
|
||||||
|
case "System.SByte": return $"({getExp(operandExp)})::int2";
|
||||||
|
case "System.Single": return $"({getExp(operandExp)})::float4";
|
||||||
|
case "System.String": return $"({getExp(operandExp)})::text";
|
||||||
|
case "System.UInt16": return $"({getExp(operandExp)})::int2";
|
||||||
|
case "System.UInt32": return $"({getExp(operandExp)})::int4";
|
||||||
|
case "System.UInt64": return $"({getExp(operandExp)})::int8";
|
||||||
|
case "System.Guid": return $"({getExp(operandExp)})::uuid";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case ExpressionType.Call:
|
||||||
|
var callExp = exp as MethodCallExpression;
|
||||||
|
|
||||||
|
switch (callExp.Method.Name)
|
||||||
|
{
|
||||||
|
case "Parse":
|
||||||
|
case "TryParse":
|
||||||
|
switch (callExp.Method.DeclaringType.NullableTypeOrThis().ToString())
|
||||||
|
{
|
||||||
|
case "System.Boolean": return $"(({getExp(callExp.Arguments[0])})::varchar not in ('0','false','f','no'))";
|
||||||
|
case "System.Byte": return $"({getExp(callExp.Arguments[0])})::int2";
|
||||||
|
case "System.Char": return $"substr(({getExp(callExp.Arguments[0])})::char, 1, 1)";
|
||||||
|
case "System.DateTime": return ExpressionConstDateTime(callExp.Arguments[0]) ?? $"({getExp(callExp.Arguments[0])})::timestamp";
|
||||||
|
case "System.Decimal": return $"({getExp(callExp.Arguments[0])})::numeric";
|
||||||
|
case "System.Double": return $"({getExp(callExp.Arguments[0])})::float8";
|
||||||
|
case "System.Int16": return $"({getExp(callExp.Arguments[0])})::int2";
|
||||||
|
case "System.Int32": return $"({getExp(callExp.Arguments[0])})::int4";
|
||||||
|
case "System.Int64": return $"({getExp(callExp.Arguments[0])})::int8";
|
||||||
|
case "System.SByte": return $"({getExp(callExp.Arguments[0])})::int2";
|
||||||
|
case "System.Single": return $"({getExp(callExp.Arguments[0])})::float4";
|
||||||
|
case "System.UInt16": return $"({getExp(callExp.Arguments[0])})::int2";
|
||||||
|
case "System.UInt32": return $"({getExp(callExp.Arguments[0])})::int4";
|
||||||
|
case "System.UInt64": return $"({getExp(callExp.Arguments[0])})::int8";
|
||||||
|
case "System.Guid": return $"({getExp(callExp.Arguments[0])})::uuid";
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case "NewGuid":
|
||||||
|
return null;
|
||||||
|
case "Next":
|
||||||
|
if (callExp.Object?.Type == typeof(Random)) return "(random()*1000000000)::int4";
|
||||||
|
return null;
|
||||||
|
case "NextDouble":
|
||||||
|
if (callExp.Object?.Type == typeof(Random)) return "random()";
|
||||||
|
return null;
|
||||||
|
case "Random":
|
||||||
|
if (callExp.Method.DeclaringType.IsNumberType()) return "random()";
|
||||||
|
return null;
|
||||||
|
case "ToString":
|
||||||
|
if (callExp.Object != null) return callExp.Arguments.Count == 0 ? $"({getExp(callExp.Object)})::text" : null;
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
var objExp = callExp.Object;
|
||||||
|
var objType = objExp?.Type;
|
||||||
|
if (objType?.FullName == "System.Byte[]") return null;
|
||||||
|
|
||||||
|
var argIndex = 0;
|
||||||
|
if (objType == null && callExp.Method.DeclaringType == typeof(Enumerable))
|
||||||
|
{
|
||||||
|
objExp = callExp.Arguments.FirstOrDefault();
|
||||||
|
objType = objExp?.Type;
|
||||||
|
argIndex++;
|
||||||
|
|
||||||
|
if (objType == typeof(string))
|
||||||
|
{
|
||||||
|
switch (callExp.Method.Name)
|
||||||
|
{
|
||||||
|
case "First":
|
||||||
|
case "FirstOrDefault":
|
||||||
|
return $"substr({getExp(callExp.Arguments[0])}, 1, 1)";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (objType == null) objType = callExp.Method.DeclaringType;
|
||||||
|
if (objType != null || objType.IsArrayOrList())
|
||||||
|
{
|
||||||
|
string left = null;
|
||||||
|
switch (objType.FullName)
|
||||||
|
{
|
||||||
|
case "Newtonsoft.Json.Linq.JToken":
|
||||||
|
case "Newtonsoft.Json.Linq.JObject":
|
||||||
|
case "Newtonsoft.Json.Linq.JArray":
|
||||||
|
left = objExp == null ? null : getExp(objExp);
|
||||||
|
switch (callExp.Method.Name)
|
||||||
|
{
|
||||||
|
case "get_Item": return $"{left}->{getExp(callExp.Arguments[argIndex])}";
|
||||||
|
case "Any": return $"(jsonb_array_length(coalesce({left},'[]')) > 0)";
|
||||||
|
case "Contains":
|
||||||
|
var json = getExp(callExp.Arguments[argIndex]);
|
||||||
|
if (objType == typeof(JArray))
|
||||||
|
return $"(coalesce({left},'[]') ? ({json})::text)";
|
||||||
|
if (json.StartsWith("'") && json.EndsWith("'"))
|
||||||
|
return $"(coalesce({left},'{{}}') @> {_common.FormatSql("{0}", JToken.Parse(json.Trim('\'')))})";
|
||||||
|
return $"(coalesce({left},'{{}}') @> ({json})::jsonb)";
|
||||||
|
case "ContainsKey": return $"(coalesce({left},'{{}}') ? {getExp(callExp.Arguments[argIndex])})";
|
||||||
|
case "Concat":
|
||||||
|
var right2 = getExp(callExp.Arguments[argIndex]);
|
||||||
|
return $"(coalesce({left},'{{}}') || {right2})";
|
||||||
|
case "LongCount":
|
||||||
|
case "Count": return $"jsonb_array_length(coalesce({left},'[]'))";
|
||||||
|
case "Parse":
|
||||||
|
var json2 = getExp(callExp.Arguments[argIndex]);
|
||||||
|
if (json2.StartsWith("'") && json2.EndsWith("'")) return _common.FormatSql("{0}", JToken.Parse(json2.Trim('\'')));
|
||||||
|
return $"({json2})::jsonb";
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (objType == typeof(Dictionary<string, string>))
|
||||||
|
{
|
||||||
|
left = objExp == null ? null : getExp(objExp);
|
||||||
|
switch (callExp.Method.Name)
|
||||||
|
{
|
||||||
|
case "get_Item": return $"{left}->{getExp(callExp.Arguments[argIndex])}";
|
||||||
|
case "Contains":
|
||||||
|
var right = getExp(callExp.Arguments[argIndex]);
|
||||||
|
return $"({left} @> ({right}))";
|
||||||
|
case "ContainsKey": return $"({left} ? {getExp(callExp.Arguments[argIndex])})";
|
||||||
|
case "Concat": return $"({left} || {getExp(callExp.Arguments[argIndex])})";
|
||||||
|
case "GetLength":
|
||||||
|
case "GetLongLength":
|
||||||
|
case "Count": return $"case when {left} is null then 0 else array_length(akeys({left}),1) end";
|
||||||
|
case "Keys": return $"akeys({left})";
|
||||||
|
case "Values": return $"avals({left})";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
switch (callExp.Method.Name)
|
||||||
|
{
|
||||||
|
case "Any":
|
||||||
|
left = objExp == null ? null : getExp(objExp);
|
||||||
|
if (left.StartsWith("(") || left.EndsWith(")")) left = $"array[{left.TrimStart('(').TrimEnd(')')}]";
|
||||||
|
return $"(case when {left} is null then 0 else array_length({left},1) end > 0)";
|
||||||
|
case "Contains":
|
||||||
|
tsc.SetMapColumnTmp(null);
|
||||||
|
var args1 = getExp(callExp.Arguments[argIndex]);
|
||||||
|
var oldMapType = tsc.SetMapTypeReturnOld(tsc.mapTypeTmp);
|
||||||
|
var oldDbParams = objExp?.NodeType == ExpressionType.MemberAccess ? tsc.SetDbParamsReturnOld(null) : null; //#900 UseGenerateCommandParameterWithLambda(true) 子查询 bug、以及 #1173 参数化 bug
|
||||||
|
tsc.isNotSetMapColumnTmp = true;
|
||||||
|
left = objExp == null ? null : getExp(objExp);
|
||||||
|
tsc.isNotSetMapColumnTmp = false;
|
||||||
|
tsc.SetMapColumnTmp(null).SetMapTypeReturnOld(oldMapType);
|
||||||
|
if (oldDbParams != null) tsc.SetDbParamsReturnOld(oldDbParams);
|
||||||
|
//判断 in 或 array @> array
|
||||||
|
if (left.StartsWith("array[") || left.EndsWith("]"))
|
||||||
|
return $"({args1}) in ({left.Substring(6, left.Length - 7)})";
|
||||||
|
if (left.StartsWith("(") || left.EndsWith(")")) //在各大 Provider AdoProvider 中已约定,500元素分割, 3空格\r\n4空格
|
||||||
|
return $"(({args1}) in {left.Replace(", \r\n \r\n", $") \r\n OR ({args1}) in (")})";
|
||||||
|
if (args1.StartsWith("(") || args1.EndsWith(")")) args1 = $"array[{args1.TrimStart('(').TrimEnd(')')}]";
|
||||||
|
args1 = $"array[{args1}]";
|
||||||
|
if (objExp != null)
|
||||||
|
{
|
||||||
|
var dbinfo = _common._orm.CodeFirst.GetDbInfo(objExp.Type);
|
||||||
|
if (dbinfo != null) args1 = $"{args1}::{dbinfo.dbtype}";
|
||||||
|
}
|
||||||
|
return $"({left} @> {args1})";
|
||||||
|
case "Concat":
|
||||||
|
left = objExp == null ? null : getExp(objExp);
|
||||||
|
if (left.StartsWith("(") || left.EndsWith(")")) left = $"array[{left.TrimStart('(').TrimEnd(')')}]";
|
||||||
|
var right2 = getExp(callExp.Arguments[argIndex]);
|
||||||
|
if (right2.StartsWith("(") || right2.EndsWith(")")) right2 = $"array[{right2.TrimStart('(').TrimEnd(')')}]";
|
||||||
|
return $"({left} || {right2})";
|
||||||
|
case "GetLength":
|
||||||
|
case "GetLongLength":
|
||||||
|
case "Length":
|
||||||
|
case "Count":
|
||||||
|
left = objExp == null ? null : getExp(objExp);
|
||||||
|
if (left.StartsWith("(") || left.EndsWith(")")) left = $"array[{left.TrimStart('(').TrimEnd(')')}]";
|
||||||
|
return $"case when {left} is null then 0 else array_length({left},1) end";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case ExpressionType.MemberAccess:
|
||||||
|
var memExp = exp as MemberExpression;
|
||||||
|
var memParentExp = memExp.Expression?.Type;
|
||||||
|
if (memParentExp?.FullName == "System.Byte[]") return null;
|
||||||
|
if (memParentExp != null)
|
||||||
|
{
|
||||||
|
if (memParentExp.IsArray == true)
|
||||||
|
{
|
||||||
|
var left = getExp(memExp.Expression);
|
||||||
|
if (left.StartsWith("(") || left.EndsWith(")")) left = $"array[{left.TrimStart('(').TrimEnd(')')}]";
|
||||||
|
switch (memExp.Member.Name)
|
||||||
|
{
|
||||||
|
case "Length":
|
||||||
|
case "Count": return $"case when {left} is null then 0 else array_length({left},1) end";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
switch (memParentExp.FullName)
|
||||||
|
{
|
||||||
|
case "Newtonsoft.Json.Linq.JToken":
|
||||||
|
case "Newtonsoft.Json.Linq.JObject":
|
||||||
|
case "Newtonsoft.Json.Linq.JArray":
|
||||||
|
var left = getExp(memExp.Expression);
|
||||||
|
switch (memExp.Member.Name)
|
||||||
|
{
|
||||||
|
case "Count": return $"jsonb_array_length(coalesce({left},'[]'))";
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (memParentExp == typeof(Dictionary<string, string>))
|
||||||
|
{
|
||||||
|
var left = getExp(memExp.Expression);
|
||||||
|
switch (memExp.Member.Name)
|
||||||
|
{
|
||||||
|
case "Count": return $"case when {left} is null then 0 else array_length(akeys({left}),1) end";
|
||||||
|
case "Keys": return $"akeys({left})";
|
||||||
|
case "Values": return $"avals({left})";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case ExpressionType.NewArrayInit:
|
||||||
|
var arrExp = exp as NewArrayExpression;
|
||||||
|
var arrSb = new StringBuilder();
|
||||||
|
arrSb.Append("array[");
|
||||||
|
for (var a = 0; a < arrExp.Expressions.Count; a++)
|
||||||
|
{
|
||||||
|
if (a > 0) arrSb.Append(",");
|
||||||
|
arrSb.Append(getExp(arrExp.Expressions[a]));
|
||||||
|
}
|
||||||
|
if (arrSb.Length == 1) arrSb.Append("NULL");
|
||||||
|
return arrSb.Append("]").ToString();
|
||||||
|
case ExpressionType.ListInit:
|
||||||
|
var listExp = exp as ListInitExpression;
|
||||||
|
var listSb = new StringBuilder();
|
||||||
|
listSb.Append("(");
|
||||||
|
for (var a = 0; a < listExp.Initializers.Count; a++)
|
||||||
|
{
|
||||||
|
if (listExp.Initializers[a].Arguments.Any() == false) continue;
|
||||||
|
if (a > 0) listSb.Append(",");
|
||||||
|
listSb.Append(getExp(listExp.Initializers[a].Arguments.FirstOrDefault()));
|
||||||
|
}
|
||||||
|
if (listSb.Length == 1) listSb.Append("NULL");
|
||||||
|
return listSb.Append(")").ToString();
|
||||||
|
case ExpressionType.New:
|
||||||
|
var newExp = exp as NewExpression;
|
||||||
|
if (typeof(IList).IsAssignableFrom(newExp.Type))
|
||||||
|
{
|
||||||
|
if (newExp.Arguments.Count == 0) return "(NULL)";
|
||||||
|
if (typeof(IEnumerable).IsAssignableFrom(newExp.Arguments[0].Type) == false) return "(NULL)";
|
||||||
|
return getExp(newExp.Arguments[0]);
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public override string ExpressionLambdaToSqlMemberAccessString(MemberExpression exp, ExpTSC tsc)
|
||||||
|
{
|
||||||
|
if (exp.Expression == null)
|
||||||
|
{
|
||||||
|
switch (exp.Member.Name)
|
||||||
|
{
|
||||||
|
case "Empty": return "''";
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
var left = ExpressionLambdaToSql(exp.Expression, tsc);
|
||||||
|
switch (exp.Member.Name)
|
||||||
|
{
|
||||||
|
case "Length": return $"char_length({left})";
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
public override string ExpressionLambdaToSqlMemberAccessDateTime(MemberExpression exp, ExpTSC tsc)
|
||||||
|
{
|
||||||
|
if (exp.Expression == null)
|
||||||
|
{
|
||||||
|
switch (exp.Member.Name)
|
||||||
|
{
|
||||||
|
case "Now": return _common.Now;
|
||||||
|
case "UtcNow": return _common.NowUtc;
|
||||||
|
case "Today": return "current_date";
|
||||||
|
case "MinValue": return "'0001/1/1 0:00:00'::timestamp";
|
||||||
|
case "MaxValue": return "'9999/12/31 23:59:59'::timestamp";
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
var left = ExpressionLambdaToSql(exp.Expression, tsc);
|
||||||
|
switch (exp.Member.Name)
|
||||||
|
{
|
||||||
|
case "Date": return $"({left})::date";
|
||||||
|
case "TimeOfDay": return $"(extract(epoch from ({left})::time)*1000000)";
|
||||||
|
case "DayOfWeek": return $"extract(dow from ({left})::timestamp)";
|
||||||
|
case "Day": return $"extract(day from ({left})::timestamp)";
|
||||||
|
case "DayOfYear": return $"extract(doy from ({left})::timestamp)";
|
||||||
|
case "Month": return $"extract(month from ({left})::timestamp)";
|
||||||
|
case "Year": return $"extract(year from ({left})::timestamp)";
|
||||||
|
case "Hour": return $"extract(hour from ({left})::timestamp)";
|
||||||
|
case "Minute": return $"extract(minute from ({left})::timestamp)";
|
||||||
|
case "Second": return $"extract(second from ({left})::timestamp)";
|
||||||
|
case "Millisecond": return $"(extract(milliseconds from ({left})::timestamp)-extract(second from ({left})::timestamp)*1000)";
|
||||||
|
case "Ticks": return $"(extract(epoch from ({left})::timestamp)*10000000+621355968000000000)";
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
public override string ExpressionLambdaToSqlMemberAccessTimeSpan(MemberExpression exp, ExpTSC tsc)
|
||||||
|
{
|
||||||
|
if (exp.Expression == null)
|
||||||
|
{
|
||||||
|
switch (exp.Member.Name)
|
||||||
|
{
|
||||||
|
case "Zero": return "0";
|
||||||
|
case "MinValue": return "-922337203685477580"; //微秒 Ticks / 10
|
||||||
|
case "MaxValue": return "922337203685477580";
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
var left = ExpressionLambdaToSql(exp.Expression, tsc);
|
||||||
|
switch (exp.Member.Name)
|
||||||
|
{
|
||||||
|
case "Days": return $"floor(({left})/{(long)1000000 * 60 * 60 * 24})";
|
||||||
|
case "Hours": return $"floor(({left})/{(long)1000000 * 60 * 60}%24)";
|
||||||
|
case "Milliseconds": return $"(floor(({left})/1000)::int8%1000)";
|
||||||
|
case "Minutes": return $"(floor(({left})/{(long)1000000 * 60})::int8%60)";
|
||||||
|
case "Seconds": return $"(floor(({left})/1000000)::int8%60)";
|
||||||
|
case "Ticks": return $"(({left})*10)";
|
||||||
|
case "TotalDays": return $"(({left})/{(long)1000000 * 60 * 60 * 24})";
|
||||||
|
case "TotalHours": return $"(({left})/{(long)1000000 * 60 * 60})";
|
||||||
|
case "TotalMilliseconds": return $"(({left})/1000)";
|
||||||
|
case "TotalMinutes": return $"(({left})/{(long)1000000 * 60})";
|
||||||
|
case "TotalSeconds": return $"(({left})/1000000)";
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public override string ExpressionLambdaToSqlCallString(MethodCallExpression exp, ExpTSC tsc)
|
||||||
|
{
|
||||||
|
Func<Expression, string> getExp = exparg => ExpressionLambdaToSql(exparg, tsc);
|
||||||
|
if (exp.Object == null)
|
||||||
|
{
|
||||||
|
switch (exp.Method.Name)
|
||||||
|
{
|
||||||
|
case "IsNullOrEmpty":
|
||||||
|
var arg1 = getExp(exp.Arguments[0]);
|
||||||
|
return $"({arg1} is null or {arg1} = '')";
|
||||||
|
case "IsNullOrWhiteSpace":
|
||||||
|
var arg2 = getExp(exp.Arguments[0]);
|
||||||
|
return $"({arg2} is null or {arg2} = '' or ltrim({arg2}) = '')";
|
||||||
|
case "Concat":
|
||||||
|
return _common.StringConcat(exp.Arguments.Select(a => getExp(a)).ToArray(), null);
|
||||||
|
case "Format":
|
||||||
|
if (exp.Arguments[0].NodeType != ExpressionType.Constant) throw new Exception(CoreStrings.Not_Implemented_Expression_ParameterUseConstant(exp,exp.Arguments[0]));
|
||||||
|
var expArgsHack = exp.Arguments.Count == 2 && exp.Arguments[1].NodeType == ExpressionType.NewArrayInit ?
|
||||||
|
(exp.Arguments[1] as NewArrayExpression).Expressions : exp.Arguments.Where((a, z) => z > 0);
|
||||||
|
//3个 {} 时,Arguments 解析出来是分开的
|
||||||
|
//4个 {} 时,Arguments[1] 只能解析这个出来,然后里面是 NewArray []
|
||||||
|
var expArgs = expArgsHack.Select(a =>
|
||||||
|
{
|
||||||
|
var atype = (a as UnaryExpression)?.Operand.Type.NullableTypeOrThis() ?? a.Type.NullableTypeOrThis();
|
||||||
|
if (atype == typeof(string)) return $"'||{_common.IsNull(ExpressionLambdaToSql(a, tsc), "''")}||'";
|
||||||
|
return $"'||{_common.IsNull($"({ExpressionLambdaToSql(a, tsc)})::text", "''")}||'";
|
||||||
|
}).ToArray();
|
||||||
|
return string.Format(ExpressionLambdaToSql(exp.Arguments[0], tsc), expArgs);
|
||||||
|
case "Join":
|
||||||
|
if (exp.IsStringJoin(out var tolistObjectExp, out var toListMethod, out var toListArgs1))
|
||||||
|
{
|
||||||
|
var newToListArgs0 = Expression.Call(tolistObjectExp, toListMethod,
|
||||||
|
Expression.Lambda(
|
||||||
|
Expression.Call(
|
||||||
|
typeof(SqlExtExtensions).GetMethod("StringJoinPgsqlGroupConcat"),
|
||||||
|
Expression.Convert(toListArgs1.Body, typeof(object)),
|
||||||
|
Expression.Convert(exp.Arguments[0], typeof(object))),
|
||||||
|
toListArgs1.Parameters));
|
||||||
|
var newToListSql = getExp(newToListArgs0);
|
||||||
|
return newToListSql;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
var left = getExp(exp.Object);
|
||||||
|
switch (exp.Method.Name)
|
||||||
|
{
|
||||||
|
case "StartsWith":
|
||||||
|
case "EndsWith":
|
||||||
|
case "Contains":
|
||||||
|
var args0Value = getExp(exp.Arguments[0]);
|
||||||
|
if (args0Value == "NULL") return $"({left}) IS NULL";
|
||||||
|
if (args0Value.Contains("%"))
|
||||||
|
{
|
||||||
|
if (exp.Method.Name == "StartsWith") return $"strpos({args0Value}, {left}) = 1";
|
||||||
|
if (exp.Method.Name == "EndsWith") return $"strpos({args0Value}, {left}) = char_length({args0Value})";
|
||||||
|
return $"strpos({args0Value}, {left}) > 0";
|
||||||
|
}
|
||||||
|
var likeOpt = "LIKE";
|
||||||
|
if (exp.Arguments.Count > 1)
|
||||||
|
{
|
||||||
|
if (exp.Arguments[1].Type == typeof(bool) ||
|
||||||
|
exp.Arguments[1].Type == typeof(StringComparison)) likeOpt = "ILIKE";
|
||||||
|
}
|
||||||
|
if (exp.Method.Name == "StartsWith") return $"({left}) {likeOpt} {(args0Value.EndsWith("'") ? args0Value.Insert(args0Value.Length - 1, "%") : $"(({args0Value})::text || '%')")}";
|
||||||
|
if (exp.Method.Name == "EndsWith") return $"({left}) {likeOpt} {(args0Value.StartsWith("'") ? args0Value.Insert(1, "%") : $"('%' || ({args0Value})::text)")}";
|
||||||
|
if (args0Value.StartsWith("'") && args0Value.EndsWith("'")) return $"({left}) {likeOpt} {args0Value.Insert(1, "%").Insert(args0Value.Length, "%")}";
|
||||||
|
return $"({left}) {likeOpt} ('%' || ({args0Value})::text || '%')";
|
||||||
|
case "ToLower": return $"lower({left})";
|
||||||
|
case "ToUpper": return $"upper({left})";
|
||||||
|
case "Substring":
|
||||||
|
var substrArgs1 = getExp(exp.Arguments[0]);
|
||||||
|
if (long.TryParse(substrArgs1, out var testtrylng1)) substrArgs1 = (testtrylng1 + 1).ToString();
|
||||||
|
else substrArgs1 += "+1";
|
||||||
|
if (exp.Arguments.Count == 1) return $"substr({left}, {substrArgs1})";
|
||||||
|
return $"substr({left}, {substrArgs1}, {getExp(exp.Arguments[1])})";
|
||||||
|
case "IndexOf": return $"(strpos({left}, {getExp(exp.Arguments[0])})-1)";
|
||||||
|
case "PadLeft":
|
||||||
|
if (exp.Arguments.Count == 1) return $"lpad({left}, {getExp(exp.Arguments[0])})";
|
||||||
|
return $"lpad({left}, {getExp(exp.Arguments[0])}, {getExp(exp.Arguments[1])})";
|
||||||
|
case "PadRight":
|
||||||
|
if (exp.Arguments.Count == 1) return $"rpad({left}, {getExp(exp.Arguments[0])})";
|
||||||
|
return $"rpad({left}, {getExp(exp.Arguments[0])}, {getExp(exp.Arguments[1])})";
|
||||||
|
case "Trim":
|
||||||
|
case "TrimStart":
|
||||||
|
case "TrimEnd":
|
||||||
|
if (exp.Arguments.Count == 0)
|
||||||
|
{
|
||||||
|
if (exp.Method.Name == "Trim") return $"trim({left})";
|
||||||
|
if (exp.Method.Name == "TrimStart") return $"ltrim({left})";
|
||||||
|
if (exp.Method.Name == "TrimEnd") return $"rtrim({left})";
|
||||||
|
}
|
||||||
|
var trimArg1 = "";
|
||||||
|
var trimArg2 = "";
|
||||||
|
foreach (var argsTrim02 in exp.Arguments)
|
||||||
|
{
|
||||||
|
var argsTrim01s = new[] { argsTrim02 };
|
||||||
|
if (argsTrim02.NodeType == ExpressionType.NewArrayInit)
|
||||||
|
{
|
||||||
|
var arritem = argsTrim02 as NewArrayExpression;
|
||||||
|
argsTrim01s = arritem.Expressions.ToArray();
|
||||||
|
}
|
||||||
|
foreach (var argsTrim01 in argsTrim01s)
|
||||||
|
{
|
||||||
|
var trimChr = getExp(argsTrim01).Trim('\'');
|
||||||
|
if (trimChr.Length == 1) trimArg1 += trimChr;
|
||||||
|
else trimArg2 += $" || ({trimChr})";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (exp.Method.Name == "Trim") left = $"trim({left}, {_common.FormatSql("{0}", trimArg1)}{trimArg2})";
|
||||||
|
if (exp.Method.Name == "TrimStart") left = $"ltrim({left}, {_common.FormatSql("{0}", trimArg1)}{trimArg2})";
|
||||||
|
if (exp.Method.Name == "TrimEnd") left = $"rtrim({left}, {_common.FormatSql("{0}", trimArg1)}{trimArg2})";
|
||||||
|
return left;
|
||||||
|
case "Replace": return $"replace({left}, {getExp(exp.Arguments[0])}, {getExp(exp.Arguments[1])})";
|
||||||
|
case "CompareTo": return $"case when {left} = {getExp(exp.Arguments[0])} then 0 when {left} > {getExp(exp.Arguments[0])} then 1 else -1 end";
|
||||||
|
case "Equals": return $"({left} = ({getExp(exp.Arguments[0])})::text)";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
public override string ExpressionLambdaToSqlCallMath(MethodCallExpression exp, ExpTSC tsc)
|
||||||
|
{
|
||||||
|
Func<Expression, string> getExp = exparg => ExpressionLambdaToSql(exparg, tsc);
|
||||||
|
switch (exp.Method.Name)
|
||||||
|
{
|
||||||
|
case "Abs": return $"abs({getExp(exp.Arguments[0])})";
|
||||||
|
case "Sign": return $"sign({getExp(exp.Arguments[0])})";
|
||||||
|
case "Floor": return $"floor({getExp(exp.Arguments[0])})";
|
||||||
|
case "Ceiling": return $"ceiling({getExp(exp.Arguments[0])})";
|
||||||
|
case "Round":
|
||||||
|
if (exp.Arguments.Count > 1 && exp.Arguments[1].Type.FullName == "System.Int32") return $"round({getExp(exp.Arguments[0])}, {getExp(exp.Arguments[1])})";
|
||||||
|
return $"round({getExp(exp.Arguments[0])})";
|
||||||
|
case "Exp": return $"exp({getExp(exp.Arguments[0])})";
|
||||||
|
case "Log": return $"log({getExp(exp.Arguments[0])})";
|
||||||
|
case "Log10": return $"log10({getExp(exp.Arguments[0])})";
|
||||||
|
case "Pow": return $"pow({getExp(exp.Arguments[0])}, {getExp(exp.Arguments[1])})";
|
||||||
|
case "Sqrt": return $"sqrt({getExp(exp.Arguments[0])})";
|
||||||
|
case "Cos": return $"cos({getExp(exp.Arguments[0])})";
|
||||||
|
case "Sin": return $"sin({getExp(exp.Arguments[0])})";
|
||||||
|
case "Tan": return $"tan({getExp(exp.Arguments[0])})";
|
||||||
|
case "Acos": return $"acos({getExp(exp.Arguments[0])})";
|
||||||
|
case "Asin": return $"asin({getExp(exp.Arguments[0])})";
|
||||||
|
case "Atan": return $"atan({getExp(exp.Arguments[0])})";
|
||||||
|
case "Atan2": return $"atan2({getExp(exp.Arguments[0])}, {getExp(exp.Arguments[1])})";
|
||||||
|
case "Truncate": return $"trunc({getExp(exp.Arguments[0])}, 0)";
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
public override string ExpressionLambdaToSqlCallDateTime(MethodCallExpression exp, ExpTSC tsc)
|
||||||
|
{
|
||||||
|
Func<Expression, string> getExp = exparg => ExpressionLambdaToSql(exparg, tsc);
|
||||||
|
if (exp.Object == null)
|
||||||
|
{
|
||||||
|
switch (exp.Method.Name)
|
||||||
|
{
|
||||||
|
case "Compare": return $"extract(epoch from ({getExp(exp.Arguments[0])})::timestamp-({getExp(exp.Arguments[1])})::timestamp)";
|
||||||
|
case "DaysInMonth": return $"extract(day from ({getExp(exp.Arguments[0])} || '-' || {getExp(exp.Arguments[1])} || '-01')::timestamp+'1 month'::interval-'1 day'::interval)";
|
||||||
|
case "Equals": return $"(({getExp(exp.Arguments[0])})::timestamp = ({getExp(exp.Arguments[1])})::timestamp)";
|
||||||
|
|
||||||
|
case "IsLeapYear":
|
||||||
|
var isLeapYearArgs1 = getExp(exp.Arguments[0]);
|
||||||
|
return $"(({isLeapYearArgs1})::int8%4=0 AND ({isLeapYearArgs1})::int8%100<>0 OR ({isLeapYearArgs1})::int8%400=0)";
|
||||||
|
|
||||||
|
case "Parse": return ExpressionConstDateTime(exp.Arguments[0]) ?? $"({getExp(exp.Arguments[0])})::timestamp";
|
||||||
|
case "ParseExact":
|
||||||
|
case "TryParse":
|
||||||
|
case "TryParseExact": return ExpressionConstDateTime(exp.Arguments[0]) ?? $"({getExp(exp.Arguments[0])})::timestamp";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
var left = getExp(exp.Object);
|
||||||
|
var args1 = exp.Arguments.Count == 0 ? null : getExp(exp.Arguments[0]);
|
||||||
|
switch (exp.Method.Name)
|
||||||
|
{
|
||||||
|
case "Add": return $"(({left})::timestamp+((({args1})/1000)||' milliseconds')::interval)";
|
||||||
|
case "AddDays": return $"(({left})::timestamp+(({args1})||' day')::interval)";
|
||||||
|
case "AddHours": return $"(({left})::timestamp+(({args1})||' hour')::interval)";
|
||||||
|
case "AddMilliseconds": return $"(({left})::timestamp+(({args1})||' milliseconds')::interval)";
|
||||||
|
case "AddMinutes": return $"(({left})::timestamp+(({args1})||' minute')::interval)";
|
||||||
|
case "AddMonths": return $"(({left})::timestamp+(({args1})||' month')::interval)";
|
||||||
|
case "AddSeconds": return $"(({left})::timestamp+(({args1})||' second')::interval)";
|
||||||
|
case "AddTicks": return $"(({left})::timestamp+(({args1})/10||' microseconds')::interval)";
|
||||||
|
case "AddYears": return $"(({left})::timestamp+(({args1})||' year')::interval)";
|
||||||
|
case "Subtract":
|
||||||
|
switch ((exp.Arguments[0].Type.IsNullableType() ? exp.Arguments[0].Type.GetGenericArguments().FirstOrDefault() : exp.Arguments[0].Type).FullName)
|
||||||
|
{
|
||||||
|
case "System.DateTime": return $"(extract(epoch from ({left})::timestamp-({args1})::timestamp)*1000000)";
|
||||||
|
case "System.TimeSpan": return $"(({left})::timestamp-((({args1})/1000)||' milliseconds')::interval)";
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case "Equals": return $"({left} = ({args1})::timestamp)";
|
||||||
|
case "CompareTo": return $"extract(epoch from ({left})::timestamp-({args1})::timestamp)";
|
||||||
|
case "ToString":
|
||||||
|
if (left.EndsWith("::timestamp") == false) left = $"({left})::timestamp";
|
||||||
|
if (exp.Arguments.Count == 0) return $"to_char({left},'YYYY-MM-DD HH24:MI:SS.US')";
|
||||||
|
switch (args1)
|
||||||
|
{
|
||||||
|
case "'yyyy-MM-dd HH:mm:ss'": return $"to_char({left},'YYYY-MM-DD HH24:MI:SS')";
|
||||||
|
case "'yyyy-MM-dd HH:mm'": return $"to_char({left},'YYYY-MM-DD HH24:MI')";
|
||||||
|
case "'yyyy-MM-dd HH'": return $"to_char({left},'YYYY-MM-DD HH24')";
|
||||||
|
case "'yyyy-MM-dd'": return $"to_char({left},'YYYY-MM-DD')";
|
||||||
|
case "'yyyy-MM'": return $"to_char({left},'YYYY-MM')";
|
||||||
|
case "'yyyyMMddHHmmss'": return $"to_char({left},'YYYYMMDDHH24MISS')";
|
||||||
|
case "'yyyyMMddHHmm'": return $"to_char({left},'YYYYMMDDHH24MI')";
|
||||||
|
case "'yyyyMMddHH'": return $"to_char({left},'YYYYMMDDHH24')";
|
||||||
|
case "'yyyyMMdd'": return $"to_char({left},'YYYYMMDD')";
|
||||||
|
case "'yyyyMM'": return $"to_char({left},'YYYYMM')";
|
||||||
|
case "'yyyy'": return $"to_char({left},'YYYY')";
|
||||||
|
case "'HH:mm:ss'": return $"to_char({left},'HH24:MI:SS')";
|
||||||
|
}
|
||||||
|
args1 = Regex.Replace(args1, "(yyyy|yy|MM|dd|HH|hh|mm|ss|tt)", m =>
|
||||||
|
{
|
||||||
|
switch (m.Groups[1].Value)
|
||||||
|
{
|
||||||
|
case "yyyy": return $"YYYY";
|
||||||
|
case "yy": return $"YY";
|
||||||
|
case "MM": return $"%_a1";
|
||||||
|
case "dd": return $"%_a2";
|
||||||
|
case "HH": return $"%_a3";
|
||||||
|
case "hh": return $"%_a4";
|
||||||
|
case "mm": return $"%_a5";
|
||||||
|
case "ss": return $"SS";
|
||||||
|
case "tt": return $"%_a6";
|
||||||
|
}
|
||||||
|
return m.Groups[0].Value;
|
||||||
|
});
|
||||||
|
var argsFinds = new[] { "YYYY", "YY", "%_a1", "%_a2", "%_a3", "%_a4", "%_a5", "SS", "%_a6" };
|
||||||
|
var argsSpts = Regex.Split(args1, "(M|d|H|h|m|s|t)");
|
||||||
|
for (var a = 0; a < argsSpts.Length; a++)
|
||||||
|
{
|
||||||
|
switch (argsSpts[a])
|
||||||
|
{
|
||||||
|
case "M": argsSpts[a] = $"ltrim(to_char({left},'MM'),'0')"; break;
|
||||||
|
case "d": argsSpts[a] = $"case when substr(to_char({left},'DD'),1,1) = '0' then substr(to_char({left},'DD'),2,1) else to_char({left},'DD') end"; break;
|
||||||
|
case "H": argsSpts[a] = $"case when substr(to_char({left},'HH24'),1,1) = '0' then substr(to_char({left},'HH24'),2,1) else to_char({left},'HH24') end"; break;
|
||||||
|
case "h": argsSpts[a] = $"case when substr(to_char({left},'HH12'),1,1) = '0' then substr(to_char({left},'HH12'),2,1) else to_char({left},'HH12') end"; break;
|
||||||
|
case "m": argsSpts[a] = $"case when substr(to_char({left},'MI'),1,1) = '0' then substr(to_char({left},'MI'),2,1) else to_char({left},'MI') end"; break;
|
||||||
|
case "s": argsSpts[a] = $"case when substr(to_char({left},'SS'),1,1) = '0' then substr(to_char({left},'SS'),2,1) else to_char({left},'SS') end"; break;
|
||||||
|
case "t": argsSpts[a] = $"rtrim(to_char({left},'AM'),'M')"; break;
|
||||||
|
default:
|
||||||
|
var argsSptsA = argsSpts[a];
|
||||||
|
if (argsSptsA.StartsWith("'")) argsSptsA = argsSptsA.Substring(1);
|
||||||
|
if (argsSptsA.EndsWith("'")) argsSptsA = argsSptsA.Remove(argsSptsA.Length - 1);
|
||||||
|
argsSpts[a] = argsFinds.Any(m => argsSptsA.Contains(m)) ? $"to_char({left},'{argsSptsA}')" : $"'{argsSptsA}'";
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (argsSpts.Length > 0) args1 = $"({string.Join(" || ", argsSpts.Where(a => a != "''"))})";
|
||||||
|
return args1.Replace("%_a1", "MM").Replace("%_a2", "DD").Replace("%_a3", "HH24").Replace("%_a4", "HH12").Replace("%_a5", "MI").Replace("%_a6", "AM");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
public override string ExpressionLambdaToSqlCallTimeSpan(MethodCallExpression exp, ExpTSC tsc)
|
||||||
|
{
|
||||||
|
Func<Expression, string> getExp = exparg => ExpressionLambdaToSql(exparg, tsc);
|
||||||
|
if (exp.Object == null)
|
||||||
|
{
|
||||||
|
switch (exp.Method.Name)
|
||||||
|
{
|
||||||
|
case "Compare": return $"({getExp(exp.Arguments[0])}-({getExp(exp.Arguments[1])}))";
|
||||||
|
case "Equals": return $"({getExp(exp.Arguments[0])} = {getExp(exp.Arguments[1])})";
|
||||||
|
case "FromDays": return $"(({getExp(exp.Arguments[0])})*{(long)1000000 * 60 * 60 * 24})";
|
||||||
|
case "FromHours": return $"(({getExp(exp.Arguments[0])})*{(long)1000000 * 60 * 60})";
|
||||||
|
case "FromMilliseconds": return $"(({getExp(exp.Arguments[0])})*1000)";
|
||||||
|
case "FromMinutes": return $"(({getExp(exp.Arguments[0])})*{(long)1000000 * 60})";
|
||||||
|
case "FromSeconds": return $"(({getExp(exp.Arguments[0])})*1000000)";
|
||||||
|
case "FromTicks": return $"(({getExp(exp.Arguments[0])})/10)";
|
||||||
|
case "Parse": return $"({getExp(exp.Arguments[0])})::int8";
|
||||||
|
case "ParseExact":
|
||||||
|
case "TryParse":
|
||||||
|
case "TryParseExact": return $"({getExp(exp.Arguments[0])})::int8";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
var left = getExp(exp.Object);
|
||||||
|
var args1 = exp.Arguments.Count == 0 ? null : getExp(exp.Arguments[0]);
|
||||||
|
switch (exp.Method.Name)
|
||||||
|
{
|
||||||
|
case "Add": return $"({left}+{args1})";
|
||||||
|
case "Subtract": return $"({left}-({args1}))";
|
||||||
|
case "Equals": return $"({left} = {args1})";
|
||||||
|
case "CompareTo": return $"({left}-({args1}))";
|
||||||
|
case "ToString": return $"({left})::varchar";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
public override string ExpressionLambdaToSqlCallConvert(MethodCallExpression exp, ExpTSC tsc)
|
||||||
|
{
|
||||||
|
Func<Expression, string> getExp = exparg => ExpressionLambdaToSql(exparg, tsc);
|
||||||
|
if (exp.Object == null)
|
||||||
|
{
|
||||||
|
switch (exp.Method.Name)
|
||||||
|
{
|
||||||
|
case "ToBoolean": return $"(({getExp(exp.Arguments[0])})::varchar not in ('0','false','f','no'))";
|
||||||
|
case "ToByte": return $"({getExp(exp.Arguments[0])})::int2";
|
||||||
|
case "ToChar": return $"substr(({getExp(exp.Arguments[0])})::char, 1, 1)";
|
||||||
|
case "ToDateTime": return ExpressionConstDateTime(exp.Arguments[0]) ?? $"({getExp(exp.Arguments[0])})::timestamp";
|
||||||
|
case "ToDecimal": return $"({getExp(exp.Arguments[0])})::numeric";
|
||||||
|
case "ToDouble": return $"({getExp(exp.Arguments[0])})::float8";
|
||||||
|
case "ToInt16": return $"({getExp(exp.Arguments[0])})::int2";
|
||||||
|
case "ToInt32": return $"({getExp(exp.Arguments[0])})::int4";
|
||||||
|
case "ToInt64": return $"({getExp(exp.Arguments[0])})::int8";
|
||||||
|
case "ToSByte": return $"({getExp(exp.Arguments[0])})::int2";
|
||||||
|
case "ToSingle": return $"({getExp(exp.Arguments[0])})::float4";
|
||||||
|
case "ToString": return $"({getExp(exp.Arguments[0])})::text";
|
||||||
|
case "ToUInt16": return $"({getExp(exp.Arguments[0])})::int2";
|
||||||
|
case "ToUInt32": return $"({getExp(exp.Arguments[0])})::int4";
|
||||||
|
case "ToUInt64": return $"({getExp(exp.Arguments[0])})::int8";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
20
Providers/FreeSql.Provider.Xugu/XuguExtensions.cs
Normal file
20
Providers/FreeSql.Provider.Xugu/XuguExtensions.cs
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
using FreeSql;
|
||||||
|
using FreeSql.Xugu.Curd;
|
||||||
|
using System.Data;
|
||||||
|
using System.Linq.Expressions;
|
||||||
|
using System.Text;
|
||||||
|
using XuguClient;
|
||||||
|
|
||||||
|
public static partial class FreeSqlXuguGlobalExtensions
|
||||||
|
{
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 特殊处理类似 string.Format 的使用方法,防止注入,以及 IS NULL 转换
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="that"></param>
|
||||||
|
/// <param name="args"></param>
|
||||||
|
/// <returns></returns>
|
||||||
|
public static string FormatXuguSQL(this string that, params object[] args) => _xgsqlAdo.Addslashes(that, args);
|
||||||
|
static FreeSql.Xugu.XuguAdo _xgsqlAdo = new FreeSql.Xugu.XuguAdo();
|
||||||
|
|
||||||
|
}
|
131
Providers/FreeSql.Provider.Xugu/XuguProvider.cs
Normal file
131
Providers/FreeSql.Provider.Xugu/XuguProvider.cs
Normal file
@ -0,0 +1,131 @@
|
|||||||
|
using FreeSql.Internal;
|
||||||
|
using FreeSql.Internal.CommonProvider;
|
||||||
|
using FreeSql.Xugu.Curd;
|
||||||
|
using Newtonsoft.Json;
|
||||||
|
using Newtonsoft.Json.Linq;
|
||||||
|
using System;
|
||||||
|
using System.Collections;
|
||||||
|
using System.Data.Common;
|
||||||
|
using System.Linq.Expressions;
|
||||||
|
using System.Numerics;
|
||||||
|
using System.Reflection;
|
||||||
|
using System.Threading;
|
||||||
|
|
||||||
|
namespace FreeSql.Xugu
|
||||||
|
{
|
||||||
|
|
||||||
|
public class XuguProvider<TMark> : BaseDbProvider, IFreeSql<TMark>
|
||||||
|
{
|
||||||
|
static XuguProvider()
|
||||||
|
{
|
||||||
|
Utils.dicExecuteArrayRowReadClassOrTuple[typeof(BigInteger)] = true;
|
||||||
|
Utils.dicExecuteArrayRowReadClassOrTuple[typeof(BitArray)] = true;
|
||||||
|
//Utils.dicExecuteArrayRowReadClassOrTuple[typeof(NpgsqlPoint)] = true;
|
||||||
|
//Utils.dicExecuteArrayRowReadClassOrTuple[typeof(NpgsqlLine)] = true;
|
||||||
|
//Utils.dicExecuteArrayRowReadClassOrTuple[typeof(NpgsqlLSeg)] = true;
|
||||||
|
//Utils.dicExecuteArrayRowReadClassOrTuple[typeof(NpgsqlBox)] = true;
|
||||||
|
//Utils.dicExecuteArrayRowReadClassOrTuple[typeof(NpgsqlPath)] = true;
|
||||||
|
//Utils.dicExecuteArrayRowReadClassOrTuple[typeof(NpgsqlPolygon)] = true;
|
||||||
|
//Utils.dicExecuteArrayRowReadClassOrTuple[typeof(NpgsqlCircle)] = true;
|
||||||
|
//Utils.dicExecuteArrayRowReadClassOrTuple[typeof((IPAddress Address, int Subnet))] = true;
|
||||||
|
//Utils.dicExecuteArrayRowReadClassOrTuple[typeof(IPAddress)] = true;
|
||||||
|
//Utils.dicExecuteArrayRowReadClassOrTuple[typeof(PhysicalAddress)] = true;
|
||||||
|
//Utils.dicExecuteArrayRowReadClassOrTuple[typeof(NpgsqlRange<int>)] = true;
|
||||||
|
//Utils.dicExecuteArrayRowReadClassOrTuple[typeof(NpgsqlRange<long>)] = true;
|
||||||
|
//Utils.dicExecuteArrayRowReadClassOrTuple[typeof(NpgsqlRange<decimal>)] = true;
|
||||||
|
//Utils.dicExecuteArrayRowReadClassOrTuple[typeof(NpgsqlRange<DateTime>)] = true;
|
||||||
|
|
||||||
|
//Utils.dicExecuteArrayRowReadClassOrTuple[typeof(PostgisPoint)] = true;
|
||||||
|
//Utils.dicExecuteArrayRowReadClassOrTuple[typeof(PostgisLineString)] = true;
|
||||||
|
//Utils.dicExecuteArrayRowReadClassOrTuple[typeof(PostgisPolygon)] = true;
|
||||||
|
//Utils.dicExecuteArrayRowReadClassOrTuple[typeof(PostgisMultiPoint)] = true;
|
||||||
|
//Utils.dicExecuteArrayRowReadClassOrTuple[typeof(PostgisMultiLineString)] = true;
|
||||||
|
//Utils.dicExecuteArrayRowReadClassOrTuple[typeof(PostgisMultiPolygon)] = true;
|
||||||
|
//Utils.dicExecuteArrayRowReadClassOrTuple[typeof(PostgisGeometry)] = true;
|
||||||
|
//Utils.dicExecuteArrayRowReadClassOrTuple[typeof(PostgisGeometryCollection)] = true;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
//Utils.dicExecuteArrayRowReadClassOrTuple[typeof(Dictionary<string, string>)] = true;
|
||||||
|
//Utils.dicExecuteArrayRowReadClassOrTuple[typeof(JToken)] = true;
|
||||||
|
//Utils.dicExecuteArrayRowReadClassOrTuple[typeof(JObject)] = true;
|
||||||
|
//Utils.dicExecuteArrayRowReadClassOrTuple[typeof(JArray)] = true;
|
||||||
|
|
||||||
|
var MethodJTokenFromObject = typeof(JToken).GetMethod("FromObject", new[] { typeof(object) });
|
||||||
|
var MethodJObjectFromObject = typeof(JObject).GetMethod("FromObject", new[] { typeof(object) });
|
||||||
|
var MethodJArrayFromObject = typeof(JArray).GetMethod("FromObject", new[] { typeof(object) });
|
||||||
|
var MethodJTokenParse = typeof(JToken).GetMethod("Parse", new[] { typeof(string) });
|
||||||
|
var MethodJObjectParse = typeof(JObject).GetMethod("Parse", new[] { typeof(string) });
|
||||||
|
var MethodJArrayParse = typeof(JArray).GetMethod("Parse", new[] { typeof(string) });
|
||||||
|
var MethodJsonConvertDeserializeObject = typeof(JsonConvert).GetMethod("DeserializeObject", new[] { typeof(string), typeof(Type) });
|
||||||
|
var MethodToString = typeof(Utils).GetMethod("ToStringConcat", BindingFlags.Public | BindingFlags.Static, null, new[] { typeof(object) }, null);
|
||||||
|
Utils.GetDataReaderValueBlockExpressionSwitchTypeFullName.Add((LabelTarget returnTarget, Expression valueExp, Type type) =>
|
||||||
|
{
|
||||||
|
switch (type.FullName)
|
||||||
|
{
|
||||||
|
case "Newtonsoft.Json.Linq.JToken":
|
||||||
|
return Expression.IfThenElse(
|
||||||
|
Expression.TypeIs(valueExp, typeof(string)),
|
||||||
|
Expression.Return(returnTarget, Expression.TypeAs(Expression.Call(MethodJTokenParse, Expression.Convert(valueExp, typeof(string))), typeof(JToken))),
|
||||||
|
Expression.Return(returnTarget, Expression.TypeAs(Expression.Call(MethodJTokenFromObject, valueExp), typeof(JToken))));
|
||||||
|
case "Newtonsoft.Json.Linq.JObject":
|
||||||
|
return Expression.IfThenElse(
|
||||||
|
Expression.TypeIs(valueExp, typeof(string)),
|
||||||
|
Expression.Return(returnTarget, Expression.TypeAs(Expression.Call(MethodJObjectParse, Expression.Convert(valueExp, typeof(string))), typeof(JObject))),
|
||||||
|
Expression.Return(returnTarget, Expression.TypeAs(Expression.Call(MethodJObjectFromObject, valueExp), typeof(JObject))));
|
||||||
|
case "Newtonsoft.Json.Linq.JArray":
|
||||||
|
return Expression.IfThenElse(
|
||||||
|
Expression.TypeIs(valueExp, typeof(string)),
|
||||||
|
Expression.Return(returnTarget, Expression.TypeAs(Expression.Call(MethodJArrayParse, Expression.Convert(valueExp, typeof(string))), typeof(JArray))),
|
||||||
|
Expression.Return(returnTarget, Expression.TypeAs(Expression.Call(MethodJArrayFromObject, valueExp), typeof(JArray))));
|
||||||
|
//case "Npgsql.LegacyPostgis.PostgisGeometry":
|
||||||
|
// return Expression.Return(returnTarget, valueExp);
|
||||||
|
//case "NetTopologySuite.Geometries.Geometry":
|
||||||
|
// return Expression.Return(returnTarget, valueExp);
|
||||||
|
}
|
||||||
|
if (typeof(IList).IsAssignableFrom(type))
|
||||||
|
return Expression.IfThenElse(
|
||||||
|
Expression.TypeIs(valueExp, typeof(string)),
|
||||||
|
Expression.Return(returnTarget, Expression.TypeAs(Expression.Call(MethodJsonConvertDeserializeObject, Expression.Convert(valueExp, typeof(string)), Expression.Constant(type, typeof(Type))), type)),
|
||||||
|
Expression.Return(returnTarget, Expression.TypeAs(Expression.Call(MethodJsonConvertDeserializeObject, Expression.Convert(Expression.Call(MethodToString, valueExp), typeof(string)), Expression.Constant(type, typeof(Type))), type)));
|
||||||
|
return null;
|
||||||
|
});
|
||||||
|
|
||||||
|
Select0Provider._dicMethodDataReaderGetValue[typeof(Guid)] = typeof(DbDataReader).GetMethod("GetGuid", new Type[] { typeof(int) });
|
||||||
|
}
|
||||||
|
|
||||||
|
public override ISelect<T1> CreateSelectProvider<T1>(object dywhere) => new XuguSelect<T1>(this, this.InternalCommonUtils, this.InternalCommonExpression, dywhere);
|
||||||
|
public override IInsert<T1> CreateInsertProvider<T1>() => new XuguInsert<T1>(this, this.InternalCommonUtils, this.InternalCommonExpression);
|
||||||
|
public override IUpdate<T1> CreateUpdateProvider<T1>(object dywhere) => new XuguUpdate<T1>(this, this.InternalCommonUtils, this.InternalCommonExpression, dywhere);
|
||||||
|
public override IDelete<T1> CreateDeleteProvider<T1>(object dywhere) => new XuguDelete<T1>(this, this.InternalCommonUtils, this.InternalCommonExpression, dywhere);
|
||||||
|
public override IInsertOrUpdate<T1> CreateInsertOrUpdateProvider<T1>() => new XuguInsertOrUpdate<T1>(this, this.InternalCommonUtils, this.InternalCommonExpression);
|
||||||
|
|
||||||
|
public XuguProvider(string masterConnectionString, string[] slaveConnectionString, Func<DbConnection> connectionFactory = null)
|
||||||
|
{
|
||||||
|
this.InternalCommonUtils = new XuguUtils(this);
|
||||||
|
this.InternalCommonExpression = new XuguExpression(this.InternalCommonUtils);
|
||||||
|
|
||||||
|
this.Ado = new XuguAdo(this.InternalCommonUtils, masterConnectionString, slaveConnectionString, connectionFactory);
|
||||||
|
this.Aop = new AopProvider();
|
||||||
|
|
||||||
|
this.DbFirst = new XuguDbFirst(this, this.InternalCommonUtils, this.InternalCommonExpression);
|
||||||
|
this.CodeFirst = new XuguCodeFirst(this, this.InternalCommonUtils, this.InternalCommonExpression);
|
||||||
|
|
||||||
|
//this.Aop.AuditDataReader += (_, e) =>
|
||||||
|
//{
|
||||||
|
// var dbtype = e.DataReader.GetDataTypeName(e.Index);
|
||||||
|
// var m = Regex.Match(dbtype, @"numeric\((\d+)\)", RegexOptions.IgnoreCase);
|
||||||
|
// if (m.Success && int.Parse(m.Groups[1].Value) > 19)
|
||||||
|
// e.Value = e.DataReader.GetFieldValue<BigInteger>(e.Index);
|
||||||
|
//};
|
||||||
|
}
|
||||||
|
|
||||||
|
~XuguProvider() => this.Dispose();
|
||||||
|
int _disposeCounter;
|
||||||
|
public override void Dispose()
|
||||||
|
{
|
||||||
|
if (Interlocked.Increment(ref _disposeCounter) != 1) return;
|
||||||
|
(this.Ado as AdoProvider)?.Dispose();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
185
Providers/FreeSql.Provider.Xugu/XuguUtils.cs
Normal file
185
Providers/FreeSql.Provider.Xugu/XuguUtils.cs
Normal file
@ -0,0 +1,185 @@
|
|||||||
|
using FreeSql.Internal;
|
||||||
|
using FreeSql.Internal.Model;
|
||||||
|
using System;
|
||||||
|
using System.Collections;
|
||||||
|
using System.Collections.Concurrent;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Data.Common;
|
||||||
|
using System.Globalization;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Net;
|
||||||
|
using System.Numerics;
|
||||||
|
using System.Text;
|
||||||
|
using XuguClient;
|
||||||
|
|
||||||
|
namespace FreeSql.Xugu
|
||||||
|
{
|
||||||
|
|
||||||
|
class XuguUtils : CommonUtils
|
||||||
|
{
|
||||||
|
public XuguUtils(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;
|
||||||
|
}
|
||||||
|
public override string QuoteSqlNameAdapter(params string[] name)
|
||||||
|
{
|
||||||
|
if (name.Length == 1)
|
||||||
|
{
|
||||||
|
var nametrim = name[0].Trim();
|
||||||
|
if (nametrim.StartsWith("(") && nametrim.EndsWith(")"))
|
||||||
|
return nametrim; //原生SQL
|
||||||
|
if (nametrim.StartsWith("\"") && nametrim.EndsWith("\""))
|
||||||
|
return nametrim;
|
||||||
|
return $"\"{nametrim.Replace(".", "\".\"")}\"";
|
||||||
|
}
|
||||||
|
return $"\"{string.Join("\".\"", name)}\"";
|
||||||
|
}
|
||||||
|
static Dictionary<string, Func<object, object>> dicGetParamterValue = new Dictionary<string, Func<object, object>> {
|
||||||
|
//{ typeof(JToken).FullName, a => string.Concat(a) }, { typeof(JToken[]).FullName, a => getParamterArrayValue(typeof(string), a, null) },
|
||||||
|
//{ typeof(JObject).FullName, a => string.Concat(a) }, { typeof(JObject[]).FullName, a => getParamterArrayValue(typeof(string), a, null) },
|
||||||
|
//{ typeof(JArray).FullName, a => string.Concat(a) }, { typeof(JArray[]).FullName, a => getParamterArrayValue(typeof(string), a, null) },
|
||||||
|
{ typeof(uint).FullName, a => long.Parse(string.Concat(a)) }, { typeof(uint[]).FullName, a => getParamterArrayValue(typeof(long), a, 0) }, { typeof(uint?[]).FullName, a => getParamterArrayValue(typeof(long?), a, null) },
|
||||||
|
{ typeof(ulong).FullName, a => decimal.Parse(string.Concat(a)) }, { typeof(ulong[]).FullName, a => getParamterArrayValue(typeof(decimal), a, 0) }, { typeof(ulong?[]).FullName, a => getParamterArrayValue(typeof(decimal?), a, null) },
|
||||||
|
{ typeof(ushort).FullName, a => int.Parse(string.Concat(a)) }, { typeof(ushort[]).FullName, a => getParamterArrayValue(typeof(int), a, 0) }, { typeof(ushort?[]).FullName, a => getParamterArrayValue(typeof(int?), a, null) },
|
||||||
|
{ typeof(byte).FullName, a => short.Parse(string.Concat(a)) }, { typeof(byte[]).FullName, a => getParamterArrayValue(typeof(short), a, 0) }, { typeof(byte?[]).FullName, a => getParamterArrayValue(typeof(short?), a, null) },
|
||||||
|
{ typeof(sbyte).FullName, a => short.Parse(string.Concat(a)) }, { typeof(sbyte[]).FullName, a => getParamterArrayValue(typeof(short), a, 0) }, { typeof(sbyte?[]).FullName, a => getParamterArrayValue(typeof(short?), a, null) },
|
||||||
|
{ typeof(char).FullName, a => string.Concat(a).Replace('\0', ' ').ToCharArray().FirstOrDefault() },
|
||||||
|
{ typeof(BigInteger).FullName, a => BigInteger.Parse(string.Concat(a), System.Globalization.NumberStyles.Any) }, { typeof(BigInteger[]).FullName, a => getParamterArrayValue(typeof(BigInteger), a, 0) }, { typeof(BigInteger?[]).FullName, a => getParamterArrayValue(typeof(BigInteger?), a, null) },
|
||||||
|
|
||||||
|
|
||||||
|
{ typeof((IPAddress Address, int Subnet)).FullName, a => {
|
||||||
|
var inet = ((IPAddress Address, int Subnet))a;
|
||||||
|
if (inet.Address == null) return (IPAddress.Any, inet.Subnet);
|
||||||
|
return inet;
|
||||||
|
} },
|
||||||
|
{ typeof((IPAddress Address, int Subnet)[]).FullName, a => getParamterArrayValue(typeof((IPAddress Address, int Subnet)), a, (IPAddress.Any, 0)) },
|
||||||
|
{ typeof((IPAddress Address, int Subnet)?[]).FullName, a => getParamterArrayValue(typeof((IPAddress Address, int Subnet)?), a, null) },
|
||||||
|
};
|
||||||
|
static object getParamterValue(Type type, object value, int level = 0)
|
||||||
|
{
|
||||||
|
if (type.FullName == "System.Byte[]") return value;
|
||||||
|
if (type.FullName == "System.Char[]") return value;
|
||||||
|
if (type.IsArray && level == 0)
|
||||||
|
{
|
||||||
|
var elementType = type.GetElementType();
|
||||||
|
Type enumType = null;
|
||||||
|
if (elementType.IsEnum) enumType = elementType;
|
||||||
|
else if (elementType.IsNullableType() && elementType.GenericTypeArguments.First().IsEnum) enumType = elementType.GenericTypeArguments.First();
|
||||||
|
if (enumType != null) return enumType.GetCustomAttributes(typeof(FlagsAttribute), false).Any() ?
|
||||||
|
getParamterArrayValue(typeof(long), value, elementType.IsEnum ? null : enumType.CreateInstanceGetDefaultValue()) :
|
||||||
|
getParamterArrayValue(typeof(int), value, elementType.IsEnum ? null : enumType.CreateInstanceGetDefaultValue());
|
||||||
|
return dicGetParamterValue.TryGetValue(type.FullName, out var trydicarr) ? trydicarr(value) : value;
|
||||||
|
}
|
||||||
|
if (type.IsNullableType()) type = type.GenericTypeArguments.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 XGParameters { ParameterName = QuoteParamterName(parameterName), Value = value };
|
||||||
|
|
||||||
|
var tp = _orm.CodeFirst.GetDbInfo(type)?.type;
|
||||||
|
if (col != null)
|
||||||
|
{
|
||||||
|
var dbtype = (XGDbType)_orm.DbFirst.GetDbType(new DatabaseModel.DbColumnInfo { DbTypeText = col.DbTypeText });
|
||||||
|
if (dbtype != null)
|
||||||
|
{
|
||||||
|
if (col.DbPrecision != 0) ret.Precision = col.DbPrecision;
|
||||||
|
if (col.DbScale != 0) ret.Scale = col.DbScale;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_params?.Add(ret);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
public override DbParameter[] GetDbParamtersByObject(string sql, object obj) =>
|
||||||
|
Utils.GetDbParamtersByObject<XGParameters>(sql, obj, "@", (name, type, value) =>
|
||||||
|
{
|
||||||
|
if (value != null) value = getParamterValue(type, value);
|
||||||
|
var ret = new XGParameters { ParameterName = $"@{name}", Value = value };
|
||||||
|
|
||||||
|
var tp = _orm.CodeFirst.GetDbInfo(type)?.type;
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
});
|
||||||
|
|
||||||
|
public override string FormatSql(string sql, params object[] args) => sql?.FormatXuguSQL(args);
|
||||||
|
|
||||||
|
public override string TrimQuoteSqlName(string name)
|
||||||
|
{
|
||||||
|
var nametrim = name.Trim();
|
||||||
|
if (nametrim.StartsWith("(") && nametrim.EndsWith(")"))
|
||||||
|
return nametrim; //原生SQL
|
||||||
|
return $"{nametrim.Trim('"').Replace("\".\"", ".").Replace(".\"", ".")}";
|
||||||
|
}
|
||||||
|
public override string[] SplitTableName(string name) => GetSplitTableNames(name, '"', '"', 2);
|
||||||
|
public override string QuoteParamterName(string name) => $"@{name}";
|
||||||
|
public override string IsNull(string sql, object value) => $"coalesce({sql}, {value})";
|
||||||
|
public override string StringConcat(string[] objs, Type[] types) => $"{string.Join(" || ", objs)}";
|
||||||
|
public override string Mod(string left, string right, Type leftType, Type rightType) => $"{left} % {right}";
|
||||||
|
public override string Div(string left, string right, Type leftType, Type rightType) => $"{left} / {right}";
|
||||||
|
public override string Now => "current_timestamp";
|
||||||
|
public override string NowUtc => "(current_timestamp at time zone 'UTC')";
|
||||||
|
|
||||||
|
public override string QuoteWriteParamterAdapter(Type type, string paramterName) => paramterName;
|
||||||
|
protected override string QuoteReadColumnAdapter(Type type, Type mapType, string columnName) => columnName;
|
||||||
|
|
||||||
|
static ConcurrentDictionary<Type, bool> _dicIsAssignableFromPostgisGeometry = new ConcurrentDictionary<Type, bool>();
|
||||||
|
public override string GetNoneParamaterSqlValue(List<DbParameter> specialParams, string specialParamFlag, ColumnInfo col, Type type, object value)
|
||||||
|
{
|
||||||
|
if (value == null) return "NULL";
|
||||||
|
if (type.IsNumberType()) return string.Format(CultureInfo.InvariantCulture, "{0}", value);
|
||||||
|
|
||||||
|
value = getParamterValue(type, value);
|
||||||
|
var type2 = value.GetType();
|
||||||
|
if (type2 == typeof(byte[])) return $"'\\x{CommonUtils.BytesSqlRaw(value as byte[])}'";
|
||||||
|
if (type2 == typeof(TimeSpan) || type2 == typeof(TimeSpan?))
|
||||||
|
{
|
||||||
|
var ts = (TimeSpan)value;
|
||||||
|
return $"'{Math.Min(24, (int)Math.Floor(ts.TotalHours))}:{ts.Minutes}:{ts.Seconds}'";
|
||||||
|
}
|
||||||
|
else if (value is Array)
|
||||||
|
{
|
||||||
|
var valueArr = value as Array;
|
||||||
|
var eleType = type2.GetElementType();
|
||||||
|
var len = valueArr.GetLength(0);
|
||||||
|
var sb = new StringBuilder().Append("ARRAY[");
|
||||||
|
for (var a = 0; a < len; a++)
|
||||||
|
{
|
||||||
|
var item = valueArr.GetValue(a);
|
||||||
|
if (a > 0) sb.Append(",");
|
||||||
|
sb.Append(GetNoneParamaterSqlValue(specialParams, specialParamFlag, col, eleType, item));
|
||||||
|
}
|
||||||
|
sb.Append("]");
|
||||||
|
var dbinfo = _orm.CodeFirst.GetDbInfo(type);
|
||||||
|
if (dbinfo != null) sb.Append("::").Append(dbinfo.dbtype);
|
||||||
|
return sb.ToString();
|
||||||
|
}
|
||||||
|
else if (type2 == typeof(BitArray))
|
||||||
|
{
|
||||||
|
return $"'{(value as BitArray).To1010()}'";
|
||||||
|
}
|
||||||
|
else if (dicGetParamterValue.ContainsKey(type2.FullName))
|
||||||
|
{
|
||||||
|
value = string.Concat(value);
|
||||||
|
}
|
||||||
|
return FormatSql("{0}", value, 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
BIN
Providers/FreeSql.Provider.Xugu/key.snk
Normal file
BIN
Providers/FreeSql.Provider.Xugu/key.snk
Normal file
Binary file not shown.
Loading…
x
Reference in New Issue
Block a user