feat(TDengine): 支持websocket连接,无需安装sdk

This commit is contained in:
Diego
2025-06-09 12:38:30 +08:00
parent f426c1533d
commit 40574b776f
19 changed files with 591 additions and 18 deletions

View File

@@ -8,4 +8,6 @@
// QQ群605534569
//------------------------------------------------------------------------------
global using SqlSugar.TDengineAdo;
global using ThingsGateway.NewLife.Extension;

View File

@@ -1106,6 +1106,9 @@ namespace SqlSugar
public List<string> AutoAppendedColumns { get; set; }
public Dictionary<string, string> MappingKeys { get; set; }
public List<KeyValuePair<string, string>> SelectNewIgnoreColumns { get; set; }
public bool IsAnyParameterExpression { get; set; }
#endregion
private string GetTableName(string entityName)

View File

@@ -395,7 +395,12 @@ namespace SqlSugar
item.FieldValue = "null";
}
builder.AppendFormat(temp, type, item.FieldName.ToSqlFilter(), "=", parameterName);
parameters.Add(new SugarParameter(parameterName, GetFieldValue(item)));
var p = new SugarParameter(parameterName, GetFieldValue(item));
if (item.CSharpTypeName == "DateOnly")
{
p.DbType = System.Data.DbType.Date;
}
parameters.Add(p);
}
}
#endregion

View File

@@ -313,6 +313,7 @@ namespace SqlSugar
private void Select(MemberInitExpression expression, ExpressionParameter parameter, bool isSingle)
{
var isAnyParameterExpression = false;
foreach (MemberBinding binding in expression.Bindings)
{
if (binding.BindingType != MemberBindingType.Assignment)
@@ -347,8 +348,16 @@ namespace SqlSugar
item = (item as UnaryExpression).Operand;
}
}
if (item is ParameterExpression)
{
isAnyParameterExpression = true;
}
ResolveNewExpressions(parameter, item, memberName);
}
if (isAnyParameterExpression && this.Context?.SugarContext?.QueryBuilder is QueryBuilder builder)
{
builder.IsAnyParameterExpression = true;
}
}
private static bool IsNullable(Type memtype)

View File

@@ -261,6 +261,29 @@ namespace SqlSugar
var tType = typeof(T);
var classProperties = tType.GetProperties()
.Where(p => p.GetIndexParameters().Length == 0).ToList();
if (this.QueryBuilder is QueryBuilder q)
{
if (q.IsAnyParameterExpression)
{
if (q.SelectValue is LambdaExpression lambda)
{
if (lambda.Body is MemberInitExpression memberInit)
{
// 获取memberInit中定义的属性名称
var memberNames = memberInit.Bindings
.OfType<MemberAssignment>()
.Select(b => b.Member.Name)
.ToHashSet();
// 过滤掉不在memberInit中的属性
classProperties = classProperties
.Where(p => memberNames.Contains(p.Name))
.ToList();
}
}
}
}
var reval = new List<T>();
if (reader?.IsClosed == false)
{

View File

@@ -1470,6 +1470,10 @@ namespace SqlSugar
CSharpTypeName = ctypename,
FieldValue = value
};
if (ctypename == "DateOnly")
{
return Convert.ToDateTime(value);
}
if (string.IsNullOrEmpty(item.FieldValue) && item.CSharpTypeName.HasValue() && !item.CSharpTypeName.EqualCase("string"))
{
return null;

View File

@@ -0,0 +1,35 @@
namespace SqlSugar.TDengineAdo;
internal static class Helper
{
public static long DateTimeToLong19(DateTime dateTime)
{
DateTimeOffset dateTimeOffset = dateTime.Kind != DateTimeKind.Utc ? new DateTimeOffset(dateTime.ToUniversalTime()) : new DateTimeOffset(dateTime, TimeSpan.Zero);
return dateTimeOffset.ToUnixTimeSeconds() * 1000000000L + dateTimeOffset.Ticks % 10000000L * 100L;
}
public static DateTime Long16ToDateTime(long timestampInMicroseconds)
{
long seconds = timestampInMicroseconds / 1000000L;
long num = timestampInMicroseconds % 1000000L;
return DateTimeOffset.FromUnixTimeSeconds(seconds).AddTicks(num * 10L).LocalDateTime;
}
public static DateTime Long19ToDateTime(long timestampInNanoseconds)
{
long seconds = timestampInNanoseconds / 1000000000L;
long num = timestampInNanoseconds % 1000000000L;
return DateTimeOffset.FromUnixTimeSeconds(seconds).AddTicks(num / 100L).LocalDateTime;
}
public static long DateTimeToLong16(DateTime dateTime)
{
DateTimeOffset dateTimeOffset = dateTime.Kind != DateTimeKind.Utc ? new DateTimeOffset(dateTime.ToUniversalTime()) : new DateTimeOffset(dateTime, TimeSpan.Zero);
return dateTimeOffset.ToUnixTimeSeconds() * 1000000L + dateTimeOffset.Ticks % 10000000L / 10L;
}
public static long ToUnixTimestamp(DateTime dateTime)
{
return dateTime.Kind == DateTimeKind.Utc ? new DateTimeOffset(dateTime).ToUnixTimeMilliseconds() : new DateTimeOffset(dateTime.ToUniversalTime()).ToUnixTimeMilliseconds();
}
}

View File

@@ -0,0 +1,142 @@
using System.Data;
using System.Data.Common;
using System.Text.RegularExpressions;
using TDengine.Data.Client;
using TDengine.Driver;
namespace SqlSugar.TDengineAdo;
public class TDengineCommand : DbCommand
{
private string commandText;
private TDengineConnection connection;
private TDengineParameterCollection _DbParameterCollection;
public TDengineCommand()
{
}
public TDengineCommand(string commandText, TDengineConnection connection)
{
this.CommandText = commandText;
this.Connection = connection;
}
public override string CommandText
{
get => this.commandText;
set => this.commandText = value;
}
public override int CommandTimeout { get; set; }
public override CommandType CommandType { get; set; }
public override bool DesignTimeVisible { get; set; }
public override UpdateRowSource UpdatedRowSource { get; set; }
protected override DbConnection DbConnection
{
get => (DbConnection)this.connection;
set => this.connection = (TDengineConnection)value;
}
protected override DbParameterCollection DbParameterCollection
{
get
{
if (this._DbParameterCollection == null)
this._DbParameterCollection = new TDengineParameterCollection();
return (DbParameterCollection)this._DbParameterCollection;
}
}
protected override DbTransaction DbTransaction { get; set; }
public override void Cancel() => throw new NotImplementedException();
public override int ExecuteNonQuery()
{
try
{
this.connection.Open();
long num = this.connection.connection.Exec(this.GetNoParameterSql(this.commandText));
this.connection.Close();
return num > (long)int.MaxValue ? int.MaxValue : Convert.ToInt32(num);
}
catch
{
this.connection.Close();
throw;
}
}
public override object ExecuteScalar()
{
try
{
this.connection.Open();
IRows irows = this.connection.connection.Query(this.GetNoParameterSql(this.commandText));
using (irows)
{
irows.Read();
this.connection.Close();
return irows.GetValue(0);
}
}
catch
{
this.connection.Close();
throw;
}
}
public new DbDataReader ExecuteReader()
{
try
{
this.connection.Open();
TDengineDataReader tdengineDataReader = new TDengineDataReader(this.connection.connection.Query(this.GetNoParameterSql(this.commandText)));
this.connection.Close();
return (DbDataReader)tdengineDataReader;
}
catch
{
this.connection.Close();
throw;
}
}
public override void Prepare() => throw new NotImplementedException();
protected override void Dispose(bool disposing) => base.Dispose(disposing);
protected override DbParameter CreateDbParameter() => throw new NotImplementedException();
protected override DbDataReader ExecuteDbDataReader(CommandBehavior behavior)
{
return this.ExecuteReader();
}
private string GetNoParameterSql(string sql)
{
foreach (TDengineParameter tdengineParameter in (IEnumerable<TDengineParameter>)this.Parameters.Cast<TDengineParameter>().OrderByDescending<TDengineParameter, int>((Func<TDengineParameter, int>)(it => it.parameterName.Length)))
{
if (!tdengineParameter.parameterName.Contains('@'))
tdengineParameter.parameterName = "@" + tdengineParameter.parameterName;
object obj = tdengineParameter.value;
if (tdengineParameter.value == null || tdengineParameter.value == DBNull.Value)
sql = Regex.Replace(sql, tdengineParameter.parameterName, "null", RegexOptions.IgnoreCase);
else if (tdengineParameter.value is DateTime)
{
DateTime dateTime = (DateTime)tdengineParameter.value;
sql = !tdengineParameter.IsMicrosecond ? (!tdengineParameter.IsNanosecond ? Regex.Replace(sql, tdengineParameter.parameterName, Helper.ToUnixTimestamp(dateTime).ToString() ?? "", RegexOptions.IgnoreCase) : Regex.Replace(sql, tdengineParameter.parameterName, Helper.DateTimeToLong19(dateTime).ToString() ?? "", RegexOptions.IgnoreCase)) : Regex.Replace(sql, tdengineParameter.parameterName, Helper.DateTimeToLong16(dateTime).ToString() ?? "", RegexOptions.IgnoreCase);
}
else
sql = tdengineParameter.value is string || tdengineParameter.value != null ? Regex.Replace(sql, tdengineParameter.parameterName, "'" + tdengineParameter.value.ToString().Replace("'", "''") + "'", RegexOptions.IgnoreCase) : Regex.Replace(sql, tdengineParameter.parameterName, "'" + tdengineParameter.value?.ToString() + "'", RegexOptions.IgnoreCase);
}
return sql;
}
}

View File

@@ -0,0 +1,73 @@
using System.Data;
using System.Data.Common;
using TDengine.Driver;
using TDengine.Driver.Client;
namespace SqlSugar.TDengineAdo;
public class TDengineConnection : DbConnection
{
internal ITDengineClient connection;
private ConnectionStringBuilder connectionStringBuilder;
public TDengineConnection(string connectionString)
{
connectionStringBuilder = new ConnectionStringBuilder(connectionString);
this.connection = DbDriver.Open(connectionStringBuilder);
}
public override string ConnectionString
{
get
{
return connectionStringBuilder.ConnectionString;
}
set => throw new NotSupportedException();
}
public override string Database => connectionStringBuilder.Database;
public override string DataSource => connectionStringBuilder.Host;
public override string ServerVersion => "Unknown";
public override ConnectionState State
{
get => this.connection != null ? ConnectionState.Open : ConnectionState.Closed;
}
protected override DbTransaction BeginDbTransaction(IsolationLevel isolationLevel)
{
throw new NotSupportedException(nameof(BeginDbTransaction));
}
public override void Close()
{
if (this.connection == null)
return;
((IDisposable)this.connection).Dispose();
this.connection = (ITDengineClient)null;
}
public override void Open()
{
if (this.connection == null)
this.connection = DbDriver.Open(connectionStringBuilder);
else if (this.connection == null)
this.connection = DbDriver.Open(connectionStringBuilder);
if (string.IsNullOrEmpty(this.Database))
return;
this.connection.Exec("use " + this.Database);
}
protected override DbCommand CreateDbCommand() => (DbCommand)new TDengineCommand();
protected DbCommand CreateDbCommand(string commandText)
{
return (DbCommand)new TDengineCommand(commandText, this);
}
protected override void Dispose(bool disposing) => this.Close();
public override void ChangeDatabase(string databaseName) => connectionStringBuilder.Database = databaseName;
}

View File

@@ -0,0 +1,102 @@
using System.Data;
using System.Data.Common;
namespace SqlSugar.TDengineAdo;
public class TDengineDataAdapter : IDataAdapter
{
private TDengineCommand command;
private string sql;
private TDengineConnection _TDengineConnection;
public TDengineDataAdapter(TDengineCommand command) => this.command = command;
public TDengineDataAdapter()
{
}
public TDengineDataAdapter(string sql, TDengineConnection _TDengineConnection)
{
this.sql = sql;
this._TDengineConnection = _TDengineConnection;
}
public TDengineCommand SelectCommand
{
get
{
if (this.command == null)
this.command = new TDengineCommand(this.sql, this._TDengineConnection);
return this.command;
}
set => this.command = value;
}
public ITableMappingCollection TableMappings => throw new NotImplementedException();
public void Fill(DataTable dt)
{
if (dt == null)
dt = new DataTable();
DataColumnCollection columns = dt.Columns;
DataRowCollection rows = dt.Rows;
using (DbDataReader dbDataReader = this.command.ExecuteReader())
{
for (int ordinal = 0; ordinal < dbDataReader.FieldCount; ++ordinal)
{
string str = dbDataReader.GetName(ordinal).Trim();
if (!columns.Contains(str))
columns.Add(new DataColumn(str, dbDataReader.GetFieldType(ordinal)));
else
columns.Add(new DataColumn(str + ordinal.ToString(), dbDataReader.GetFieldType(ordinal)));
}
while (dbDataReader.Read())
{
DataRow row = dt.NewRow();
for (int index = 0; index < columns.Count; ++index)
row[columns[index].ColumnName] = dbDataReader.GetValue(index) ?? (object)DBNull.Value;
dt.Rows.Add(row);
}
}
dt.AcceptChanges();
}
public void Fill(DataSet ds)
{
if (ds == null)
ds = new DataSet();
using (DbDataReader dbDataReader = this.command.ExecuteReader())
{
do
{
DataTable table = new DataTable();
DataColumnCollection columns = table.Columns;
DataRowCollection rows = table.Rows;
for (int ordinal = 0; ordinal < dbDataReader.FieldCount; ++ordinal)
{
string str = dbDataReader.GetName(ordinal).Trim();
if (!columns.Contains(str))
columns.Add(new DataColumn(str, dbDataReader.GetFieldType(ordinal)));
else
columns.Add(new DataColumn(str + ordinal.ToString(), dbDataReader.GetFieldType(ordinal)));
}
while (dbDataReader.Read())
{
DataRow row = table.NewRow();
for (int index = 0; index < columns.Count; ++index)
row[columns[index].ColumnName] = dbDataReader.GetValue(index);
table.Rows.Add(row);
}
table.AcceptChanges();
ds.Tables.Add(table);
}
while (dbDataReader.NextResult());
}
}
}

View File

@@ -0,0 +1,81 @@
using System.Data;
using System.Data.Common;
namespace SqlSugar.TDengineAdo;
public class TDengineParameter : DbParameter
{
public string parameterName;
private int size;
private System.Data.DbType dbType;
public object value { get; set; }
public bool IsMicrosecond { get; set; }
public bool IsNanosecond { get; set; }
public TDengineParameter(string parameterName, object value, System.Data.DbType dbType = System.Data.DbType.Object, int size = 0)
{
this.parameterName = parameterName;
this.value = value;
this.size = size;
this.dbType = dbType;
}
public override System.Data.DbType DbType
{
get => this.dbType;
set => this.dbType = value;
}
public override int Size
{
get => this.size;
set => this.size = value;
}
public override string ParameterName
{
get => this.parameterName;
set => this.parameterName = value;
}
public override object Value
{
get => this.value;
set => this.value = value;
}
public override void ResetDbType() => throw new NotImplementedException();
public override string SourceColumn
{
get => throw new NotImplementedException();
set => throw new NotImplementedException();
}
public override bool IsNullable
{
get => throw new NotImplementedException();
set => throw new NotImplementedException();
}
public override DataRowVersion SourceVersion
{
get => throw new NotImplementedException();
set => throw new NotImplementedException();
}
public override ParameterDirection Direction
{
get => throw new NotImplementedException();
set => throw new NotImplementedException();
}
public override bool SourceColumnNullMapping
{
get => throw new NotImplementedException();
set => throw new NotImplementedException();
}
}

View File

@@ -0,0 +1,102 @@
using System.Collections;
using System.Data.Common;
namespace SqlSugar.TDengineAdo;
public class TDengineParameterCollection : DbParameterCollection
{
private List<TDengineParameter> parameters = new List<TDengineParameter>();
public override int Count => this.parameters.Count;
public override object SyncRoot => ((ICollection)this.parameters).SyncRoot;
public override int Add(object value)
{
this.parameters.Add((TDengineParameter)value);
return this.parameters.Count - 1;
}
public override void AddRange(Array values)
{
foreach (TDengineParameter tdengineParameter in values)
this.parameters.Add(tdengineParameter);
}
public override void Clear() => this.parameters.Clear();
public override bool Contains(string value)
{
foreach (DbParameter parameter in this.parameters)
{
if (parameter.ParameterName.Equals(value, StringComparison.OrdinalIgnoreCase))
return true;
}
return false;
}
public override bool Contains(object value)
{
return this.parameters.Contains((TDengineParameter)value);
}
public override void CopyTo(Array array, int index)
{
for (int index1 = 0; index1 < this.parameters.Count; ++index1)
array.SetValue((object)this.parameters[index1], index + index1);
}
public override IEnumerator GetEnumerator() => (IEnumerator)this.parameters.GetEnumerator();
public override int IndexOf(string parameterName)
{
for (int index = 0; index < this.parameters.Count; ++index)
{
if (this.parameters[index].ParameterName.Equals(parameterName, StringComparison.OrdinalIgnoreCase))
return index;
}
return -1;
}
public override int IndexOf(object value) => this.parameters.IndexOf((TDengineParameter)value);
public override void Insert(int index, object value)
{
this.parameters.Insert(index, (TDengineParameter)value);
}
public override void Remove(object value) => this.parameters.Remove((TDengineParameter)value);
public override void RemoveAt(int index) => this.parameters.RemoveAt(index);
public override void RemoveAt(string parameterName)
{
int index = this.IndexOf(parameterName);
if (index < 0)
return;
this.parameters.RemoveAt(index);
}
protected override DbParameter GetParameter(int index) => (DbParameter)this.parameters[index];
protected override DbParameter GetParameter(string parameterName)
{
int index = this.IndexOf(parameterName);
return index >= 0 ? (DbParameter)this.parameters[index] : (DbParameter)null;
}
protected override void SetParameter(int index, DbParameter value)
{
if (index < 0 || index >= this.parameters.Count)
throw new IndexOutOfRangeException("Index is out of range.");
this.parameters[index] = value != null ? (TDengineParameter)value : throw new ArgumentNullException(nameof(value), "Parameter cannot be null.");
}
protected override void SetParameter(string parameterName, DbParameter value)
{
int index = this.IndexOf(parameterName);
if (index == -1)
throw new IndexOutOfRangeException("Parameter not found.");
this.parameters[index] = value != null ? (TDengineParameter)value : throw new ArgumentNullException(nameof(value), "Parameter cannot be null.");
}
}

View File

@@ -1,7 +1,4 @@

using SqlSugar.TDengineAdo;
using System.Data;
using System.Data;
using System.Globalization;
using System.Text;

View File

@@ -1,8 +1,5 @@
using SqlSugar.TDengineAdo;
using System.Data;
using System.Data;
using System.Data.Common;
using System.Text.RegularExpressions;
namespace SqlSugar.TDengine
{
public partial class TDengineProvider : AdoProvider
@@ -21,7 +18,7 @@ namespace SqlSugar.TDengine
try
{
var TDengineConnectionString = base.Context.CurrentConnectionConfig.ConnectionString;
TDengineConnectionString = Regex.Replace(TDengineConnectionString, @"\;db\=", ";Database=", RegexOptions.IgnoreCase);
//TDengineConnectionString = Regex.Replace(TDengineConnectionString, @"\;db\=", ";Database=", RegexOptions.IgnoreCase);
base._DbConnection = new TDengineConnection(TDengineConnectionString);
}
catch (Exception)

View File

@@ -1,6 +1,4 @@
using SqlSugar.TDengineAdo;
using System.Data;
using System.Data;
using System.Data.Common;
using System.Text;

View File

@@ -28,7 +28,7 @@
<PackageReference Include="MySqlConnector" Version="2.4.0" />
<PackageReference Include="Npgsql" Version="9.0.3" />
<PackageReference Include="CsvHelper" Version="33.1.0" />
<PackageReference Include="TDengine.Ado.Data" Version="3.1.7" />
<PackageReference Include="TDengine.Connector" Version="3.1.6" />
<PackageReference Include="Oracle.ManagedDataAccess.Core" Version="23.8.0" />
<PackageReference Include="Oscar.Data.SqlClient" Version="4.2.18" />
<PackageReference Include="System.Data.Common" Version="4.3.0" />

View File

@@ -1,8 +1,8 @@
<Project>
<PropertyGroup>
<PluginVersion>10.7.37</PluginVersion>
<ProPluginVersion>10.7.37</ProPluginVersion>
<PluginVersion>10.7.38</PluginVersion>
<ProPluginVersion>10.7.38</ProPluginVersion>
<AuthenticationVersion>2.5.0</AuthenticationVersion>
</PropertyGroup>

View File

@@ -33,7 +33,7 @@ public partial class TDengineDBProducer : BusinessBaseWithCacheIntervalVariableM
internal readonly RealDBProducerProperty _driverPropertys = new()
{
DbType = DbType.TDengine,
BigTextConnectStr = "Host=localhost;Port=6030;Username=root;Password=taosdata;Database=power"
BigTextConnectStr = "protocol=WebSocket;host=localhost;port=6041;useSSL=false;username=root;password=taosdata;db=power"
};
private readonly TDengineDBProducerVariableProperty _variablePropertys = new();
/// <inheritdoc/>

View File

@@ -1,6 +1,6 @@
<Project>
<PropertyGroup>
<Version>10.7.37</Version>
<Version>10.7.38</Version>
</PropertyGroup>
<ItemGroup>