From 57b0347c9431c9346d84bf7f3b02d288beaae98c Mon Sep 17 00:00:00 2001 From: d4ilys <963922242@qq.com> Date: Thu, 30 Nov 2023 15:48:59 +0800 Subject: [PATCH] =?UTF-8?q?=E6=B5=8B=E8=AF=95Array=E5=B8=B8=E7=94=A8?= =?UTF-8?q?=E6=9F=A5=E8=AF=A2=E5=87=BD=E6=95=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../ClickHouse/ClickHouseTest3.cs | 249 +++++++++++++++++- FreeSql.Tests/FreeSql.Tests/FreeSql.Tests.xml | 72 +++++ .../ClickHouseCodeFirst.cs | 6 +- .../ClickHouseExpression.cs | 48 +++- .../ClickHouseExtensions.cs | 45 +++- .../Curd/ClickHouseInsert.cs | 31 ++- 6 files changed, 416 insertions(+), 35 deletions(-) diff --git a/FreeSql.Tests/FreeSql.Tests/ClickHouse/ClickHouseTest3.cs b/FreeSql.Tests/FreeSql.Tests/ClickHouse/ClickHouseTest3.cs index b92f5915..8cd0473a 100644 --- a/FreeSql.Tests/FreeSql.Tests/ClickHouse/ClickHouseTest3.cs +++ b/FreeSql.Tests/FreeSql.Tests/ClickHouse/ClickHouseTest3.cs @@ -1,8 +1,11 @@ using System; using System.Collections; using System.Collections.Generic; +using System.ComponentModel.DataAnnotations; using System.Linq; +using System.Linq.Expressions; using System.Text; +using System.Threading; using System.Threading.Tasks; using FreeSql.DataAnnotations; using Newtonsoft.Json; @@ -126,15 +129,15 @@ namespace FreeSql.Tests.ClickHouse { var source = new List() { - new ArrayMappingTestSimple + new() { Name = "daily", - Tags1 = new [] { "e", "f", "g" }, - Tags2 = new [] { 3, 45, 100, 400 }, - Tags3 = new [] { false, true, false } + Tags1 = Array.Empty(), + Tags2 = new[] { 3, 45, 100, 400 }, + Tags3 = new[] { false, true, false } } }; - var str = _fsql.Insert(source).ExecuteAffrows(); + var str = _fsql.Insert(source).ExecuteAffrows(); } /// @@ -146,8 +149,176 @@ namespace FreeSql.Tests.ClickHouse var list = _fsql.Select().ToList(); _output.WriteLine(JsonConvert.SerializeObject(list)); } + + /// + /// 测试Array常用查询函数 + /// + [Fact] + public void ArraySelectAnySync() + { + var sql = _fsql.Select().Where(a => !a.Tags1.Any()).ToList(a => a.Name); + _output.WriteLine(JsonConvert.SerializeObject(sql)); + } + + + /// + /// 测试Array常用查询函数 + /// + [Fact] + public void ArraySelectLengthSync() + { + var sql = _fsql.Select().ToList(a => a.Tags1.Count()); + _output.WriteLine(JsonConvert.SerializeObject(sql)); + + var sql2 = _fsql.Select().Where(a => a.Tags1.Count() > 5).ToList(a => a.Tags1); + _output.WriteLine(JsonConvert.SerializeObject(sql2)); + } + + + /// + /// 测试Array常用查询函数 + /// + [Fact] + public void ArraySelectContainsSync() + { + var sql = _fsql.Select().ToList(a => a.Tags1.Contains("a")); + _output.WriteLine(JsonConvert.SerializeObject(sql)); + + var sql2 = _fsql.Select().Where(a => a.Tags2.Contains(2)).ToList(a => a.Tags2); + _output.WriteLine(JsonConvert.SerializeObject(sql2)); + } + + /// + /// 测试Array常用查询函数 + /// + [Fact] + public void ArraySelectConcatSync() + { + var list = new List() { "f" }; + var sql = _fsql.Select().ToList(a => a.Tags1.Concat(list)); + _output.WriteLine(JsonConvert.SerializeObject(sql)); + + } + + /// + /// 测试ArrayFilter测试 + /// + [Fact] + public void ArrayFilterFuncTest() + { + //var list = _fsql.Select().Where(a => a.Tags2.ArrayFilter(o => o == 1).Any()) + // .ToSql(); + + + ////SELECT a.`name`, a.`tags1`, a.`tags2`, a.`tags3` + ////FROM `table_test_array_simple` a + ////WHERE (arrayFilter(x -> x = '1', a.`tags2`) != []) + + //_output.WriteLine(JsonConvert.SerializeObject(list)); + } + + /// + /// 测试ArrayFilter测试 + /// + [Fact] + public void IsPrimaryTest() + { + _fsql.CodeFirst.SyncStructure(); + } + + /// + /// https://github.com/dotnetcore/FreeSql/issues/969 + /// + [Fact] + public async Task UriStringIsTooLongTest() + { + _fsql.CodeFirst.SyncStructure(); + var json = + "[{\"date\":\"2021-12-19T02:47:53.4365075 08:00\",\"temperatureC\":6,\"temperatureF\":42,\"summary\":\"Balmy\"},{\"date\":\"2021-12-20T02:47:53.4366893 08:00\",\"temperatureC\":36,\"temperatureF\":96,\"summary\":\"Bracing\"},{\"date\":\"2021-12-21T02:47:53.4366903 08:00\",\"temperatureC\":-15,\"temperatureF\":6,\"summary\":\"Bracing\"},{\"date\":\"2021-12-22T02:47:53.4366904 08:00\",\"temperatureC\":14,\"temperatureF\":57,\"summary\":\"Cool\"},{\"date\":\"2021-12-23T02:47:53.4366905 08:00\",\"temperatureC\":29,\"temperatureF\":84,\"summary\":\"Mild\"}][{\"date\":\"2021-12-19T02:47:53.4365075 08:00\",\"temperatureC\":6,\"temperatureF\":42,\"summary\":\"Balmy\"},{\"date\":\"2021-12-20T02:47:53.4366893 08:00\",\"temperatureC\":36,\"temperatureF\":96,\"summary\":\"Bracing\"},{\"date\":\"2021-12-21T02:47:53.4366903 08:00\",\"temperatureC\":-15,\"temperatureF\":6,\"summary\":\"Bracing\"},{\"date\":\"2021-12-22T02:47:53.4366904 08:00\",\"temperatureC\":14,\"temperatureF\":57,\"summary\":\"Cool\"},{\"date\":\"2021-12-23T02:47:53.4366905 08:00\",\"temperatureC\":29,\"temperatureF\":84,\"summary\":\"Mild\"}[{\"date\":\"2021-12-19T02:47:53.4365075 08:00\",\"temperatureC\":6,\"temperatureF\":42,\"summary\":\"Balmy\"},{\"date\":\"2021-12-20T02:47:53.4366893 08:00\",\"temperatureC\":36,\"temperatureF\":96,\"summary\":\"Bracing\"},{\"date\":\"2021-12-21T02:47:53.4366903 08:00\",\"temperatureC\":-15,\"temperatureF\":6,\"summary\":\"Bracing\"},{\"date\":\"2021-12-22T02:47:53.4366904 08:00\",\"temperatureC\":14,\"temperatureF\":57,\"summary\":\"Cool\"},{\"date\":\"2021-12-23T02:47:53.4366905 08:00\",\"temperatureC\":29,\"temperatureF\":84,\"summary\":\"Mild\"}[{\"date\":\"2021-12-19T02:47:53.4365075 08:00\",\"temperatureC\":6,\"temperatureF\":42,\"summary\":\"Balmy\"},{\"date\":\"2021-12-20T02:47:53.4366893 08:00\",\"temperatureC\":36,\"temperatureF\":96,\"summary\":\"Bracing\"},{\"date\":\"2021-12-21T02:47:53.4366903 08:00\",\"temperatureC\":-15,\"temperatureF\":6,\"summary\":\"Bracing\"},{\"date\":\"2021-12-22T02:47:53.4366904 08:00\",\"temperatureC\":14,\"temperatureF\":57,\"summary\":\"Cool\"},{\"date\":\"2021-12-23T02:47:53.4366905 08:00\",\"temperatureC\":29,\"temperatureF\":84,\"summary\":\"Mild\"}[{\"date\":\"2021-12-19T02:47:53.4365075 08:00\",\"temperatureC\":6,\"temperatureF\":42,\"summary\":\"Balmy\"},{\"date\":\"2021-12-20T02:47:53.4366893 08:00\",\"temperatureC\":36,\"temperatureF\":96,\"summary\":\"Bracing\"},{\"date\":\"2021-12-21T02:47:53.4366903 08:00\",\"temperatureC\":-15,\"temperatureF\":6,\"summary\":\"Bracing\"},{\"date\":\"2021-12-22T02:47:53.4366904 08:00\",\"temperatureC\":14,\"temperatureF\":57,\"summary\":\"Cool\"},{\"date\":\"2021-12-23T02:47:53.4366905 08:00\",\"temperatureC\":29,\"temperatureF\":84,\"summary\":\"Mild\"}[{\"date\":\"2021-12-19T02:47:53.4365075 08:00\",\"temperatureC\":6,\"temperatureF\":42,\"summary\":\"Balmy\"},{\"date\":\"2021-12-20T02:47:53.4366893 08:00\",\"temperatureC\":36,\"temperatureF\":96,\"summary\":\"Bracing\"},{\"date\":\"2021-12-21T02:47:53.4366903 08:00\",\"temperatureC\":-15,\"temperatureF\":6,\"summary\":\"Bracing\"},{\"date\":\"2021-12-22T02:47:53.4366904 08:00\",\"temperatureC\":14,\"temperatureF\":57,\"summary\":\"Cool\"},{\"date\":\"2021-12-23T02:47:53.4366905 08:00\",\"temperatureC\":29,\"temperatureF\":84,\"summary\":\"Mild\"}[{\"date\":\"2021-12-19T02:47:53.4365075 08:00\",\"temperatureC\":6,\"temperatureF\":42,\"summary\":\"Balmy\"},{\"date\":\"2021-12-20T02:47:53.4366893 08:00\",\"temperatureC\":36,\"temperatureF\":96,\"summary\":\"Bracing\"},{\"date\":\"2021-12-21T02:47:53.4366903 08:00\",\"temperatureC\":-15,\"temperatureF\":6,\"summary\":\"Bracing\"},{\"date\":\"2021-12-22T02:47:53.4366904 08:00\",\"temperatureC\":14,\"temperatureF\":57,\"summary\":\"Cool\"},{\"date\":\"2021-12-23T02:47:53.4366905 08:00\",\"temperatureC\":29,\"temperatureF\":84,\"summary\":\"Mild\"}[{\"date\":\"2021-12-19T02:47:53.4365075 08:00\",\"temperatureC\":6,\"temperatureF\":42,\"summary\":\"Balmy\"},{\"date\":\"2021-12-20T02:47:53.4366893 08:00\",\"temperatureC\":36,\"temperatureF\":96,\"summary\":\"Bracing\"},{\"date\":\"2021-12-21T02:47:53.4366903 08:00\",\"temperatureC\":-15,\"temperatureF\":6,\"summary\":\"Bracing\"},{\"date\":\"2021-12-22T02:47:53.4366904 08:00\",\"temperatureC\":14,\"temperatureF\":57,\"summary\":\"Cool\"},{\"date\":\"2021-12-23T02:47:53.4366905 08:00\",\"temperatureC\":29,\"temperatureF\":84,\"summary\":\"Mild\"}[{\"date\":\"2021-12-19T02:47:53.4365075 08:00\",\"temperatureC\":6,\"temperatureF\":42,\"summary\":\"Balmy\"},{\"date\":\"2021-12-20T02:47:53.4366893 08:00\",\"temperatureC\":36,\"temperatureF\":96,\"summary\":\"Bracing\"},{\"date\":\"2021-12-21T02:47:53.4366903 08:00\",\"temperatureC\":-15,\"temperatureF\":6,\"summary\":\"Bracing\"},{\"date\":\"2021-12-22T02:47:53.4366904 08:00\",\"temperatureC\":14,\"temperatureF\":57,\"summary\":\"Cool\"},{\"date\":\"2021-12-23T02:47:53.4366905 08:00\",\"temperatureC\":29,\"temperatureF\":84,\"summary\":\"Mild\"}[{\"date\":\"2021-12-19T02:47:53.4365075 08:00\",\"temperatureC\":6,\"temperatureF\":42,\"summary\":\"Balmy\"},{\"date\":\"2021-12-20T02:47:53.4366893 08:00\",\"temperatureC\":36,\"temperatureF\":96,\"summary\":\"Bracing\"},{\"date\":\"2021-12-21T02:47:53.4366903 08:00\",\"temperatureC\":-15,\"temperatureF\":6,\"summary\":\"Bracing\"},{\"date\":\"2021-12-22T02:47:53.4366904 08:00\",\"temperatureC\":14,\"temperatureF\":57,\"summary\":\"Cool\"},{\"date\":\"2021-12-23T02:47:53.4366905 08:00\",\"temperatureC\":29,\"temperatureF\":84,\"summary\":\"Mild\"}[{\"date\":\"2021-12-19T02:47:53.4365075 08:00\",\"temperatureC\":6,\"temperatureF\":42,\"summary\":\"Balmy\"},{\"date\":\"2021-12-20T02:47:53.4366893 08:00\",\"temperatureC\":36,\"temperatureF\":96,\"summary\":\"Bracing\"},{\"date\":\"2021-12-21T02:47:53.4366903 08:00\",\"temperatureC\":-15,\"temperatureF\":6,\"summary\":\"Bracing\"},{\"date\":\"2021-12-22T02:47:53.4366904 08:00\",\"temperatureC\":14,\"temperatureF\":57,\"summary\":\"Cool\"},{\"date\":\"2021-12-23T02:47:53.4366905 08:00\",\"temperatureC\":29,\"temperatureF\":84,\"summary\":\"Mild\"}[{\"date\":\"2021-12-19T02:47:53.4365075 08:00\",\"temperatureC\":6,\"temperatureF\":42,\"summary\":\"Balmy\"},{\"date\":\"2021-12-20T02:47:53.4366893 08:00\",\"temperatureC\":36,\"temperatureF\":96,\"summary\":\"Bracing\"},{\"date\":\"2021-12-21T02:47:53.4366903 08:00\",\"temperatureC\":-15,\"temperatureF\":6,\"summary\":\"Bracing\"},{\"date\":\"2021-12-22T02:47:53.4366904 08:00\",\"temperatureC\":14,\"temperatureF\":57,\"summary\":\"Cool\"},{\"date\":\"2021-12-23T02:47:53.4366905 08:00\",\"temperatureC\":29,\"temperatureF\":84,\"summary\":\"Mild\"}[{\"date\":\"2021-12-19T02:47:53.4365075 08:00\",\"temperatureC\":6,\"temperatureF\":42,\"summary\":\"Balmy\"},{\"date\":\"2021-12-20T02:47:53.4366893 08:00\",\"temperatureC\":36,\"temperatureF\":96,\"summary\":\"Bracing\"},{\"date\":\"2021-12-21T02:47:53.4366903 08:00\",\"temperatureC\":-15,\"temperatureF\":6,\"summary\":\"Bracing\"},{\"date\":\"2021-12-22T02:47:53.4366904 08:00\",\"temperatureC\":14,\"temperatureF\":57,\"summary\":\"Cool\"},{\"date\":\"2021-12-23T02:47:53.4366905 08:00\",\"temperatureC\":29,\"temperatureF\":84,\"summary\":\"Mild\"}[{\"date\":\"2021-12-19T02:47:53.4365075 08:00\",\"temperatureC\":6,\"temperatureF\":42,\"summary\":\"Balmy\"},{\"date\":\"2021-12-20T02:47:53.4366893 08:00\",\"temperatureC\":36,\"temperatureF\":96,\"summary\":\"Bracing\"},{\"date\":\"2021-12-21T02:47:53.4366903 08:00\",\"temperatureC\":-15,\"temperatureF\":6,\"summary\":\"Bracing\"},{\"date\":\"2021-12-22T02:47:53.4366904 08:00\",\"temperatureC\":14,\"temperatureF\":57,\"summary\":\"Cool\"},{\"date\":\"2021-12-23T02:47:53.4366905 08:00\",\"temperatureC\":29,\"temperatureF\":84,\"summary\":\"Mild\"}"; + + json += json; + json += json; + json += json; + json += json; + json += json; + json += json; + json += json; + json += json; + json += json; + json += json; + json += json; + json += json; + json += json; + json += json; + + var t = new TestTable + { + Id = Guid.NewGuid().ToString(), + Content = json, + Content2 = json, + Time = DateTime.Now + }; + + //单个插入报错 + await _fsql.Insert(t).ExecuteAffrowsAsync(); + + // await _fsql.Insert(t).ExecuteBulkCopyAsync(); + } + + + /// + /// 测试BulkCopy单条 + /// + /// + [Fact] + public async Task TestBulkCopySingle() + { + var t = new TestTable + { + Id = Guid.NewGuid().ToString(), + Content = "1", + Content2 = "2", + Time = DateTime.Now + }; + + //单个插入报错 + await _fsql.Insert(t).ExecuteAffrowsAsync(); + + await _fsql.Insert(t).ExecuteBulkCopyAsync(); + + _fsql.Insert(t).ExecuteBulkCopy(); + } + + /// + /// 测试BulkCopy多条 + /// + /// + [Fact] + public async Task TestBulkCopyMany() + { + var t = new List(); + + foreach (var i in Enumerable.Range(0, 10)) + { + t.Add(new TestTable + { + Id = Guid.NewGuid().ToString(), + Content = i.ToString(), + Content2 = i.ToString(), + Time = DateTime.Now + }); + } + + //单个插入报错 + await _fsql.Insert(t).ExecuteAffrowsAsync(); + + await _fsql.Insert(t).ExecuteBulkCopyAsync(); + + _fsql.Insert(t).ExecuteBulkCopy(); + } } + [Table(Name = "table_test_bool")] public class BoolMappingTest { @@ -191,10 +362,74 @@ namespace FreeSql.Tests.ClickHouse [Column(Name = "name", IsPrimary = true)] public string Name { get; set; } - [Column(Name = "tags1")] public string [] Tags1 { get; set; } + [Column(Name = "tags1")] public string[] Tags1 { get; set; } [Column(Name = "tags2")] public int[] Tags2 { get; set; } - [Column(Name = "tags3")] public bool [] Tags3 { get; set; } + [Column(Name = "tags3")] public bool[] Tags3 { get; set; } + } + + /// + /// Http请求信息统计 + /// + [Table(Name = "http_context_record")] + public class HttpContextRecord + { + [Column(Name = "id", IsPrimary = true)] + public string Id { get; set; } + + /// + /// 请求模板 + /// + [Column(Name = "request_total_key", StringLength = 80)] + public string RequestTotalKey { get; set; } + + /// + /// 请求量 + /// + [Column(Name = "total")] + public long Total { get; set; } + + /// + /// 记录请求类型 + /// + [Column(Name = "type")] + public int Type { get; set; } + + /// + /// 添加时间 + /// + [Column(Name = "add_time")] + public DateTime AddTime { get; set; } + } + + public class ContentRecord + { + [Column(IsPrimary = true)] public string Id { get; set; } + + public string? Content1 { get; set; } + + public string? Content2 { get; set; } + + public string? Content3 { get; set; } + + public string Content4 { get; set; } + } + + internal class TestTable + { + [Required] [Column(IsIdentity = true)] public string Id { get; set; } + + [Column(StringLength = -2)] public string Content { get; set; } + + [Column(StringLength = -2)] public string Content2 { get; set; } + + [Column(DbType = "DateTime64(3, 'Asia/Shanghai')")] + public DateTime Time { get; set; } + + public override string ToString() + { + return $"Id:{Id} Content:{Content} Content2:{Content2} Time:{Time}"; + } } } \ No newline at end of file diff --git a/FreeSql.Tests/FreeSql.Tests/FreeSql.Tests.xml b/FreeSql.Tests/FreeSql.Tests/FreeSql.Tests.xml index 13f136a0..fa03b482 100644 --- a/FreeSql.Tests/FreeSql.Tests/FreeSql.Tests.xml +++ b/FreeSql.Tests/FreeSql.Tests/FreeSql.Tests.xml @@ -44,6 +44,78 @@ 测试Array类型映射 + + + 测试Array常用查询函数 + + + + + 测试Array常用查询函数 + + + + + 测试Array常用查询函数 + + + + + 测试Array常用查询函数 + + + + + 测试ArrayFilter测试 + + + + + 测试ArrayFilter测试 + + + + + https://github.com/dotnetcore/FreeSql/issues/969 + + + + + 测试BulkCopy单条 + + + + + + 测试BulkCopy多条 + + + + + + Http请求信息统计 + + + + + 请求模板 + + + + + 请求量 + + + + + 记录请求类型 + + + + + 添加时间 + + 实时数据 diff --git a/Providers/FreeSql.Provider.ClickHouse/ClickHouseCodeFirst.cs b/Providers/FreeSql.Provider.ClickHouse/ClickHouseCodeFirst.cs index 77bb5991..f56737fd 100644 --- a/Providers/FreeSql.Provider.ClickHouse/ClickHouseCodeFirst.cs +++ b/Providers/FreeSql.Provider.ClickHouse/ClickHouseCodeFirst.cs @@ -583,9 +583,13 @@ where a.database in ({0}) and a.table in ({1})", tboldname ?? tbname); if (isPrimary) { if (dbType.Contains("Nullable")) - return dbType.Replace("Nullable(", "") + { + var res = dbType.Replace("Nullable(", "") .Replace(")", "") .Replace(" NOT NULL", ""); + return res; + } + return dbType; } diff --git a/Providers/FreeSql.Provider.ClickHouse/ClickHouseExpression.cs b/Providers/FreeSql.Provider.ClickHouse/ClickHouseExpression.cs index cc613093..d4a7ea74 100644 --- a/Providers/FreeSql.Provider.ClickHouse/ClickHouseExpression.cs +++ b/Providers/FreeSql.Provider.ClickHouse/ClickHouseExpression.cs @@ -5,6 +5,7 @@ using System.Collections; using System.Collections.Generic; using System.Linq; using System.Linq.Expressions; +using System.Reflection; using System.Text; using System.Text.RegularExpressions; @@ -121,27 +122,51 @@ namespace FreeSql.ClickHouse case "First": case "FirstOrDefault": return $"substr({getExp(callExp.Arguments[0])}, 1, 1)"; + } } } if (objType == null) objType = callExp.Method.DeclaringType; if (objType != null || objType.IsArrayOrList()) { - if (argIndex >= callExp.Arguments.Count) break; - 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; + //if (argIndex >= callExp.Arguments.Count) break; + //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; var left = objExp == null ? null : getExp(objExp); - tsc.isNotSetMapColumnTmp = false; - tsc.SetMapColumnTmp(null).SetMapTypeReturnOld(oldMapType); - if (oldDbParams != null) tsc.SetDbParamsReturnOld(oldDbParams); + //tsc.isNotSetMapColumnTmp = false; + //tsc.SetMapColumnTmp(null).SetMapTypeReturnOld(oldMapType); + //if (oldDbParams != null) tsc.SetDbParamsReturnOld(oldDbParams); switch (callExp.Method.Name) { + 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 length({left}) end)"; + 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 length({left}) end > 0)"; case "Contains": - //判断 in //在各大 Provider AdoProvider 中已约定,500元素分割, 3空格\r\n4空格 - return $"(({args1}) in {left.Replace(", \r\n \r\n", $") \r\n OR ({args1}) in (")})"; + 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); + if (left.StartsWith("(") || left.EndsWith(")")) left = $"array[{left.TrimStart('(').TrimEnd(')')}]"; + return $"(hasAny({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 $"(arrayConcat({left} || {right2}))"; } } break; @@ -181,7 +206,6 @@ namespace FreeSql.ClickHouse } return null; } - public override string ExpressionLambdaToSqlMemberAccessString(MemberExpression exp, ExpTSC tsc) { if (exp.Expression == null) diff --git a/Providers/FreeSql.Provider.ClickHouse/ClickHouseExtensions.cs b/Providers/FreeSql.Provider.ClickHouse/ClickHouseExtensions.cs index bc3bc7c3..36428c07 100644 --- a/Providers/FreeSql.Provider.ClickHouse/ClickHouseExtensions.cs +++ b/Providers/FreeSql.Provider.ClickHouse/ClickHouseExtensions.cs @@ -2,24 +2,30 @@ using FreeSql.ClickHouse.Curd; using FreeSql.Internal.CommonProvider; using System; +using System.Collections.Generic; using System.Linq.Expressions; +using System.Threading; +using System.Threading.Tasks; +using FreeSql.DataAnnotations; public static partial class FreeSqlClickHouseGlobalExtensions { - /// /// 特殊处理类似 string.Format 的使用方法,防止注入,以及 IS NULL 转换 /// /// /// /// - public static string FormatClickHouse(this string that, params object[] args) => _clickHouseAdo.Addslashes(that, args); + public static string FormatClickHouse(this string that, params object[] args) => + _clickHouseAdo.Addslashes(that, args); + static FreeSql.ClickHouse.ClickHouseAdo _clickHouseAdo = new FreeSql.ClickHouse.ClickHouseAdo(); /// /// Clickhouse limit by /// - public static ISelect LimitBy(this ISelect that, Expression> selector, int limit, int offset = 0) + public static ISelect LimitBy(this ISelect that, Expression> selector, int limit, + int offset = 0) { if (limit <= 0 && offset <= 0) return that; var s0p = that as ClickHouseSelect; @@ -34,6 +40,7 @@ public static partial class FreeSqlClickHouseGlobalExtensions { s0p._orderby = oldOrderBy; } + return that; } @@ -52,4 +59,36 @@ public static partial class FreeSqlClickHouseGlobalExtensions s0p._sample = $"SAMPLE {k}"; return that; } + + /// + /// 批量快速插入 + /// + /// + /// + /// + public static async Task ExecuteBulkCopyAsync(this IInsert that) where T : class + { + try + { + var insert = that as ClickHouseInsert; + await insert.InternalBulkCopyAsync(); + } + catch (Exception e) + { + throw e; + } + + return 0; + } + + /// + /// 批量快速插入 + /// + /// + /// + /// + public static int ExecuteBulkCopy(this IInsert insert) where T : class + { + return ExecuteBulkCopyAsync(insert).ConfigureAwait(false).GetAwaiter().GetResult(); + } } diff --git a/Providers/FreeSql.Provider.ClickHouse/Curd/ClickHouseInsert.cs b/Providers/FreeSql.Provider.ClickHouse/Curd/ClickHouseInsert.cs index 0645397a..9b6eb58d 100644 --- a/Providers/FreeSql.Provider.ClickHouse/Curd/ClickHouseInsert.cs +++ b/Providers/FreeSql.Provider.ClickHouse/Curd/ClickHouseInsert.cs @@ -57,18 +57,7 @@ namespace FreeSql.ClickHouse.Curd { before = new Aop.CurdBeforeEventArgs(_table.Type, _table, Aop.CurdType.Insert, null, _params); _orm.Aop.CurdBeforeHandler?.Invoke(this, before); - var data = ToDataTable(); - using (var conn = _orm.Ado.MasterPool.Get()) - { - using (var bulkCopyInterface = new ClickHouseBulkCopy(conn.Value as ClickHouseConnection) - { - DestinationTableName = data.TableName, - BatchSize = _source.Count - }) - { - bulkCopyInterface.WriteToServerAsync(data, default).Wait(); - } - } + InternalBulkCopyAsync().ConfigureAwait(false).GetAwaiter().GetResult(); return affrows; } catch (Exception ex) @@ -85,6 +74,24 @@ namespace FreeSql.ClickHouse.Curd return base.RawExecuteAffrows(); } + internal async Task InternalBulkCopyAsync() + { + var data = ToDataTable(); + using (var conn = _orm.Ado.MasterPool.Get()) + { + using (var bulkCopyInterface = new ClickHouseBulkCopy(conn.Value as ClickHouseConnection) + { + DestinationTableName = data.TableName, + BatchSize = _source.Count + }) + { + await bulkCopyInterface.WriteToServerAsync(data, default); + } + } + return 0; + + } + private IDictionary GetValue(T u, System.Reflection.PropertyInfo[] columns) { try