3
3
using System . Buffers . Text ;
4
4
using System . Collections . Generic ;
5
5
using System . Data ;
6
+ using System . Linq ;
6
7
using System . Text ;
7
8
using System . Threading ;
8
9
using System . Threading . Tasks ;
@@ -20,6 +21,7 @@ public MySqlBulkCopy(MySqlConnection connection, MySqlTransaction? transaction =
20
21
{
21
22
m_connection = connection ?? throw new ArgumentNullException ( nameof ( connection ) ) ;
22
23
m_transaction = transaction ;
24
+ ColumnMappings = new List < MySqlBulkCopyColumnMapping > ( ) ;
23
25
}
24
26
25
27
public int BulkCopyTimeout { get ; set ; }
@@ -44,6 +46,15 @@ public MySqlBulkCopy(MySqlConnection connection, MySqlTransaction? transaction =
44
46
/// </remarks>
45
47
public event MySqlRowsCopiedEventHandler ? RowsCopied ;
46
48
49
+ /// <summary>
50
+ /// A collection of <see cref="MySqlBulkCopyColumnMapping"/> objects. If the columns being copied from the
51
+ /// data source line up one-to-one with the columns in the destination table then populating this collection is
52
+ /// unnecessary. Otherwise, this should be filled with a collection of <see cref="MySqlBulkCopyColumnMapping"/> objects
53
+ /// specifying how source columns are to be mapped onto destination columns. If one column mapping is specified,
54
+ /// then all must be specified.
55
+ /// </summary>
56
+ public List < MySqlBulkCopyColumnMapping > ColumnMappings { get ; }
57
+
47
58
#if ! NETSTANDARD1_3
48
59
public void WriteToServer ( DataTable dataTable )
49
60
{
@@ -134,16 +145,17 @@ private async ValueTask WriteToServerAsync(IOBehavior ioBehavior, CancellationTo
134
145
closeConnection = true ;
135
146
}
136
147
137
- using ( var cmd = new MySqlCommand ( "select * from " + QuoteIdentifier ( tableName ) + ";" , m_connection , m_transaction ) )
138
- using ( var reader = ( MySqlDataReader ) await cmd . ExecuteReaderAsync ( CommandBehavior . SchemaOnly , ioBehavior , cancellationToken ) . ConfigureAwait ( false ) )
148
+ // if no user-supplied column mappings, compute them from the destination schema
149
+ if ( ColumnMappings . Count == 0 )
139
150
{
151
+ using var cmd = new MySqlCommand ( "select * from " + QuoteIdentifier ( tableName ) + ";" , m_connection , m_transaction ) ;
152
+ using var reader = ( MySqlDataReader ) await cmd . ExecuteReaderAsync ( CommandBehavior . SchemaOnly , ioBehavior , cancellationToken ) . ConfigureAwait ( false ) ;
140
153
var schema = reader . GetColumnSchema ( ) ;
141
154
for ( var i = 0 ; i < schema . Count ; i ++ )
142
155
{
143
156
if ( schema [ i ] . DataTypeName == "BIT" )
144
157
{
145
- bulkLoader . Columns . Add ( $ "@col{ i } ") ;
146
- bulkLoader . Expressions . Add ( $ "`{ reader . GetName ( i ) } ` = CAST(@col{ i } AS UNSIGNED)") ;
158
+ ColumnMappings . Add ( new MySqlBulkCopyColumnMapping ( i , $ "@col{ i } ", $ "`{ reader . GetName ( i ) } ` = CAST(@col{ i } AS UNSIGNED)") ) ;
147
159
}
148
160
else if ( schema [ i ] . DataTypeName == "YEAR" )
149
161
{
@@ -155,17 +167,37 @@ private async ValueTask WriteToServerAsync(IOBehavior ioBehavior, CancellationTo
155
167
var type = schema [ i ] . DataType ;
156
168
if ( type == typeof ( byte [ ] ) || ( type == typeof ( Guid ) && ( m_connection . GuidFormat == MySqlGuidFormat . Binary16 || m_connection . GuidFormat == MySqlGuidFormat . LittleEndianBinary16 || m_connection . GuidFormat == MySqlGuidFormat . TimeSwapBinary16 ) ) )
157
169
{
158
- bulkLoader . Columns . Add ( $ "@col{ i } ") ;
159
- bulkLoader . Expressions . Add ( $ "`{ reader . GetName ( i ) } ` = UNHEX(@col{ i } )") ;
170
+ ColumnMappings . Add ( new MySqlBulkCopyColumnMapping ( i , $ "@col{ i } ", $ "`{ reader . GetName ( i ) } ` = UNHEX(@col{ i } )") ) ;
160
171
}
161
172
else
162
173
{
163
- bulkLoader . Columns . Add ( QuoteIdentifier ( reader . GetName ( i ) ) ) ;
174
+ ColumnMappings . Add ( new MySqlBulkCopyColumnMapping ( i , reader . GetName ( i ) ) ) ;
164
175
}
165
176
}
166
177
}
167
178
}
168
179
180
+ // set columns and expressions from the column mappings
181
+ for ( var i = 0 ; i < m_valuesEnumerator ! . FieldCount ; i ++ )
182
+ {
183
+ var columnMapping = ColumnMappings . FirstOrDefault ( x => x . SourceOrdinal == i ) ;
184
+ if ( columnMapping is null )
185
+ {
186
+ bulkLoader . Columns . Add ( "@`\uE002 \b ignore`" ) ;
187
+ }
188
+ else
189
+ {
190
+ if ( columnMapping . DestinationColumn . Length == 0 )
191
+ throw new InvalidOperationException ( "MySqlBulkCopyColumnMapping.DestinationName is not set." ) ;
192
+ if ( columnMapping . DestinationColumn [ 0 ] == '@' )
193
+ bulkLoader . Columns . Add ( columnMapping . DestinationColumn ) ;
194
+ else
195
+ bulkLoader . Columns . Add ( QuoteIdentifier ( columnMapping . DestinationColumn ) ) ;
196
+ if ( columnMapping . Expression is object )
197
+ bulkLoader . Expressions . Add ( columnMapping . Expression ) ;
198
+ }
199
+ }
200
+
169
201
await bulkLoader . LoadAsync ( ioBehavior , cancellationToken ) . ConfigureAwait ( false ) ;
170
202
171
203
if ( closeConnection )
0 commit comments