@@ -324,6 +324,18 @@ var q = db.From<Person>()
324
324
Dictionary < int , List < string >> results = db .Lookup <int , string >(q );
325
325
```
326
326
327
+ The new ` db.KeyValuePair<K,V> ` API is similar to ` db.Dictionary<K,V> ` where it uses the ** first 2 columns** for its Key/Value Pairs to
328
+ create a Dictionary but is more appropriate when the results can contain duplicate Keys or when ordering needs to be preserved:
329
+
330
+ ``` csharp
331
+ var q = db .From <StatsLog >()
332
+ .GroupBy (x => x .Name )
333
+ .Select (x => new { x .Name , Count = Sql .Count (" *" ) })
334
+ .OrderByDescending (" Count" );
335
+
336
+ var results = db .KeyValuePairs <string , int >(q );
337
+ ```
338
+
327
339
### INSERT, UPDATE and DELETEs
328
340
329
341
To see the behaviour of the different APIs, all examples uses this simple model
@@ -1092,6 +1104,15 @@ using (var multi = db.QueryMultiple(q.ToSelectStatement()))
1092
1104
}
1093
1105
```
1094
1106
1107
+ ### SELECT DISTINCT in SelectMulti
1108
+
1109
+ [ SelectMulti] ( https://github.com/ServiceStack/ServiceStack.OrmLite#selecting-multiple-columns-across-joined-tables ) APIs for populating
1110
+ multiple tables now supports ** SELECT DISTINCT** with:
1111
+
1112
+ ``` csharp
1113
+ var tuples = db .SelectMulti <Customer , CustomerAddress >(q .SelectDistinct ());
1114
+ ```
1115
+
1095
1116
### Select data from multiple tables into a Custom POCO
1096
1117
1097
1118
Another implicit behaviour when selecting from a typed SqlExpression is that results are mapped to the
@@ -1469,22 +1490,23 @@ var q = db.From<Table>()
1469
1490
.Select (x => x .Join1 .Join2 .IntValue );
1470
1491
```
1471
1492
1472
- ### JOIN aliases
1493
+ ### Table aliases
1473
1494
1474
- You can specify join aliases when joining same table multiple times together to differentiate from any
1475
- ambiguous columns, e.g:
1495
+ The ` TableAlias ` APIs lets you specify table aliases when joining same table multiple times together to differentiate from any
1496
+ ambiguous columns in Queries with multiple self-reference joins , e.g:
1476
1497
1477
1498
``` csharp
1478
- var q = db .From <Sale >()
1479
- .LeftJoin <ContactIssue >((s ,c ) => s .SellerId == c .Id , db .JoinAlias (" seller" ))
1480
- .LeftJoin <ContactIssue >((s ,c ) => s .BuyerId == c .Id , db .JoinAlias (" buyer" ))
1481
- .Select <Sale , ContactIssue >((s ,c ) => new {
1482
- s ,
1483
- BuyerFirstName = Sql .JoinAlias (c .FirstName , " buyer" ),
1484
- BuyerLastName = Sql .JoinAlias (c .LastName , " buyer" ),
1485
- SellerFirstName = Sql .JoinAlias (c .FirstName , " seller" ),
1486
- SellerLastName = Sql .JoinAlias (c .LastName , " seller" ),
1499
+ var q = db .From <Page >(db .TableAlias (" p1" ))
1500
+ .Join <Page >((p1 , p2 ) =>
1501
+ p1 .PageId == p2 .PageId &&
1502
+ p2 .ActivityId == activityId , db .TableAlias (" p2" ))
1503
+ .Join <Page ,Category >((p2 ,c ) => Sql .TableAlias (p2 .Category ) == c .Id )
1504
+ .Join <Page ,Page >((p1 ,p2 ) => Sql .TableAlias (p1 .Rank ," p1" ) < Sql .TableAlias (p2 .Rank ," p2" ))
1505
+ .Select <Page >(p => new {
1506
+ ActivityId = Sql .TableAlias (p .ActivityId , " p2" )
1487
1507
});
1508
+
1509
+ var rows = db .Select (q );
1488
1510
```
1489
1511
1490
1512
### Unique Constraints
@@ -1683,6 +1705,28 @@ SQLite offers [additional fine-grained behavior](https://sqlite.org/lang_conflic
1683
1705
- IGNORE
1684
1706
- REPLACE
1685
1707
1708
+ ### GetTableNames and GetTableNamesWithRowCounts APIs
1709
+
1710
+ As the queries for retrieving table names can vary amongst different RDBMS's, we've abstracted their implementations behind uniform APIs
1711
+ where you can now get a list of table names and their row counts for all supported RDBMS's with:
1712
+
1713
+ ``` csharp
1714
+ List < string > tableNames = db .GetTableNames ();
1715
+
1716
+ List < KeyValuePair < string ,long >> tableNamesWithRowCounts = db .GetTableNamesWithRowCounts ();
1717
+ ```
1718
+
1719
+ > ` *Async ` variants also available
1720
+
1721
+ Both APIs can be called with an optional ` schema ` if you only want the tables for a specific schema.
1722
+ It defaults to using the more efficient RDBMS APIs, which if offered typically returns an approximate estimate of rowcounts in each table.
1723
+
1724
+ If you need exact table row counts, you can specify ` live:true ` :
1725
+
1726
+ ``` csharp
1727
+ var tablesWithRowCounts = db .GetTableNamesWithRowCounts (live :true );
1728
+ ```
1729
+
1686
1730
### Modify Custom Schema
1687
1731
1688
1732
OrmLite provides Typed APIs for modifying Table Schemas that makes it easy to inspect the state of an
@@ -2951,7 +2995,7 @@ whilst the new `[SqlServerCollate]` attribute can be used to specify an SQL Serv
2951
2995
2952
2996
## PostgreSQL Features
2953
2997
2954
- ### PostgreSQL Data Types
2998
+ ### PostgreSQL Rich Data Types
2955
2999
2956
3000
The ` [PgSql*] ` specific attributes lets you use attributes to define PostgreSQL rich data types, e.g:
2957
3001
@@ -2975,6 +3019,139 @@ public class MyPostgreSqlTable
2975
3019
}
2976
3020
```
2977
3021
3022
+ By default all arrays of .NET's built-in ** numeric** , ** string** and ** DateTime** types will be stored in PostgreSQL array types:
3023
+
3024
+ ``` csharp
3025
+ public class Table
3026
+ {
3027
+ public Guid Id { get ; set ; }
3028
+
3029
+ public int [] Ints { get ; set ; }
3030
+ public long [] Longs { get ; set ; }
3031
+ public float [] Floats { get ; set ; }
3032
+ public double [] Doubles { get ; set ; }
3033
+ public decimal [] Decimals { get ; set ; }
3034
+ public string [] Strings { get ; set ; }
3035
+ public DateTime [] DateTimes { get ; set ; }
3036
+ public DateTimeOffset [] DateTimeOffsets { get ; set ; }
3037
+ }
3038
+ ```
3039
+
3040
+ You can opt-in to annotate other collections like ` List<T> ` to also be stored in array types by annotating them with ` [Pgsql*] ` attributes, e.g:
3041
+
3042
+ ``` csharp
3043
+ public class Table
3044
+ {
3045
+ public Guid Id { get ; set ; }
3046
+
3047
+ [PgSqlIntArray ]
3048
+ public List <int > ListInts { get ; set ; }
3049
+ [PgSqlBigIntArray ]
3050
+ public List <long > ListLongs { get ; set ; }
3051
+ [PgSqlFloatArray ]
3052
+ public List <float > ListFloats { get ; set ; }
3053
+ [PgSqlDoubleArray ]
3054
+ public List <double > ListDoubles { get ; set ; }
3055
+ [PgSqlDecimalArray ]
3056
+ public List <decimal > ListDecimals { get ; set ; }
3057
+ [PgSqlTextArray ]
3058
+ public List <string > ListStrings { get ; set ; }
3059
+ [PgSqlTimestamp ]
3060
+ public List <DateTime > ListDateTimes { get ; set ; }
3061
+ [PgSqlTimestampTz ]
3062
+ public List <DateTimeOffset > ListDateTimeOffsets { get ; set ; }
3063
+ }
3064
+ ```
3065
+
3066
+ Alternatively if you ** always** want ` List<T> ` stored in Array types, you can register them in the ` PostgreSqlDialect.Provider ` :
3067
+
3068
+ ``` csharp
3069
+ PostgreSqlDialect .Provider .RegisterConverter <List <string >>(new PostgreSqlStringArrayConverter ());
3070
+ PostgreSqlDialect .Provider .RegisterConverter <List <int >>(new PostgreSqlIntArrayConverter ());
3071
+ PostgreSqlDialect .Provider .RegisterConverter <List <long >>(new PostgreSqlLongArrayConverter ());
3072
+ PostgreSqlDialect .Provider .RegisterConverter <List <float >>(new PostgreSqlFloatArrayConverter ());
3073
+ PostgreSqlDialect .Provider .RegisterConverter <List <double >>(new PostgreSqlDoubleArrayConverter ());
3074
+ PostgreSqlDialect .Provider .RegisterConverter <List <decimal >>(new PostgreSqlDecimalArrayConverter ());
3075
+ PostgreSqlDialect .Provider .RegisterConverter <List <DateTime >>(new PostgreSqlDateTimeTimeStampArrayConverter ());
3076
+ PostgreSqlDialect .Provider .RegisterConverter <List <DateTimeOffset >>(new PostgreSqlDateTimeOffsetTimeStampTzArrayConverter ());
3077
+ ```
3078
+
3079
+ ### Hstore support
3080
+
3081
+ To use ` hstore ` , its extension needs to be enabled in your PostgreSQL RDBMS by running:
3082
+
3083
+ CREATE EXTENSION hstore;
3084
+
3085
+ Which can then be enabled in OrmLite with:
3086
+
3087
+ ``` csharp
3088
+ PostgreSqlDialect .Instance .UseHstore = true ;
3089
+ ```
3090
+
3091
+ Where it will now store ** string Dictionaries** in ` Hstore ` columns:
3092
+
3093
+ ``` csharp
3094
+ public class TableHstore
3095
+ {
3096
+ public int Id { get ; set ; }
3097
+
3098
+ public Dictionary <string ,string > Dictionary { get ; set ; }
3099
+ public IDictionary <string ,string > IDictionary { get ; set ; }
3100
+ }
3101
+
3102
+ db .DropAndCreateTable <TableHstore >();
3103
+
3104
+ db .Insert (new TableHstore
3105
+ {
3106
+ Id = 1 ,
3107
+ Dictionary = new Dictionary <string , string > { {" A" , " 1" } },
3108
+ IDictionary = new Dictionary <string , string > { {" B" , " 2" } },
3109
+ });
3110
+ ```
3111
+
3112
+ Where they can than be queried in postgres using [ Hstore SQL Syntax] ( https://www.postgresql.org/docs/9.0/hstore.html ) :
3113
+
3114
+ ``` csharp
3115
+ db .Single (db .From <PostgreSqlTypes >().Where (" dictionary -> 'A' = '1'" )).Id // = 1
3116
+ ```
3117
+
3118
+ Thanks to [ @cthames ] ( https://forums.servicestack.net/users/cthames/activity ) for this feature.
3119
+
3120
+ ### JSON data types
3121
+
3122
+ If you instead wanted to store arbitrary complex types in PostgreSQL's rich column types to enable deep querying in postgres,
3123
+ you'd instead annotate them with ` [PgSqlJson] ` or ` [PgSqlJsonB] ` , e.g:
3124
+
3125
+ ``` csharp
3126
+ public class TableJson
3127
+ {
3128
+ public int Id { get ; set ; }
3129
+
3130
+ [PgSqlJson ]
3131
+ public ComplexType ComplexTypeJson { get ; set ; }
3132
+
3133
+ [PgSqlJsonB ]
3134
+ public ComplexType ComplexTypeJsonb { get ; set ; }
3135
+ }
3136
+
3137
+ db .Insert (new TableJson
3138
+ {
3139
+ Id = 1 ,
3140
+ ComplexTypeJson = new ComplexType {
3141
+ Id = 2 , SubType = new SubType { Name = " JSON" }
3142
+ },
3143
+ ComplexTypeJsonb = new ComplexType {
3144
+ Id = 3 , SubType = new SubType { Name = " JSONB" }
3145
+ },
3146
+ });
3147
+ ```
3148
+
3149
+ Where they can then be queried on the server with [ JSON SQL Syntax and functions] ( https://www.postgresql.org/docs/9.3/functions-json.html ) :
3150
+
3151
+ ``` csharp
3152
+ var result = db .Single <TableJson >(" table_json->'SubType'->>'Name' = 'JSON'" );
3153
+ ```
3154
+
2978
3155
# Limitations
2979
3156
2980
3157
### Single Primary Key
0 commit comments