30
30
using System . Runtime . InteropServices ;
31
31
#endif
32
32
using System . Collections . Generic ;
33
- #if NO_CONCURRENT
34
- using ConcurrentStringDictionary = System . Collections . Generic . Dictionary < string , object > ;
35
- using SQLite . Extensions ;
36
- #else
37
- using ConcurrentStringDictionary = System . Collections . Concurrent . ConcurrentDictionary < string , object > ;
38
- #endif
39
33
using System . Reflection ;
40
34
using System . Linq ;
41
35
using System . Linq . Expressions ;
@@ -1578,7 +1572,7 @@ public int Insert (object obj, string extra, Type objType)
1578
1572
vals [ i ] = cols [ i ] . GetValue ( obj ) ;
1579
1573
}
1580
1574
1581
- var insertCmd = map . GetInsertCommand ( this , extra ) ;
1575
+ var insertCmd = GetInsertCommand ( map , extra ) ;
1582
1576
int count ;
1583
1577
1584
1578
lock ( insertCmd ) {
@@ -1605,6 +1599,61 @@ public int Insert (object obj, string extra, Type objType)
1605
1599
return count ;
1606
1600
}
1607
1601
1602
+ readonly Dictionary < Tuple < string , string > , PreparedSqlLiteInsertCommand > _insertCommandMap = new Dictionary < Tuple < string , string > , PreparedSqlLiteInsertCommand > ( ) ;
1603
+
1604
+ PreparedSqlLiteInsertCommand GetInsertCommand ( TableMapping map , string extra )
1605
+ {
1606
+ PreparedSqlLiteInsertCommand prepCmd ;
1607
+
1608
+ var key = Tuple . Create ( map . MappedType . FullName , extra ) ;
1609
+
1610
+ lock ( _insertCommandMap ) {
1611
+ _insertCommandMap . TryGetValue ( key , out prepCmd ) ;
1612
+ }
1613
+
1614
+ if ( prepCmd == null ) {
1615
+ prepCmd = CreateInsertCommand ( map , extra ) ;
1616
+ var added = false ;
1617
+ lock ( _insertCommandMap ) {
1618
+ if ( ! _insertCommandMap . ContainsKey ( key ) ) {
1619
+ _insertCommandMap . Add ( key , prepCmd ) ;
1620
+ added = true ;
1621
+ }
1622
+ }
1623
+ if ( ! added ) {
1624
+ prepCmd . Dispose ( ) ;
1625
+ }
1626
+ }
1627
+
1628
+ return prepCmd ;
1629
+ }
1630
+
1631
+ PreparedSqlLiteInsertCommand CreateInsertCommand ( TableMapping map , string extra )
1632
+ {
1633
+ var cols = map . InsertColumns ;
1634
+ string insertSql ;
1635
+ if ( cols . Length == 0 && map . Columns . Length == 1 && map . Columns [ 0 ] . IsAutoInc ) {
1636
+ insertSql = string . Format ( "insert {1} into \" {0}\" default values" , map . TableName , extra ) ;
1637
+ }
1638
+ else {
1639
+ var replacing = string . Compare ( extra , "OR REPLACE" , StringComparison . OrdinalIgnoreCase ) == 0 ;
1640
+
1641
+ if ( replacing ) {
1642
+ cols = map . InsertOrReplaceColumns ;
1643
+ }
1644
+
1645
+ insertSql = string . Format ( "insert {3} into \" {0}\" ({1}) values ({2})" , map . TableName ,
1646
+ string . Join ( "," , ( from c in cols
1647
+ select "\" " + c . Name + "\" " ) . ToArray ( ) ) ,
1648
+ string . Join ( "," , ( from c in cols
1649
+ select "?" ) . ToArray ( ) ) , extra ) ;
1650
+
1651
+ }
1652
+
1653
+ var insertCommand = new PreparedSqlLiteInsertCommand ( this , insertSql ) ;
1654
+ return insertCommand ;
1655
+ }
1656
+
1608
1657
/// <summary>
1609
1658
/// Updates all of the columns of a table using the specified object
1610
1659
/// except for its primary key.
@@ -1844,10 +1893,11 @@ protected virtual void Dispose (bool disposing)
1844
1893
if ( _open && Handle != NullHandle ) {
1845
1894
try {
1846
1895
if ( disposing ) {
1847
- if ( _mappings != null ) {
1848
- foreach ( var sqlInsertCommand in _mappings . Values ) {
1896
+ lock ( _insertCommandMap ) {
1897
+ foreach ( var sqlInsertCommand in _insertCommandMap . Values ) {
1849
1898
sqlInsertCommand . Dispose ( ) ;
1850
1899
}
1900
+ _insertCommandMap . Clear ( ) ;
1851
1901
}
1852
1902
1853
1903
var r = useClose2 ? SQLite3 . Close2 ( Handle ) : SQLite3 . Close ( Handle ) ;
@@ -2114,7 +2164,6 @@ from p in ti.DeclaredProperties
2114
2164
// People should not be calling Get/Find without a PK
2115
2165
GetByPrimaryKeySql = string . Format ( "select * from \" {0}\" limit 1" , TableName ) ;
2116
2166
}
2117
- _insertCommandMap = new ConcurrentStringDictionary ( ) ;
2118
2167
}
2119
2168
2120
2169
public bool HasAutoIncPK { get ; private set ; }
@@ -2156,59 +2205,6 @@ public Column FindColumn (string columnName)
2156
2205
return exact ;
2157
2206
}
2158
2207
2159
- ConcurrentStringDictionary _insertCommandMap ;
2160
-
2161
- public PreparedSqlLiteInsertCommand GetInsertCommand ( SQLiteConnection conn , string extra )
2162
- {
2163
- object prepCmdO ;
2164
-
2165
- if ( ! _insertCommandMap . TryGetValue ( extra , out prepCmdO ) ) {
2166
- var prepCmd = CreateInsertCommand ( conn , extra ) ;
2167
- prepCmdO = prepCmd ;
2168
- if ( ! _insertCommandMap . TryAdd ( extra , prepCmd ) ) {
2169
- // Concurrent add attempt beat us.
2170
- prepCmd . Dispose ( ) ;
2171
- _insertCommandMap . TryGetValue ( extra , out prepCmdO ) ;
2172
- }
2173
- }
2174
- return ( PreparedSqlLiteInsertCommand ) prepCmdO ;
2175
- }
2176
-
2177
- PreparedSqlLiteInsertCommand CreateInsertCommand ( SQLiteConnection conn , string extra )
2178
- {
2179
- var cols = InsertColumns ;
2180
- string insertSql ;
2181
- if ( ! cols . Any ( ) && Columns . Count ( ) == 1 && Columns [ 0 ] . IsAutoInc ) {
2182
- insertSql = string . Format ( "insert {1} into \" {0}\" default values" , TableName , extra ) ;
2183
- }
2184
- else {
2185
- var replacing = string . Compare ( extra , "OR REPLACE" , StringComparison . OrdinalIgnoreCase ) == 0 ;
2186
-
2187
- if ( replacing ) {
2188
- cols = InsertOrReplaceColumns ;
2189
- }
2190
-
2191
- insertSql = string . Format ( "insert {3} into \" {0}\" ({1}) values ({2})" , TableName ,
2192
- string . Join ( "," , ( from c in cols
2193
- select "\" " + c . Name + "\" " ) . ToArray ( ) ) ,
2194
- string . Join ( "," , ( from c in cols
2195
- select "?" ) . ToArray ( ) ) , extra ) ;
2196
-
2197
- }
2198
-
2199
- var insertCommand = new PreparedSqlLiteInsertCommand ( conn ) ;
2200
- insertCommand . CommandText = insertSql ;
2201
- return insertCommand ;
2202
- }
2203
-
2204
- protected internal void Dispose ( )
2205
- {
2206
- foreach ( var pair in _insertCommandMap ) {
2207
- ( ( PreparedSqlLiteInsertCommand ) pair . Value ) . Dispose ( ) ;
2208
- }
2209
- _insertCommandMap = null ;
2210
- }
2211
-
2212
2208
public class Column
2213
2209
{
2214
2210
PropertyInfo _prop ;
@@ -2845,32 +2841,37 @@ object ReadCol (Sqlite3Statement stmt, int index, SQLite3.ColType type, Type clr
2845
2841
/// <summary>
2846
2842
/// Since the insert never changed, we only need to prepare once.
2847
2843
/// </summary>
2848
- public class PreparedSqlLiteInsertCommand : IDisposable
2844
+ class PreparedSqlLiteInsertCommand : IDisposable
2849
2845
{
2850
- public bool Initialized { get ; set ; }
2846
+ bool Initialized ;
2851
2847
2852
- protected SQLiteConnection Connection { get ; set ; }
2848
+ SQLiteConnection Connection ;
2853
2849
2854
- public string CommandText { get ; set ; }
2850
+ string CommandText ;
2855
2851
2856
- protected Sqlite3Statement Statement { get ; set ; }
2857
- internal static readonly Sqlite3Statement NullStatement = default ( Sqlite3Statement ) ;
2852
+ Sqlite3Statement Statement ;
2853
+ static readonly Sqlite3Statement NullStatement = default ( Sqlite3Statement ) ;
2858
2854
2859
- internal PreparedSqlLiteInsertCommand ( SQLiteConnection conn )
2855
+ public PreparedSqlLiteInsertCommand ( SQLiteConnection conn , string commandText )
2860
2856
{
2861
2857
Connection = conn ;
2858
+ CommandText = commandText ;
2862
2859
}
2863
2860
2864
2861
public int ExecuteNonQuery ( object [ ] source )
2865
2862
{
2863
+ if ( Initialized && Statement == NullStatement ) {
2864
+ throw new ObjectDisposedException ( nameof ( PreparedSqlLiteInsertCommand ) ) ;
2865
+ }
2866
+
2866
2867
if ( Connection . Trace ) {
2867
2868
Connection . Tracer ? . Invoke ( "Executing: " + CommandText ) ;
2868
2869
}
2869
2870
2870
2871
var r = SQLite3 . Result . OK ;
2871
2872
2872
2873
if ( ! Initialized ) {
2873
- Statement = Prepare ( ) ;
2874
+ Statement = SQLite3 . Prepare2 ( Connection . Handle , CommandText ) ;
2874
2875
Initialized = true ;
2875
2876
}
2876
2877
@@ -2902,28 +2903,19 @@ public int ExecuteNonQuery (object[] source)
2902
2903
}
2903
2904
}
2904
2905
2905
- protected virtual Sqlite3Statement Prepare ( )
2906
- {
2907
- var stmt = SQLite3 . Prepare2 ( Connection . Handle , CommandText ) ;
2908
- return stmt ;
2909
- }
2910
-
2911
2906
public void Dispose ( )
2912
2907
{
2913
2908
Dispose ( true ) ;
2914
2909
GC . SuppressFinalize ( this ) ;
2915
2910
}
2916
2911
2917
- private void Dispose ( bool disposing )
2912
+ void Dispose ( bool disposing )
2918
2913
{
2919
- if ( Statement != NullStatement ) {
2920
- try {
2921
- SQLite3 . Finalize ( Statement ) ;
2922
- }
2923
- finally {
2924
- Statement = NullStatement ;
2925
- Connection = null ;
2926
- }
2914
+ var s = Statement ;
2915
+ Statement = NullStatement ;
2916
+ Connection = null ;
2917
+ if ( s != NullStatement ) {
2918
+ SQLite3 . Finalize ( s ) ;
2927
2919
}
2928
2920
}
2929
2921
@@ -4074,24 +4066,3 @@ public enum ColType : int
4074
4066
}
4075
4067
}
4076
4068
}
4077
-
4078
- #if NO_CONCURRENT
4079
- namespace SQLite . Extensions
4080
- {
4081
- public static class ListEx
4082
- {
4083
- public static bool TryAdd < TKey , TValue > ( this IDictionary < TKey , TValue > dict , TKey key , TValue value )
4084
- {
4085
- try {
4086
- dict . Add ( key , value ) ;
4087
- return true ;
4088
- }
4089
- catch ( ArgumentException ) {
4090
- return false ;
4091
- }
4092
- }
4093
- }
4094
- }
4095
- #endif
4096
-
4097
-
0 commit comments