|
1 | | -using System.Data; |
2 | | - |
3 | 1 | using BenchmarkDotNet.Attributes; |
4 | 2 |
|
5 | 3 | using DotNet.Testcontainers.Containers; |
6 | 4 |
|
7 | 5 | using EFCore.BulkExtensions; |
8 | 6 |
|
9 | | -using Microsoft.Data.SqlClient; |
10 | | -using Microsoft.Data.Sqlite; |
11 | | -using Microsoft.EntityFrameworkCore; |
12 | | - |
13 | | -using Npgsql; |
| 7 | +using LinqToDB.EntityFrameworkCore; |
14 | 8 |
|
15 | 9 | using PhenX.EntityFrameworkCore.BulkInsert.Extensions; |
16 | 10 |
|
17 | 11 | namespace PhenX.EntityFrameworkCore.BulkInsert.Benchmark; |
18 | 12 |
|
19 | | -public abstract class LibComparator |
| 13 | +public abstract partial class LibComparator |
20 | 14 | { |
21 | 15 | [Params(500_000/*, 1_000_000/*, 10_000_000*/)] |
22 | 16 | public int N; |
@@ -44,6 +38,7 @@ protected LibComparator() |
44 | 38 | { |
45 | 39 | DbContainer = GetDbContainer(); |
46 | 40 | DbContainer?.StartAsync().GetAwaiter().GetResult(); |
| 41 | + LinqToDBForEFTools.Initialize(); |
47 | 42 | } |
48 | 43 |
|
49 | 44 | protected abstract void ConfigureDbContext(); |
@@ -89,6 +84,12 @@ public void RawInsert() |
89 | 84 | } |
90 | 85 | } |
91 | 86 |
|
| 87 | + [Benchmark] |
| 88 | + public async Task Linq2Db() |
| 89 | + { |
| 90 | + await DbContext.BulkCopyAsync(data); |
| 91 | + } |
| 92 | + |
92 | 93 | [Benchmark] |
93 | 94 | public async Task Z_EntityFramework_Extensions_EFCore() |
94 | 95 | { |
@@ -121,147 +122,10 @@ await DbContext.BulkInsertAsync(data, options => |
121 | 122 | // }); |
122 | 123 | // } |
123 | 124 |
|
124 | | - [Benchmark] |
125 | | - public async Task EFCore_SaveChanges() |
126 | | - { |
127 | | - DbContext.AddRange(data); |
128 | | - await DbContext.SaveChangesAsync(); |
129 | | - } |
130 | | - |
131 | | - private void RawInsertPostgreSql() |
132 | | - { |
133 | | - using var connection = (NpgsqlConnection)DbContext.Database.GetDbConnection(); |
134 | | - if (connection.State != ConnectionState.Open) |
135 | | - { |
136 | | - connection.Open(); |
137 | | - } |
138 | | - |
139 | | - const string copyCommand = $""" |
140 | | - COPY "{nameof(TestEntity)}" ( |
141 | | - "Name", |
142 | | - "Price", |
143 | | - "Identifier", |
144 | | - "CreatedAt", |
145 | | - "UpdatedAt", |
146 | | - "StringEnumValue", |
147 | | - "NumericEnumValue" |
148 | | - ) FROM STDIN (FORMAT BINARY) |
149 | | - """; |
150 | | - |
151 | | - using var writer = connection.BeginBinaryImport(copyCommand); |
152 | | - foreach (var entity in data) |
153 | | - { |
154 | | - writer.StartRow(); |
155 | | - writer.Write(entity.Name); |
156 | | - writer.Write(entity.Price); |
157 | | - writer.Write(entity.Identifier); |
158 | | - writer.Write(entity.CreatedAt); |
159 | | - writer.Write(entity.UpdatedAt); |
160 | | - writer.Write(entity.StringEnumValue.ToString()); |
161 | | - writer.Write((int)entity.NumericEnumValue); |
162 | | - } |
163 | | - |
164 | | - writer.Complete(); |
165 | | - } |
166 | | - |
167 | | - private void RawInsertSqlite() |
168 | | - { |
169 | | - var connection = (SqliteConnection)DbContext.Database.GetDbConnection(); |
170 | | - if (connection.State != ConnectionState.Open) |
171 | | - { |
172 | | - connection.Open(); |
173 | | - } |
174 | | - using var transaction = connection.BeginTransaction(); |
175 | | - using var command = connection.CreateCommand(); |
176 | | - command.CommandText = $""" |
177 | | - INSERT INTO "{nameof(TestEntity)}" ( |
178 | | - "Name", |
179 | | - "Price", |
180 | | - "Identifier", |
181 | | - "CreatedAt", |
182 | | - "UpdatedAt", |
183 | | - "StringEnumValue", |
184 | | - "NumericEnumValue" |
185 | | - ) VALUES (@Name, @Price, @Identifier, @CreatedAt, @UpdatedAt, @StringEnumValue, @NumericEnumValue) |
186 | | - """; |
187 | | - |
188 | | - command.Parameters.Add(new SqliteParameter("@Name", DbType.String)); |
189 | | - command.Parameters.Add(new SqliteParameter("@Price", DbType.Decimal)); |
190 | | - command.Parameters.Add(new SqliteParameter("@Identifier", DbType.Guid)); |
191 | | - command.Parameters.Add(new SqliteParameter("@CreatedAt", DbType.DateTime)); |
192 | | - command.Parameters.Add(new SqliteParameter("@UpdatedAt", DbType.DateTime2)); |
193 | | - command.Parameters.Add(new SqliteParameter("@StringEnumValue", DbType.String)); |
194 | | - command.Parameters.Add(new SqliteParameter("@NumericEnumValue", DbType.Int32)); |
195 | | - |
196 | | - foreach (var entity in data) |
197 | | - { |
198 | | - command.Parameters["@Name"].Value = entity.Name; |
199 | | - command.Parameters["@Price"].Value = entity.Price; |
200 | | - command.Parameters["@Identifier"].Value = entity.Identifier; |
201 | | - command.Parameters["@CreatedAt"].Value = entity.CreatedAt; |
202 | | - command.Parameters["@UpdatedAt"].Value = entity.UpdatedAt; |
203 | | - command.Parameters["@StringEnumValue"].Value = entity.StringEnumValue.ToString(); |
204 | | - command.Parameters["@NumericEnumValue"].Value = (int)entity.NumericEnumValue; |
205 | | - |
206 | | - command.ExecuteNonQuery(); |
207 | | - } |
208 | | - |
209 | | - transaction.Commit(); |
210 | | - } |
211 | | - |
212 | | - private void RawInsertSqlServer() |
213 | | - { |
214 | | - var connection = (SqlConnection)DbContext.Database.GetDbConnection(); |
215 | | - if (connection.State != ConnectionState.Open) |
216 | | - { |
217 | | - connection.Open(); |
218 | | - } |
219 | | - |
220 | | - using var bulkCopy = new SqlBulkCopy(connection); |
221 | | - |
222 | | - bulkCopy.DestinationTableName = nameof(TestEntity); |
223 | | - bulkCopy.BatchSize = 50_000; |
224 | | - bulkCopy.BulkCopyTimeout = 60; |
225 | | - |
226 | | - bulkCopy.ColumnMappings.Add("Name", "Name"); |
227 | | - bulkCopy.ColumnMappings.Add("Price", "Price"); |
228 | | - bulkCopy.ColumnMappings.Add("Identifier", "Identifier"); |
229 | | - bulkCopy.ColumnMappings.Add("CreatedAt", "CreatedAt"); |
230 | | - bulkCopy.ColumnMappings.Add("UpdatedAt", "UpdatedAt"); |
231 | | - bulkCopy.ColumnMappings.Add("StringEnumValue", "StringEnumValue"); |
232 | | - bulkCopy.ColumnMappings.Add("NumericEnumValue", "NumericEnumValue"); |
233 | | - |
234 | | - var dataTable = new DataTable(); |
235 | | - dataTable.Columns.Add("Name", typeof(string)); |
236 | | - dataTable.Columns.Add("Price", typeof(decimal)); |
237 | | - dataTable.Columns.Add("Identifier", typeof(Guid)); |
238 | | - dataTable.Columns.Add("CreatedAt", typeof(DateTime)); |
239 | | - dataTable.Columns.Add("UpdatedAt", typeof(DateTimeOffset)); |
240 | | - dataTable.Columns.Add("StringEnumValue", typeof(string)); |
241 | | - dataTable.Columns.Add("NumericEnumValue", typeof(int)); |
242 | | - |
243 | | - foreach (var entity in data) |
244 | | - { |
245 | | - var row = dataTable.NewRow(); |
246 | | - row["Name"] = entity.Name; |
247 | | - row["Price"] = entity.Price; |
248 | | - row["Identifier"] = entity.Identifier; |
249 | | - row["CreatedAt"] = entity.CreatedAt; |
250 | | - row["UpdatedAt"] = entity.UpdatedAt; |
251 | | - row["StringEnumValue"] = entity.StringEnumValue.ToString(); |
252 | | - row["NumericEnumValue"] = (int)entity.NumericEnumValue; |
253 | | - dataTable.Rows.Add(row); |
254 | | - |
255 | | - if (dataTable.Rows.Count >= 50_000) |
256 | | - { |
257 | | - bulkCopy.WriteToServer(dataTable); |
258 | | - dataTable.Clear(); |
259 | | - } |
260 | | - } |
261 | | - |
262 | | - if (dataTable.Rows.Count > 0) |
263 | | - { |
264 | | - bulkCopy.WriteToServer(dataTable); |
265 | | - } |
266 | | - } |
| 125 | + // [Benchmark] |
| 126 | + // public async Task EFCore_SaveChanges() |
| 127 | + // { |
| 128 | + // DbContext.AddRange(data); |
| 129 | + // await DbContext.SaveChangesAsync(); |
| 130 | + // } |
267 | 131 | } |
0 commit comments