From 54e1ed6fdb87e999d29ced1d9809bf9443eda85b Mon Sep 17 00:00:00 2001 From: Daily <963922242@qq.com> Date: Thu, 30 May 2024 10:47:10 +0800 Subject: [PATCH 1/4] =?UTF-8?q?=E6=B5=8B=E8=AF=95=E5=B9=B6=E4=BF=AE?= =?UTF-8?q?=E5=A4=8DCilckhouse=20CodeFirst=E4=B8=BB=E9=94=AE=E9=97=AE?= =?UTF-8?q?=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- FreeSql.DbContext/FreeSql.DbContext.xml | 9 + .../ClickHouse/ClickhouseIssueTest.cs | 136 ++++++++ FreeSql/FreeSql.xml | 299 ++++++++++++++++++ .../ClickHouseCodeFirst.cs | 34 +- 4 files changed, 459 insertions(+), 19 deletions(-) create mode 100644 FreeSql.Tests/FreeSql.Tests/ClickHouse/ClickhouseIssueTest.cs diff --git a/FreeSql.DbContext/FreeSql.DbContext.xml b/FreeSql.DbContext/FreeSql.DbContext.xml index 6c9bef48..197e6480 100644 --- a/FreeSql.DbContext/FreeSql.DbContext.xml +++ b/FreeSql.DbContext/FreeSql.DbContext.xml @@ -826,5 +826,14 @@ + + + 批量注入 Repository,可以参考代码自行调整 + + + + + + diff --git a/FreeSql.Tests/FreeSql.Tests/ClickHouse/ClickhouseIssueTest.cs b/FreeSql.Tests/FreeSql.Tests/ClickHouse/ClickhouseIssueTest.cs new file mode 100644 index 00000000..dac6315a --- /dev/null +++ b/FreeSql.Tests/FreeSql.Tests/ClickHouse/ClickhouseIssueTest.cs @@ -0,0 +1,136 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using FreeSql.DataAnnotations; +using Xunit; +using Xunit.Abstractions; + +namespace FreeSql.Tests.ClickHouse +{ + public class ClickhouseIssueTest + { + private readonly ITestOutputHelper _output; + + private static IFreeSql _fsql; + + public ClickhouseIssueTest(ITestOutputHelper output) + { + _output = output; + + _fsql = new FreeSqlBuilder().UseConnectionString(DataType.ClickHouse, + "Host=192.168.1.123;Port=8123;Database=test_issue;Compress=True;Min Pool Size=1") + .UseMonitorCommand(cmd => _output.WriteLine($"线程:{cmd.CommandText}\r\n")) + .UseNoneCommandParameter(true) + .UseAdoConnectionPool(true) + .Build(); + } + + #region https: //github.com/dotnetcore/FreeSql/issues/1813 + + [Fact] + public void TestIssue1813() + { + //var personsUpdate = new List + //{ + // new Person + // { + // Id = 1, + // Name = $"test2{DateTime.Now.Millisecond}", + // Age = 20, + // CreateTime = DateTime.Now + // }, + // new Person + // { + // Id = 2, + // Name = "test3"+ 286, + // Age = 22, + // CreateTime = DateTime.Now + // } + //}; + + //_fsql.Update().SetSource() + } + + [Fact] + public void TestIssue1813CodeFirst() + { + _fsql.CodeFirst.SyncStructure(); + var insertSingle = _fsql.Insert(new Person + { + Name = $"test{DateTime.Now.Millisecond}", + Age = 18, + CreateTime = DateTime.Now + }).ExecuteAffrows(); + + _output.WriteLine(insertSingle.ToString()); + + var persons = new List + { + new Person + { + Name = $"test2{DateTime.Now.Millisecond}", + Age = 20, + CreateTime = DateTime.Now + }, + new Person + { + Name = "test3" + 286, + Age = 22, + CreateTime = DateTime.Now + } + }; + + var insertMany = _fsql.Insert(persons).ExecuteAffrows(); + } + [Fact] + public void TestIssue1813CodeFirst2() + { + _fsql.CodeFirst.SyncStructure(); + var insertSingle = _fsql.Insert(new Person + { + Id = Guid.NewGuid().ToString(), + Name = $"test{DateTime.Now.Millisecond}", + Age = 18, + CreateTime = DateTime.Now + }).ExecuteAffrows(); + + _output.WriteLine(insertSingle.ToString()); + + var persons = new List + { + new Person + { + Id = Guid.NewGuid().ToString(), + Name = $"test2{DateTime.Now.Millisecond}", + Age = 20, + CreateTime = DateTime.Now + }, + new Person + { + Id = Guid.NewGuid().ToString(), + Name = "test3" + 286, + Age = 22, + CreateTime = DateTime.Now + } + }; + + var insertMany = _fsql.Insert(persons).ExecuteAffrows(); + } + + + + public class Person + { + [Column(IsPrimary = true, IsIdentity = true)] + public string Id { get; set; } + public string Name { get; set; } + public int Age { get; set; } + public DateTime CreateTime { get; set; } + public DateTime? UpdateTime { get; set; } + } + + #endregion + } +} \ No newline at end of file diff --git a/FreeSql/FreeSql.xml b/FreeSql/FreeSql.xml index 4bdcab9f..5f6a3f2a 100644 --- a/FreeSql/FreeSql.xml +++ b/FreeSql/FreeSql.xml @@ -1104,6 +1104,93 @@ + + + 动态创建实体类型 + + + + + 配置Class + + 类名 + 类标记的特性[Table(Name = "xxx")] [Index(xxxx)] + + + + + 获取类型构建器,可作为要构建的Type来引用 + + + + + 配置属性 + + 属性名称 + 属性类型 + 属性标记的特性-支持多个 + + + + + 配置属性 + + 属性名称 + 属性类型 + 该属性是否重写父类属性 + 属性标记的特性-支持多个 + + + + + 配置属性 + + 属性名称 + 属性类型 + 该属性是否重写父类属性 + 属性默认值 + 属性标记的特性-支持多个 + + + + + 配置父类 + + 父类类型 + + + + + Override属性 + + + + + + Emit动态创建出Class - Type + + + + + + Emit动态创建出Class - Type,不附带获取TableInfo + + + + + + 首字母小写 + + + + + + + 首字母大写 + + + + 获取实体的主键值,以 "*|_,[,_|*" 分割,当任意一个主键属性无值时,返回 "" @@ -3283,6 +3370,13 @@ + + + 执行SQL语句,返回更新后的记录 + 注意:此方法只有 Postgresql/SqlServer 有效果 + + + 指定事务对象 @@ -3627,6 +3721,177 @@ + + + 测试数据库是否连接正确,本方法执行如下命令: + MySql/SqlServer/PostgreSQL/达梦/人大金仓/神通: SELECT 1 + Oracle: SELECT 1 FROM dual + + 命令超时设置(秒) + + true: 成功, false: 失败 + + + + 查询,若使用读写分离,查询【从库】条件cmdText.StartsWith("SELECT "),否则查询【主库】 + + + + + + + + + + 查询,ExecuteReaderAsync(dr => {}, "select * from user where age > @age", new { age = 25 }) + 提示:parms 参数还可以传 Dictionary<string, object> + + + + + + + + + 查询 + + + + + + + + + 查询,ExecuteArrayAsync("select * from user where age > @age", new { age = 25 }) + 提示:parms 参数还可以传 Dictionary<string, object> + + + + + + + + + 查询 + + + + + + + + + 查询,ExecuteDataSetAsync("select * from user where age > @age; select 2", new { age = 25 }) + 提示:parms 参数还可以传 Dictionary<string, object> + + + + + + + + + 查询 + + + + + + + + + 查询,ExecuteDataTableAsync("select * from user where age > @age", new { age = 25 }) + 提示:parms 参数还可以传 Dictionary<string, object> + + + + + + + + + 在【主库】执行 + + + + + + + + + 在【主库】执行,ExecuteNonQueryAsync("delete from user where age > @age", new { age = 25 }) + 提示:parms 参数还可以传 Dictionary<string, object> + + + + + + + + + 在【主库】执行 + + + + + + + + + 在【主库】执行,ExecuteScalarAsync("select 1 from user where age > @age", new { age = 25 }) + 提示:parms 参数还可以传 Dictionary<string, object> + + + + + + + + + 执行SQL返回对象集合,QueryAsync<User>("select * from user where age > @age", new SqlParameter { ParameterName = "age", Value = 25 }) + + + + + + + + + + + 执行SQL返回对象集合,QueryAsync<User>("select * from user where age > @age", new { age = 25 }) + 提示:parms 参数还可以传 Dictionary<string, object> + + + + + + + + + + 执行SQL返回对象集合,Query<User>("select * from user where age > @age; select * from address", new SqlParameter { ParameterName = "age", Value = 25 }) + + + + + + + + + + + + 执行SQL返回对象集合,Query<User, Address>("select * from user where age > @age; select * from address", new { age = 25 }) + 提示:parms 参数还可以传 Dictionary<string, object> + + + + + + + + 可自定义解析表达式 @@ -4626,6 +4891,12 @@ 超时 + + + 获取资源 + + + 使用完毕后,归还资源 @@ -4701,6 +4972,12 @@ 资源对象 + + + 从对象池获取对象成功的时候触发,通过该方法统计或初始化对象 + + 资源对象 + 归还对象给对象池的时候触发 @@ -5631,6 +5908,28 @@ 请使用 fsql.InsertDict(dict) 方法插入字典数据 + + + 动态构建Class Type + + + + + + 根据字典,创建 table 对应的实体对象 + + + + + + + + 根据实体对象,创建 table 对应的字典 + + + + + C#: that >= between && that <= and diff --git a/Providers/FreeSql.Provider.ClickHouse/ClickHouseCodeFirst.cs b/Providers/FreeSql.Provider.ClickHouse/ClickHouseCodeFirst.cs index bd4e4854..15704eef 100644 --- a/Providers/FreeSql.Provider.ClickHouse/ClickHouseCodeFirst.cs +++ b/Providers/FreeSql.Provider.ClickHouse/ClickHouseCodeFirst.cs @@ -254,25 +254,25 @@ namespace FreeSql.ClickHouse sb.Append("TYPE set(8192) GRANULARITY 5,"); } - sb.Remove(sb.Length - 1, 1); + //sb.Remove(sb.Length - 1, 1); + + if (tb.Primarys.Any()) + { + var primaryKeys = string.Join(",", tb.Primarys.Select(p => _commonUtils.QuoteSqlName(p.Attribute.Name))); + sb.Append(" \r\n PRIMARY KEY "); + sb.Append($"( {primaryKeys} ) "); + } + sb.Append("\r\n) "); sb.Append("\r\nENGINE = MergeTree()"); if (tb.Primarys.Any()) { - sb.Append(" \r\nORDER BY ( "); - var ls = new StringBuilder(); - foreach (var tbcol in tb.Primarys) - ls.Append(_commonUtils.QuoteSqlName(tbcol.Attribute.Name)).Append(", "); - sb.Append(ls); - sb.Remove(sb.Length - 2, 2); - sb.Append(" )"); - sb.Append(" \r\nPRIMARY KEY "); - sb.Append($"({ls}) "); - sb.Remove(sb.Length - 2, 2).Append(","); + var primaryKeys = string.Join(",", tb.Primarys.Select(p => _commonUtils.QuoteSqlName(p.Attribute.Name))); + sb.Append(" \r\nORDER BY "); + sb.Append($"( {primaryKeys} ) "); } - sb.Remove(sb.Length - 1, 1); //if (string.IsNullOrEmpty(tb.Comment) == false) // sb.Append(" Comment=").Append(_commonUtils.FormatSql("{0}", tb.Comment)); sb.Append(" SETTINGS index_granularity = 8192;\r\n"); @@ -477,16 +477,12 @@ where a.database in ({0}) and a.table in ({1})", tboldname ?? tbname); if (tb.Primarys.Any()) { + var primaryKeys = string.Join(",", tb.Primarys.Select(p => _commonUtils.QuoteSqlName(p.Attribute.Name))); sb.Append(" \r\nORDER BY ( "); - var ls = new StringBuilder(); - foreach (var tbcol in tb.Primarys) - ls.Append(_commonUtils.QuoteSqlName(tbcol.Attribute.Name)).Append(", "); - sb.Append(ls); - sb.Remove(sb.Length - 2, 2); + sb.Append(primaryKeys); sb.Append(" )"); sb.Append(" \r\nPRIMARY KEY "); - sb.Append($"({ls}) "); - sb.Remove(sb.Length - 2, 2).Append(","); + sb.Append($"({primaryKeys}) "); } sb.Remove(sb.Length - 1, 1); From 9aef33e3df2951039ff2d3db3a9c9e397ae2c969 Mon Sep 17 00:00:00 2001 From: Daily <963922242@qq.com> Date: Thu, 30 May 2024 11:27:49 +0800 Subject: [PATCH 2/4] =?UTF-8?q?=E8=A7=A3=E5=86=B3ClickHouse=20=E6=89=B9?= =?UTF-8?q?=E9=87=8F=E6=9B=B4=E6=96=B0DateTime=E9=97=AE=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../ClickHouse/ClickhouseIssueTest.cs | 48 +++++++++++-------- .../ClickHouseUtils.cs | 2 +- .../Curd/ClickHouseUpdate.cs | 11 +++++ 3 files changed, 41 insertions(+), 20 deletions(-) diff --git a/FreeSql.Tests/FreeSql.Tests/ClickHouse/ClickhouseIssueTest.cs b/FreeSql.Tests/FreeSql.Tests/ClickHouse/ClickhouseIssueTest.cs index dac6315a..71bf127f 100644 --- a/FreeSql.Tests/FreeSql.Tests/ClickHouse/ClickhouseIssueTest.cs +++ b/FreeSql.Tests/FreeSql.Tests/ClickHouse/ClickhouseIssueTest.cs @@ -22,7 +22,7 @@ namespace FreeSql.Tests.ClickHouse _fsql = new FreeSqlBuilder().UseConnectionString(DataType.ClickHouse, "Host=192.168.1.123;Port=8123;Database=test_issue;Compress=True;Min Pool Size=1") .UseMonitorCommand(cmd => _output.WriteLine($"线程:{cmd.CommandText}\r\n")) - .UseNoneCommandParameter(true) + .UseNoneCommandParameter(false) .UseAdoConnectionPool(true) .Build(); } @@ -32,25 +32,35 @@ namespace FreeSql.Tests.ClickHouse [Fact] public void TestIssue1813() { - //var personsUpdate = new List - //{ - // new Person - // { - // Id = 1, - // Name = $"test2{DateTime.Now.Millisecond}", - // Age = 20, - // CreateTime = DateTime.Now - // }, - // new Person - // { - // Id = 2, - // Name = "test3"+ 286, - // Age = 22, - // CreateTime = DateTime.Now - // } - //}; + //普通修改 + _fsql.Update() + .Set(p => p.Name == "update_name") + .Set(p => p.UpdateTime == DateTime.Now) + .Where(p => p.Id == "25e8d92e-29f2-43ff-b861-9ade0eec4041") + .ExecuteAffrows(); + + //批量修改 + var updatePerson = new List(); + updatePerson.Add(new Person + { + Id = "9cd7af52-85cc-4d26-898a-4020cadb0491", + Name = "update_name1", + UpdateTime = DateTime.Now + }); + + updatePerson.Add(new Person + { + Id = "bd9f9ed6-bd03-4675-abb4-12b7fdac7678", + Name = "update_name2", + UpdateTime = DateTime.Now + }); + + _fsql.Update().SetSource(updatePerson).UpdateColumns(person => new + { + person.Name, + person.UpdateTime, + }).ExecuteAffrows(); - //_fsql.Update().SetSource() } [Fact] diff --git a/Providers/FreeSql.Provider.ClickHouse/ClickHouseUtils.cs b/Providers/FreeSql.Provider.ClickHouse/ClickHouseUtils.cs index a4b93bb2..0061b284 100644 --- a/Providers/FreeSql.Provider.ClickHouse/ClickHouseUtils.cs +++ b/Providers/FreeSql.Provider.ClickHouse/ClickHouseUtils.cs @@ -158,7 +158,7 @@ namespace FreeSql.ClickHouse var ts = (TimeSpan)value; value = $"{Math.Floor(ts.TotalHours)}:{ts.Minutes}:{ts.Seconds}"; } - else if (value is Array) + else if (value is Array) { var valueArr = value as Array; var eleType = type.GetElementType(); diff --git a/Providers/FreeSql.Provider.ClickHouse/Curd/ClickHouseUpdate.cs b/Providers/FreeSql.Provider.ClickHouse/Curd/ClickHouseUpdate.cs index 3714bc27..740f63be 100644 --- a/Providers/FreeSql.Provider.ClickHouse/Curd/ClickHouseUpdate.cs +++ b/Providers/FreeSql.Provider.ClickHouse/Curd/ClickHouseUpdate.cs @@ -7,6 +7,7 @@ using System.Linq; using System.Text; using System.Threading; using System.Threading.Tasks; +using DateTime = System.DateTime; namespace FreeSql.ClickHouse.Curd { @@ -167,6 +168,16 @@ namespace FreeSql.ClickHouse.Curd var colsql = _noneParameter ? _commonUtils.GetNoneParamaterSqlValue(_paramsSource, "u", col, col.Attribute.MapType, val) : _commonUtils.QuoteWriteParamterAdapter(col.Attribute.MapType, _commonUtils.QuoteParamterName($"p_{_paramsSource.Count}")); + + //判断是否是DateTime类型,如果是DateTime类型,需要转换成ClickHouse支持的时间格式 + if (col.Attribute.MapType == typeof(DateTime) || col.Attribute.MapType == typeof(DateTime?) ) + { + //获取当前实时区 + var timeZone = TimeZoneInfo.Local; + + colsql = $"toDateTime({colsql},'Asia/Shanghai')"; + } + cwsb.Append(_commonUtils.RewriteColumn(col, colsql)); if (_noneParameter == false) _commonUtils.AppendParamter(_paramsSource, null, col, col.Attribute.MapType, val); From 989cf290f645bb3552ff578ed0ba18e7d32cb7d0 Mon Sep 17 00:00:00 2001 From: Daily <963922242@qq.com> Date: Thu, 30 May 2024 11:39:48 +0800 Subject: [PATCH 3/4] =?UTF-8?q?=E6=B5=8B=E8=AF=95ClickHouse=20=E6=89=B9?= =?UTF-8?q?=E9=87=8F=E6=9B=B4=E6=96=B0DateTime=E9=97=AE=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../ClickHouse/ClickhouseIssueTest.cs | 24 +++++++++++-------- .../Curd/ClickHouseUpdate.cs | 2 -- 2 files changed, 14 insertions(+), 12 deletions(-) diff --git a/FreeSql.Tests/FreeSql.Tests/ClickHouse/ClickhouseIssueTest.cs b/FreeSql.Tests/FreeSql.Tests/ClickHouse/ClickhouseIssueTest.cs index 71bf127f..cf84442a 100644 --- a/FreeSql.Tests/FreeSql.Tests/ClickHouse/ClickhouseIssueTest.cs +++ b/FreeSql.Tests/FreeSql.Tests/ClickHouse/ClickhouseIssueTest.cs @@ -22,7 +22,7 @@ namespace FreeSql.Tests.ClickHouse _fsql = new FreeSqlBuilder().UseConnectionString(DataType.ClickHouse, "Host=192.168.1.123;Port=8123;Database=test_issue;Compress=True;Min Pool Size=1") .UseMonitorCommand(cmd => _output.WriteLine($"线程:{cmd.CommandText}\r\n")) - .UseNoneCommandParameter(false) + .UseNoneCommandParameter(true) .UseAdoConnectionPool(true) .Build(); } @@ -45,22 +45,25 @@ namespace FreeSql.Tests.ClickHouse { Id = "9cd7af52-85cc-4d26-898a-4020cadb0491", Name = "update_name1", - UpdateTime = DateTime.Now + UpdateTime = DateTime.Now, + CreateTime = DateTime.Parse("2024-05-30 10:01:02") }); updatePerson.Add(new Person { Id = "bd9f9ed6-bd03-4675-abb4-12b7fdac7678", Name = "update_name2", - UpdateTime = DateTime.Now + UpdateTime = DateTime.Now, + CreateTime = DateTime.Parse("2024-05-30 10:01:02") }); - _fsql.Update().SetSource(updatePerson).UpdateColumns(person => new - { - person.Name, - person.UpdateTime, - }).ExecuteAffrows(); - + var sql = _fsql.Update().SetSource(updatePerson) + .UpdateColumns(person => new + { + person.Name, + person.UpdateTime, + person.CreateTime + }).ToSql(); } [Fact] @@ -94,6 +97,7 @@ namespace FreeSql.Tests.ClickHouse var insertMany = _fsql.Insert(persons).ExecuteAffrows(); } + [Fact] public void TestIssue1813CodeFirst2() { @@ -130,11 +134,11 @@ namespace FreeSql.Tests.ClickHouse } - public class Person { [Column(IsPrimary = true, IsIdentity = true)] public string Id { get; set; } + public string Name { get; set; } public int Age { get; set; } public DateTime CreateTime { get; set; } diff --git a/Providers/FreeSql.Provider.ClickHouse/Curd/ClickHouseUpdate.cs b/Providers/FreeSql.Provider.ClickHouse/Curd/ClickHouseUpdate.cs index 740f63be..9f90cdab 100644 --- a/Providers/FreeSql.Provider.ClickHouse/Curd/ClickHouseUpdate.cs +++ b/Providers/FreeSql.Provider.ClickHouse/Curd/ClickHouseUpdate.cs @@ -173,8 +173,6 @@ namespace FreeSql.ClickHouse.Curd if (col.Attribute.MapType == typeof(DateTime) || col.Attribute.MapType == typeof(DateTime?) ) { //获取当前实时区 - var timeZone = TimeZoneInfo.Local; - colsql = $"toDateTime({colsql},'Asia/Shanghai')"; } From a53cbdd3db9a6490b28c8d0e1caf7711d28b86e8 Mon Sep 17 00:00:00 2001 From: Daily <963922242@qq.com> Date: Thu, 30 May 2024 14:30:08 +0800 Subject: [PATCH 4/4] =?UTF-8?q?ClickHouse=E8=A1=A8=E5=88=86=E5=8C=BA?= =?UTF-8?q?=E6=94=AF=E6=8C=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../ClickHouse/ClickhouseIssueTest.cs | 32 +++++++++++++++ .../ClickHousePartitionAttribute.cs | 17 ++++++++ .../ClickHouseCodeFirst.cs | 40 +++++++++++++++---- 3 files changed, 81 insertions(+), 8 deletions(-) create mode 100644 Providers/FreeSql.Provider.ClickHouse/Attributes/ClickHousePartitionAttribute.cs diff --git a/FreeSql.Tests/FreeSql.Tests/ClickHouse/ClickhouseIssueTest.cs b/FreeSql.Tests/FreeSql.Tests/ClickHouse/ClickhouseIssueTest.cs index cf84442a..a518aeff 100644 --- a/FreeSql.Tests/FreeSql.Tests/ClickHouse/ClickhouseIssueTest.cs +++ b/FreeSql.Tests/FreeSql.Tests/ClickHouse/ClickhouseIssueTest.cs @@ -4,6 +4,7 @@ using System.Linq; using System.Text; using System.Threading.Tasks; using FreeSql.DataAnnotations; +using FreeSql.Provider.ClickHouse.Attributes; using Xunit; using Xunit.Abstractions; @@ -141,10 +142,41 @@ namespace FreeSql.Tests.ClickHouse public string Name { get; set; } public int Age { get; set; } + public DateTime CreateTime { get; set; } + public DateTime? UpdateTime { get; set; } } #endregion + + #region https: //github.com/dotnetcore/FreeSql/issues/1814 + + public class Test1814Table + { + [Column(IsPrimary = true, IsIdentity = true)] + public int Id { get; set; } + + public string Name { get; set; } + + [ClickHousePartition] + [Column(Name = "create_time")] + public DateTime CreateTime { get; set; } + } + + [Fact] + public void TestIssue1814() + { + _fsql.CodeFirst.SyncStructure(); + + var insert = _fsql.Insert(new Test1814Table + { + Name = "test", + CreateTime = DateTime.Now + }).ExecuteAffrows(); + + var query = _fsql.Select().ToList(); + } + #endregion } } \ No newline at end of file diff --git a/Providers/FreeSql.Provider.ClickHouse/Attributes/ClickHousePartitionAttribute.cs b/Providers/FreeSql.Provider.ClickHouse/Attributes/ClickHousePartitionAttribute.cs new file mode 100644 index 00000000..c19c31dd --- /dev/null +++ b/Providers/FreeSql.Provider.ClickHouse/Attributes/ClickHousePartitionAttribute.cs @@ -0,0 +1,17 @@ +using System; +using System.Collections.Generic; +using System.Text; + +namespace FreeSql.Provider.ClickHouse.Attributes +{ + [AttributeUsage(AttributeTargets.Property)] + public class ClickHousePartitionAttribute : Attribute + { + public ClickHousePartitionAttribute(string format = "toYYYYMM({0})") + { + Format = format; + } + + public string Format { get; set; } + } +} \ No newline at end of file diff --git a/Providers/FreeSql.Provider.ClickHouse/ClickHouseCodeFirst.cs b/Providers/FreeSql.Provider.ClickHouse/ClickHouseCodeFirst.cs index 15704eef..110172ee 100644 --- a/Providers/FreeSql.Provider.ClickHouse/ClickHouseCodeFirst.cs +++ b/Providers/FreeSql.Provider.ClickHouse/ClickHouseCodeFirst.cs @@ -8,8 +8,10 @@ using System.Linq; using System.Text; using System.Text.RegularExpressions; using System.Data.Common; +using System.Reflection; using FreeSql.Internal.ObjectPool; using ClickHouse.Client.ADO; +using FreeSql.Provider.ClickHouse.Attributes; namespace FreeSql.ClickHouse { @@ -95,10 +97,11 @@ namespace FreeSql.ClickHouse { var arrayDbType = $"Array({value.dbtype})"; var defaultArray = new ArrayList(0); - return new DbInfoResult(Convert.ToInt32(DbType.Object), arrayDbType, arrayDbType, false,defaultArray); + return new DbInfoResult(Convert.ToInt32(DbType.Object), arrayDbType, arrayDbType, false, + defaultArray); } - } + return null; } @@ -132,7 +135,7 @@ namespace FreeSql.ClickHouse if (interfaces.Any(t => t.Name == "IEnumerable")) flag = true; - if (type.Name == "Array") + if (type.Name == "Array") { flag = true; resultType = typeof(string); @@ -173,7 +176,8 @@ namespace FreeSql.ClickHouse if (tb == null) throw new Exception(CoreStrings.S_Type_IsNot_Migrable(obj.tableSchema.Type.FullName)); if (tb.Columns.Any() == false) - throw new Exception(CoreStrings.S_Type_IsNot_Migrable_0Attributes(obj.tableSchema.Type.FullName)); + throw new Exception( + CoreStrings.S_Type_IsNot_Migrable_0Attributes(obj.tableSchema.Type.FullName)); var tbname = _commonUtils.SplitTableName(tb.DbName); if (tbname?.Length == 1) tbname = new[] { database, tbname[0] }; @@ -258,7 +262,8 @@ namespace FreeSql.ClickHouse if (tb.Primarys.Any()) { - var primaryKeys = string.Join(",", tb.Primarys.Select(p => _commonUtils.QuoteSqlName(p.Attribute.Name))); + var primaryKeys = string.Join(",", + tb.Primarys.Select(p => _commonUtils.QuoteSqlName(p.Attribute.Name))); sb.Append(" \r\n PRIMARY KEY "); sb.Append($"( {primaryKeys} ) "); } @@ -268,14 +273,32 @@ namespace FreeSql.ClickHouse if (tb.Primarys.Any()) { - var primaryKeys = string.Join(",", tb.Primarys.Select(p => _commonUtils.QuoteSqlName(p.Attribute.Name))); + var primaryKeys = string.Join(",", + tb.Primarys.Select(p => _commonUtils.QuoteSqlName(p.Attribute.Name))); sb.Append(" \r\nORDER BY "); sb.Append($"( {primaryKeys} ) "); } + //查找属性是否标记了分区特性 + var partitionColumnInfos = tb.Properties.Where( + c => c.Value.GetCustomAttribute() != null).ToList(); + + if (partitionColumnInfos != null && partitionColumnInfos.Any()) + { + var partitionProperty = partitionColumnInfos.First(); + + var partitionColumnInfo = tb.Columns.FirstOrDefault(pair => + pair.Value.CsName == partitionProperty.Value.Name); + var partitionName = _commonUtils.QuoteSqlName(partitionColumnInfo.Value.Attribute.Name); + var partitionAttribute = partitionProperty.Value + .GetCustomAttribute(); + sb.Append($" \r\nPARTITION BY {string.Format(partitionAttribute.Format, partitionName)}"); + } + + //if (string.IsNullOrEmpty(tb.Comment) == false) // sb.Append(" Comment=").Append(_commonUtils.FormatSql("{0}", tb.Comment)); - sb.Append(" SETTINGS index_granularity = 8192;\r\n"); + sb.Append(" \r\nSETTINGS index_granularity = 8192;\r\n"); continue; } @@ -477,7 +500,8 @@ where a.database in ({0}) and a.table in ({1})", tboldname ?? tbname); if (tb.Primarys.Any()) { - var primaryKeys = string.Join(",", tb.Primarys.Select(p => _commonUtils.QuoteSqlName(p.Attribute.Name))); + var primaryKeys = string.Join(",", + tb.Primarys.Select(p => _commonUtils.QuoteSqlName(p.Attribute.Name))); sb.Append(" \r\nORDER BY ( "); sb.Append(primaryKeys); sb.Append(" )");