diff --git a/FreeSql.Repository/FreeSql.Repository.csproj b/FreeSql.Repository/FreeSql.Repository.csproj index dd70adab..df8463e1 100644 --- a/FreeSql.Repository/FreeSql.Repository.csproj +++ b/FreeSql.Repository/FreeSql.Repository.csproj @@ -1,21 +1,21 @@  - - netstandard2.0 - 0.3.14 - YeXiangQin - FreeSql 通用仓库层实现,支持 MySql/SqlServer/PostgreSQL/Oracle/Sqlite,读写分离、分表分库。 - https://github.com/2881099/FreeSql - FreeSql ORM Repository - true - + + netstandard2.0 + 0.3.15 + YeXiangQin + FreeSql Implementation of General Repository, Support MySql/SqlServer/PostgreSQL/Oracle/Sqlite, and read/write separation、and split table. + https://github.com/2881099/FreeSql/wiki/Repository + FreeSql ORM Repository + true + - - - + + + - - - + + + diff --git a/FreeSql.Tests/MySql/Curd/MySqlSelectTest.cs b/FreeSql.Tests/MySql/Curd/MySqlSelectTest.cs index 9a3782ed..74f0aa64 100644 --- a/FreeSql.Tests/MySql/Curd/MySqlSelectTest.cs +++ b/FreeSql.Tests/MySql/Curd/MySqlSelectTest.cs @@ -95,8 +95,8 @@ namespace FreeSql.Tests.MySql { Assert.Equal(1, g.mysql.Insert().AppendData(items.First()).ExecuteAffrows()); Assert.Equal(10, g.mysql.Insert().AppendData(items).ExecuteAffrows()); - items = Enumerable.Range(0, 9989).Select(a => new Topic { Title = "newtitle" + a, CreateTime = DateTime.Now }).ToList(); - Assert.Equal(9989, g.mysql.Insert(items).ExecuteAffrows()); + //items = Enumerable.Range(0, 9989).Select(a => new Topic { Title = "newtitle" + a, CreateTime = DateTime.Now }).ToList(); + //Assert.Equal(9989, g.mysql.Insert(items).ExecuteAffrows()); var dt1 = select.Limit(10).ToDataTable(); var dt2 = select.Limit(10).ToDataTable("id, 111222"); diff --git a/FreeSql.Tests/Oracle/Curd/OracleSelectTest.cs b/FreeSql.Tests/Oracle/Curd/OracleSelectTest.cs index 015a70f2..ecb04ba4 100644 --- a/FreeSql.Tests/Oracle/Curd/OracleSelectTest.cs +++ b/FreeSql.Tests/Oracle/Curd/OracleSelectTest.cs @@ -32,16 +32,25 @@ namespace FreeSql.Tests.Oracle { public List Types { get; set; } } + class TopicInserts { + public Guid Id { get; set; } + public int Clicks { get; set; } + public int TestTypeInfoGuid { get; set; } + public TestTypeInfo Type { get; set; } + public string Title { get; set; } + public DateTime CreateTime { get; set; } + } + [Fact] public void ToDataTable() { - var items = new List(); - for (var a = 0; a < 10; a++) items.Add(new Topic { Id = a + 1, Title = $"newtitle{a}", Clicks = a * 100, CreateTime = DateTime.Now }); + var items = new List(); + for (var a = 0; a < 11; a++) items.Add(new TopicInserts { Title = $"newtitle{a}", Clicks = a * 100, CreateTime = DateTime.Now }); - Assert.Equal(1, g.oracle.Insert().AppendData(items.First()).ExecuteAffrows()); - Assert.Equal(10, g.oracle.Insert().AppendData(items).ExecuteAffrows()); + //Assert.Equal(1, g.oracle.Insert().AppendData(items.First()).ExecuteAffrows()); + Assert.Equal(11, g.oracle.Insert().AppendData(items).ExecuteAffrows()); - items = Enumerable.Range(0, 9989).Select(a => new Topic { Title = "newtitle" + a, CreateTime = DateTime.Now }).ToList(); - Assert.Equal(9989, g.oracle.Insert(items).ExecuteAffrows()); + //items = Enumerable.Range(0, 9989).Select(a => new TopicInserts { Title = "newtitle" + a, CreateTime = DateTime.Now }).ToList(); + //Assert.Equal(9989, g.oracle.Insert(items).ExecuteAffrows()); var dt1 = select.Limit(10).ToDataTable(); var dt2 = select.Limit(10).ToDataTable("id, 111222"); diff --git a/FreeSql.Tests/PostgreSQL/Curd/PostgreSQLSelectTest.cs b/FreeSql.Tests/PostgreSQL/Curd/PostgreSQLSelectTest.cs index 28009ff5..3173de2d 100644 --- a/FreeSql.Tests/PostgreSQL/Curd/PostgreSQLSelectTest.cs +++ b/FreeSql.Tests/PostgreSQL/Curd/PostgreSQLSelectTest.cs @@ -32,6 +32,21 @@ namespace FreeSql.Tests.PostgreSQL { public List Types { get; set; } } + [Fact] + public void ToDataTable() { + var items = new List(); + for (var a = 0; a < 10; a++) items.Add(new Topic { Id = a + 1, Title = $"newtitle{a}", Clicks = a * 100, CreateTime = DateTime.Now }); + + Assert.Single(g.pgsql.Insert().AppendData(items.First()).ExecuteInserted()); + Assert.Equal(10, g.pgsql.Insert().AppendData(items).ExecuteInserted().Count); + + //items = Enumerable.Range(0, 9989).Select(a => new Topic { Title = "newtitle" + a, CreateTime = DateTime.Now }).ToList(); + //Assert.Equal(9989, g.pgsql.Insert(items).ExecuteAffrows()); + + var dt1 = select.Limit(10).ToDataTable(); + var dt2 = select.Limit(10).ToDataTable("id, 222"); + var dt3 = select.Limit(10).ToDataTable(a => new { a.Id, a.Type.Name, now = DateTime.Now }); + } [Fact] public void ToList() { var t1 = g.pgsql.Select().Where("").Where(a => a.Id > 0).Skip(100).Limit(200).ToSql(); diff --git a/FreeSql.Tests/SqlServer/Curd/SqlServerDeleteTest.cs b/FreeSql.Tests/SqlServer/Curd/SqlServerDeleteTest.cs index c48cd061..d3f78e56 100644 --- a/FreeSql.Tests/SqlServer/Curd/SqlServerDeleteTest.cs +++ b/FreeSql.Tests/SqlServer/Curd/SqlServerDeleteTest.cs @@ -69,7 +69,7 @@ namespace FreeSql.Tests.SqlServer { var item = g.sqlserver.Insert(new Topic { Title = "xxxx", CreateTime = DateTime.Now }).ExecuteInserted(); Assert.Equal(item[0].Id, delete.Where(a => a.Id == item[0].Id).ExecuteDeleted()[0].Id); - var items = Enumerable.Range(0, 3001).Select(a => new Topic { Title = "xxxx" + a, CreateTime = DateTime.Now }); + var items = Enumerable.Range(0, 301).Select(a => new Topic { Title = "xxxx" + a, CreateTime = DateTime.Now }); var itemsInserted = g.sqlserver.Insert(items).ExecuteInserted(); Assert.Equal(items.First().Title, itemsInserted[0].Title); diff --git a/FreeSql.Tests/SqlServer/Curd/SqlServerInsertTest.cs b/FreeSql.Tests/SqlServer/Curd/SqlServerInsertTest.cs index 6ac71c5b..5ffab670 100644 --- a/FreeSql.Tests/SqlServer/Curd/SqlServerInsertTest.cs +++ b/FreeSql.Tests/SqlServer/Curd/SqlServerInsertTest.cs @@ -14,6 +14,7 @@ namespace FreeSql.Tests.SqlServer { [Column(IsIdentity = true, IsPrimary = true)] public int Id { get; set; } public int? Clicks { get; set; } + public int TestTypeInfoGuid { get; set; } public TestTypeInfo Type { get; set; } public string Title { get; set; } public DateTime CreateTime { get; set; } @@ -24,16 +25,16 @@ namespace FreeSql.Tests.SqlServer { var items = new List(); for (var a = 0; a < 10; a++) items.Add(new Topic { Id = a + 1, Title = $"newtitle{a}", Clicks = a * 100, CreateTime = DateTime.Now }); - var sql = insert.AppendData(items.First()).ToSql(); + var sql = insert.IgnoreColumns(a => a.TestTypeInfoGuid).AppendData(items.First()).ToSql(); Assert.Equal("INSERT INTO [tb_topic]([Clicks], [Title], [CreateTime]) VALUES(@Clicks0, @Title0, @CreateTime0)", sql); - sql = insert.AppendData(items).ToSql(); + sql = insert.IgnoreColumns(a => a.TestTypeInfoGuid).AppendData(items).ToSql(); Assert.Equal("INSERT INTO [tb_topic]([Clicks], [Title], [CreateTime]) VALUES(@Clicks0, @Title0, @CreateTime0), (@Clicks1, @Title1, @CreateTime1), (@Clicks2, @Title2, @CreateTime2), (@Clicks3, @Title3, @CreateTime3), (@Clicks4, @Title4, @CreateTime4), (@Clicks5, @Title5, @CreateTime5), (@Clicks6, @Title6, @CreateTime6), (@Clicks7, @Title7, @CreateTime7), (@Clicks8, @Title8, @CreateTime8), (@Clicks9, @Title9, @CreateTime9)", sql); sql = insert.AppendData(items).InsertColumns(a => a.Title).ToSql(); Assert.Equal("INSERT INTO [tb_topic]([Title]) VALUES(@Title0), (@Title1), (@Title2), (@Title3), (@Title4), (@Title5), (@Title6), (@Title7), (@Title8), (@Title9)", sql); - sql = insert.AppendData(items).IgnoreColumns(a => a.CreateTime).ToSql(); + sql = insert.IgnoreColumns(a => new { a.CreateTime, a.TestTypeInfoGuid }).AppendData(items).ToSql(); Assert.Equal("INSERT INTO [tb_topic]([Clicks], [Title]) VALUES(@Clicks0, @Title0), (@Clicks1, @Title1), (@Clicks2, @Title2), (@Clicks3, @Title3), (@Clicks4, @Title4), (@Clicks5, @Title5), (@Clicks6, @Title6), (@Clicks7, @Title7), (@Clicks8, @Title8), (@Clicks9, @Title9)", sql); } @@ -53,10 +54,10 @@ namespace FreeSql.Tests.SqlServer { var items = new List(); for (var a = 0; a < 10; a++) items.Add(new Topic { Id = a + 1, Title = $"newtitle{a}", Clicks = a * 100, CreateTime = DateTime.Now }); - var sql = insert.AppendData(items).IgnoreColumns(a => a.CreateTime).ToSql(); + var sql = insert.AppendData(items).IgnoreColumns(a => new { a.CreateTime, a.TestTypeInfoGuid }).ToSql(); Assert.Equal("INSERT INTO [tb_topic]([Clicks], [Title]) VALUES(@Clicks0, @Title0), (@Clicks1, @Title1), (@Clicks2, @Title2), (@Clicks3, @Title3), (@Clicks4, @Title4), (@Clicks5, @Title5), (@Clicks6, @Title6), (@Clicks7, @Title7), (@Clicks8, @Title8), (@Clicks9, @Title9)", sql); - sql = insert.AppendData(items).IgnoreColumns(a => new { a.Title, a.CreateTime }).ToSql(); + sql = insert.AppendData(items).IgnoreColumns(a => new { a.Title, a.CreateTime, a.TestTypeInfoGuid }).ToSql(); Assert.Equal("INSERT INTO [tb_topic]([Clicks]) VALUES(@Clicks0), (@Clicks1), (@Clicks2), (@Clicks3), (@Clicks4), (@Clicks5), (@Clicks6), (@Clicks7), (@Clicks8), (@Clicks9)", sql); } [Fact] @@ -67,8 +68,8 @@ namespace FreeSql.Tests.SqlServer { Assert.Equal(1, insert.AppendData(items.First()).ExecuteAffrows()); Assert.Equal(10, insert.AppendData(items).ExecuteAffrows()); - items = Enumerable.Range(0, 9989).Select(a => new Topic { Title = "newtitle" + a, CreateTime = DateTime.Now }).ToList(); - Assert.Equal(9989, g.sqlserver.Insert(items).ExecuteAffrows()); + //items = Enumerable.Range(0, 9989).Select(a => new Topic { Title = "newtitle" + a, CreateTime = DateTime.Now }).ToList(); + //Assert.Equal(9989, g.sqlserver.Insert(items).ExecuteAffrows()); } [Fact] public void ExecuteIdentity() { @@ -78,9 +79,9 @@ namespace FreeSql.Tests.SqlServer { Assert.NotEqual(0, insert.AppendData(items.First()).ExecuteIdentity()); - items = Enumerable.Range(0, 9999).Select(a => new Topic { Title = "newtitle" + a, CreateTime = DateTime.Now }).ToList(); - var lastId = g.sqlite.Select().Max(a => a.Id); - Assert.NotEqual(lastId, g.sqlserver.Insert(items).ExecuteIdentity()); + //items = Enumerable.Range(0, 9999).Select(a => new Topic { Title = "newtitle" + a, CreateTime = DateTime.Now }).ToList(); + //var lastId = g.sqlite.Select().Max(a => a.Id); + //Assert.NotEqual(lastId, g.sqlserver.Insert(items).ExecuteIdentity()); } [Fact] public void ExecuteInserted() { @@ -89,7 +90,7 @@ namespace FreeSql.Tests.SqlServer { var items2 = insert.AppendData(items).ExecuteInserted(); - items = Enumerable.Range(0, 9990).Select(a => new Topic { Title = "newtitle" + a, CreateTime = DateTime.Now }).ToList(); + items = Enumerable.Range(0, 90).Select(a => new Topic { Title = "newtitle" + a, CreateTime = DateTime.Now }).ToList(); var itemsInserted = g.sqlserver.Insert(items).ExecuteInserted(); Assert.Equal(items.First().Title, itemsInserted.First().Title); Assert.Equal(items.Last().Title, itemsInserted.Last().Title); @@ -100,28 +101,28 @@ namespace FreeSql.Tests.SqlServer { var items = new List(); for (var a = 0; a < 10; a++) items.Add(new Topic { Id = a + 1, Title = $"newtitle{a}", Clicks = a * 100, CreateTime = DateTime.Now }); - var sql = insert.AppendData(items.First()).AsTable(a => "tb_topicAsTable").ToSql(); + var sql = insert.IgnoreColumns(a => a.TestTypeInfoGuid).AppendData(items.First()).AsTable(a => "tb_topicAsTable").ToSql(); Assert.Equal("INSERT INTO [tb_topicAsTable]([Clicks], [Title], [CreateTime]) VALUES(@Clicks0, @Title0, @CreateTime0)", sql); - sql = insert.AppendData(items).AsTable(a => "tb_topicAsTable").ToSql(); + sql = insert.IgnoreColumns(a => a.TestTypeInfoGuid).AppendData(items).AsTable(a => "tb_topicAsTable").ToSql(); Assert.Equal("INSERT INTO [tb_topicAsTable]([Clicks], [Title], [CreateTime]) VALUES(@Clicks0, @Title0, @CreateTime0), (@Clicks1, @Title1, @CreateTime1), (@Clicks2, @Title2, @CreateTime2), (@Clicks3, @Title3, @CreateTime3), (@Clicks4, @Title4, @CreateTime4), (@Clicks5, @Title5, @CreateTime5), (@Clicks6, @Title6, @CreateTime6), (@Clicks7, @Title7, @CreateTime7), (@Clicks8, @Title8, @CreateTime8), (@Clicks9, @Title9, @CreateTime9)", sql); - sql = insert.AppendData(items).InsertColumns(a => a.Title).AsTable(a => "tb_topicAsTable").ToSql(); + sql = insert.IgnoreColumns(a => a.TestTypeInfoGuid).AppendData(items).InsertColumns(a => a.Title).AsTable(a => "tb_topicAsTable").ToSql(); Assert.Equal("INSERT INTO [tb_topicAsTable]([Title]) VALUES(@Title0), (@Title1), (@Title2), (@Title3), (@Title4), (@Title5), (@Title6), (@Title7), (@Title8), (@Title9)", sql); - sql = insert.AppendData(items).IgnoreColumns(a => a.CreateTime).AsTable(a => "tb_topicAsTable").ToSql(); + sql = insert.IgnoreColumns(a => new { a.CreateTime, a.TestTypeInfoGuid }).AppendData(items).AsTable(a => "tb_topicAsTable").ToSql(); Assert.Equal("INSERT INTO [tb_topicAsTable]([Clicks], [Title]) VALUES(@Clicks0, @Title0), (@Clicks1, @Title1), (@Clicks2, @Title2), (@Clicks3, @Title3), (@Clicks4, @Title4), (@Clicks5, @Title5), (@Clicks6, @Title6), (@Clicks7, @Title7), (@Clicks8, @Title8), (@Clicks9, @Title9)", sql); - sql = insert.AppendData(items).InsertColumns(a => a.Title).AsTable(a => "tb_topicAsTable").ToSql(); + sql = insert.IgnoreColumns(a => new { a.Title, a.TestTypeInfoGuid }).InsertColumns(a => a.Title).AppendData(items).AsTable(a => "tb_topicAsTable").ToSql(); Assert.Equal("INSERT INTO [tb_topicAsTable]([Title]) VALUES(@Title0), (@Title1), (@Title2), (@Title3), (@Title4), (@Title5), (@Title6), (@Title7), (@Title8), (@Title9)", sql); - sql = insert.AppendData(items).InsertColumns(a => new { a.Title, a.Clicks }).AsTable(a => "tb_topicAsTable").ToSql(); + sql = insert.IgnoreColumns(a => a.TestTypeInfoGuid).AppendData(items).InsertColumns(a => new { a.Title, a.Clicks }).AsTable(a => "tb_topicAsTable").ToSql(); Assert.Equal("INSERT INTO [tb_topicAsTable]([Clicks], [Title]) VALUES(@Clicks0, @Title0), (@Clicks1, @Title1), (@Clicks2, @Title2), (@Clicks3, @Title3), (@Clicks4, @Title4), (@Clicks5, @Title5), (@Clicks6, @Title6), (@Clicks7, @Title7), (@Clicks8, @Title8), (@Clicks9, @Title9)", sql); - sql = insert.AppendData(items).IgnoreColumns(a => a.CreateTime).AsTable(a => "tb_topicAsTable").ToSql(); + sql = insert.IgnoreColumns(a => new { a.CreateTime, a.TestTypeInfoGuid }).AppendData(items).AsTable(a => "tb_topicAsTable").ToSql(); Assert.Equal("INSERT INTO [tb_topicAsTable]([Clicks], [Title]) VALUES(@Clicks0, @Title0), (@Clicks1, @Title1), (@Clicks2, @Title2), (@Clicks3, @Title3), (@Clicks4, @Title4), (@Clicks5, @Title5), (@Clicks6, @Title6), (@Clicks7, @Title7), (@Clicks8, @Title8), (@Clicks9, @Title9)", sql); - sql = insert.AppendData(items).IgnoreColumns(a => new { a.Title, a.CreateTime }).AsTable(a => "tb_topicAsTable").ToSql(); + sql = insert.IgnoreColumns(a => new { a.CreateTime, a.Title, a.TestTypeInfoGuid }).AppendData(items).AsTable(a => "tb_topicAsTable").ToSql(); Assert.Equal("INSERT INTO [tb_topicAsTable]([Clicks]) VALUES(@Clicks0), (@Clicks1), (@Clicks2), (@Clicks3), (@Clicks4), (@Clicks5), (@Clicks6), (@Clicks7), (@Clicks8), (@Clicks9)", sql); } } diff --git a/FreeSql.Tests/SqlServer/Curd/SqlServerSelectTest.cs b/FreeSql.Tests/SqlServer/Curd/SqlServerSelectTest.cs index cf715a22..9168caaf 100644 --- a/FreeSql.Tests/SqlServer/Curd/SqlServerSelectTest.cs +++ b/FreeSql.Tests/SqlServer/Curd/SqlServerSelectTest.cs @@ -13,7 +13,7 @@ namespace FreeSql.Tests.SqlServer { class Topic { [Column(IsIdentity = true, IsPrimary = true)] public int Id { get; set; } - public int Clicks { get; set; } + public int? Clicks { get; set; } public int TestTypeInfoGuid { get; set; } public TestTypeInfo Type { get; set; } public string Title { get; set; } @@ -490,7 +490,7 @@ namespace FreeSql.Tests.SqlServer { } [Fact] public void ToAggregate() { - var sql = select.ToAggregate(a => new { sum = a.Sum(a.Key.Id + 11.11), avg = a.Avg(a.Key.Id), count = a.Count(), max = a.Max(a.Key.Id), min = a.Min(a.Key.Id) }); + var sql = select.ToAggregate(a => new { sum = a.Sum(a.Key.Id + 11.11), avg = a.Avg(Convert.ToInt64(a.Key.Id)), count = a.Count(), max = a.Max(a.Key.Id), min = a.Min(a.Key.Id) }); } [Fact] public void OrderBy() { diff --git a/FreeSql.Tests/SqlServer/Curd/SqlServerUpdateTest.cs b/FreeSql.Tests/SqlServer/Curd/SqlServerUpdateTest.cs index 906f1cea..da798f79 100644 --- a/FreeSql.Tests/SqlServer/Curd/SqlServerUpdateTest.cs +++ b/FreeSql.Tests/SqlServer/Curd/SqlServerUpdateTest.cs @@ -12,6 +12,7 @@ namespace FreeSql.Tests.SqlServer { [Column(IsIdentity = true, IsPrimary = true)] public int Id { get; set; } public int? Clicks { get; set; } + public int TestTypeInfoGuid { get; set; } public TestTypeInfo Type { get; set; } public string Title { get; set; } public DateTime CreateTime { get; set; } @@ -28,24 +29,24 @@ namespace FreeSql.Tests.SqlServer { [Fact] public void SetSource() { - var sql = update.SetSource(new Topic { Id = 1, Title = "newtitle" }).ToSql().Replace("\r\n", ""); + var sql = update.SetSource(new Topic { Id = 1, Title = "newtitle" }).IgnoreColumns(a => a.TestTypeInfoGuid).ToSql().Replace("\r\n", ""); Assert.Equal("UPDATE [tb_topic] SET [Clicks] = @p_0, [Title] = @p_1, [CreateTime] = @p_2 WHERE ([Id] = 1)", sql); var items = new List(); for (var a = 0; a < 10; a++) items.Add(new Topic { Id = a + 1, Title = $"newtitle{a}", Clicks = a * 100 }); - sql = update.SetSource(items).ToSql().Replace("\r\n", ""); + sql = update.SetSource(items).IgnoreColumns(a => a.TestTypeInfoGuid).ToSql().Replace("\r\n", ""); Assert.Equal("UPDATE [tb_topic] SET [Clicks] = CASE [Id] WHEN 1 THEN @p_0 WHEN 2 THEN @p_1 WHEN 3 THEN @p_2 WHEN 4 THEN @p_3 WHEN 5 THEN @p_4 WHEN 6 THEN @p_5 WHEN 7 THEN @p_6 WHEN 8 THEN @p_7 WHEN 9 THEN @p_8 WHEN 10 THEN @p_9 END, [Title] = CASE [Id] WHEN 1 THEN @p_10 WHEN 2 THEN @p_11 WHEN 3 THEN @p_12 WHEN 4 THEN @p_13 WHEN 5 THEN @p_14 WHEN 6 THEN @p_15 WHEN 7 THEN @p_16 WHEN 8 THEN @p_17 WHEN 9 THEN @p_18 WHEN 10 THEN @p_19 END, [CreateTime] = CASE [Id] WHEN 1 THEN @p_20 WHEN 2 THEN @p_21 WHEN 3 THEN @p_22 WHEN 4 THEN @p_23 WHEN 5 THEN @p_24 WHEN 6 THEN @p_25 WHEN 7 THEN @p_26 WHEN 8 THEN @p_27 WHEN 9 THEN @p_28 WHEN 10 THEN @p_29 END WHERE ([Id] IN (1,2,3,4,5,6,7,8,9,10))", sql); - sql = update.SetSource(items).IgnoreColumns(a => new { a.Clicks, a.CreateTime }).ToSql().Replace("\r\n", ""); + sql = update.SetSource(items).IgnoreColumns(a => new { a.Clicks, a.CreateTime, a.TestTypeInfoGuid }).ToSql().Replace("\r\n", ""); Assert.Equal("UPDATE [tb_topic] SET [Title] = CASE [Id] WHEN 1 THEN @p_0 WHEN 2 THEN @p_1 WHEN 3 THEN @p_2 WHEN 4 THEN @p_3 WHEN 5 THEN @p_4 WHEN 6 THEN @p_5 WHEN 7 THEN @p_6 WHEN 8 THEN @p_7 WHEN 9 THEN @p_8 WHEN 10 THEN @p_9 END WHERE ([Id] IN (1,2,3,4,5,6,7,8,9,10))", sql); - sql = update.SetSource(items).Set(a => a.CreateTime, new DateTime(2020,1,1)).ToSql().Replace("\r\n", ""); + sql = update.SetSource(items).IgnoreColumns(a => a.TestTypeInfoGuid).Set(a => a.CreateTime, new DateTime(2020,1,1)).ToSql().Replace("\r\n", ""); Assert.Equal("UPDATE [tb_topic] SET [CreateTime] = @p_0 WHERE ([Id] IN (1,2,3,4,5,6,7,8,9,10))", sql); } [Fact] public void IgnoreColumns() { - var sql = update.SetSource(new Topic { Id = 1, Title = "newtitle" }).IgnoreColumns(a => new { a.Clicks, a.CreateTime }).ToSql().Replace("\r\n", ""); + var sql = update.SetSource(new Topic { Id = 1, Title = "newtitle" }).IgnoreColumns(a => new { a.Clicks, a.CreateTime, a.TestTypeInfoGuid }).ToSql().Replace("\r\n", ""); Assert.Equal("UPDATE [tb_topic] SET [Title] = @p_0 WHERE ([Id] = 1)", sql); } [Fact] diff --git a/FreeSql.Tests/Sqlite/Curd/SqliteSelectTest.cs b/FreeSql.Tests/Sqlite/Curd/SqliteSelectTest.cs index 2c705611..02046f9e 100644 --- a/FreeSql.Tests/Sqlite/Curd/SqliteSelectTest.cs +++ b/FreeSql.Tests/Sqlite/Curd/SqliteSelectTest.cs @@ -81,8 +81,8 @@ namespace FreeSql.Tests.Sqlite { Assert.Equal(1, g.sqlite.Insert().AppendData(items.First()).ExecuteAffrows()); Assert.Equal(10, g.sqlite.Insert().AppendData(items).ExecuteAffrows()); - items = Enumerable.Range(0, 9989).Select(a => new Topic { Title = "newtitle" + a, CreateTime = DateTime.Now }).ToList(); - Assert.Equal(9989, g.sqlite.Insert(items).ExecuteAffrows()); + //items = Enumerable.Range(0, 9989).Select(a => new Topic { Title = "newtitle" + a, CreateTime = DateTime.Now }).ToList(); + //Assert.Equal(9989, g.sqlite.Insert(items).ExecuteAffrows()); var dt1 = select.Limit(10).ToDataTable(); var dt2 = select.Limit(10).ToDataTable("id, 111222"); diff --git a/FreeSql.Tests/Sqlite/Curd/SqliteUpdateTest.cs b/FreeSql.Tests/Sqlite/Curd/SqliteUpdateTest.cs index 71961310..19d450fb 100644 --- a/FreeSql.Tests/Sqlite/Curd/SqliteUpdateTest.cs +++ b/FreeSql.Tests/Sqlite/Curd/SqliteUpdateTest.cs @@ -12,6 +12,7 @@ namespace FreeSql.Tests.Sqlite { [Column(IsIdentity = true, IsPrimary = true)] public int Id { get; set; } public int? Clicks { get; set; } + public int TestTypeInfoGuid { get; set; } public TestTypeInfo Type { get; set; } public string Title { get; set; } public DateTime CreateTime { get; set; } @@ -28,24 +29,24 @@ namespace FreeSql.Tests.Sqlite { [Fact] public void SetSource() { - var sql = update.SetSource(new Topic { Id = 1, Title = "newtitle" }).ToSql().Replace("\r\n", ""); + var sql = update.SetSource(new Topic { Id = 1, Title = "newtitle" }).IgnoreColumns(a => a.TestTypeInfoGuid).ToSql().Replace("\r\n", ""); Assert.Equal("UPDATE \"tb_topic\" SET \"Clicks\" = @p_0, \"Title\" = @p_1, \"CreateTime\" = @p_2 WHERE (\"Id\" = 1)", sql); var items = new List(); for (var a = 0; a < 10; a++) items.Add(new Topic { Id = a + 1, Title = $"newtitle{a}", Clicks = a * 100 }); - sql = update.SetSource(items).ToSql().Replace("\r\n", ""); + sql = update.SetSource(items).IgnoreColumns(a => a.TestTypeInfoGuid).ToSql().Replace("\r\n", ""); Assert.Equal("UPDATE \"tb_topic\" SET \"Clicks\" = CASE \"Id\" WHEN 1 THEN @p_0 WHEN 2 THEN @p_1 WHEN 3 THEN @p_2 WHEN 4 THEN @p_3 WHEN 5 THEN @p_4 WHEN 6 THEN @p_5 WHEN 7 THEN @p_6 WHEN 8 THEN @p_7 WHEN 9 THEN @p_8 WHEN 10 THEN @p_9 END, \"Title\" = CASE \"Id\" WHEN 1 THEN @p_10 WHEN 2 THEN @p_11 WHEN 3 THEN @p_12 WHEN 4 THEN @p_13 WHEN 5 THEN @p_14 WHEN 6 THEN @p_15 WHEN 7 THEN @p_16 WHEN 8 THEN @p_17 WHEN 9 THEN @p_18 WHEN 10 THEN @p_19 END, \"CreateTime\" = CASE \"Id\" WHEN 1 THEN @p_20 WHEN 2 THEN @p_21 WHEN 3 THEN @p_22 WHEN 4 THEN @p_23 WHEN 5 THEN @p_24 WHEN 6 THEN @p_25 WHEN 7 THEN @p_26 WHEN 8 THEN @p_27 WHEN 9 THEN @p_28 WHEN 10 THEN @p_29 END WHERE (\"Id\" IN (1,2,3,4,5,6,7,8,9,10))", sql); - sql = update.SetSource(items).IgnoreColumns(a => new { a.Clicks, a.CreateTime }).ToSql().Replace("\r\n", ""); + sql = update.SetSource(items).IgnoreColumns(a => new { a.Clicks, a.CreateTime, a.TestTypeInfoGuid }).ToSql().Replace("\r\n", ""); Assert.Equal("UPDATE \"tb_topic\" SET \"Title\" = CASE \"Id\" WHEN 1 THEN @p_0 WHEN 2 THEN @p_1 WHEN 3 THEN @p_2 WHEN 4 THEN @p_3 WHEN 5 THEN @p_4 WHEN 6 THEN @p_5 WHEN 7 THEN @p_6 WHEN 8 THEN @p_7 WHEN 9 THEN @p_8 WHEN 10 THEN @p_9 END WHERE (\"Id\" IN (1,2,3,4,5,6,7,8,9,10))", sql); - sql = update.SetSource(items).Set(a => a.CreateTime, new DateTime(2020,1,1)).ToSql().Replace("\r\n", ""); + sql = update.SetSource(items).IgnoreColumns(a => a.TestTypeInfoGuid).Set(a => a.CreateTime, new DateTime(2020,1,1)).ToSql().Replace("\r\n", ""); Assert.Equal("UPDATE \"tb_topic\" SET \"CreateTime\" = @p_0 WHERE (\"Id\" IN (1,2,3,4,5,6,7,8,9,10))", sql); } [Fact] public void IgnoreColumns() { - var sql = update.SetSource(new Topic { Id = 1, Title = "newtitle" }).IgnoreColumns(a => new { a.Clicks, a.CreateTime }).ToSql().Replace("\r\n", ""); + var sql = update.SetSource(new Topic { Id = 1, Title = "newtitle" }).IgnoreColumns(a => new { a.Clicks, a.CreateTime, a.TestTypeInfoGuid }).ToSql().Replace("\r\n", ""); Assert.Equal("UPDATE \"tb_topic\" SET \"Title\" = @p_0 WHERE (\"Id\" = 1)", sql); } [Fact] diff --git a/FreeSql/DataType.cs b/FreeSql/DataType.cs new file mode 100644 index 00000000..12ec3c06 --- /dev/null +++ b/FreeSql/DataType.cs @@ -0,0 +1,7 @@ +using System; +using System.Collections.Generic; +using System.Text; + +namespace FreeSql { + public enum DataType { MySql, SqlServer, PostgreSQL, Oracle, Sqlite } +} diff --git a/FreeSql/Extensions/FreeSqlGlobalExtensions.cs b/FreeSql/Extensions/FreeSqlGlobalExtensions.cs index b69d8d43..f943ec40 100644 --- a/FreeSql/Extensions/FreeSqlGlobalExtensions.cs +++ b/FreeSql/Extensions/FreeSqlGlobalExtensions.cs @@ -1,8 +1,6 @@ -using NpgsqlTypes; -using System; -using System.Collections; -using System.Collections.Generic; +using System; using System.Collections.Concurrent; +using System.Collections.Generic; using System.ComponentModel; using System.Data; using System.Drawing; diff --git a/FreeSql/Extensions/FreeSqlStringExtensions.cs b/FreeSql/Extensions/FreeSqlStringExtensions.cs deleted file mode 100644 index e3186bd2..00000000 --- a/FreeSql/Extensions/FreeSqlStringExtensions.cs +++ /dev/null @@ -1,43 +0,0 @@ -public static class FreeSqlStringExtensions { - - /// - /// 特殊处理类似 string.Format 的使用方法,防止注入,以及 IS NULL 转换 - /// - /// - /// - /// - public static string FormatMySql(this string that, params object[] args) => _mysqlAdo.Addslashes(that, args); - static FreeSql.MySql.MySqlAdo _mysqlAdo = new FreeSql.MySql.MySqlAdo(); - /// - /// 特殊处理类似 string.Format 的使用方法,防止注入,以及 IS NULL 转换 - /// - /// - /// - /// - public static string FormatSqlServer(this string that, params object[] args) => _sqlserverAdo.Addslashes(that, args); - static FreeSql.SqlServer.SqlServerAdo _sqlserverAdo = new FreeSql.SqlServer.SqlServerAdo(); - /// - /// 特殊处理类似 string.Format 的使用方法,防止注入,以及 IS NULL 转换 - /// - /// - /// - /// - public static string FormatPostgreSQL(this string that, params object[] args) => _postgresqlAdo.Addslashes(that, args); - static FreeSql.PostgreSQL.PostgreSQLAdo _postgresqlAdo = new FreeSql.PostgreSQL.PostgreSQLAdo(); - /// - /// 特殊处理类似 string.Format 的使用方法,防止注入,以及 IS NULL 转换 - /// - /// - /// - /// - public static string FormatOracleSQL(this string that, params object[] args) => _oracleAdo.Addslashes(that, args); - static FreeSql.Oracle.OracleAdo _oracleAdo = new FreeSql.Oracle.OracleAdo(); - /// - /// 特殊处理类似 string.Format 的使用方法,防止注入,以及 IS NULL 转换 - /// - /// - /// - /// - public static string FormatSqlite (this string that, params object[] args) => _sqliteAdo.Addslashes(that, args); - static FreeSql.Sqlite.SqliteAdo _sqliteAdo = new FreeSql.Sqlite.SqliteAdo(); -} diff --git a/FreeSql/FreeSql.MySql.csproj b/FreeSql/FreeSql.MySql.csproj new file mode 100644 index 00000000..0393902c --- /dev/null +++ b/FreeSql/FreeSql.MySql.csproj @@ -0,0 +1,44 @@ + + + + netstandard2.0 + 0.3.14 + true + YeXiangQin + 打造 .NETCore 最方便的 ORM,DbFirst 与 CodeFirst 混合使用,提供从实体同步数据库,或者从数据库生成实体代码,支持 MySql/SqlServer/PostgreSQL/Oracle/Sqlite,读写分离、分表分库。 + https://github.com/2881099/FreeSql + FreeSql ORM + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/FreeSql/FreeSql.csproj b/FreeSql/FreeSql.csproj index d93d6104..d43b6fa9 100644 --- a/FreeSql/FreeSql.csproj +++ b/FreeSql/FreeSql.csproj @@ -1,30 +1,28 @@  - - netstandard2.0 - 0.3.14 - true - YeXiangQin - 打造 .NETCore 最方便的 ORM,DbFirst 与 CodeFirst 混合使用,提供从实体同步数据库,或者从数据库生成实体代码,支持 MySql/SqlServer/PostgreSQL/Oracle/Sqlite,读写分离、分表分库。 - https://github.com/2881099/FreeSql - FreeSql ORM - + + netstandard2.0 + 0.3.15 + true + YeXiangQin + FreeSql is the most convenient ORM in dotnet. It supports Mysql, Postgresql, SqlServer, Oracle and Sqlite. + https://github.com/2881099/FreeSql + FreeSql ORM + - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + diff --git a/FreeSql/FreeSqlBuilder.cs b/FreeSql/FreeSqlBuilder.cs index a484d42e..4c8d75c5 100644 --- a/FreeSql/FreeSqlBuilder.cs +++ b/FreeSql/FreeSqlBuilder.cs @@ -1,9 +1,7 @@ using Microsoft.Extensions.Caching.Distributed; using Microsoft.Extensions.Logging; using System; -using System.Collections.Generic; using System.Data.Common; -using System.Text; namespace FreeSql { public class FreeSqlBuilder { @@ -16,6 +14,7 @@ namespace FreeSql { bool _isSyncStructureToLower = false; bool _isSyncStructureToUpper = false; bool _isConfigEntityFromDbFirst = false; + bool _isNoneCommandParameter = false; bool _isLazyLoading = false; Action _aopCommandExecuting = null; Action _aopCommandExecuted = null; @@ -96,6 +95,15 @@ namespace FreeSql { return this; } /// + /// 不使用命令参数化执行,针对 Insert/Update,也可临时使用 IInsert/IUpdate.NoneParameter() + /// + /// + /// + public FreeSqlBuilder UseNoneCommandParameter(bool value) { + _isNoneCommandParameter = value; + return this; + } + /// /// 延时加载导航属性对象,导航属性需要声明 virtual /// /// @@ -131,6 +139,7 @@ namespace FreeSql { ret.CodeFirst.IsSyncStructureToLower = _isSyncStructureToLower; ret.CodeFirst.IsSyncStructureToUpper = _isSyncStructureToUpper; ret.CodeFirst.IsConfigEntityFromDbFirst = _isConfigEntityFromDbFirst; + ret.CodeFirst.IsNoneCommandParameter = _isNoneCommandParameter; ret.CodeFirst.IsLazyLoading = _isLazyLoading; var ado = ret.Ado as Internal.CommonProvider.AdoProvider; ado.AopCommandExecuting += _aopCommandExecuting; @@ -139,6 +148,4 @@ namespace FreeSql { return ret; } } - - public enum DataType { MySql, SqlServer, PostgreSQL, Oracle, Sqlite } } diff --git a/FreeSql/FreeUtil.cs b/FreeSql/FreeUtil.cs index 02eb631b..9d7fb805 100644 --- a/FreeSql/FreeUtil.cs +++ b/FreeSql/FreeUtil.cs @@ -1,10 +1,5 @@ -using NpgsqlTypes; -using System; -using System.Collections; -using System.Collections.Generic; +using System; using System.Diagnostics; -using System.Linq; -using System.Text; using System.Threading; public static class FreeUtil { diff --git a/FreeSql/Interface/Curd/IInsert.cs b/FreeSql/Interface/Curd/IInsert.cs index 1661b07d..328acdd2 100644 --- a/FreeSql/Interface/Curd/IInsert.cs +++ b/FreeSql/Interface/Curd/IInsert.cs @@ -40,6 +40,12 @@ namespace FreeSql { /// IInsert IgnoreColumns(Expression> columns); + /// + /// 不使用参数化,可通过 IFreeSql.CodeFirst.IsNotCommandParameter 全局性设置 + /// + /// + IInsert NoneParameter(); + /// /// 设置表名规则,可用于分库/分表,参数1:默认表名;返回值:新表名; /// diff --git a/FreeSql/Interface/Curd/IUpdate.cs b/FreeSql/Interface/Curd/IUpdate.cs index 6059cf6f..684a08d3 100644 --- a/FreeSql/Interface/Curd/IUpdate.cs +++ b/FreeSql/Interface/Curd/IUpdate.cs @@ -14,6 +14,12 @@ namespace FreeSql { /// IUpdate WithTransaction(DbTransaction transaction); + /// + /// 不使用参数化,可通过 IFreeSql.CodeFirst.IsNotCommandParameter 全局性设置 + /// + /// + IUpdate NoneParameter(); + /// /// 更新数据,设置更新的实体 /// diff --git a/FreeSql/Interface/ICodeFirst.cs b/FreeSql/Interface/ICodeFirst.cs index 2545f301..39689dd8 100644 --- a/FreeSql/Interface/ICodeFirst.cs +++ b/FreeSql/Interface/ICodeFirst.cs @@ -22,6 +22,10 @@ namespace FreeSql { /// bool IsConfigEntityFromDbFirst { get; set; } /// + /// 不使用命令参数化执行,针对 Insert/Update + /// + bool IsNoneCommandParameter { get; set; } + /// /// 延时加载导航属性对象,导航属性需要声明 virtual /// bool IsLazyLoading { get; set; } diff --git a/FreeSql/Internal/CommonProvider/InsertProvider.cs b/FreeSql/Internal/CommonProvider/InsertProvider.cs index a9516340..397df8ca 100644 --- a/FreeSql/Internal/CommonProvider/InsertProvider.cs +++ b/FreeSql/Internal/CommonProvider/InsertProvider.cs @@ -1,4 +1,5 @@ using FreeSql.Internal.Model; +using SafeObjectPool; using System; using System.Collections.Generic; using System.Data; @@ -18,6 +19,7 @@ namespace FreeSql.Internal.CommonProvider { protected Dictionary _ignore = new Dictionary(StringComparer.CurrentCultureIgnoreCase); protected TableInfo _table; protected Func _tableRule; + protected bool _noneParameter; protected DbParameter[] _params; protected DbTransaction _transaction; @@ -26,6 +28,7 @@ namespace FreeSql.Internal.CommonProvider { _commonUtils = commonUtils; _commonExpression = commonExpression; _table = _commonUtils.GetTableByEntity(typeof(T1)); + _noneParameter = _orm.CodeFirst.IsNoneCommandParameter; if (_orm.CodeFirst.IsAutoSyncStructure) _orm.CodeFirst.SyncStructure(); } @@ -33,6 +36,10 @@ namespace FreeSql.Internal.CommonProvider { _transaction = transaction; return this; } + public IInsert NoneParameter() { + _noneParameter = false; + return this; + } public IInsert AppendData(T1 source) { if (source != null) _source.Add(source); @@ -43,8 +50,228 @@ namespace FreeSql.Internal.CommonProvider { return this; } - public virtual int ExecuteAffrows() => _orm.Ado.ExecuteNonQuery(_transaction, CommandType.Text, this.ToSql(), _params); - public virtual Task ExecuteAffrowsAsync() => _orm.Ado.ExecuteNonQueryAsync(_transaction, CommandType.Text, this.ToSql(), _params); + #region 参数化数据限制,或values数量限制 + internal List[] SplitSource(int valuesLimit, int parameterLimit) { + valuesLimit = valuesLimit - 1; + parameterLimit = parameterLimit - 1; + if (_source == null || _source.Any() == false) return new List[0]; + if (_source.Count == 1) return new[] { _source }; + if (_noneParameter) { + if (_source.Count < valuesLimit) return new[] { _source }; + + var execCount = (int)Math.Ceiling(1.0 * _source.Count / valuesLimit); + var ret = new List[execCount]; + for (var a = 0; a < execCount; a++) { + var subSource = new List(); + subSource = _source.GetRange(a * valuesLimit, Math.Min(valuesLimit, _source.Count - a * valuesLimit)); + ret[a] = subSource; + } + return ret; + } else { + var colSum = _table.Columns.Count - _ignore.Count; + var takeMax = parameterLimit / colSum; + var pamTotal = colSum * _source.Count; + if (pamTotal < parameterLimit) return new[] { _source }; + + var execCount = (int)Math.Ceiling(1.0 * pamTotal / parameterLimit); + var ret = new List[execCount]; + for (var a = 0; a < execCount; a++) { + var subSource = new List(); + subSource = _source.GetRange(a * takeMax, Math.Min(takeMax, _source.Count - a * takeMax)); + ret[a] = subSource; + } + return ret; + } + } + internal int SplitExecuteAffrows(int valuesLimit, int parameterLimit) { + var ss = SplitSource(valuesLimit, parameterLimit); + if (ss.Any() == false) return 0; + if (ss.Length == 1) return this.RawExecuteAffrows(); + + var ret = 0; + if (_transaction != null) { + for (var a = 0; a < ss.Length; a++) { + _source = ss[a]; + ret += this.RawExecuteAffrows(); + } + } else { + using (var conn = _orm.Ado.MasterPool.Get()) { + _transaction = conn.Value.BeginTransaction(); + try { + for (var a = 0; a < ss.Length; a++) { + _source = ss[a]; + ret += this.RawExecuteAffrows(); + } + _transaction.Commit(); + } catch { + _transaction.Rollback(); + throw; + } + _transaction = null; + } + } + return ret; + } + async internal Task SplitExecuteAffrowsAsync(int valuesLimit, int parameterLimit) { + var ss = SplitSource(valuesLimit, parameterLimit); + if (ss.Any() == false) return 0; + if (ss.Length == 1) return await this.RawExecuteAffrowsAsync(); + + var ret = 0; + if (_transaction != null) { + for (var a = 0; a < ss.Length; a++) { + _source = ss[a]; + ret += await this.RawExecuteAffrowsAsync(); + } + } else { + using (var conn = await _orm.Ado.MasterPool.GetAsync()) { + _transaction = conn.Value.BeginTransaction(); + try { + for (var a = 0; a < ss.Length; a++) { + _source = ss[a]; + ret += await this.RawExecuteAffrowsAsync(); + } + _transaction.Commit(); + } catch { + _transaction.Rollback(); + throw; + } + _transaction = null; + } + } + return ret; + } + internal long SplitExecuteIdentity(int valuesLimit, int parameterLimit) { + var ss = SplitSource(valuesLimit, parameterLimit); + if (ss.Any() == false) return 0; + if (ss.Length == 1) return this.RawExecuteIdentity(); + + long ret = 0; + if (_transaction != null) { + for (var a = 0; a < ss.Length; a++) { + _source = ss[a]; + if (a < ss.Length - 1) this.RawExecuteAffrows(); + else ret = this.RawExecuteIdentity(); + } + } else { + using (var conn = _orm.Ado.MasterPool.Get()) { + _transaction = conn.Value.BeginTransaction(); + try { + for (var a = 0; a < ss.Length; a++) { + _source = ss[a]; + if (a < ss.Length - 1) this.RawExecuteAffrows(); + else ret = this.RawExecuteIdentity(); + } + _transaction.Commit(); + } catch { + _transaction.Rollback(); + throw; + } + _transaction = null; + } + } + return ret; + } + async internal Task SplitExecuteIdentityAsync(int valuesLimit, int parameterLimit) { + var ss = SplitSource(valuesLimit, parameterLimit); + if (ss.Any() == false) return 0; + if (ss.Length == 1) return await this.RawExecuteIdentityAsync(); + + long ret = 0; + if (_transaction != null) { + for (var a = 0; a < ss.Length; a++) { + _source = ss[a]; + if (a < ss.Length - 1) await this.RawExecuteAffrowsAsync(); + else ret = await this.RawExecuteIdentityAsync(); + } + } else { + using (var conn = await _orm.Ado.MasterPool.GetAsync()) { + _transaction = conn.Value.BeginTransaction(); + try { + for (var a = 0; a < ss.Length; a++) { + _source = ss[a]; + if (a < ss.Length - 1) await this.RawExecuteAffrowsAsync(); + else ret = await this.RawExecuteIdentityAsync(); + } + _transaction.Commit(); + } catch { + _transaction.Rollback(); + throw; + } + _transaction = null; + } + } + return ret; + } + internal List SplitExecuteInserted(int valuesLimit, int parameterLimit) { + var ss = SplitSource(valuesLimit, parameterLimit); + if (ss.Any() == false) return new List(); + if (ss.Length == 1) return this.RawExecuteInserted(); + + var ret = new List(); + if (_transaction != null) { + for (var a = 0; a < ss.Length; a++) { + _source = ss[a]; + ret.AddRange(this.RawExecuteInserted()); + } + } else { + using (var conn = _orm.Ado.MasterPool.Get()) { + _transaction = conn.Value.BeginTransaction(); + try { + for (var a = 0; a < ss.Length; a++) { + _source = ss[a]; + ret.AddRange(this.RawExecuteInserted()); + } + _transaction.Commit(); + } catch { + _transaction.Rollback(); + throw; + } + _transaction = null; + } + } + return ret; + } + async internal Task> SplitExecuteInsertedAsync(int valuesLimit, int parameterLimit) { + var ss = SplitSource(valuesLimit, parameterLimit); + if (ss.Any() == false) return new List(); + if (ss.Length == 1) return await this.RawExecuteInsertedAsync(); + + var ret = new List(); + if (_transaction != null) { + for (var a = 0; a < ss.Length; a++) { + _source = ss[a]; + ret.AddRange(await this.RawExecuteInsertedAsync()); + } + } else { + using (var conn = await _orm.Ado.MasterPool.GetAsync()) { + _transaction = conn.Value.BeginTransaction(); + try { + for (var a = 0; a < ss.Length; a++) { + _source = ss[a]; + ret.AddRange(await this.RawExecuteInsertedAsync()); + } + _transaction.Commit(); + } catch { + _transaction.Rollback(); + throw; + } + _transaction = null; + } + } + return ret; + } + #endregion + + internal int RawExecuteAffrows() => _orm.Ado.ExecuteNonQuery(_transaction, CommandType.Text, ToSql(), _params); + internal Task RawExecuteAffrowsAsync() => _orm.Ado.ExecuteNonQueryAsync(_transaction, CommandType.Text, ToSql(), _params); + internal abstract long RawExecuteIdentity(); + internal abstract Task RawExecuteIdentityAsync(); + internal abstract List RawExecuteInserted(); + internal abstract Task> RawExecuteInsertedAsync(); + + public virtual int ExecuteAffrows() => RawExecuteAffrows(); + public virtual Task ExecuteAffrowsAsync() => RawExecuteAffrowsAsync(); public abstract long ExecuteIdentity(); public abstract Task ExecuteIdentityAsync(); public abstract List ExecuteInserted(); @@ -81,9 +308,8 @@ namespace FreeSql.Internal.CommonProvider { ++colidx; } sb.Append(") VALUES"); - //_params = new DbParameter[colidx * _source.Count]; - _params = new DbParameter[0]; - //_params = new DbParameter[colidx * 5]; //批量添加第5行起,不使用参数化 + _params = _noneParameter ? new DbParameter[0] : new DbParameter[colidx * _source.Count]; + var specialParams = new List(); var didx = 0; foreach (var d in _source) { if (didx > 0) sb.Append(", "); @@ -98,17 +324,19 @@ namespace FreeSql.Internal.CommonProvider { if (col.Attribute.IsPrimary && (col.CsType == typeof(Guid) || col.CsType == typeof(Guid?)) && (val == null || (Guid)val == Guid.Empty)) tryp.SetValue(d, val = FreeUtil.NewMongodbId()); } - //if (didx >= 5) - sb.Append(_commonUtils.GetNoneParamaterSqlValue(col.CsType, val)); - //else { - // sb.Append(_commonUtils.QuoteWriteParamter(col.CsType, $"{_commonUtils.QuoteParamterName(col.CsName)}{didx}")); - // _params[didx * colidx + colidx2] = _commonUtils.AppendParamter(null, $"{col.CsName}{didx}", col.CsType, val); - //} + if (_noneParameter) + sb.Append(_commonUtils.GetNoneParamaterSqlValue(specialParams, col.CsType, val)); + else { + sb.Append(_commonUtils.QuoteWriteParamter(col.CsType, _commonUtils.QuoteParamterName($"{col.CsName}{didx}"))); + _params[didx * colidx + colidx2] = _commonUtils.AppendParamter(null, $"{col.CsName}{didx}", col.CsType, val); + } ++colidx2; } sb.Append(")"); ++didx; } + if (_noneParameter && specialParams.Any()) + _params = specialParams.ToArray(); return sb.ToString(); } } diff --git a/FreeSql/Internal/CommonProvider/SelectProvider/Select0Provider.cs b/FreeSql/Internal/CommonProvider/SelectProvider/Select0Provider.cs index 8b7ec137..bec20864 100644 --- a/FreeSql/Internal/CommonProvider/SelectProvider/Select0Provider.cs +++ b/FreeSql/Internal/CommonProvider/SelectProvider/Select0Provider.cs @@ -279,7 +279,7 @@ namespace FreeSql.Internal.CommonProvider { public Func Read { get; set; } } protected GetAllFieldExpressionTreeInfo GetAllFieldExpressionTree() { - return _dicGetAllFieldExpressionTree.GetOrAdd(string.Join("+", _tables.Select(a => $"{_commonUtils.DbName}-{a.Table.DbName}-{a.Alias}-{a.Type}")), s => { + return _dicGetAllFieldExpressionTree.GetOrAdd(string.Join("+", _tables.Select(a => $"{_orm.Ado.DataType}-{a.Table.DbName}-{a.Alias}-{a.Type}")), s => { var tb1 = _tables.First().Table; var type = tb1.TypeLazy ?? tb1.Type; var props = tb1.Properties; diff --git a/FreeSql/Internal/CommonProvider/UpdateProvider.cs b/FreeSql/Internal/CommonProvider/UpdateProvider.cs index 14fd0c73..25b2a7d2 100644 --- a/FreeSql/Internal/CommonProvider/UpdateProvider.cs +++ b/FreeSql/Internal/CommonProvider/UpdateProvider.cs @@ -22,6 +22,7 @@ namespace FreeSql.Internal.CommonProvider { protected StringBuilder _set = new StringBuilder(); protected List _params = new List(); protected List _paramsSource = new List(); + protected bool _noneParameter; protected DbTransaction _transaction; public UpdateProvider(IFreeSql orm, CommonUtils commonUtils, CommonExpression commonExpression, object dywhere) { @@ -29,6 +30,7 @@ namespace FreeSql.Internal.CommonProvider { _commonUtils = commonUtils; _commonExpression = commonExpression; _table = _commonUtils.GetTableByEntity(typeof(T1)); + _noneParameter = _orm.CodeFirst.IsNoneCommandParameter; this.Where(_commonUtils.WhereObject(_table, "", dywhere)); if (_orm.CodeFirst.IsAutoSyncStructure) _orm.CodeFirst.SyncStructure(); } @@ -37,6 +39,10 @@ namespace FreeSql.Internal.CommonProvider { _transaction = transaction; return this; } + public IUpdate NoneParameter() { + _noneParameter = false; + return this; + } public int ExecuteAffrows() { var sql = this.ToSql(); @@ -70,8 +76,13 @@ namespace FreeSql.Internal.CommonProvider { _commonExpression.ExpressionSelectColumn_MemberAccess(null, cols, SelectTableInfoType.From, column?.Body, true, null); if (cols.Count != 1) return this; var col = cols.First(); - _set.Append(", ").Append(_commonUtils.QuoteSqlName(col.Column.Attribute.Name)).Append(" = ").Append(_commonUtils.QuoteWriteParamter(col.Column.CsType, $"{_commonUtils.QuoteParamterName("p_")}{_params.Count}")); - _commonUtils.AppendParamter(_params, null, col.Column.CsType, value); + _set.Append(", ").Append(_commonUtils.QuoteSqlName(col.Column.Attribute.Name)).Append(" = "); + if (_noneParameter) { + _set.Append(_commonUtils.GetNoneParamaterSqlValue(_params, col.Column.CsType, value)); + } else { + _set.Append(_commonUtils.QuoteWriteParamter(col.Column.CsType, $"{_commonUtils.QuoteParamterName("p_")}{_params.Count}")); + _commonUtils.AppendParamter(_params, null, col.Column.CsType, value); + } //foreach (var t in _source) Utils.FillPropertyValue(t, tryf.CsName, value); return this; } @@ -131,8 +142,14 @@ namespace FreeSql.Internal.CommonProvider { foreach (var col in _table.Columns.Values) { if (col.Attribute.IsIdentity == false && _ignore.ContainsKey(col.CsName) == false) { if (colidx > 0) sb.Append(", "); - sb.Append(_commonUtils.QuoteSqlName(col.Attribute.Name)).Append(" = ").Append(_commonUtils.QuoteWriteParamter(col.CsType, _commonUtils.QuoteParamterName($"p_{_paramsSource.Count}"))); - _commonUtils.AppendParamter(_paramsSource, null, col.CsType, _table.Properties.TryGetValue(col.CsName, out var tryp) ? tryp.GetValue(_source.First()) : null); + sb.Append(_commonUtils.QuoteSqlName(col.Attribute.Name)).Append(" = "); + var value = _table.Properties.TryGetValue(col.CsName, out var tryp) ? tryp.GetValue(_source.First()) : null; + if (_noneParameter) { + sb.Append(_commonUtils.GetNoneParamaterSqlValue(_paramsSource, col.CsType, value)); + } else { + sb.Append(_commonUtils.QuoteWriteParamter(col.CsType, _commonUtils.QuoteParamterName($"p_{_paramsSource.Count}"))); + _commonUtils.AppendParamter(_paramsSource, null, col.CsType, value); + } ++colidx; } } @@ -171,8 +188,14 @@ namespace FreeSql.Internal.CommonProvider { // ++pkidx; //} //if (_table.Primarys.Length > 1) sb.Append(")"); - sb.Append(" THEN ").Append(_commonUtils.QuoteWriteParamter(col.CsType, _commonUtils.QuoteParamterName($"p_{_paramsSource.Count}"))); - _commonUtils.AppendParamter(_paramsSource, null, col.CsType, _table.Properties.TryGetValue(col.CsName, out var tryp) ? tryp.GetValue(d) : DBNull.Value); + sb.Append(" THEN "); + var value = _table.Properties.TryGetValue(col.CsName, out var tryp) ? tryp.GetValue(d) : DBNull.Value; + if (_noneParameter) { + sb.Append(_commonUtils.GetNoneParamaterSqlValue(_paramsSource, col.CsType, value)); + } else { + sb.Append(_commonUtils.QuoteWriteParamter(col.CsType, _commonUtils.QuoteParamterName($"p_{_paramsSource.Count}"))); + _commonUtils.AppendParamter(_paramsSource, null, col.CsType, value); + } } sb.Append(" END"); ++colidx; diff --git a/FreeSql/Internal/CommonUtils.cs b/FreeSql/Internal/CommonUtils.cs index 04375939..f90a61f4 100644 --- a/FreeSql/Internal/CommonUtils.cs +++ b/FreeSql/Internal/CommonUtils.cs @@ -13,9 +13,9 @@ using System.Text; namespace FreeSql.Internal { internal abstract class CommonUtils { - internal abstract string GetNoneParamaterSqlValue(Type type, object value); - internal abstract DbParameter[] GetDbParamtersByObject(string sql, object obj); + internal abstract string GetNoneParamaterSqlValue(List specialParams, Type type, object value); internal abstract DbParameter AppendParamter(List _params, string parameterName, Type type, object value); + internal abstract DbParameter[] GetDbParamtersByObject(string sql, object obj); internal abstract string FormatSql(string sql, params object[] args); internal abstract string QuoteSqlName(string name); internal abstract string QuoteParamterName(string name); @@ -24,7 +24,6 @@ namespace FreeSql.Internal { internal abstract string Mod(string left, string right, Type leftType, Type rightType); internal abstract string QuoteWriteParamter(Type type, string paramterName); internal abstract string QuoteReadColumn(Type type, string columnName); - internal abstract string DbName { get; } internal IFreeSql _orm { get; set; } internal ICodeFirst CodeFirst => _orm.CodeFirst; diff --git a/FreeSql/Internal/UtilsExpressionTree.cs b/FreeSql/Internal/UtilsExpressionTree.cs index 0f6db3fb..1a4afe21 100644 --- a/FreeSql/Internal/UtilsExpressionTree.cs +++ b/FreeSql/Internal/UtilsExpressionTree.cs @@ -1,37 +1,28 @@ using FreeSql.DataAnnotations; using FreeSql.Internal.Model; using Newtonsoft.Json.Linq; -using Npgsql.LegacyPostgis; -using NpgsqlTypes; using System; -using System.Collections; using System.Collections.Concurrent; using System.Collections.Generic; -using System.Data; using System.Data.Common; -using System.Diagnostics; -using System.IO; using System.Linq; using System.Linq.Expressions; -using System.Net; -using System.Net.NetworkInformation; using System.Reflection; using System.Text; using System.Text.RegularExpressions; -using System.Threading; namespace FreeSql.Internal { class Utils { - static ConcurrentDictionary> _cacheGetTableByEntity = new ConcurrentDictionary>(); + static ConcurrentDictionary> _cacheGetTableByEntity = new ConcurrentDictionary>(); internal static void RemoveTableByEntity(Type entity, CommonUtils common) { if (entity.FullName.StartsWith("<>f__AnonymousType")) return; - var tbc = _cacheGetTableByEntity.GetOrAdd(common.DbName, k1 => new ConcurrentDictionary()); //区分数据库类型缓存 + var tbc = _cacheGetTableByEntity.GetOrAdd(common._orm.Ado.DataType, k1 => new ConcurrentDictionary()); //区分数据库类型缓存 tbc.TryRemove(entity, out var trytb); } internal static TableInfo GetTableByEntity(Type entity, CommonUtils common) { if (entity.FullName.StartsWith("<>f__AnonymousType")) return null; - var tbc = _cacheGetTableByEntity.GetOrAdd(common.DbName, k1 => new ConcurrentDictionary()); //区分数据库类型缓存 + var tbc = _cacheGetTableByEntity.GetOrAdd(common._orm.Ado.DataType, k1 => new ConcurrentDictionary()); //区分数据库类型缓存 if (tbc.TryGetValue(entity, out var trytb)) return trytb; if (common.CodeFirst.GetDbInfo(entity) != null) return null; @@ -528,39 +519,39 @@ namespace FreeSql.Internal { [typeof(byte[])] = true, [typeof(string)] = true, [typeof(Guid)] = true, - [typeof(MygisPoint)] = true, - [typeof(MygisLineString)] = true, - [typeof(MygisPolygon)] = true, - [typeof(MygisMultiPoint)] = true, - [typeof(MygisMultiLineString)] = true, - [typeof(MygisMultiPolygon)] = true, - [typeof(BitArray)] = true, - [typeof(NpgsqlPoint)] = true, - [typeof(NpgsqlLine)] = true, - [typeof(NpgsqlLSeg)] = true, - [typeof(NpgsqlBox)] = true, - [typeof(NpgsqlPath)] = true, - [typeof(NpgsqlPolygon)] = true, - [typeof(NpgsqlCircle)] = true, - [typeof((IPAddress Address, int Subnet))] = true, - [typeof(IPAddress)] = true, - [typeof(PhysicalAddress)] = true, - [typeof(NpgsqlRange)] = true, - [typeof(NpgsqlRange)] = true, - [typeof(NpgsqlRange)] = true, - [typeof(NpgsqlRange)] = true, - [typeof(PostgisPoint)] = true, - [typeof(PostgisLineString)] = true, - [typeof(PostgisPolygon)] = true, - [typeof(PostgisMultiPoint)] = true, - [typeof(PostgisMultiLineString)] = true, - [typeof(PostgisMultiPolygon)] = true, - [typeof(PostgisGeometry)] = true, - [typeof(PostgisGeometryCollection)] = true, - [typeof(Dictionary)] = true, - [typeof(JToken)] = true, - [typeof(JObject)] = true, - [typeof(JArray)] = true, + //[typeof(MygisPoint)] = true, + //[typeof(MygisLineString)] = true, + //[typeof(MygisPolygon)] = true, + //[typeof(MygisMultiPoint)] = true, + //[typeof(MygisMultiLineString)] = true, + //[typeof(MygisMultiPolygon)] = true, + //[typeof(BitArray)] = true, + //[typeof(NpgsqlPoint)] = true, + //[typeof(NpgsqlLine)] = true, + //[typeof(NpgsqlLSeg)] = true, + //[typeof(NpgsqlBox)] = true, + //[typeof(NpgsqlPath)] = true, + //[typeof(NpgsqlPolygon)] = true, + //[typeof(NpgsqlCircle)] = true, + //[typeof((IPAddress Address, int Subnet))] = true, + //[typeof(IPAddress)] = true, + //[typeof(PhysicalAddress)] = true, + //[typeof(NpgsqlRange)] = true, + //[typeof(NpgsqlRange)] = true, + //[typeof(NpgsqlRange)] = true, + //[typeof(NpgsqlRange)] = true, + //[typeof(PostgisPoint)] = true, + //[typeof(PostgisLineString)] = true, + //[typeof(PostgisPolygon)] = true, + //[typeof(PostgisMultiPoint)] = true, + //[typeof(PostgisMultiLineString)] = true, + //[typeof(PostgisMultiPolygon)] = true, + //[typeof(PostgisGeometry)] = true, + //[typeof(PostgisGeometryCollection)] = true, + //[typeof(Dictionary)] = true, + //[typeof(JToken)] = true, + //[typeof(JObject)] = true, + //[typeof(JArray)] = true, }; internal static ConcurrentDictionary> _dicExecuteArrayRowReadClassOrTuple = new ConcurrentDictionary>(); internal class RowInfo { diff --git a/FreeSql/MySql/Curd/MySqlInsert.cs b/FreeSql/MySql/Curd/MySqlInsert.cs index eeb27ab5..8c2da2ba 100644 --- a/FreeSql/MySql/Curd/MySqlInsert.cs +++ b/FreeSql/MySql/Curd/MySqlInsert.cs @@ -11,20 +11,27 @@ namespace FreeSql.MySql.Curd { : base(orm, commonUtils, commonExpression) { } - public override long ExecuteIdentity() { + public override int ExecuteAffrows() => base.SplitExecuteAffrows(5000, 3000); + public override Task ExecuteAffrowsAsync() => base.SplitExecuteAffrowsAsync(5000, 3000); + public override long ExecuteIdentity() => base.SplitExecuteIdentity(5000, 3000); + public override Task ExecuteIdentityAsync() => base.SplitExecuteIdentityAsync(5000, 3000); + public override List ExecuteInserted() => base.SplitExecuteInserted(5000, 3000); + public override Task> ExecuteInsertedAsync() => base.SplitExecuteInsertedAsync(5000, 3000); + + + internal override long RawExecuteIdentity() { var sql = this.ToSql(); if (string.IsNullOrEmpty(sql)) return 0; return long.TryParse(string.Concat(_orm.Ado.ExecuteScalar(_transaction, CommandType.Text, string.Concat(sql, "; SELECT LAST_INSERT_ID();"), _params)), out var trylng) ? trylng : 0; } - async public override Task ExecuteIdentityAsync() { + async internal override Task RawExecuteIdentityAsync() { var sql = this.ToSql(); if (string.IsNullOrEmpty(sql)) return 0; return long.TryParse(string.Concat(await _orm.Ado.ExecuteScalarAsync(_transaction, CommandType.Text, string.Concat(sql, "; SELECT LAST_INSERT_ID();"), _params)), out var trylng) ? trylng : 0; } - - public override List ExecuteInserted() { + internal override List RawExecuteInserted() { var sql = this.ToSql(); if (string.IsNullOrEmpty(sql)) return new List(); @@ -39,7 +46,7 @@ namespace FreeSql.MySql.Curd { } return _orm.Ado.Query(_transaction, CommandType.Text, sb.ToString(), _params); } - async public override Task> ExecuteInsertedAsync() { + async internal override Task> RawExecuteInsertedAsync() { var sql = this.ToSql(); if (string.IsNullOrEmpty(sql)) return new List(); diff --git a/FreeSql/MySql/MySqlCodeFirst.cs b/FreeSql/MySql/MySqlCodeFirst.cs index db3ce210..d67a77d8 100644 --- a/FreeSql/MySql/MySqlCodeFirst.cs +++ b/FreeSql/MySql/MySqlCodeFirst.cs @@ -23,10 +23,11 @@ namespace FreeSql.MySql { _commonExpression = commonExpression; } - public bool IsAutoSyncStructure { get; set; } = true; + public bool IsAutoSyncStructure { get; set; } = false; public bool IsSyncStructureToLower { get; set; } = false; public bool IsSyncStructureToUpper { get; set; } = false; public bool IsConfigEntityFromDbFirst { get; set; } = false; + public bool IsNoneCommandParameter { get; set; } = false; public bool IsLazyLoading { get; set; } = false; static object _dicCsToDbLock = new object(); diff --git a/FreeSql/MySql/MySqlExtensions.cs b/FreeSql/MySql/MySqlExtensions.cs new file mode 100644 index 00000000..84665bf3 --- /dev/null +++ b/FreeSql/MySql/MySqlExtensions.cs @@ -0,0 +1,11 @@ +public static class FreeSqlMySqlExtensions { + + /// + /// 特殊处理类似 string.Format 的使用方法,防止注入,以及 IS NULL 转换 + /// + /// + /// + /// + public static string FormatMySql(this string that, params object[] args) => _mysqlAdo.Addslashes(that, args); + static FreeSql.MySql.MySqlAdo _mysqlAdo = new FreeSql.MySql.MySqlAdo(); +} diff --git a/FreeSql/MySql/MySqlProvider.cs b/FreeSql/MySql/MySqlProvider.cs index b4becf70..ad45157a 100644 --- a/FreeSql/MySql/MySqlProvider.cs +++ b/FreeSql/MySql/MySqlProvider.cs @@ -12,6 +12,15 @@ namespace FreeSql.MySql { class MySqlProvider : IFreeSql { + static MySqlProvider() { + Utils.dicExecuteArrayRowReadClassOrTuple.Add(typeof(MygisPoint), true); + Utils.dicExecuteArrayRowReadClassOrTuple.Add(typeof(MygisLineString), true); + Utils.dicExecuteArrayRowReadClassOrTuple.Add(typeof(MygisPolygon), true); + Utils.dicExecuteArrayRowReadClassOrTuple.Add(typeof(MygisMultiPoint), true); + Utils.dicExecuteArrayRowReadClassOrTuple.Add(typeof(MygisMultiLineString), true); + Utils.dicExecuteArrayRowReadClassOrTuple.Add(typeof(MygisMultiPolygon), true); + } + public ISelect Select() where T1 : class => new MySqlSelect(this, this.InternalCommonUtils, this.InternalCommonExpression, null); public ISelect Select(object dywhere) where T1 : class => new MySqlSelect(this, this.InternalCommonUtils, this.InternalCommonExpression, dywhere); public IInsert Insert() where T1 : class => new MySqlInsert(this, this.InternalCommonUtils, this.InternalCommonExpression); diff --git a/FreeSql/MySql/MySqlUtils.cs b/FreeSql/MySql/MySqlUtils.cs index 77955b57..0fd846f3 100644 --- a/FreeSql/MySql/MySqlUtils.cs +++ b/FreeSql/MySql/MySqlUtils.cs @@ -14,8 +14,7 @@ namespace FreeSql.MySql { internal override DbParameter AppendParamter(List _params, string parameterName, Type type, object value) { if (string.IsNullOrEmpty(parameterName)) parameterName = $"p_{_params?.Count}"; - else if (_orm.CodeFirst.IsSyncStructureToLower) parameterName = parameterName.ToLower(); - var ret = new MySqlParameter { ParameterName = $"?{parameterName}", Value = value }; + var ret = new MySqlParameter { ParameterName = QuoteParamterName(parameterName), Value = value }; var tp = _orm.CodeFirst.GetDbInfo(type)?.type; if (tp != null) { if ((MySqlDbType)tp.Value == MySqlDbType.Geometry) { @@ -72,7 +71,7 @@ namespace FreeSql.MySql { return columnName; } - internal override string GetNoneParamaterSqlValue(Type type, object value) { + internal override string GetNoneParamaterSqlValue(List specialParams, Type type, object value) { if (value == null) return "NULL"; if (type == typeof(byte[])) { var bytes = value as byte[]; @@ -88,7 +87,5 @@ namespace FreeSql.MySql { } return FormatSql("{0}", value, 1); } - - internal override string DbName => "MySql"; } } diff --git a/FreeSql/Oracle/Curd/OracleInsert.cs b/FreeSql/Oracle/Curd/OracleInsert.cs index 153cfef0..eda29036 100644 --- a/FreeSql/Oracle/Curd/OracleInsert.cs +++ b/FreeSql/Oracle/Curd/OracleInsert.cs @@ -16,6 +16,14 @@ namespace FreeSql.Oracle.Curd { : base(orm, commonUtils, commonExpression) { } + public override int ExecuteAffrows() => base.SplitExecuteAffrows(500, 999); + public override Task ExecuteAffrowsAsync() => base.SplitExecuteAffrowsAsync(500, 999); + public override long ExecuteIdentity() => base.SplitExecuteIdentity(500, 999); + public override Task ExecuteIdentityAsync() => base.SplitExecuteIdentityAsync(500, 999); + public override List ExecuteInserted() => base.SplitExecuteInserted(500, 999); + public override Task> ExecuteInsertedAsync() => base.SplitExecuteInsertedAsync(500, 999); + + public override string ToSql() { if (_source == null || _source.Any() == false) return null; var sb = new StringBuilder(); @@ -40,9 +48,8 @@ namespace FreeSql.Oracle.Curd { } sbtb.Append(") "); - //_params = new DbParameter[colidx * _source.Count]; - _params = new DbParameter[0]; - //_params = new DbParameter[colidx * 5]; //批量添加第5行起,不使用参数化 + _params = _noneParameter ? new DbParameter[0] : new DbParameter[colidx * _source.Count]; + var specialParams = new List(); var didx = 0; foreach (var d in _source) { if (_source.Count > 1) sb.Append("\r\n"); @@ -59,24 +66,24 @@ namespace FreeSql.Oracle.Curd { if (col.Attribute.IsPrimary && (col.CsType == typeof(Guid) || col.CsType == typeof(Guid?)) && (val == null || (Guid)val == Guid.Empty)) tryp.SetValue(d, val = FreeUtil.NewMongodbId()); } - //if (didx >= 5) - sb.Append(_commonUtils.GetNoneParamaterSqlValue(col.CsType, val)); - //else { - // sb.Append(_commonUtils.QuoteWriteParamter(col.CsType, $"{_commonUtils.QuoteParamterName(col.CsName)}{didx}")); - // _params[didx * colidx + colidx2] = _commonUtils.AppendParamter(null, $"{col.CsName}{didx}", col.CsType, val); - //} + if (_noneParameter) + sb.Append(_commonUtils.GetNoneParamaterSqlValue(specialParams, col.CsType, val)); + else { + sb.Append(_commonUtils.QuoteWriteParamter(col.CsType, _commonUtils.QuoteParamterName($"{col.CsName}{didx}"))); + _params[didx * colidx + colidx2] = _commonUtils.AppendParamter(null, $"{col.CsName}{didx}", col.CsType, val); + } ++colidx2; } } sb.Append(")"); ++didx; } - //if (_source.Count > 1) sb.Append("\r\n SELECT 1 FROM DUAL"); + if (_source.Count > 1) sb.Append("\r\n SELECT 1 FROM DUAL"); return sb.ToString(); } ColumnInfo _identCol; - public override long ExecuteIdentity() { + internal override long RawExecuteIdentity() { var sql = this.ToSql(); if (string.IsNullOrEmpty(sql)) return 0; @@ -90,7 +97,7 @@ namespace FreeSql.Oracle.Curd { _orm.Ado.ExecuteNonQuery(_transaction, CommandType.Text, $"{sql} RETURNING {identColName} INTO {identParam.ParameterName}", _params.Concat(new[] { identParam }).ToArray()); return long.TryParse(string.Concat(identParam.Value), out var trylng) ? trylng : 0; } - async public override Task ExecuteIdentityAsync() { + async internal override Task RawExecuteIdentityAsync() { var sql = this.ToSql(); if (string.IsNullOrEmpty(sql)) return 0; @@ -105,53 +112,19 @@ namespace FreeSql.Oracle.Curd { return long.TryParse(string.Concat(identParam.Value), out var trylng) ? trylng : 0; } - public override List ExecuteInserted() { - throw new NotImplementedException(); + internal override List RawExecuteInserted() { + var sql = this.ToSql(); + if (string.IsNullOrEmpty(sql)) return new List(); -// var sql = this.ToSql(); -// if (string.IsNullOrEmpty(sql)) return new List(); - -// var sb = new StringBuilder(); -// sb.Append(@"declare -//type v_tp_rec is record("); - -// var colidx = 0; -// foreach (var col in _table.Columns.Values) { -// if (colidx > 0) sb.Append(", "); -// sb.Append(_commonUtils.QuoteSqlName(col.CsName)).Append(" ").Append(_commonUtils.QuoteSqlName(_tableRule?.Invoke(_table.DbName) ?? _table.DbName))).Append(".").Append(_commonUtils.QuoteSqlName(col.Attribute.Name)).Append("%type"); -// ++colidx; -// } -// sb.Append(@"); -//type v_tp_tab is table of v_tp_rec; -//v_tab v_tp_tab; -//begin -//"); - -// sb.Append(sql).Append(" RETURNING "); -// colidx = 0; -// foreach (var col in _table.Columns.Values) { -// if (colidx > 0) sb.Append(", "); -// sb.Append(_commonUtils.QuoteReadColumn(col.CsType, _commonUtils.QuoteSqlName(col.Attribute.Name))); -// ++colidx; -// } -// sb.Append(@"bulk collect into v_tab; -//for i in 1..v_tab.count loop -// dbms_output.put_line("); -// //v_tab(i).empno||'-'||v_tab(i).ename -// colidx = 0; -// foreach (var col in _table.Columns.Values) { -// if (colidx > 0) sb.Append("||'-'||"); -// sb.Append("v_tab(i).").Append(_commonUtils.QuoteSqlName(col.CsName)); -// ++colidx; -// } -// sb.Append(@"); -//end loop; -//end; -//"); -// return _orm.Ado.Query(_transaction, CommandType.Text, sb.ToString(), _params); + this.ExecuteAffrows(); + return _source; } - public override Task> ExecuteInsertedAsync() { - throw new NotImplementedException(); + async internal override Task> RawExecuteInsertedAsync() { + var sql = this.ToSql(); + if (string.IsNullOrEmpty(sql)) return new List(); + + await this.ExecuteAffrowsAsync(); + return _source; } } } diff --git a/FreeSql/Oracle/OracleCodeFirst.cs b/FreeSql/Oracle/OracleCodeFirst.cs index ea20540b..fd66fca7 100644 --- a/FreeSql/Oracle/OracleCodeFirst.cs +++ b/FreeSql/Oracle/OracleCodeFirst.cs @@ -23,11 +23,11 @@ namespace FreeSql.Oracle { _commonExpression = commonExpression; } - public bool IsAutoSyncStructure { get; set; } = true; - public bool IsQuoteSqlName { get; set; } = true; + public bool IsAutoSyncStructure { get; set; } = false; public bool IsSyncStructureToLower { get; set; } = false; public bool IsSyncStructureToUpper { get; set; } = false; public bool IsConfigEntityFromDbFirst { get; set; } = false; + public bool IsNoneCommandParameter { get; set; } = false; public bool IsLazyLoading { get; set; } = false; static object _dicCsToDbLock = new object(); diff --git a/FreeSql/Oracle/OracleExtensions.cs b/FreeSql/Oracle/OracleExtensions.cs new file mode 100644 index 00000000..93282299 --- /dev/null +++ b/FreeSql/Oracle/OracleExtensions.cs @@ -0,0 +1,11 @@ +public static class FreeSqlOracleExtensions { + + /// + /// 特殊处理类似 string.Format 的使用方法,防止注入,以及 IS NULL 转换 + /// + /// + /// + /// + public static string FormatOracleSQL(this string that, params object[] args) => _oracleAdo.Addslashes(that, args); + static FreeSql.Oracle.OracleAdo _oracleAdo = new FreeSql.Oracle.OracleAdo(); +} diff --git a/FreeSql/Oracle/OracleUtils.cs b/FreeSql/Oracle/OracleUtils.cs index d58e348e..d5b5d377 100644 --- a/FreeSql/Oracle/OracleUtils.cs +++ b/FreeSql/Oracle/OracleUtils.cs @@ -14,14 +14,13 @@ namespace FreeSql.Oracle { internal override DbParameter AppendParamter(List _params, string parameterName, Type type, object value) { if (string.IsNullOrEmpty(parameterName)) parameterName = $"p_{_params?.Count}"; - else if (_orm.CodeFirst.IsSyncStructureToLower) parameterName = parameterName.ToLower(); var dbtype = (OracleDbType)_orm.CodeFirst.GetDbInfo(type)?.type; if (dbtype == OracleDbType.Boolean) { if (value == null) value = null; else value = (bool)value == true ? 1 : 0; dbtype = OracleDbType.Int16; } - var ret = new OracleParameter { ParameterName = $":{parameterName}", OracleDbType = dbtype, Value = value }; + var ret = new OracleParameter { ParameterName = QuoteParamterName(parameterName), OracleDbType = dbtype, Value = value }; _params?.Add(ret); return ret; } @@ -48,7 +47,7 @@ namespace FreeSql.Oracle { internal override string QuoteWriteParamter(Type type, string paramterName) => paramterName; internal override string QuoteReadColumn(Type type, string columnName) => columnName; - internal override string GetNoneParamaterSqlValue(Type type, object value) { + internal override string GetNoneParamaterSqlValue(List specialParams, Type type, object value) { if (value == null) return "NULL"; if (type == typeof(byte[])) { var bytes = value as byte[]; @@ -61,7 +60,5 @@ namespace FreeSql.Oracle { } return FormatSql("{0}", value, 1); } - - internal override string DbName => "Oracle"; } } diff --git a/FreeSql/PostgreSQL/Curd/PostgreSQLInsert.cs b/FreeSql/PostgreSQL/Curd/PostgreSQLInsert.cs index 8e6ea38c..b36e0987 100644 --- a/FreeSql/PostgreSQL/Curd/PostgreSQLInsert.cs +++ b/FreeSql/PostgreSQL/Curd/PostgreSQLInsert.cs @@ -12,7 +12,15 @@ namespace FreeSql.PostgreSQL.Curd { : base(orm, commonUtils, commonExpression) { } - public override long ExecuteIdentity() { + public override int ExecuteAffrows() => base.SplitExecuteAffrows(5000, 3000); + public override Task ExecuteAffrowsAsync() => base.SplitExecuteAffrowsAsync(5000, 3000); + public override long ExecuteIdentity() => base.SplitExecuteIdentity(5000, 3000); + public override Task ExecuteIdentityAsync() => base.SplitExecuteIdentityAsync(5000, 3000); + public override List ExecuteInserted() => base.SplitExecuteInserted(5000, 3000); + public override Task> ExecuteInsertedAsync() => base.SplitExecuteInsertedAsync(5000, 3000); + + + internal override long RawExecuteIdentity() { var sql = this.ToSql(); if (string.IsNullOrEmpty(sql)) return 0; @@ -23,7 +31,7 @@ namespace FreeSql.PostgreSQL.Curd { } return long.TryParse(string.Concat(_orm.Ado.ExecuteScalar(_transaction, CommandType.Text, string.Concat(sql, " RETURNING ", _commonUtils.QuoteSqlName(identCols.First().Value.Attribute.Name)), _params)), out var trylng) ? trylng : 0; } - async public override Task ExecuteIdentityAsync() { + async internal override Task RawExecuteIdentityAsync() { var sql = this.ToSql(); if (string.IsNullOrEmpty(sql)) return 0; @@ -35,7 +43,7 @@ namespace FreeSql.PostgreSQL.Curd { return long.TryParse(string.Concat(await _orm.Ado.ExecuteScalarAsync(_transaction, CommandType.Text, string.Concat(sql, " RETURNING ", _commonUtils.QuoteSqlName(identCols.First().Value.Attribute.Name)), _params)), out var trylng) ? trylng : 0; } - public override List ExecuteInserted() { + internal override List RawExecuteInserted() { var sql = this.ToSql(); if (string.IsNullOrEmpty(sql)) return new List(); @@ -50,7 +58,7 @@ namespace FreeSql.PostgreSQL.Curd { } return _orm.Ado.Query(_transaction, CommandType.Text, sb.ToString(), _params); } - async public override Task> ExecuteInsertedAsync() { + async internal override Task> RawExecuteInsertedAsync() { var sql = this.ToSql(); if (string.IsNullOrEmpty(sql)) return new List(); diff --git a/FreeSql/PostgreSQL/PostgreSQLCodeFirst.cs b/FreeSql/PostgreSQL/PostgreSQLCodeFirst.cs index c6b402b1..54bc7fad 100644 --- a/FreeSql/PostgreSQL/PostgreSQLCodeFirst.cs +++ b/FreeSql/PostgreSQL/PostgreSQLCodeFirst.cs @@ -28,10 +28,11 @@ namespace FreeSql.PostgreSQL { _commonExpression = commonExpression; } - public bool IsAutoSyncStructure { get; set; } = true; + public bool IsAutoSyncStructure { get; set; } = false; public bool IsSyncStructureToLower { get; set; } = false; public bool IsSyncStructureToUpper { get; set; } = false; public bool IsConfigEntityFromDbFirst { get; set; } = false; + public bool IsNoneCommandParameter { get; set; } = false; public bool IsLazyLoading { get; set; } = false; static object _dicCsToDbLock = new object(); diff --git a/FreeSql/PostgreSQL/PostgreSQLExtensions.cs b/FreeSql/PostgreSQL/PostgreSQLExtensions.cs new file mode 100644 index 00000000..91ea9120 --- /dev/null +++ b/FreeSql/PostgreSQL/PostgreSQLExtensions.cs @@ -0,0 +1,11 @@ +public static class FreeSqlPostgreSQLExtensions { + + /// + /// 特殊处理类似 string.Format 的使用方法,防止注入,以及 IS NULL 转换 + /// + /// + /// + /// + public static string FormatPostgreSQL(this string that, params object[] args) => _postgresqlAdo.Addslashes(that, args); + static FreeSql.PostgreSQL.PostgreSQLAdo _postgresqlAdo = new FreeSql.PostgreSQL.PostgreSQLAdo(); +} diff --git a/FreeSql/PostgreSQL/PostgreSQLProvider.cs b/FreeSql/PostgreSQL/PostgreSQLProvider.cs index 6e54ff2e..998bfa0a 100644 --- a/FreeSql/PostgreSQL/PostgreSQLProvider.cs +++ b/FreeSql/PostgreSQL/PostgreSQLProvider.cs @@ -4,14 +4,50 @@ using FreeSql.PostgreSQL.Curd; using Microsoft.Extensions.Caching.Distributed; using Microsoft.Extensions.Configuration; using Microsoft.Extensions.Logging; +using Newtonsoft.Json.Linq; +using Npgsql.LegacyPostgis; +using NpgsqlTypes; using System; +using System.Collections; using System.Collections.Generic; using System.Data.Common; +using System.Net; +using System.Net.NetworkInformation; namespace FreeSql.PostgreSQL { class PostgreSQLProvider : IFreeSql { + static PostgreSQLProvider() { + Utils.dicExecuteArrayRowReadClassOrTuple.Add(typeof(BitArray), true); + Utils.dicExecuteArrayRowReadClassOrTuple.Add(typeof(NpgsqlPoint), true); + Utils.dicExecuteArrayRowReadClassOrTuple.Add(typeof(NpgsqlLine), true); + Utils.dicExecuteArrayRowReadClassOrTuple.Add(typeof(NpgsqlLSeg), true); + Utils.dicExecuteArrayRowReadClassOrTuple.Add(typeof(NpgsqlBox), true); + Utils.dicExecuteArrayRowReadClassOrTuple.Add(typeof(NpgsqlPath), true); + Utils.dicExecuteArrayRowReadClassOrTuple.Add(typeof(NpgsqlPolygon), true); + Utils.dicExecuteArrayRowReadClassOrTuple.Add(typeof(NpgsqlCircle), true); + Utils.dicExecuteArrayRowReadClassOrTuple.Add(typeof((IPAddress Address, int Subnet)), true); + Utils.dicExecuteArrayRowReadClassOrTuple.Add(typeof(IPAddress), true); + Utils.dicExecuteArrayRowReadClassOrTuple.Add(typeof(PhysicalAddress), true); + Utils.dicExecuteArrayRowReadClassOrTuple.Add(typeof(NpgsqlRange), true); + Utils.dicExecuteArrayRowReadClassOrTuple.Add(typeof(NpgsqlRange), true); + Utils.dicExecuteArrayRowReadClassOrTuple.Add(typeof(NpgsqlRange), true); + Utils.dicExecuteArrayRowReadClassOrTuple.Add(typeof(NpgsqlRange), true); + Utils.dicExecuteArrayRowReadClassOrTuple.Add(typeof(PostgisPoint), true); + Utils.dicExecuteArrayRowReadClassOrTuple.Add(typeof(PostgisLineString), true); + Utils.dicExecuteArrayRowReadClassOrTuple.Add(typeof(PostgisPolygon), true); + Utils.dicExecuteArrayRowReadClassOrTuple.Add(typeof(PostgisMultiPoint), true); + Utils.dicExecuteArrayRowReadClassOrTuple.Add(typeof(PostgisMultiLineString), true); + Utils.dicExecuteArrayRowReadClassOrTuple.Add(typeof(PostgisMultiPolygon), true); + Utils.dicExecuteArrayRowReadClassOrTuple.Add(typeof(PostgisGeometry), true); + Utils.dicExecuteArrayRowReadClassOrTuple.Add(typeof(PostgisGeometryCollection), true); + Utils.dicExecuteArrayRowReadClassOrTuple.Add(typeof(Dictionary), true); + Utils.dicExecuteArrayRowReadClassOrTuple.Add(typeof(JToken), true); + Utils.dicExecuteArrayRowReadClassOrTuple.Add(typeof(JObject), true); + Utils.dicExecuteArrayRowReadClassOrTuple.Add(typeof(JArray), true); + } + public ISelect Select() where T1 : class => new PostgreSQLSelect(this, this.InternalCommonUtils, this.InternalCommonExpression, null); public ISelect Select(object dywhere) where T1 : class => new PostgreSQLSelect(this, this.InternalCommonUtils, this.InternalCommonExpression, dywhere); public IInsert Insert() where T1 : class => new PostgreSQLInsert(this, this.InternalCommonUtils, this.InternalCommonExpression); diff --git a/FreeSql/PostgreSQL/PostgreSQLUtils.cs b/FreeSql/PostgreSQL/PostgreSQLUtils.cs index 30d69c83..d689d1d7 100644 --- a/FreeSql/PostgreSQL/PostgreSQLUtils.cs +++ b/FreeSql/PostgreSQL/PostgreSQLUtils.cs @@ -1,9 +1,12 @@ using FreeSql.Internal; using Newtonsoft.Json.Linq; using Npgsql; +using Npgsql.LegacyPostgis; using NpgsqlTypes; using System; +using System.Collections; using System.Collections.Generic; +using System.Collections.Concurrent; using System.Data.Common; using System.Linq; using System.Net; @@ -68,9 +71,8 @@ namespace FreeSql.PostgreSQL { internal override DbParameter AppendParamter(List _params, string parameterName, Type type, object value) { if (string.IsNullOrEmpty(parameterName)) parameterName = $"p_{_params?.Count}"; - else if (_orm.CodeFirst.IsSyncStructureToLower) parameterName = parameterName.ToLower(); if (value != null) value = getParamterValue(type, value); - var ret = new NpgsqlParameter { ParameterName = $"@{parameterName}", Value = value }; + var ret = new NpgsqlParameter { ParameterName = QuoteParamterName(parameterName), Value = value }; //if (value.GetType().IsEnum || value.GetType().GenericTypeArguments.FirstOrDefault()?.IsEnum == true) { // ret.DataTypeName = ""; //} else { @@ -104,13 +106,18 @@ namespace FreeSql.PostgreSQL { internal override string QuoteWriteParamter(Type type, string paramterName) => paramterName; internal override string QuoteReadColumn(Type type, string columnName) => columnName; - internal override string GetNoneParamaterSqlValue(Type type, object value) { + static ConcurrentDictionary _dicIsAssignableFromPostgisGeometry = new ConcurrentDictionary(); + internal override string GetNoneParamaterSqlValue(List specialParams, Type type, object value) { if (value == null) return "NULL"; + if (_dicIsAssignableFromPostgisGeometry.GetOrAdd(type, t2 => typeof(PostgisGeometry).IsAssignableFrom(type.IsArray ? type.GetElementType() : type))) { + var pam = AppendParamter(specialParams, null, type, value); + return pam.ParameterName; + } value = getParamterValue(type, value); var type2 = value.GetType(); if (type2 == typeof(byte[])) { var bytes = value as byte[]; - var sb = new StringBuilder().Append("E'\\x"); + var sb = new StringBuilder().Append("'\\x"); foreach (var vc in bytes) { if (vc < 10) sb.Append("0"); sb.Append(vc.ToString("X")); @@ -118,11 +125,33 @@ namespace FreeSql.PostgreSQL { return sb.Append("'").ToString(); //val = Encoding.UTF8.GetString(val as byte[]); } else if (type2 == typeof(TimeSpan) || type2 == typeof(TimeSpan?)) { var ts = (TimeSpan)value; - value = $"{ts.Hours}:{ts.Minutes}:{ts.Seconds}"; + 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, eleType, item)); + } + sb.Append("]"); + var dbinfo = _orm.CodeFirst.GetDbInfo(type); + if (dbinfo.HasValue) sb.Append("::").Append(dbinfo.Value.dbtype); + return sb.ToString(); + } else if (type2 == typeof(BitArray)) { + return $"'{(value as BitArray).To1010()}'"; + } else if (type2 == typeof(NpgsqlLine) || type2 == typeof(NpgsqlLine?)) { + var line = value.ToString(); + return line == "{0,0,0}" ? "'{0,-1,-1}'" : $"'{line}'"; + } else if (type2 == typeof((IPAddress Address, int Subnet)) || type2 == typeof((IPAddress Address, int Subnet)?)) { + var cidr = ((IPAddress Address, int Subnet))value; + return $"'{cidr.Address}/{cidr.Subnet}'"; + } else if (dicGetParamterValue.ContainsKey(type2.FullName)) { + value = string.Concat(value); } return FormatSql("{0}", value, 1); } - - internal override string DbName => "PostgreSQL"; } } diff --git a/FreeSql/SqlServer/Curd/SqlServerInsert.cs b/FreeSql/SqlServer/Curd/SqlServerInsert.cs index a7ce2b1f..6932bf93 100644 --- a/FreeSql/SqlServer/Curd/SqlServerInsert.cs +++ b/FreeSql/SqlServer/Curd/SqlServerInsert.cs @@ -14,46 +14,28 @@ namespace FreeSql.SqlServer.Curd { : base(orm, commonUtils, commonExpression) { } - public override long ExecuteIdentity() { - //if (_source?.Count > 999) { - // List> inserts = new List>(); - // var idx = 0; - // while (idx < _source.Count) { - // var count = Math.Min(_source.Count, idx + 999) - idx; - // var insert = _orm.Insert().AppendData(_source.GetRange(idx, count)); - // _ - // inserts.Add(insert); - // idx += 999; - // } - // Object conn = null; - // var trans = _transaction; - // if (_transaction == null) { - // conn = _orm.Ado.MasterPool.Get(); - // trans = conn.Value.BeginTransaction(); - // } - // try { - // for (var a = 0; a < inserts.Count; a++) { - // inserts[a].WithTransaction(trans) - // } - // if (_transaction == null) trans.Commit(); - // } catch { - // if (_transaction == null) trans.Rollback(); - // throw; - // } - //} + public override int ExecuteAffrows() => base.SplitExecuteAffrows(1000, 2100); + public override Task ExecuteAffrowsAsync() => base.SplitExecuteAffrowsAsync(1000, 2100); + public override long ExecuteIdentity() => base.SplitExecuteIdentity(1000, 2100); + public override Task ExecuteIdentityAsync() => base.SplitExecuteIdentityAsync(1000, 2100); + public override List ExecuteInserted() => base.SplitExecuteInserted(1000, 2100); + public override Task> ExecuteInsertedAsync() => base.SplitExecuteInsertedAsync(1000, 2100); + + + internal override long RawExecuteIdentity() { var sql = this.ToSql(); if (string.IsNullOrEmpty(sql)) return 0; return long.TryParse(string.Concat(_orm.Ado.ExecuteScalar(_transaction, CommandType.Text, string.Concat(sql, "; SELECT SCOPE_IDENTITY();"), _params)), out var trylng) ? trylng : 0; } - async public override Task ExecuteIdentityAsync() { + async internal override Task RawExecuteIdentityAsync() { var sql = this.ToSql(); if (string.IsNullOrEmpty(sql)) return 0; return long.TryParse(string.Concat(await _orm.Ado.ExecuteScalarAsync(_transaction, CommandType.Text, string.Concat(sql, "; SELECT SCOPE_IDENTITY();"), _params)), out var trylng) ? trylng : 0; } - public override List ExecuteInserted() { + internal override List RawExecuteInserted() { var sql = this.ToSql(); if (string.IsNullOrEmpty(sql)) return new List(); @@ -73,7 +55,7 @@ namespace FreeSql.SqlServer.Curd { return _orm.Ado.Query(_transaction, CommandType.Text, sb.ToString(), _params); } - async public override Task> ExecuteInsertedAsync() { + async internal override Task> RawExecuteInsertedAsync() { var sql = this.ToSql(); if (string.IsNullOrEmpty(sql)) return new List(); diff --git a/FreeSql/SqlServer/SqlServerCodeFirst.cs b/FreeSql/SqlServer/SqlServerCodeFirst.cs index fa4b47d4..ee6920f0 100644 --- a/FreeSql/SqlServer/SqlServerCodeFirst.cs +++ b/FreeSql/SqlServer/SqlServerCodeFirst.cs @@ -22,10 +22,11 @@ namespace FreeSql.SqlServer { _commonExpression = commonExpression; } - public bool IsAutoSyncStructure { get; set; } = true; + public bool IsAutoSyncStructure { get; set; } = false; public bool IsSyncStructureToLower { get; set; } = false; public bool IsSyncStructureToUpper { get; set; } = false; public bool IsConfigEntityFromDbFirst { get; set; } = false; + public bool IsNoneCommandParameter { get; set; } = false; public bool IsLazyLoading { get; set; } = false; static object _dicCsToDbLock = new object(); diff --git a/FreeSql/SqlServer/SqlServerExtensions.cs b/FreeSql/SqlServer/SqlServerExtensions.cs new file mode 100644 index 00000000..b9b201a4 --- /dev/null +++ b/FreeSql/SqlServer/SqlServerExtensions.cs @@ -0,0 +1,11 @@ +public static class FreeSqlSqlServerExtensions { + + /// + /// 特殊处理类似 string.Format 的使用方法,防止注入,以及 IS NULL 转换 + /// + /// + /// + /// + public static string FormatSqlServer(this string that, params object[] args) => _sqlserverAdo.Addslashes(that, args); + static FreeSql.SqlServer.SqlServerAdo _sqlserverAdo = new FreeSql.SqlServer.SqlServerAdo(); +} diff --git a/FreeSql/SqlServer/SqlServerUtils.cs b/FreeSql/SqlServer/SqlServerUtils.cs index f4601100..9705900e 100644 --- a/FreeSql/SqlServer/SqlServerUtils.cs +++ b/FreeSql/SqlServer/SqlServerUtils.cs @@ -17,9 +17,8 @@ namespace FreeSql.SqlServer { internal override DbParameter AppendParamter(List _params, string parameterName, Type type, object value) { if (string.IsNullOrEmpty(parameterName)) parameterName = $"p_{_params?.Count}"; - else if (_orm.CodeFirst.IsSyncStructureToLower) parameterName = parameterName.ToLower(); if (value?.Equals(DateTime.MinValue) == true) value = new DateTime(1970, 1, 1); - var ret = new SqlParameter { ParameterName = $"@{parameterName}", Value = value }; + var ret = new SqlParameter { ParameterName = QuoteParamterName(parameterName), Value = value }; var tp = _orm.CodeFirst.GetDbInfo(type)?.type; if (tp != null) ret.SqlDbType = (SqlDbType)tp.Value; _params?.Add(ret); @@ -45,7 +44,7 @@ namespace FreeSql.SqlServer { internal override string QuoteWriteParamter(Type type, string paramterName) => paramterName; internal override string QuoteReadColumn(Type type, string columnName) => columnName; - internal override string GetNoneParamaterSqlValue(Type type, object value) { + internal override string GetNoneParamaterSqlValue(List specialParams, Type type, object value) { if (value == null) return "NULL"; if (type == typeof(byte[])) { var bytes = value as byte[]; @@ -61,7 +60,5 @@ namespace FreeSql.SqlServer { } return FormatSql("{0}", value, 1); } - - internal override string DbName => "SqlServer"; } } diff --git a/FreeSql/Sqlite/Curd/SqliteInsert.cs b/FreeSql/Sqlite/Curd/SqliteInsert.cs index d26750c0..84d6eef9 100644 --- a/FreeSql/Sqlite/Curd/SqliteInsert.cs +++ b/FreeSql/Sqlite/Curd/SqliteInsert.cs @@ -2,6 +2,7 @@ using System; using System.Collections.Generic; using System.Data; +using System.Linq; using System.Text; using System.Threading.Tasks; @@ -12,24 +13,39 @@ namespace FreeSql.Sqlite.Curd { : base(orm, commonUtils, commonExpression) { } - public override long ExecuteIdentity() { + public override int ExecuteAffrows() => base.SplitExecuteAffrows(5000, 999); + public override Task ExecuteAffrowsAsync() => base.SplitExecuteAffrowsAsync(5000, 999); + public override long ExecuteIdentity() => base.SplitExecuteIdentity(5000, 999); + public override Task ExecuteIdentityAsync() => base.SplitExecuteIdentityAsync(5000, 999); + public override List ExecuteInserted() => base.SplitExecuteInserted(5000, 999); + public override Task> ExecuteInsertedAsync() => base.SplitExecuteInsertedAsync(5000, 999); + + + internal override long RawExecuteIdentity() { var sql = this.ToSql(); if (string.IsNullOrEmpty(sql)) return 0; return long.TryParse(string.Concat(_orm.Ado.ExecuteScalar(_transaction, CommandType.Text, string.Concat(sql, "; SELECT last_insert_rowid();"), _params)), out var trylng) ? trylng : 0; } - async public override Task ExecuteIdentityAsync() { + async internal override Task RawExecuteIdentityAsync() { var sql = this.ToSql(); if (string.IsNullOrEmpty(sql)) return 0; return long.TryParse(string.Concat(await _orm.Ado.ExecuteScalarAsync(_transaction, CommandType.Text, string.Concat(sql, "; SELECT last_insert_rowid();"), _params)), out var trylng) ? trylng : 0; } + internal override List RawExecuteInserted() { + var sql = this.ToSql(); + if (string.IsNullOrEmpty(sql)) return new List(); - public override List ExecuteInserted() { - throw new NotImplementedException(); + this.ExecuteAffrows(); + return _source; } - public override Task> ExecuteInsertedAsync() { - throw new NotImplementedException(); + async internal override Task> RawExecuteInsertedAsync() { + var sql = this.ToSql(); + if (string.IsNullOrEmpty(sql)) return new List(); + + await this.ExecuteAffrowsAsync(); + return _source; } } } diff --git a/FreeSql/Sqlite/SqliteCodeFirst.cs b/FreeSql/Sqlite/SqliteCodeFirst.cs index 40dee30d..657b1aec 100644 --- a/FreeSql/Sqlite/SqliteCodeFirst.cs +++ b/FreeSql/Sqlite/SqliteCodeFirst.cs @@ -22,10 +22,11 @@ namespace FreeSql.Sqlite { _commonExpression = commonExpression; } - public bool IsAutoSyncStructure { get; set; } = true; + public bool IsAutoSyncStructure { get; set; } = false; public bool IsSyncStructureToLower { get; set; } = false; public bool IsSyncStructureToUpper { get; set; } = false; public bool IsConfigEntityFromDbFirst { get; set; } = false; + public bool IsNoneCommandParameter { get; set; } = false; public bool IsLazyLoading { get; set; } = false; static object _dicCsToDbLock = new object(); diff --git a/FreeSql/Sqlite/SqliteExtensions.cs b/FreeSql/Sqlite/SqliteExtensions.cs new file mode 100644 index 00000000..cd62a91d --- /dev/null +++ b/FreeSql/Sqlite/SqliteExtensions.cs @@ -0,0 +1,11 @@ +public static class FreeSqlSqliteExtensions { + + /// + /// 特殊处理类似 string.Format 的使用方法,防止注入,以及 IS NULL 转换 + /// + /// + /// + /// + public static string FormatSqlite (this string that, params object[] args) => _sqliteAdo.Addslashes(that, args); + static FreeSql.Sqlite.SqliteAdo _sqliteAdo = new FreeSql.Sqlite.SqliteAdo(); +} diff --git a/FreeSql/Sqlite/SqliteUtils.cs b/FreeSql/Sqlite/SqliteUtils.cs index 44dfc66f..6ff93ed9 100644 --- a/FreeSql/Sqlite/SqliteUtils.cs +++ b/FreeSql/Sqlite/SqliteUtils.cs @@ -15,7 +15,6 @@ namespace FreeSql.Sqlite { internal override DbParameter AppendParamter(List _params, string parameterName, Type type, object value) { if (string.IsNullOrEmpty(parameterName)) parameterName = $"p_{_params?.Count}"; - else if (_orm.CodeFirst.IsSyncStructureToLower) parameterName = parameterName.ToLower(); var dbtype = (DbType)_orm.CodeFirst.GetDbInfo(type)?.type; switch (dbtype) { case DbType.Guid: @@ -29,7 +28,7 @@ namespace FreeSql.Sqlite { dbtype = DbType.Int64; break; } - var ret = new SQLiteParameter { ParameterName = $"@{parameterName}", DbType = dbtype, Value = value }; + var ret = new SQLiteParameter { ParameterName = QuoteParamterName(parameterName), DbType = dbtype, Value = value }; _params?.Add(ret); return ret; } @@ -63,12 +62,10 @@ namespace FreeSql.Sqlite { internal override string QuoteWriteParamter(Type type, string paramterName) => paramterName; internal override string QuoteReadColumn(Type type, string columnName) => columnName; - internal override string GetNoneParamaterSqlValue(Type type, object value) { + internal override string GetNoneParamaterSqlValue(List specialParams, Type type, object value) { if (value == null) return "NULL"; if (type == typeof(byte[])) value = Encoding.UTF8.GetString(value as byte[]); return FormatSql("{0}", value, 1); } - - internal override string DbName => "Sqlite"; } }