From de9d7d3af29eda53c109bab866129c303a07ba96 Mon Sep 17 00:00:00 2001 From: yangl <303550688@qq.com> Date: Sat, 15 Feb 2025 01:12:29 +0800 Subject: [PATCH] =?UTF-8?q?=E5=A2=9E=E5=8A=A0sqlite=E6=89=B9=E9=87=8F?= =?UTF-8?q?=E6=8F=92=E5=85=A5=E6=96=B9=E5=BC=8F?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Sqlite/Curd/SqliteInsertTest.cs | 24 +++- .../SqliteExtensions.cs | 113 +++++++++++++++++- 2 files changed, 135 insertions(+), 2 deletions(-) diff --git a/FreeSql.Tests/FreeSql.Tests.Provider.Sqlite.Data/Sqlite/Curd/SqliteInsertTest.cs b/FreeSql.Tests/FreeSql.Tests.Provider.Sqlite.Data/Sqlite/Curd/SqliteInsertTest.cs index d3579aa0c..39869d914 100644 --- a/FreeSql.Tests/FreeSql.Tests.Provider.Sqlite.Data/Sqlite/Curd/SqliteInsertTest.cs +++ b/FreeSql.Tests/FreeSql.Tests.Provider.Sqlite.Data/Sqlite/Curd/SqliteInsertTest.cs @@ -1,4 +1,4 @@ -using FreeSql.DataAnnotations; +using FreeSql.DataAnnotations; using System; using System.Collections.Generic; using System.Linq; @@ -138,5 +138,27 @@ namespace FreeSql.Tests.Sqlite sql = insert.AppendData(items).IgnoreColumns(a => new { a.Title, a.CreateTime }).AsTable(a => "Topic_InsertAsTable").ToSql(); Assert.Equal("INSERT INTO \"Topic_InsertAsTable\"(\"Clicks\") VALUES(@Clicks_0), (@Clicks_1), (@Clicks_2), (@Clicks_3), (@Clicks_4), (@Clicks_5), (@Clicks_6), (@Clicks_7), (@Clicks_8), (@Clicks_9)", sql); } + + [Fact] + public void BulkInsert() + { + g.sqlite.Delete().Where(m => true).ExecuteAffrows(); + var list = new List(); + for (int i = 0; i < 10; i++) + { + list.Add(new Topic { Id = i, Clicks = i * 2, Title = "BULK" + i.ToString(), CreateTime = DateTime.Now }); + } + insert.AppendData(list).BulkInsert(); + Assert.Equal(10, g.sqlite.Select().Where(m => m.Title.StartsWith("BULK")).Count()); + + g.sqlite.Delete().Where(m => true).ExecuteAffrows(); + g.sqlite.Transaction(() => + { + g.sqlite.Insert(list).BulkInsert(); + Assert.Equal(10, g.sqlite.Select().Where(m => m.Title.StartsWith("BULK")).Count()); + }); + } + + } } diff --git a/Providers/FreeSql.Provider.Sqlite/SqliteExtensions.cs b/Providers/FreeSql.Provider.Sqlite/SqliteExtensions.cs index 6393545a6..badb17a98 100644 --- a/Providers/FreeSql.Provider.Sqlite/SqliteExtensions.cs +++ b/Providers/FreeSql.Provider.Sqlite/SqliteExtensions.cs @@ -1,4 +1,11 @@ -public static partial class FreeSqlSqliteGlobalExtensions +using FreeSql; +using System; +using System.Data; +using System.Data.Common; +using System.Text; +using static System.Runtime.CompilerServices.RuntimeHelpers; + +public static partial class FreeSqlSqliteGlobalExtensions { /// @@ -9,4 +16,108 @@ /// public static string FormatSqlite(this string that, params object[] args) => _sqliteAdo.Addslashes(that, args); static FreeSql.Sqlite.SqliteAdo _sqliteAdo = new FreeSql.Sqlite.SqliteAdo(); + public static void BulkInsert(this IInsert that) where T : class + { + var insert = that as FreeSql.Sqlite.Curd.SqliteInsert; + if (insert == null) throw new Exception(CoreErrorStrings.S_Features_Unique("BulkInsert", "Sqlite")); + + var dt = that.ToDataTable(); + if (dt.Rows.Count == 0) return; + + Action writeToServer = (tran) => + { + var insertCmd = tran.Connection.CreateCommand(); + var copyFromCommand = new StringBuilder().Append("INSERT INTO ").Append(insert._commonUtils.QuoteSqlName(dt.TableName)).Append("("); + var colIndex = 0; + foreach (DataColumn col in dt.Columns) + { + if (colIndex++ > 0) copyFromCommand.Append(", "); + copyFromCommand.Append(insert._commonUtils.QuoteSqlName(col.ColumnName)); + } + copyFromCommand.Append(") VALUES ( "); + colIndex = 0; + foreach (DataColumn col in dt.Columns) + { + if (colIndex++ > 0) copyFromCommand.Append(", "); + copyFromCommand.Append("@").Append(col.ColumnName); + + var p = insertCmd.CreateParameter(); + p.ParameterName = col.ColumnName; + var trycol = insert._table.Columns[col.ColumnName]; + var tp = insert._orm.CodeFirst.GetDbInfo(trycol.Attribute.MapType)?.type; + + insertCmd.Parameters.Add(p); + } + copyFromCommand.Append(")"); + insertCmd.CommandText = copyFromCommand.ToString(); + + foreach (DataRow r in dt.Rows) + { + foreach (DataColumn c in dt.Columns) + { + var p = insertCmd.Parameters[c.ColumnName]; + p.Value = r[c.ColumnName]; + } + insertCmd.ExecuteNonQuery(); + } + }; + + try + { + if (insert._connection == null && insert._transaction == null) + { + if (insert._orm.Ado?.TransactionCurrentThread != null) + { + writeToServer(insert._orm.Ado.TransactionCurrentThread); + } + else + { + using (var conn = insert._orm.Ado.MasterPool.Get()) + { + using (var tran = conn.Value.BeginTransaction()) + { + writeToServer(tran); + tran.Commit(); + } + } + } + } + else if (insert._transaction != null) + { + writeToServer(insert._transaction); + } + else if (insert._connection != null) + { + var isNotOpen = false; + if (insert._connection.State != System.Data.ConnectionState.Open) + { + isNotOpen = true; + insert._connection.Open(); + } + try + { + using (var tran = insert._connection.BeginTransaction()) + { + writeToServer(tran); + tran.Commit(); + } + } + finally + { + if (isNotOpen) + { + insert._connection.Close(); + } + } + } + else + { + throw new NotImplementedException($"ExecuteSqlBulkCopy {CoreErrorStrings.S_Not_Implemented_FeedBack}"); + } + } + finally + { + dt.Clear(); + } + } }