1+ namespace Simple . Data . Ado
2+ {
3+ using System ;
4+ using System . Collections . Generic ;
5+ using System . Data ;
6+ using System . Linq ;
7+ using Extensions ;
8+
9+ class AdoAdapterUpserter
10+ {
11+ private readonly AdoAdapter _adapter ;
12+ private readonly IDbConnection _connection ;
13+ private readonly IDbTransaction _transaction ;
14+
15+ public AdoAdapterUpserter ( AdoAdapter adapter ) : this ( adapter , ( IDbTransaction ) null )
16+ {
17+ }
18+
19+ public AdoAdapterUpserter ( AdoAdapter adapter , IDbConnection connection )
20+ {
21+ _adapter = adapter ;
22+ _connection = connection ;
23+ }
24+
25+ public AdoAdapterUpserter ( AdoAdapter adapter , IDbTransaction transaction )
26+ {
27+ _adapter = adapter ;
28+ _transaction = transaction ;
29+ if ( transaction != null ) _connection = transaction . Connection ;
30+ }
31+
32+ public IDictionary < string , object > Upsert ( string tableName , IDictionary < string , object > data , SimpleExpression criteria , bool resultRequired )
33+ {
34+ var connection = _connection ?? _adapter . CreateConnection ( ) ;
35+ using ( connection . MaybeDisposable ( ) )
36+ {
37+ connection . OpenIfClosed ( ) ;
38+ return Upsert ( tableName , data , criteria , resultRequired , connection ) ;
39+ }
40+ }
41+
42+ private IDictionary < string , object > Upsert ( string tableName , IDictionary < string , object > data , SimpleExpression criteria , bool resultRequired ,
43+ IDbConnection connection )
44+ {
45+ var finder = _transaction == null
46+ ? new AdoAdapterFinder ( _adapter , connection )
47+ : new AdoAdapterFinder ( _adapter , _transaction ) ;
48+ if ( finder . FindOne ( tableName , criteria ) != null )
49+ {
50+ // Don't update columns used as criteria
51+ var keys = criteria . GetOperandsOfType < ObjectReference > ( ) . Select ( o => o . GetName ( ) . Homogenize ( ) ) ;
52+ data = data . Where ( kvp => keys . All ( k => k != kvp . Key . Homogenize ( ) ) ) . ToDictionary ( ) ;
53+
54+ var commandBuilder = new UpdateHelper ( _adapter . GetSchema ( ) ) . GetUpdateCommand ( tableName , data , criteria ) ;
55+ if ( _transaction == null )
56+ {
57+ AdoAdapter . Execute ( commandBuilder , connection ) ;
58+ }
59+ else
60+ {
61+ AdoAdapter . Execute ( commandBuilder , _transaction ) ;
62+ }
63+ return resultRequired ? finder . FindOne ( tableName , criteria ) : null ;
64+ }
65+ var inserter = _transaction == null
66+ ? new AdoAdapterInserter ( _adapter , connection )
67+ : new AdoAdapterInserter ( _adapter , _transaction ) ;
68+ return inserter . Insert ( tableName , data , resultRequired ) ;
69+ }
70+
71+
72+ public IEnumerable < IDictionary < string , object > > UpsertMany ( string tableName , IList < IDictionary < string , object > > list , bool isResultRequired , Func < IDictionary < string , object > , Exception , bool > errorCallback )
73+ {
74+ foreach ( var row in list )
75+ {
76+ IDictionary < string , object > result ;
77+ try
78+ {
79+ var criteria = ExpressionHelper . CriteriaDictionaryToExpression ( tableName ,
80+ _adapter . GetKey ( tableName , row ) ) ;
81+ result = Upsert ( tableName , row , criteria , isResultRequired ) ;
82+ }
83+ catch ( Exception ex )
84+ {
85+ if ( errorCallback ( row , ex ) ) continue ;
86+ throw ;
87+ }
88+
89+ yield return result ;
90+ }
91+ }
92+
93+ public IEnumerable < IDictionary < string , object > > UpsertMany ( string tableName , IList < IDictionary < string , object > > list , IList < string > keyFieldNames , bool isResultRequired , Func < IDictionary < string , object > , Exception , bool > errorCallback )
94+ {
95+ foreach ( var row in list )
96+ {
97+ IDictionary < string , object > result ;
98+ try
99+ {
100+ var criteria = GetCriteria ( tableName , keyFieldNames , row ) ;
101+ result = Upsert ( tableName , row , criteria , isResultRequired ) ;
102+ }
103+ catch ( Exception ex )
104+ {
105+ if ( errorCallback ( row , ex ) ) continue ;
106+ throw ;
107+ }
108+
109+ yield return result ;
110+ }
111+ }
112+
113+ private static SimpleExpression GetCriteria ( string tableName , IEnumerable < string > criteriaFieldNames ,
114+ IDictionary < string , object > record )
115+ {
116+ var criteria = new Dictionary < string , object > ( ) ;
117+
118+ foreach ( var criteriaFieldName in criteriaFieldNames )
119+ {
120+ var name = criteriaFieldName ;
121+ var keyValuePair = record . SingleOrDefault ( kvp => kvp . Key . Homogenize ( ) . Equals ( name . Homogenize ( ) ) ) ;
122+ if ( string . IsNullOrWhiteSpace ( keyValuePair . Key ) )
123+ {
124+ throw new InvalidOperationException ( "Key field value not set." ) ;
125+ }
126+
127+ criteria . Add ( criteriaFieldName , keyValuePair . Value ) ;
128+ record . Remove ( keyValuePair ) ;
129+ }
130+ return ExpressionHelper . CriteriaDictionaryToExpression ( tableName , criteria ) ;
131+ }
132+ }
133+ }
0 commit comments