1
1
using System ;
2
2
using System . Collections . Generic ;
3
+ using System . Configuration ;
3
4
using System . Data ;
4
5
using System . Diagnostics ;
5
6
using System . Linq ;
@@ -19,10 +20,11 @@ static SimpleCRUD()
19
20
{
20
21
SetDialect ( _dialect ) ;
21
22
}
22
-
23
+
23
24
private static Dialect _dialect = Dialect . SQLServer ;
24
25
private static string _encapsulation ;
25
26
private static string _getIdentitySql ;
27
+ private static string _getPagedListSql ;
26
28
27
29
/// <summary>
28
30
/// Returns the current dialect name
@@ -44,16 +46,19 @@ public static void SetDialect(Dialect dialect)
44
46
_dialect = Dialect . PostgreSQL ;
45
47
_encapsulation = "{0}" ;
46
48
_getIdentitySql = string . Format ( "SELECT LASTVAL() AS id" ) ;
49
+ _getPagedListSql = "Select {SelectColumns} from {TableName} {WhereClause} Order By {OrderBy} LIMIT {RowsPerPage} OFFSET (({PageNumber}-1) * {RowsPerPage})" ;
47
50
break ;
48
51
case Dialect . SQLite :
49
52
_dialect = Dialect . SQLite ;
50
53
_encapsulation = "{0}" ;
51
54
_getIdentitySql = string . Format ( "SELECT LAST_INSERT_ROWID() AS id" ) ;
55
+ _getPagedListSql = "Select {SelectColumns} from {TableName} {WhereClause} Order By {OrderBy} LIMIT {RowsPerPage} OFFSET (({PageNumber}-1) * {RowsPerPage})" ;
52
56
break ;
53
57
default :
54
58
_dialect = Dialect . SQLServer ;
55
59
_encapsulation = "[{0}]" ;
56
60
_getIdentitySql = string . Format ( "SELECT CAST(SCOPE_IDENTITY() AS BIGINT) AS [id]" ) ;
61
+ _getPagedListSql = "SELECT * FROM (SELECT ROW_NUMBER() OVER(ORDER BY {OrderBy}) AS PagedNumber, {SelectColumns} FROM {TableName} {WhereClause}) AS u WHERE PagedNUMBER BETWEEN (({PageNumber} - 1) * {RowsPerPage} + 1) AND ({PageNumber} * {RowsPerPage})" ;
57
62
break ;
58
63
}
59
64
}
@@ -155,7 +160,6 @@ public static IEnumerable<T> GetList<T>(this IDbConnection connection, string co
155
160
var name = GetTableName ( currenttype ) ;
156
161
157
162
var sb = new StringBuilder ( ) ;
158
- var whereprops = GetAllProperties ( conditions ) . ToArray ( ) ;
159
163
sb . Append ( "Select " ) ;
160
164
//create a new empty instance of the type to get the base properties
161
165
BuildSelect ( sb , GetScaffoldableProperties ( ( T ) Activator . CreateInstance ( typeof ( T ) ) ) . ToArray ( ) ) ;
@@ -169,7 +173,6 @@ public static IEnumerable<T> GetList<T>(this IDbConnection connection, string co
169
173
return connection . Query < T > ( sb . ToString ( ) ) ;
170
174
}
171
175
172
-
173
176
/// <summary>
174
177
/// <para>By default queries the table matching the class name</para>
175
178
/// <para>-Table name can be overridden by adding an attribute on your class [Table("YourTableName")]</para>
@@ -183,6 +186,56 @@ public static IEnumerable<T> GetList<T>(this IDbConnection connection)
183
186
return connection . GetList < T > ( new { } ) ;
184
187
}
185
188
189
+ /// <summary>
190
+ /// <para>By default queries the table matching the class name</para>
191
+ /// <para>-Table name can be overridden by adding an attribute on your class [Table("YourTableName")]</para>
192
+ /// <para>conditions is an SQL where clause ex: "where name='bob'" - not required </para>
193
+ /// <para>orderby is a column or list of columns to order by ex: "lastname, age desc" - not required - default is by primary key</para>
194
+ /// <para>Returns a list of entities that match where conditions</para>
195
+ /// </summary>
196
+ /// <typeparam name="T"></typeparam>
197
+ /// <param name="connection"></param>
198
+ /// <param name="pageNumber"></param>
199
+ /// <param name="rowsPerPage"></param>
200
+ /// <param name="conditions"></param>
201
+ /// <param name="orderby"></param>
202
+ /// <returns>Gets a paged list of entities with optional exact match where conditions</returns>
203
+ public static IEnumerable < T > GetListPaged < T > ( this IDbConnection connection , int pageNumber , int rowsPerPage , string conditions , string orderby )
204
+ {
205
+ if ( string . IsNullOrEmpty ( _getPagedListSql ) )
206
+ throw new Exception ( "GetListPage is not supported with the current SQL Dialect" ) ;
207
+
208
+ if ( pageNumber < 1 )
209
+ throw new Exception ( "Page must be greater than 0" ) ;
210
+
211
+ var currenttype = typeof ( T ) ;
212
+ var idProps = GetIdProperties ( currenttype ) . ToList ( ) ;
213
+ if ( ! idProps . Any ( ) )
214
+ throw new ArgumentException ( "Entity must have at least one [Key] property" ) ;
215
+
216
+ var name = GetTableName ( currenttype ) ;
217
+ var sb = new StringBuilder ( ) ;
218
+ var query = _getPagedListSql ;
219
+ if ( string . IsNullOrEmpty ( orderby ) )
220
+ {
221
+ orderby = idProps . First ( ) . Name ;
222
+ }
223
+
224
+ //create a new empty instance of the type to get the base properties
225
+ BuildSelect ( sb , GetScaffoldableProperties ( ( T ) Activator . CreateInstance ( typeof ( T ) ) ) . ToArray ( ) ) ;
226
+ query = query . Replace ( "{SelectColumns}" , sb . ToString ( ) ) ;
227
+ query = query . Replace ( "{TableName}" , name ) ;
228
+ query = query . Replace ( "{PageNumber}" , pageNumber . ToString ( ) ) ;
229
+ query = query . Replace ( "{RowsPerPage}" , rowsPerPage . ToString ( ) ) ;
230
+ query = query . Replace ( "{OrderBy}" , orderby ) ;
231
+ query = query . Replace ( "{WhereClause}" , conditions ) ;
232
+
233
+ if ( Debugger . IsAttached )
234
+ Trace . WriteLine ( String . Format ( "GetListPaged<{0}>: {1}" , currenttype , query ) ) ;
235
+
236
+ return connection . Query < T > ( query ) ;
237
+ }
238
+
186
239
/// <summary>
187
240
/// <para>Inserts a row into the database</para>
188
241
/// <para>By default inserts into the table matching the class name</para>
@@ -219,6 +272,7 @@ public static IEnumerable<T> GetList<T>(this IDbConnection connection)
219
272
public static TKey Insert < TKey > ( this IDbConnection connection , object entityToInsert , IDbTransaction transaction = null , int ? commandTimeout = null )
220
273
{
221
274
var idProps = GetIdProperties ( entityToInsert ) . ToList ( ) ;
275
+
222
276
if ( ! idProps . Any ( ) )
223
277
throw new ArgumentException ( "Insert<T> only supports an entity with a [Key] or Id property" ) ;
224
278
if ( idProps . Count ( ) > 1 )
@@ -231,9 +285,9 @@ public static TKey Insert<TKey>(this IDbConnection connection, object entityToIn
231
285
{
232
286
throw new Exception ( "Invalid return type" ) ;
233
287
}
234
- if ( keytype == typeof ( Guid ) )
288
+ if ( keytype == typeof ( Guid ) )
235
289
{
236
- var guidvalue = ( Guid ) idProps . First ( ) . GetValue ( entityToInsert , null ) ;
290
+ var guidvalue = ( Guid ) idProps . First ( ) . GetValue ( entityToInsert , null ) ;
237
291
if ( guidvalue == Guid . Empty )
238
292
{
239
293
var newguid = SequentialGuid ( ) ;
@@ -252,20 +306,20 @@ public static TKey Insert<TKey>(this IDbConnection connection, object entityToIn
252
306
BuildInsertValues ( entityToInsert , sb ) ;
253
307
sb . Append ( ")" ) ;
254
308
255
- if ( keytype == typeof ( Guid ) )
309
+ if ( keytype == typeof ( Guid ) )
256
310
{
257
311
sb . Append ( ";select '" + idProps . First ( ) . GetValue ( entityToInsert , null ) + "' as id" ) ;
258
312
}
259
313
else
260
314
{
261
- sb . Append ( ";" + _getIdentitySql ) ;
315
+ sb . Append ( ";" + _getIdentitySql ) ;
262
316
}
263
-
317
+
264
318
if ( Debugger . IsAttached )
265
319
Trace . WriteLine ( String . Format ( "Insert: {0}" , sb ) ) ;
266
320
267
321
var r = connection . Query ( sb . ToString ( ) , entityToInsert , transaction , true , commandTimeout ) ;
268
-
322
+
269
323
if ( keytype == typeof ( Guid ) )
270
324
{
271
325
return ( TKey ) idProps . First ( ) . GetValue ( entityToInsert , null ) ;
@@ -387,6 +441,68 @@ public static int Delete<T>(this IDbConnection connection, object id, IDbTransac
387
441
return connection . Execute ( sb . ToString ( ) , dynParms , transaction , commandTimeout ) ;
388
442
}
389
443
444
+ /// <summary>
445
+ /// <para>Deletes a list of records in the database</para>
446
+ /// <para>By default deletes records in the table matching the class name</para>
447
+ /// <para>-Table name can be overridden by adding an attribute on your class [Table("YourTableName")]</para>
448
+ /// <para>Deletes records where that match the where clause</para>
449
+ /// <para>conditions is an SQL where clause ex: "where name='bob'"</para>
450
+
451
+ /// <para>The number of records effected</para>
452
+ /// <para>Supports transaction and command timeout</para>
453
+ /// </summary>
454
+ /// <typeparam name="T"></typeparam>
455
+ /// <param name="connection"></param>
456
+ /// <param name="conditions"></param>
457
+ /// <param name="transaction"></param>
458
+ /// <param name="commandTimeout"></param>
459
+ /// <returns>The number of records effected</returns>
460
+ public static int DeleteList < T > ( this IDbConnection connection , string conditions , IDbTransaction transaction = null , int ? commandTimeout = null )
461
+ {
462
+ if ( string . IsNullOrEmpty ( conditions ) )
463
+ throw new ArgumentException ( "DeleteList<T> requires a where clause" ) ;
464
+ if ( ! conditions . ToLower ( ) . Contains ( "where" ) )
465
+ throw new ArgumentException ( "DeleteList<T> requires a where clause and must contain the WHERE keyword" ) ;
466
+
467
+ var currenttype = typeof ( T ) ;
468
+ var name = GetTableName ( currenttype ) ;
469
+
470
+ var sb = new StringBuilder ( ) ;
471
+ sb . AppendFormat ( "Delete from {0}" , name ) ;
472
+ sb . Append ( " " + conditions ) ;
473
+
474
+ if ( Debugger . IsAttached )
475
+ Trace . WriteLine ( String . Format ( "DeleteList<{0}> {1}" , currenttype , sb ) ) ;
476
+
477
+ return connection . Execute ( sb . ToString ( ) , null , transaction , commandTimeout ) ;
478
+ }
479
+
480
+ /// <summary>
481
+ /// <para>By default queries the table matching the class name</para>
482
+ /// <para>-Table name can be overridden by adding an attribute on your class [Table("YourTableName")]</para>
483
+ /// <para>Returns a number of records entity by a single id from table T</para>
484
+ /// <para>conditions is an SQL where clause ex: "where name='bob'" - not required </para>
485
+ /// </summary>
486
+ /// <typeparam name="T"></typeparam>
487
+ /// <param name="connection"></param>
488
+ /// <param name="conditions"></param>
489
+ /// <returns>Returns a count of records.</returns>
490
+ public static int RecordCount < T > ( this IDbConnection connection , string conditions = "" )
491
+ {
492
+ var currenttype = typeof ( T ) ;
493
+ var name = GetTableName ( currenttype ) ;
494
+ var sb = new StringBuilder ( ) ;
495
+ sb . Append ( "Select count(1)" ) ;
496
+ sb . AppendFormat ( " from {0}" , name ) ;
497
+ sb . Append ( " " + conditions ) ;
498
+
499
+ if ( Debugger . IsAttached )
500
+ Trace . WriteLine ( String . Format ( "RecordCount<{0}>: {1}" , currenttype , sb ) ) ;
501
+
502
+ return connection . Query < int > ( sb . ToString ( ) ) . Single ( ) ;
503
+ }
504
+
505
+
390
506
//build update statement based on list on an entity
391
507
private static void BuildUpdateSet ( object entityToUpdate , StringBuilder sb )
392
508
{
@@ -536,13 +652,13 @@ private static bool IsReadOnly(PropertyInfo pi)
536
652
//Get all properties that are NOT named Id, DO NOT have the Key attribute, and are not marked ReadOnly
537
653
private static IEnumerable < PropertyInfo > GetUpdateableProperties ( object entity )
538
654
{
539
- var updateableProperties = GetScaffoldableProperties ( entity ) ;
655
+ var updateableProperties = GetScaffoldableProperties ( entity ) ;
540
656
//remove ones with ID
541
657
updateableProperties = updateableProperties . Where ( p => p . Name != "Id" ) ;
542
658
//remove ones with key attribute
543
- updateableProperties = updateableProperties . Where ( p=> p . GetCustomAttributes ( true ) . Any ( attr => attr . GetType ( ) . Name == "KeyAttribute" ) == false ) ;
659
+ updateableProperties = updateableProperties . Where ( p => p . GetCustomAttributes ( true ) . Any ( attr => attr . GetType ( ) . Name == "KeyAttribute" ) == false ) ;
544
660
//remove ones that are readonly
545
- updateableProperties = updateableProperties . Where ( p=> p . GetCustomAttributes ( true ) . Any ( attr => ( attr . GetType ( ) . Name == "ReadOnlyAttribute" ) && IsReadOnly ( p ) ) == false ) ;
661
+ updateableProperties = updateableProperties . Where ( p => p . GetCustomAttributes ( true ) . Any ( attr => ( attr . GetType ( ) . Name == "ReadOnlyAttribute" ) && IsReadOnly ( p ) ) == false ) ;
546
662
547
663
return updateableProperties ;
548
664
}
0 commit comments