@@ -866,6 +866,51 @@ var track = db.SingleById<Track>(1);
866
866
var tracks = db .SelectByIds <Track >(new []{ 1 ,2 ,3 });
867
867
```
868
868
869
+ ### Ensure APIs
870
+
871
+ The new ` Ensure() ` API on OrmLite's typed ` SqlExpression<T> ` can be used to ensure that a condition is always applied irrespective
872
+ of other conditions, e.g:
873
+
874
+ #### Typed API
875
+
876
+ ``` csharp
877
+ var q = db .From <Rockstar >();
878
+ q .Ensure (x => x .Id == 1 ); // always applied
879
+
880
+ // ...
881
+ q .Where (x => x .Age == 27 );
882
+ q .Or (x => x .LivingStatus == LivingStatus .Dead );
883
+
884
+ var rows = db .Select (q );
885
+ ```
886
+
887
+ #### Custom Parameterized SQL Expression
888
+
889
+ Custom SQL Ensure parameterized expressions:
890
+
891
+ ``` csharp
892
+ q .Ensure (" Id = {0}" , 1 );
893
+ ```
894
+
895
+ #### Multiple Ensure expressions
896
+
897
+ ``` csharp
898
+ var q = db
899
+ .From <Rockstar >()
900
+ .Join <RockstarAlbum >((r ,a ) => r .Id == a .RockstarId );
901
+
902
+ q .Ensure <Rockstar ,RockstarAlbum >((r ,a ) => a .Name == " Nevermind" && r .Id == a .RockstarId );
903
+
904
+ q .Where (x => x .Age == 27 )
905
+ .Or (x => x .LivingStatus == LivingStatus .Dead );
906
+
907
+ q .Ensure (x => x .Id == 3 );
908
+
909
+ var rows = db .Select (q );
910
+ ```
911
+
912
+ These APIs are useful for mandatory filters like "Soft Deletes" and Multitenant records.
913
+
869
914
## Nested Typed Sub SqlExpressions
870
915
871
916
The ` Sql.In() ` API supports nesting and combining of multiple Typed SQL Expressions together
@@ -898,23 +943,39 @@ var names = new List<string>{ "foo", "bar", "qux" };
898
943
var results = db .SqlList <Table >(" SELECT * FROM Table WHERE Name IN (@names)" , new { names });
899
944
```
900
945
946
+ ### Spread Util
947
+
948
+ The ` SqlSpread() ` API is useful to generate an escaped list of parameterized values for use in SQL ` IN() ` statements and SQL functions:
949
+
950
+ ``` csharp
951
+ var dialect = db .Dialect ();
952
+ dialect .SqlSpread (1 , 2 , 3 ); // = 1,2,3
953
+ dialect .SqlSpread (" A" , " B" , " C" ); // = 'A','B','C'
954
+ dialect .SqlSpread (" A'B" , " C\" D" ); // = 'A''B','C\"D'
955
+ ```
956
+
901
957
### Custom SQL using PostgreSQL Arrays
902
958
903
- If using PostgreSQL you can take advantage of its complex Array Types and utilize its [ Array Functions and Operators ] ( https://www.postgresql.org/docs/9.6/functions-array .html ) , e.g:
959
+ The ` PgSql.Array() ` provides a typed API for generating [ PostgreSQL Array Expressions ] ( https://www.postgresql.org/docs/current/arrays .html ) , e.g:
904
960
905
961
``` csharp
906
- var ids = new []{ 1 , 2 , 3 };
907
- var q = Db .From <Table >()
908
- .Where (" ARRAY[{0}] && ref_ids" , ids .Join (" ," ))
909
- var results = db .Select (q );
962
+ PgSql .Array (1 ,2 ,3 ) // = ARRAY[1,2,3]
963
+ var strings = new []{ " A" ," B" ," C" };
964
+ PgSql .Array (strings ) // = ARRAY['A','B','C']
910
965
```
911
966
912
- When comparing a string collection you can use ` SqlInValues ` to create a quoted SQL IN list, e.g :
967
+ Which you can safely use in Custom SQL Expressions that use PostgreSQL's native ARRAY support :
913
968
914
969
``` csharp
915
- var q = Db .From <Table >()
916
- .Where ($" ARRAY[{new SqlInValues (cities ).ToSqlInString ()}] && cities" );
917
- var results = db .Select (q );
970
+ q .And ($" {PgSql .Array (anyTechnologyIds )} && technology_ids" )
971
+ q .And ($" {PgSql .Array (labelSlugs )} && labels" );
972
+ ```
973
+
974
+ If you want and empty collection to return ` null ` instead of an empty ` ARRAY[] ` you can use the ` nullIfEmpty ` overload:
975
+
976
+ ``` csharp
977
+ PgSql .Array (new string [0 ], nullIfEmpty :true ) // = null
978
+ PgSql .Array (new []{" A" ," B" ," C" }, nullIfEmpty :true ) // = ARRAY['A','B','C']
918
979
```
919
980
920
981
### Lazy Queries
@@ -972,7 +1033,7 @@ var q = db.From<Customer>()
972
1033
var dbCustomers = db .Select <Customer >(q );
973
1034
```
974
1035
975
- This query rougly maps to the following SQL:
1036
+ This query roughly maps to the following SQL:
976
1037
977
1038
``` sql
978
1039
SELECT Customer.*
@@ -1338,6 +1399,59 @@ Custom Key/Value Dictionary:
1338
1399
Dictionary < string ,string > rows = db .Dictionary <string ,string >(q );
1339
1400
```
1340
1401
1402
+ ### Dictionary APIs
1403
+
1404
+ OrmLite's Dictionary APIs allow you to customize which parts of a Data Model should be modified by
1405
+ converting it into then manipulating an Object Dictionary, e.g:
1406
+
1407
+ #### Insert by Dictionary
1408
+
1409
+ ``` csharp
1410
+ var row = new Person { FirstName = " John" , LastName = " Smith" };
1411
+ Dictionary < string ,object > obj = row .ToObjectDictionary ();
1412
+ obj [nameof (Person .LastName )] = null ;
1413
+
1414
+ row .Id = (int ) db .Insert <Person >(obj , selectIdentity :true );
1415
+ ```
1416
+
1417
+ #### Update by Dictionary
1418
+
1419
+ ``` csharp
1420
+ Person row = db .SingleById <Person >(row .Id );
1421
+ var obj = row .ToObjectDictionary ();
1422
+ obj [nameof (Person .LastName )] = " Smith" ;
1423
+ db .Update <Person >(obj );
1424
+ ```
1425
+
1426
+ #### UpdateOnly by Dictionary
1427
+
1428
+ ``` csharp
1429
+ // By Primary Key Id
1430
+ var fields = new Dictionary <string , object > {
1431
+ [nameof (Person .Id )] = 1 ,
1432
+ [nameof (Person .FirstName )] = " John" ,
1433
+ [nameof (Person .LastName )] = null ,
1434
+ };
1435
+
1436
+ db .UpdateOnly <Person >(fields );
1437
+
1438
+ // By Custom Where Expression
1439
+ var fields = new Dictionary <string , object > {
1440
+ [nameof (Person .FirstName )] = " John" ,
1441
+ [nameof (Person .LastName )] = null ,
1442
+ };
1443
+
1444
+ db .UpdateOnly <Person >(fields , p => p .LastName == " Hendrix" );
1445
+ ```
1446
+
1447
+ #### Delete by Dictionary
1448
+
1449
+ ``` csharp
1450
+ db .Delete <Rockstar >(new Dictionary <string , object > {
1451
+ [" Age" ] = 27
1452
+ });
1453
+ ```
1454
+
1341
1455
### BelongsTo Attribute
1342
1456
1343
1457
The ` [BelongTo] ` attribute can be used for specifying how Custom POCO results are mapped when the resultset is ambiguous, e.g:
@@ -2247,6 +2361,41 @@ CREATE TABLE "PocoTable"
2247
2361
2248
2362
> OrmLite replaces any variable placeholders with the value in each RDBMS DialectProvider's ` Variables ` Dictionary.
2249
2363
2364
+ ### Custom Insert and Update Expressions
2365
+
2366
+ The ` [CustomInsert] ` and ` [CustomUpdate] ` attributes can be used to override what values rows are inserted during INSERT's and UPDATE's.
2367
+
2368
+ We can use this to insert a salted and hashed password using PostgreSQL native functions:
2369
+
2370
+ ``` csharp
2371
+ public class CustomSqlUser
2372
+ {
2373
+ [AutoIncrement ]
2374
+ public int Id { get ; set ; }
2375
+
2376
+ public string Email { get ; set ; }
2377
+
2378
+ [CustomInsert (" crypt({0}, gen_salt('bf'))" ),
2379
+ CustomUpdate (" crypt({0}, gen_salt('bf'))" )]
2380
+ public string Password { get ; set ; }
2381
+ }
2382
+
2383
+ var user = new CustomSqlUser {
2384
+
2385
+ Password = " secret"
2386
+ };
2387
+ db .Insert (user );
2388
+ ```
2389
+
2390
+ We can then use ` Sql.Custom() ` to create a partially typed custom query to match on the hashed password, e.g:
2391
+
2392
+ ``` csharp
2393
+ var quotedSecret = db .Dialect ().GetQuotedValue (" secret" );
2394
+ var q = db .From <CustomSqlUser >()
2395
+ .Where (x => x .Password == Sql .Custom ($" crypt({quotedSecret }, password)" ));
2396
+ var row = db .Single (q );
2397
+ ```
2398
+
2250
2399
#### Pre / Post Custom SQL Hooks when Creating and Dropping tables
2251
2400
2252
2401
Pre / Post Custom SQL Hooks allow you to inject custom SQL before and after tables are created or dropped, e.g:
@@ -3155,6 +3304,22 @@ PostgreSqlDialect.Provider.RegisterConverter<List<DateTime>>(new PostgreSqlDateT
3155
3304
PostgreSqlDialect .Provider .RegisterConverter <List <DateTimeOffset >>(new PostgreSqlDateTimeOffsetTimeStampTzArrayConverter ());
3156
3305
```
3157
3306
3307
+ ### PostgreSQL Params
3308
+
3309
+ The ` PgSql.Param() ` API provides a resolve the correct populated ` NpgsqlParameter ` and ` NpgsqlDbType ` from a C# Type
3310
+ which can be used to query custom PostgreSQL Data Types in APIs that accept ` IDbDataParameter ` parameters, e.g:
3311
+
3312
+ ``` csharp
3313
+ public class FunctionResult
3314
+ {
3315
+ public int [] Val { get ; set ; }
3316
+ }
3317
+
3318
+ var p = PgSql .Param (" paramValue" , testVal );
3319
+ var sql = " SELECT * FROM my_func(@paramValue)" ;
3320
+ var rows = db .Select <FunctionResult >(sql , new [] { p });
3321
+ ```
3322
+
3158
3323
### Hstore support
3159
3324
3160
3325
To use ` hstore ` , its extension needs to be enabled in your PostgreSQL RDBMS by running:
0 commit comments