1+ using System ;
2+ using System . Collections . Concurrent ;
3+ using System . Collections . Generic ;
4+ using System . Data ;
5+ using System . Data . Common ;
6+ using System . Dynamic ;
7+ using System . Linq ;
8+
9+ namespace Simple . Data . Ado
10+ {
11+ class AdoAdapterGetter
12+ {
13+ private readonly ConcurrentDictionary < string , ConcurrentDictionary < string , CommandTemplate > > _commandCaches =
14+ new ConcurrentDictionary < string , ConcurrentDictionary < string , CommandTemplate > > ( ) ;
15+ private readonly AdoAdapter _adapter ;
16+ private readonly IDbTransaction _transaction ;
17+ private readonly IDbConnection _connection ;
18+
19+ public AdoAdapterGetter ( AdoAdapter adapter ) : this ( adapter , null )
20+ {
21+ }
22+
23+ public AdoAdapterGetter ( AdoAdapter adapter , IDbTransaction transaction )
24+ {
25+ if ( adapter == null ) throw new ArgumentNullException ( "adapter" ) ;
26+ _adapter = adapter ;
27+
28+ if ( transaction != null )
29+ {
30+ _transaction = transaction ;
31+ _connection = transaction . Connection ;
32+ }
33+ }
34+
35+ public IDictionary < string , object > FindOne ( string tableName , SimpleExpression criteria )
36+ {
37+ if ( criteria == null ) return FindAll ( _adapter . GetSchema ( ) . BuildObjectName ( tableName ) ) . FirstOrDefault ( ) ;
38+ var commandTemplate = GetCommandTemplate ( tableName , criteria ) ;
39+ return ExecuteSingletonQuery ( commandTemplate , criteria . GetValues ( ) ) ;
40+ }
41+
42+ public Func < object [ ] , IDictionary < string , object > > CreateGetDelegate ( string tableName , params object [ ] keyValues )
43+ {
44+ var primaryKey = _adapter . GetSchema ( ) . FindTable ( tableName ) . PrimaryKey ;
45+ if ( primaryKey == null ) throw new InvalidOperationException ( "Table has no primary key." ) ;
46+ if ( primaryKey . Length != keyValues . Length ) throw new ArgumentException ( "Incorrect number of values for key." ) ;
47+
48+
49+ var commandBuilder = new GetHelper ( _adapter . GetSchema ( ) ) . GetCommand ( _adapter . GetSchema ( ) . FindTable ( tableName ) , keyValues ) ;
50+
51+ var command = commandBuilder . GetCommand ( _adapter . CreateConnection ( ) ) ;
52+ command = _adapter . CommandOptimizer . OptimizeFindOne ( command ) ;
53+
54+ var commandTemplate =
55+ commandBuilder . GetCommandTemplate (
56+ _adapter . GetSchema ( ) . FindTable ( _adapter . GetSchema ( ) . BuildObjectName ( tableName ) ) ) ;
57+
58+ var cloneable = command as ICloneable ;
59+ if ( cloneable != null )
60+ {
61+ return args => ExecuteSingletonQuery ( ( IDbCommand ) cloneable . Clone ( ) , args , commandTemplate . Index ) ;
62+ }
63+ else
64+ {
65+ return args => ExecuteSingletonQuery ( commandTemplate , args ) ;
66+ }
67+ }
68+
69+ private IDictionary < string , object > ExecuteSingletonQuery ( IDbCommand command , object [ ] parameterValues , IDictionary < string , int > index )
70+ {
71+ for ( int i = 0 ; i < command . Parameters . Count ; i ++ )
72+ {
73+ ( ( IDbDataParameter ) command . Parameters [ i ] ) . Value = FixObjectType ( parameterValues [ i ] ) ;
74+ }
75+ command . Connection = _adapter . CreateConnection ( ) ;
76+ return TryExecuteSingletonQuery ( command . Connection , command , index ) ;
77+ }
78+
79+ public IEnumerable < IDictionary < string , object > > Find ( string tableName , SimpleExpression criteria )
80+ {
81+ if ( criteria == null ) return FindAll ( _adapter . GetSchema ( ) . BuildObjectName ( tableName ) ) ;
82+ var commandTemplate = GetCommandTemplate ( tableName , criteria ) ;
83+ return ExecuteQuery ( commandTemplate , criteria . GetValues ( ) ) ;
84+ }
85+
86+ private CommandTemplate GetCommandTemplate ( string tableName , SimpleExpression criteria )
87+ {
88+ var tableCommandCache = _commandCaches . GetOrAdd ( tableName ,
89+ _ => new ConcurrentDictionary < string , CommandTemplate > ( ) ) ;
90+
91+ var hash = new ExpressionHasher ( ) . Format ( criteria ) ;
92+ return tableCommandCache . GetOrAdd ( hash ,
93+ _ =>
94+ new FindHelper ( _adapter . GetSchema ( ) )
95+ . GetFindByCommand ( _adapter . GetSchema ( ) . BuildObjectName ( tableName ) , criteria )
96+ . GetCommandTemplate ( _adapter . GetSchema ( ) . FindTable ( _adapter . GetSchema ( ) . BuildObjectName ( tableName ) ) ) ) ;
97+ }
98+
99+ private IEnumerable < IDictionary < string , object > > FindAll ( ObjectName tableName )
100+ {
101+ return ExecuteQuery ( "select * from " + _adapter . GetSchema ( ) . FindTable ( tableName ) . QualifiedName ) ;
102+ }
103+
104+ private IEnumerable < IDictionary < string , object > > ExecuteQuery ( CommandTemplate commandTemplate , IEnumerable < object > parameterValues )
105+ {
106+ var connection = _connection ?? _adapter . CreateConnection ( ) ;
107+ var command = commandTemplate . GetDbCommand ( connection , parameterValues ) ;
108+ command . Transaction = _transaction ;
109+ return TryExecuteQuery ( connection , command , commandTemplate . Index ) ;
110+ }
111+
112+ private IDictionary < string , object > ExecuteSingletonQuery ( CommandTemplate commandTemplate , IEnumerable < object > parameterValues )
113+ {
114+ var connection = _connection ?? _adapter . CreateConnection ( ) ;
115+ var command = commandTemplate . GetDbCommand ( connection , parameterValues ) ;
116+ command . Transaction = _transaction ;
117+ return TryExecuteSingletonQuery ( connection , command , commandTemplate . Index ) ;
118+ }
119+
120+ private IEnumerable < IDictionary < string , object > > ExecuteQuery ( string sql , params object [ ] values )
121+ {
122+ var connection = _connection ?? _adapter . CreateConnection ( ) ;
123+ var command = new CommandHelper ( _adapter ) . Create ( connection , sql , values ) ;
124+ command . Transaction = _transaction ;
125+ return TryExecuteQuery ( connection , command ) ;
126+ }
127+
128+ private static IEnumerable < IDictionary < string , object > > TryExecuteQuery ( IDbConnection connection , IDbCommand command )
129+ {
130+ try
131+ {
132+ return command . ToEnumerable ( connection ) ;
133+ }
134+ catch ( DbException ex )
135+ {
136+ throw new AdoAdapterException ( ex . Message , command ) ;
137+ }
138+ }
139+
140+ private static IEnumerable < IDictionary < string , object > > TryExecuteQuery ( IDbConnection connection , IDbCommand command , IDictionary < string , int > index )
141+ {
142+ try
143+ {
144+ return command . ToEnumerable ( connection , index ) ;
145+ }
146+ catch ( DbException ex )
147+ {
148+ throw new AdoAdapterException ( ex . Message , command ) ;
149+ }
150+ }
151+
152+ private static IDictionary < string , object > TryExecuteSingletonQuery ( IDbConnection connection , IDbCommand command , IDictionary < string , int > index )
153+ {
154+ command . WriteTrace ( ) ;
155+ using ( connection . MaybeDisposable ( ) )
156+ using ( command )
157+ {
158+ try
159+ {
160+ if ( connection . State != ConnectionState . Open )
161+ connection . Open ( ) ;
162+ using ( var reader = command . ExecuteReader ( ) )
163+ {
164+ if ( reader . Read ( ) )
165+ {
166+ return reader . ToDictionary ( index ) ;
167+ }
168+ }
169+ }
170+ catch ( DbException ex )
171+ {
172+ throw new AdoAdapterException ( ex . Message , command ) ;
173+ }
174+ }
175+ return null ;
176+ }
177+
178+ private static IDisposable DisposeWrap ( IDbConnection connection )
179+ {
180+ if ( connection . State == ConnectionState . Open )
181+ {
182+ return ActionDisposable . NoOp ;
183+ }
184+
185+ return new ActionDisposable ( connection . Dispose ) ;
186+ }
187+
188+ private static object FixObjectType ( object value )
189+ {
190+ if ( value == null ) return DBNull . Value ;
191+ if ( TypeHelper . IsKnownType ( value . GetType ( ) ) ) return value ;
192+ var dynamicObject = value as DynamicObject ;
193+ if ( dynamicObject != null )
194+ {
195+ return dynamicObject . ToString ( ) ;
196+ }
197+ return value ;
198+ }
199+ }
200+ }
0 commit comments