comparison Source/Data/DataProvider/DataProviderBase.cs @ 0:f990fcb411a9

Копия текущей версии из github
author cin
date Thu, 27 Mar 2014 21:46:09 +0400
parents
children
comparison
equal deleted inserted replaced
-1:000000000000 0:f990fcb411a9
1 using System;
2 using System.Collections.Generic;
3 using System.Data;
4 using System.Data.Common;
5 using System.Data.Linq;
6 using System.Linq;
7
8 namespace BLToolkit.Data.DataProvider
9 {
10 using Common;
11 using Mapping;
12 using Sql.SqlProvider;
13
14 /// <summary>
15 /// The <b>DataProviderBase</b> is a class that provides specific data provider information
16 /// for the <see cref="DbManager"/> class.
17 /// </summary>
18 /// <remarks>
19 /// See the <see cref="DbManager.AddDataProvider(DataProviderBase)"/> method to find an example.
20 /// </remarks>
21 /// <seealso cref="DbManager.AddDataProvider(DataProviderBase)">AddDataManager Method</seealso>
22 public abstract partial class DataProviderBase : IMappingSchemaProvider
23 {
24 #region Abstract Properties
25
26 /// <summary>
27 /// Returns an actual type of the connection object used by this instance of the <see cref="DbManager"/>.
28 /// </summary>
29 /// <remarks>
30 /// See the <see cref="DbManager.AddDataProvider(DataProviderBase)"/> method to find an example.
31 /// </remarks>
32 /// <seealso cref="DbManager.AddDataProvider(DataProviderBase)">AddDataManager Method</seealso>
33 /// <value>An instance of the <see cref="Type"/> class.</value>
34 public abstract Type ConnectionType { get; }
35
36 /// <summary>
37 /// Returns the data manager name.
38 /// </summary>
39 /// <remarks>
40 /// See the <see cref="DbManager.AddDataProvider(DataProviderBase)"/> method to find an example.
41 /// </remarks>
42 /// <seealso cref="DbManager.AddDataProvider(DataProviderBase)">AddDataManager Method</seealso>
43 /// <value>The data manager name.</value>
44 public abstract string Name { get; }
45
46 private string _uniqueName;
47 /// <summary>
48 /// Same as <see cref="Name"/>, but may be overridden to add two or more providers of same type.
49 /// </summary>
50 public string UniqueName
51 {
52 get { return _uniqueName ?? Name; }
53 internal set { _uniqueName = value; }
54 }
55
56 #endregion
57
58 #region Abstract Methods
59
60 /// <summary>
61 /// Creates a new instance of the <see cref="IDbConnection"/>.
62 /// </summary>
63 /// <remarks>
64 /// See the <see cref="DbManager.AddDataProvider(DataProviderBase)"/> method to find an example.
65 /// </remarks>
66 /// <seealso cref="DbManager.AddDataProvider(DataProviderBase)">AddDataManager Method</seealso>
67 /// <returns>The <see cref="IDbConnection"/> object.</returns>
68 public abstract IDbConnection CreateConnectionObject();
69
70 /// <summary>
71 /// Creates a new connection object with same connection string.
72 /// </summary>
73 /// <param name="connection">A connection object used as prototype.</param>
74 /// <returns>New connection instance.</returns>
75 public virtual IDbConnection CloneConnection(IDbConnection connection)
76 {
77 if (connection == null)
78 throw new ArgumentNullException("connection");
79
80 var cloneable = connection as ICloneable;
81
82 if (cloneable != null)
83 return (IDbConnection)cloneable.Clone();
84
85 var newConnection = CreateConnectionObject();
86
87 // This is definitelly not enought when PersistSecurityInfo set to false.
88 //
89 newConnection.ConnectionString = connection.ConnectionString;
90
91 return newConnection;
92 }
93
94 /// <summary>
95 /// Creates an instance of the <see cref="DbDataAdapter"/>.
96 /// </summary>
97 /// <remarks>
98 /// See the <see cref="DbManager.AddDataProvider(DataProviderBase)"/> method to find an example.
99 /// </remarks>
100 /// <seealso cref="DbManager.AddDataProvider(DataProviderBase)">AddDataManager Method</seealso>
101 /// <returns>The <see cref="DbDataAdapter"/> object.</returns>
102 public abstract DbDataAdapter CreateDataAdapterObject();
103
104 /// <summary>
105 /// Populates the specified <see cref="IDbCommand"/> object's Parameters collection with
106 /// parameter information for the stored procedure specified in the <see cref="IDbCommand"/>.
107 /// </summary>
108 /// <remarks>
109 /// See the <see cref="DbManager.AddDataProvider(DataProviderBase)"/> method to find an example.
110 /// </remarks>
111 /// <seealso cref="DbManager.AddDataProvider(DataProviderBase)">AddDataManager Method</seealso>
112 /// <param name="command">The <see cref="IDbCommand"/> referencing the stored procedure
113 /// for which the parameter information is to be derived.
114 /// The derived parameters will be populated into the Parameters of this command.</param>
115 /// <returns>true - parameters can be derive.</returns>
116 public abstract bool DeriveParameters(IDbCommand command);
117
118 #endregion
119
120 #region Factory methods
121
122 public virtual IDbCommand CreateCommandObject(IDbConnection connection)
123 {
124 return connection.CreateCommand();
125 }
126
127 public virtual IDbDataParameter CreateParameterObject(IDbCommand command)
128 {
129 return command.CreateParameter();
130 }
131
132 #endregion
133
134 #region IDbDataParameter methods
135
136 public virtual IDbDataParameter GetParameter(
137 IDbCommand command,
138 NameOrIndexParameter nameOrIndex)
139 {
140 return (IDbDataParameter)(nameOrIndex.ByName ?
141 command.Parameters[nameOrIndex.Name] : command.Parameters[nameOrIndex.Index]);
142 }
143
144 public virtual void AttachParameter(
145 IDbCommand command,
146 IDbDataParameter parameter)
147 {
148 command.Parameters.Add(parameter);
149 }
150
151 public virtual void SetUserDefinedType(IDbDataParameter parameter, string typeName)
152 {
153 throw new NotSupportedException(Name + " data provider does not support UDT.");
154 }
155
156 public virtual bool IsValueParameter(IDbDataParameter parameter)
157 {
158 return parameter.Direction != ParameterDirection.ReturnValue;
159 }
160
161 public virtual IDbDataParameter CloneParameter(IDbDataParameter parameter)
162 {
163 return (IDbDataParameter)((ICloneable)parameter).Clone();
164 }
165
166 public virtual bool InitParameter(IDbDataParameter parameter)
167 {
168 return false;
169 }
170
171 #endregion
172
173 #region Virtual Members
174
175 /// <summary>
176 /// Open an <see cref="IDataReader"/> into the given RefCursor object
177 /// </summary>
178 /// <param name="refCursor">The refcursor to open an <see cref="IDataReader"/> to</param>
179 /// <returns>The <see cref="IDataReader"/> into the refcursor</returns>
180 public virtual IDataReader GetRefCursorDataReader(object refCursor)
181 {
182 throw new NotSupportedException("Operation not supported on this DataProvider");
183 }
184
185 public virtual object Convert(object value, ConvertType convertType)
186 {
187 return SqlProvider.Convert(value, convertType);
188 }
189
190 public virtual DataExceptionType ConvertErrorNumberToDataExceptionType(int number)
191 {
192 return DataExceptionType.Undefined;
193 }
194
195 public virtual void InitDbManager(DbManager dbManager)
196 {
197 var schema = MappingSchema;
198
199 if (schema != null)
200 dbManager.MappingSchema = schema;
201 }
202
203 /// <summary>
204 /// One time initialization from a configuration file.
205 /// </summary>
206 /// <param name="attributes">Provider specific attributes.</param>
207 public virtual void Configure(System.Collections.Specialized.NameValueCollection attributes)
208 {
209 }
210
211 public virtual MappingSchema MappingSchema { get; set; }
212
213 public virtual void PrepareCommand(ref CommandType commandType, ref string commandText, ref IDbDataParameter[] commandParameters)
214 {
215 /*
216 if (commandParameters != null) foreach (var p in commandParameters)
217 {
218 if (p.Value is System.Data.Linq.Binary)
219 {
220 var arr = ((System.Data.Linq.Binary)p.Value).ToArray();
221
222 p.Value = arr;
223 p.DbType = DbType.Binary;
224 p.Size = arr.Length;
225 }
226 }
227 */
228 }
229
230 public virtual bool CanReuseCommand(IDbCommand command, CommandType newCommandType)
231 {
232 return true;
233 }
234
235 public virtual int ExecuteArray(IDbCommand command, int iterations)
236 {
237 // save parameter values
238 var parameters = command.Parameters
239 .OfType<IDbDataParameter>()
240 .Select(param => new
241 {
242 Parameter = param,
243 Value = param.Value as Array
244 })
245 .ToArray();
246
247 var outParameters = parameters
248 .Where(p =>
249 p.Parameter.Direction == ParameterDirection.InputOutput ||
250 p.Parameter.Direction == ParameterDirection.Output)
251 .ToArray();
252
253 // validate parameter values
254 foreach (var p in parameters)
255 {
256 if (p.Value == null)
257 {
258 throw new InvalidOperationException("ExecuteArray requires that all " +
259 "parameter values are arrays. Parameter name: " + p.Parameter.ParameterName);
260 }
261
262 if (p.Value.GetLength(0) != iterations)
263 {
264 throw new InvalidOperationException("ExecuteArray requires that array sizes are " +
265 "equal to the number of iterations. Parameter name: " + p.Parameter.ParameterName);
266 }
267 }
268
269 try
270 {
271 // run iterations
272 int rowsAffected = 0;
273 for (int iteration = 0; iteration < iterations; iteration++)
274 {
275 // copy input parameter values
276 foreach (var param in parameters)
277 {
278 SetParameterValue(param.Parameter, param.Value.GetValue(iteration));
279 }
280
281 rowsAffected += command.ExecuteNonQuery();
282
283 // return output parameter values
284 foreach (var param in outParameters)
285 {
286 var outputValue = param.Parameter.Value;
287 param.Value.SetValue(outputValue, iteration);
288 }
289 }
290
291 return rowsAffected;
292 }
293 finally
294 {
295 // restore parameter values
296 foreach (var param in parameters)
297 {
298 param.Parameter.Value = param.Value;
299 }
300 }
301 }
302
303 public virtual string GetSequenceQuery(string sequenceName)
304 {
305 return null;
306 }
307
308 public virtual string NextSequenceQuery(string sequenceName)
309 {
310 return null;
311 }
312
313 public virtual string GetReturningInto(string columnName)
314 {
315 return null;
316 }
317
318 public virtual void SetParameterValue(IDbDataParameter parameter, object value)
319 {
320 if (value is System.Data.Linq.Binary)
321 {
322 var arr = ((System.Data.Linq.Binary)value).ToArray();
323
324 parameter.Value = arr;
325 parameter.DbType = DbType.Binary;
326 parameter.Size = arr.Length;
327 }
328 else
329 parameter.Value = value;
330 }
331
332 public abstract ISqlProvider CreateSqlProvider();
333
334 private ISqlProvider _sqlProvider;
335 protected ISqlProvider SqlProvider
336 {
337 get { return _sqlProvider ?? (_sqlProvider = CreateSqlProvider()); }
338 }
339
340 public virtual IDataReader GetDataReader(MappingSchema schema, IDataReader dataReader)
341 {
342 return dataReader;
343 }
344
345 public virtual IDataReader GetDataReader(IDbCommand command, CommandBehavior commandBehavior)
346 {
347 return command.ExecuteReader(commandBehavior);
348 }
349
350 public virtual bool ParameterNamesEqual(string paramName1, string paramName2)
351 {
352 // default implementation is case-insensitive, because if we make it
353 // case-sensitive and don't overload it in all existing providers - client code may break
354 return string.Equals(paramName1, paramName2, StringComparison.OrdinalIgnoreCase);
355 }
356
357 public virtual DbType GetDbType(Type systemType)
358 {
359 if (systemType == typeof(Binary) || systemType == typeof(byte[]))
360 return DbType.Binary;
361
362 return DbType.Object;
363 }
364
365 public virtual bool IsMarsEnabled(IDbConnection conn)
366 {
367 return false;
368 }
369
370 public virtual string ProviderName { get { return ConnectionType.Namespace; } }
371 public virtual int MaxParameters { get { return 100; } }
372 public virtual int MaxBatchSize { get { return 65536; } }
373 public virtual string EndOfSql { get { return ";"; } }
374
375 #endregion
376
377 #region DataReaderEx
378
379 protected class DataReaderBase<T> : IDataReader
380 where T: IDataReader
381 {
382 public readonly T DataReader;
383
384 protected DataReaderBase(T rd)
385 {
386 DataReader = rd;
387 }
388
389 #region Implementation of IDisposable
390
391 public void Dispose()
392 {
393 DataReader.Dispose();
394 }
395
396 #endregion
397
398 #region Implementation of IDataRecord
399
400 public string GetName (int i) { return DataReader.GetName (i); }
401 public string GetDataTypeName(int i) { return DataReader.GetDataTypeName(i); }
402 public Type GetFieldType (int i) { return DataReader.GetFieldType (i); }
403 // GetValue method is virtual since it can be overridden by some data provider
404 // (For instance, OdbDataProvider uses special methodes for clob data fetching)
405 public virtual object GetValue (int i) { return DataReader.GetValue (i); }
406 public int GetValues (object[] values) { return DataReader.GetValues (values); }
407 public int GetOrdinal (string name) { return DataReader.GetOrdinal (name); }
408 public bool GetBoolean (int i) { return DataReader.GetBoolean (i); }
409 public byte GetByte (int i) { return DataReader.GetByte (i); }
410 public char GetChar (int i) { return DataReader.GetChar (i); }
411 public Guid GetGuid (int i) { return DataReader.GetGuid (i); }
412 public short GetInt16 (int i) { return DataReader.GetInt16 (i); }
413 public int GetInt32 (int i) { return DataReader.GetInt32 (i); }
414 public long GetInt64 (int i) { return DataReader.GetInt64 (i); }
415 public float GetFloat (int i) { return DataReader.GetFloat (i); }
416 public double GetDouble (int i) { return DataReader.GetDouble (i); }
417 public string GetString (int i) { return DataReader.GetString (i); }
418 public decimal GetDecimal (int i) { return DataReader.GetDecimal (i); }
419 public DateTime GetDateTime (int i) { return DataReader.GetDateTime (i); }
420 public IDataReader GetData (int i) { return DataReader.GetData (i); }
421 public bool IsDBNull (int i) { return DataReader.IsDBNull (i); }
422
423 public int FieldCount { get { return DataReader.FieldCount; } }
424
425 object IDataRecord.this[int i] { get { return DataReader[i]; } }
426 object IDataRecord.this[string name] { get { return DataReader[name]; } }
427
428 public long GetBytes(int i, long fieldOffset, byte[] buffer, int bufferoffset, int length)
429 {
430 return DataReader.GetBytes(i, fieldOffset, buffer, bufferoffset, length);
431 }
432
433 public long GetChars(int i, long fieldoffset, char[] buffer, int bufferoffset, int length)
434 {
435 return DataReader.GetChars(i, fieldoffset, buffer, bufferoffset, length);
436 }
437
438 #endregion
439
440 #region Implementation of IDataReader
441
442 public void Close () { DataReader.Close (); }
443 public DataTable GetSchemaTable() { return DataReader.GetSchemaTable(); }
444 public bool NextResult () { return DataReader.NextResult (); }
445 public bool Read () { return DataReader.Read (); }
446 public int Depth { get { return DataReader.Depth; } }
447 public bool IsClosed { get { return DataReader.IsClosed; } }
448 public int RecordsAffected { get { return DataReader.RecordsAffected; } }
449
450 #endregion
451 }
452
453 protected abstract class DataReaderEx<T> : DataReaderBase<T>, IDataReaderEx
454 where T: IDataReader
455 {
456 protected DataReaderEx(T rd) : base(rd)
457 {
458 }
459
460 #region Implementation of IDataReaderEx
461
462 public abstract DateTimeOffset GetDateTimeOffset(int i);
463
464 #endregion
465 }
466
467 #endregion
468
469 #region InsertBatch
470
471 public virtual int InsertBatchWithIdentity<T>(
472 DbManager db,
473 string insertText,
474 IEnumerable<T> collection,
475 MemberMapper[] members,
476 int maxBatchSize,
477 DbManager.ParameterProvider<T> getParameters)
478 {
479 throw new NotImplementedException("Insert batch with identity is not implemented!");
480 }
481
482 public virtual int InsertBatch<T>(
483 DbManager db,
484 string insertText,
485 IEnumerable<T> collection,
486 MemberMapper[] members,
487 int maxBatchSize,
488 DbManager.ParameterProvider<T> getParameters)
489 {
490 db.SetCommand(insertText);
491 return db.ExecuteForEach(collection, members, maxBatchSize, getParameters);
492 }
493
494 #endregion
495
496 protected int ExecuteSqlList(DbManager db, IEnumerable<string> sqlList)
497 {
498 var cnt = 0;
499
500 foreach (string sql in sqlList)
501 {
502 cnt += db.SetCommand(sql).ExecuteNonQuery();
503 }
504
505 return cnt;
506 }
507
508 public virtual DbType GetParameterDbType(DbType dbType)
509 {
510 return dbType;
511 }
512 }
513 }