15
15
using System . Data ;
16
16
using System . Diagnostics ;
17
17
using System . Linq ;
18
+ using System . Text . RegularExpressions ;
18
19
using ServiceStack . Common . Utils ;
19
20
using ServiceStack . Logging ;
20
21
@@ -235,18 +236,27 @@ public static T PopulateWithSqlReader<T>(this T objWithProperties, IDataReader d
235
236
{
236
237
foreach ( var fieldDef in fieldDefs )
237
238
{
238
- int index = NotFound ;
239
+ int index ;
239
240
if ( indexCache != null )
240
241
{
241
242
if ( ! indexCache . TryGetValue ( fieldDef . Name , out index ) )
242
243
{
243
244
index = dataReader . GetColumnIndex ( fieldDef . FieldName ) ;
245
+ if ( index == NotFound )
246
+ {
247
+ index = TryGuessColumnIndex ( fieldDef . FieldName , dataReader ) ;
248
+ }
249
+
244
250
indexCache . Add ( fieldDef . Name , index ) ;
245
251
}
246
252
}
247
253
else
248
254
{
249
255
index = dataReader . GetColumnIndex ( fieldDef . FieldName ) ;
256
+ if ( index == NotFound )
257
+ {
258
+ index = TryGuessColumnIndex ( fieldDef . FieldName , dataReader ) ;
259
+ }
250
260
}
251
261
252
262
if ( index == NotFound ) continue ;
@@ -261,6 +271,71 @@ public static T PopulateWithSqlReader<T>(this T objWithProperties, IDataReader d
261
271
return objWithProperties ;
262
272
}
263
273
274
+ private static readonly Regex AllowedPropertyCharsRegex = new Regex ( @"[^0-9a-zA-Z_]" ,
275
+ RegexOptions . Compiled | RegexOptions . CultureInvariant ) ;
276
+
277
+ private static int TryGuessColumnIndex ( string fieldName , IDataReader dataReader )
278
+ {
279
+ var fieldCount = dataReader . FieldCount ;
280
+ for ( var i = 0 ; i < fieldCount ; i ++ )
281
+ {
282
+ var dbFieldName = dataReader . GetName ( i ) ;
283
+
284
+ // First guess: Maybe the DB field has underscores? (most common)
285
+ // e.g. CustomerId (C#) vs customer_id (DB)
286
+ var dbFieldNameWithNoUnderscores = dbFieldName . Replace ( "_" , "" ) ;
287
+ if ( string . Compare ( fieldName , dbFieldNameWithNoUnderscores , StringComparison . InvariantCultureIgnoreCase ) == 0 )
288
+ {
289
+ return i ;
290
+ }
291
+
292
+ // Next guess: Maybe the DB field has special characters?
293
+ // e.g. Quantity (C#) vs quantity% (DB)
294
+ var dbFieldNameSanitized = AllowedPropertyCharsRegex . Replace ( dbFieldName , string . Empty ) ;
295
+ if ( string . Compare ( fieldName , dbFieldNameSanitized , StringComparison . InvariantCultureIgnoreCase ) == 0 )
296
+ {
297
+ return i ;
298
+ }
299
+
300
+ // Next guess: Maybe the DB field has special characters *and* has underscores?
301
+ // e.g. Quantity (C#) vs quantity_% (DB)
302
+ if ( string . Compare ( fieldName , dbFieldNameSanitized . Replace ( "_" , string . Empty ) , StringComparison . InvariantCultureIgnoreCase ) == 0 )
303
+ {
304
+ return i ;
305
+ }
306
+
307
+ // Next guess: Maybe the DB field has some prefix that we don't have in our C# field?
308
+ // e.g. CustomerId (C#) vs t130CustomerId (DB)
309
+ if ( dbFieldName . EndsWith ( fieldName , StringComparison . InvariantCultureIgnoreCase ) )
310
+ {
311
+ return i ;
312
+ }
313
+
314
+ // Next guess: Maybe the DB field has some prefix that we don't have in our C# field *and* has underscores?
315
+ // e.g. CustomerId (C#) vs t130_CustomerId (DB)
316
+ if ( dbFieldNameWithNoUnderscores . EndsWith ( fieldName , StringComparison . InvariantCultureIgnoreCase ) )
317
+ {
318
+ return i ;
319
+ }
320
+
321
+ // Next guess: Maybe the DB field has some prefix that we don't have in our C# field *and* has special characters?
322
+ // e.g. CustomerId (C#) vs t130#CustomerId (DB)
323
+ if ( dbFieldNameSanitized . EndsWith ( fieldName , StringComparison . InvariantCultureIgnoreCase ) )
324
+ {
325
+ return i ;
326
+ }
327
+
328
+ // Next guess: Maybe the DB field has some prefix that we don't have in our C# field *and* has underscores *and* has special characters?
329
+ // e.g. CustomerId (C#) vs t130#Customer_I#d (DB)
330
+ if ( dbFieldNameSanitized . Replace ( "_" , "" ) . EndsWith ( fieldName , StringComparison . InvariantCultureIgnoreCase ) )
331
+ {
332
+ return i ;
333
+ }
334
+ }
335
+
336
+ return NotFound ;
337
+ }
338
+
264
339
internal static void Update < T > ( this IDbCommand dbCmd , params T [ ] objs )
265
340
{
266
341
foreach ( var obj in objs )
0 commit comments