mirror of
https://github.com/dotnetcore/FreeSql.git
synced 2026-02-27 02:30:58 +08:00
创建TDengine相关实现
This commit is contained in:
@@ -0,0 +1,24 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>net8.0</TargetFramework>
|
||||
<ImplicitUsings>enable</ImplicitUsings>
|
||||
<Nullable>enable</Nullable>
|
||||
|
||||
<IsPackable>false</IsPackable>
|
||||
<IsTestProject>true</IsTestProject>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="coverlet.collector" Version="6.0.0" />
|
||||
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.8.0" />
|
||||
<PackageReference Include="NUnit" Version="3.14.0" />
|
||||
<PackageReference Include="NUnit.Analyzers" Version="3.9.0" />
|
||||
<PackageReference Include="NUnit3TestAdapter" Version="4.5.0" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<Using Include="NUnit.Framework" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
16
FreeSql.Tests/FreeSql.Tests.Provider.TDengine/UnitTest1.cs
Normal file
16
FreeSql.Tests/FreeSql.Tests.Provider.TDengine/UnitTest1.cs
Normal file
@@ -0,0 +1,16 @@
|
||||
namespace FreeSql.Tests.Provider.TDengine
|
||||
{
|
||||
public class Tests
|
||||
{
|
||||
[SetUp]
|
||||
public void Setup()
|
||||
{
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void Test1()
|
||||
{
|
||||
Assert.Pass();
|
||||
}
|
||||
}
|
||||
}
|
||||
18
FreeSql.sln
18
FreeSql.sln
@@ -133,6 +133,8 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "FreeSql.Tests.Provider.Duck
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "FreeSql.Provider.TDengine", "Providers\FreeSql.Provider.TDengine\FreeSql.Provider.TDengine.csproj", "{329BA8B3-4139-4CCE-AFEC-4BE9B7BED317}"
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "FreeSql.Tests.Provider.TDengine", "FreeSql.Tests\FreeSql.Tests.Provider.TDengine\FreeSql.Tests.Provider.TDengine.csproj", "{1F313BE0-5069-4B5E-BEE7-138954D293F9}"
|
||||
EndProject
|
||||
Global
|
||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||
Debug|Any CPU = Debug|Any CPU
|
||||
@@ -803,6 +805,18 @@ Global
|
||||
{329BA8B3-4139-4CCE-AFEC-4BE9B7BED317}.Release|x64.Build.0 = Release|Any CPU
|
||||
{329BA8B3-4139-4CCE-AFEC-4BE9B7BED317}.Release|x86.ActiveCfg = Release|Any CPU
|
||||
{329BA8B3-4139-4CCE-AFEC-4BE9B7BED317}.Release|x86.Build.0 = Release|Any CPU
|
||||
{1F313BE0-5069-4B5E-BEE7-138954D293F9}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{1F313BE0-5069-4B5E-BEE7-138954D293F9}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{1F313BE0-5069-4B5E-BEE7-138954D293F9}.Debug|x64.ActiveCfg = Debug|Any CPU
|
||||
{1F313BE0-5069-4B5E-BEE7-138954D293F9}.Debug|x64.Build.0 = Debug|Any CPU
|
||||
{1F313BE0-5069-4B5E-BEE7-138954D293F9}.Debug|x86.ActiveCfg = Debug|Any CPU
|
||||
{1F313BE0-5069-4B5E-BEE7-138954D293F9}.Debug|x86.Build.0 = Debug|Any CPU
|
||||
{1F313BE0-5069-4B5E-BEE7-138954D293F9}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{1F313BE0-5069-4B5E-BEE7-138954D293F9}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{1F313BE0-5069-4B5E-BEE7-138954D293F9}.Release|x64.ActiveCfg = Release|Any CPU
|
||||
{1F313BE0-5069-4B5E-BEE7-138954D293F9}.Release|x64.Build.0 = Release|Any CPU
|
||||
{1F313BE0-5069-4B5E-BEE7-138954D293F9}.Release|x86.ActiveCfg = Release|Any CPU
|
||||
{1F313BE0-5069-4B5E-BEE7-138954D293F9}.Release|x86.Build.0 = Release|Any CPU
|
||||
EndGlobalSection
|
||||
GlobalSection(SolutionProperties) = preSolution
|
||||
HideSolutionNode = FALSE
|
||||
@@ -848,8 +862,8 @@ Global
|
||||
{329BA8B3-4139-4CCE-AFEC-4BE9B7BED317} = {2A381C57-2697-427B-9F10-55DA11FD02E4}
|
||||
EndGlobalSection
|
||||
GlobalSection(ExtensibilityGlobals) = postSolution
|
||||
RESX_NeutralResourcesLanguage = en-US
|
||||
RESX_PrefixTranslations = True
|
||||
SolutionGuid = {089687FD-5D25-40AB-BA8A-A10D1E137F98}
|
||||
RESX_PrefixTranslations = True
|
||||
RESX_NeutralResourcesLanguage = en-US
|
||||
EndGlobalSection
|
||||
EndGlobal
|
||||
|
||||
@@ -65,6 +65,8 @@ namespace FreeSql
|
||||
|
||||
CustomOracle, CustomSqlServer, CustomMySql, CustomPostgreSQL,
|
||||
|
||||
DuckDB
|
||||
DuckDB,
|
||||
|
||||
TDengine
|
||||
}
|
||||
}
|
||||
|
||||
@@ -10,7 +10,7 @@ namespace FreeSql.DataAnnotations
|
||||
/// TDengine 超级表
|
||||
/// </summary>
|
||||
[AttributeUsage(AttributeTargets.Class)]
|
||||
public class TDengineSTableAttribute : Attribute
|
||||
public class STableAttribute : Attribute
|
||||
{
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,41 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Data.Common;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using FreeSql.Internal;
|
||||
using FreeSql.Internal.CommonProvider;
|
||||
using FreeSql.Internal.Model;
|
||||
using FreeSql.Internal.ObjectPool;
|
||||
|
||||
namespace FreeSql.Provider.TDengine.TDengineAdo
|
||||
{
|
||||
internal class TDengineAdo : AdoProvider
|
||||
{
|
||||
public TDengineAdo(CommonUtils util, string masterConnectionString, string[] slaveConnectionStrings, Func<DbConnection> connectionFactory) : base(DataType.TDengine, masterConnectionString, slaveConnectionStrings)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
public override object AddslashesProcessParam(object param, Type mapType, ColumnInfo mapColumn)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public override DbCommand CreateCommand()
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public override DbParameter[] GetDbParamtersByObject(string sql, object obj)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public override void ReturnConnection(IObjectPool<DbConnection> pool, Object<DbConnection> conn, Exception ex)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,250 @@
|
||||
using System;
|
||||
using System.Collections.Concurrent;
|
||||
using System.Collections.Generic;
|
||||
using System.Data;
|
||||
using System.Data.Common;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Text.RegularExpressions;
|
||||
using System.Threading.Tasks;
|
||||
using FreeSql.Internal.ObjectPool;
|
||||
using TDengine.Data.Client;
|
||||
|
||||
namespace FreeSql.Provider.TDengine.TDengineAdo
|
||||
{
|
||||
internal class TDengineConnectionPool : ObjectPool<DbConnection>
|
||||
{
|
||||
internal Action AvailableHandler;
|
||||
|
||||
internal Action UnavailableHandler;
|
||||
|
||||
|
||||
public TDengineConnectionPool(string name, string connectionString, Action availableHandler,
|
||||
Action unavailableHandler) : base(null)
|
||||
{
|
||||
this.AvailableHandler = availableHandler;
|
||||
this.UnavailableHandler = unavailableHandler;
|
||||
var policy = new TDengineConnectionPoolPolicy
|
||||
{
|
||||
InternalPool = this,
|
||||
Name = name
|
||||
};
|
||||
this.Policy = policy;
|
||||
policy.ConnectionString = connectionString;
|
||||
}
|
||||
}
|
||||
|
||||
internal class TDengineConnectionPoolPolicy : IPolicy<DbConnection>
|
||||
{
|
||||
internal TDengineConnectionPool InternalPool;
|
||||
public string Name { get; set; } = $"TDengine Connection {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 readonly 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(InternalPool, minPoolSize);
|
||||
}
|
||||
}
|
||||
|
||||
public DbConnection OnCreate()
|
||||
{
|
||||
var conn = new TDengineConnection(_connectionString);
|
||||
return conn;
|
||||
}
|
||||
|
||||
public void OnDestroy(DbConnection obj)
|
||||
{
|
||||
if (obj.State != ConnectionState.Closed) obj.Close();
|
||||
obj.Dispose();
|
||||
}
|
||||
|
||||
public void OnGetTimeout()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
public void OnGet(Object<DbConnection> obj)
|
||||
{
|
||||
if (InternalPool.IsAvailable)
|
||||
{
|
||||
if (obj.Value == null)
|
||||
{
|
||||
InternalPool.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 (InternalPool.SetUnavailable(ex, obj.LastGetTimeCopy) == true)
|
||||
throw new Exception($"【{this.Name}】Block access and wait for recovery: {ex.Message}");
|
||||
throw ex;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#if net40
|
||||
#else
|
||||
public async Task OnGetAsync(Object<DbConnection> obj)
|
||||
{
|
||||
if (InternalPool.IsAvailable)
|
||||
{
|
||||
if (obj.Value == null)
|
||||
{
|
||||
InternalPool.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 (InternalPool.SetUnavailable(ex, obj.LastGetTimeCopy) == true)
|
||||
throw new Exception($"【{this.Name}】Block access and wait for recovery: {ex.Message}");
|
||||
throw ex;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
public void OnReturn(Object<DbConnection> obj)
|
||||
{
|
||||
}
|
||||
|
||||
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 void OnAvailable()
|
||||
{
|
||||
InternalPool.AvailableHandler?.Invoke();
|
||||
}
|
||||
|
||||
public void OnUnavailable()
|
||||
{
|
||||
InternalPool.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
|
||||
{
|
||||
// ignored
|
||||
}
|
||||
|
||||
if (isThrow) throw;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
#if net40
|
||||
#else
|
||||
public static async 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
|
||||
}
|
||||
}
|
||||
28
Providers/FreeSql.Provider.TDengine/TDengineCodeFirst.cs
Normal file
28
Providers/FreeSql.Provider.TDengine/TDengineCodeFirst.cs
Normal file
@@ -0,0 +1,28 @@
|
||||
using FreeSql.Internal;
|
||||
using FreeSql.Internal.Model;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace FreeSql.Provider.TDengine
|
||||
{
|
||||
internal class TDengineCodeFirst : Internal.CommonProvider.CodeFirstProvider
|
||||
{
|
||||
public TDengineCodeFirst(IFreeSql orm, CommonUtils commonUtils, CommonExpression commonExpression) : base(orm, commonUtils, commonExpression)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
public override DbInfoResult GetDbInfo(Type type)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
protected override string GetComparisonDDLStatements(params TypeSchemaAndName[] objects)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
}
|
||||
}
|
||||
7
Providers/FreeSql.Provider.TDengine/TDengineDbFirst.cs
Normal file
7
Providers/FreeSql.Provider.TDengine/TDengineDbFirst.cs
Normal file
@@ -0,0 +1,7 @@
|
||||
namespace FreeSql.Provider.TDengine
|
||||
{
|
||||
public class TDengineDbFirst
|
||||
{
|
||||
|
||||
}
|
||||
}
|
||||
42
Providers/FreeSql.Provider.TDengine/TDengineProvider.cs
Normal file
42
Providers/FreeSql.Provider.TDengine/TDengineProvider.cs
Normal file
@@ -0,0 +1,42 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using FreeSql.Internal.CommonProvider;
|
||||
|
||||
namespace FreeSql.Provider.TDengine
|
||||
{
|
||||
internal class TDengineProvider<TMark> : BaseDbProvider, IFreeSql<TMark>
|
||||
{
|
||||
public override ISelect<T1> CreateSelectProvider<T1>(object dywhere)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public override IInsert<T1> CreateInsertProvider<T1>()
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public override IUpdate<T1> CreateUpdateProvider<T1>(object dywhere)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public override IDelete<T1> CreateDeleteProvider<T1>(object dywhere)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public override IInsertOrUpdate<T1> CreateInsertOrUpdateProvider<T1>()
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public override void Dispose()
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user