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

Копия текущей версии из github
author cin
date Thu, 27 Mar 2014 21:46:09 +0400
parents
children 1e85f66cf767
comparison
equal deleted inserted replaced
-1:000000000000 0:f990fcb411a9
1 using System;
2 using System.Collections;
3 using System.Collections.Generic;
4 using System.Data;
5 using System.Data.Common;
6 using System.Data.SqlClient;
7 using System.Linq;
8
9 using SqlException = System.Data.SqlClient.SqlException;
10 using SqlParameter = System.Data.SqlClient.SqlParameter;
11
12 namespace BLToolkit.Data.DataProvider
13 {
14 using Mapping;
15 using Sql.SqlProvider;
16
17 /// <summary>
18 /// Implements access to the Data Provider for SQL Server.
19 /// </summary>
20 /// <remarks>
21 /// See the <see cref="DbManager.AddDataProvider(DataProviderBase)"/> method to find an example.
22 /// </remarks>
23 /// <seealso cref="DbManager.AddDataProvider(DataProviderBase)">AddDataManager Method</seealso>
24 public abstract class SqlDataProviderBase : DataProviderBase
25 {
26 /// <summary>
27 /// Creates the database connection object.
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 /// <returns>The database connection object.</returns>
34 public override IDbConnection CreateConnectionObject()
35 {
36 return new SqlConnection();
37 }
38
39 /// <summary>
40 /// Creates the data adapter object.
41 /// </summary>
42 /// <remarks>
43 /// See the <see cref="DbManager.AddDataProvider(DataProviderBase)"/> method to find an example.
44 /// </remarks>
45 /// <seealso cref="DbManager.AddDataProvider(DataProviderBase)">AddDataManager Method</seealso>
46 /// <returns>A data adapter object.</returns>
47 public override DbDataAdapter CreateDataAdapterObject()
48 {
49 return new SqlDataAdapter();
50 }
51
52 /// <summary>
53 /// Populates the specified <see cref="IDbCommand"/> object's Parameters collection with
54 /// parameter information for the stored procedure specified in the <see cref="IDbCommand"/>.
55 /// </summary>
56 /// <remarks>
57 /// See the <see cref="DbManager.AddDataProvider(DataProviderBase)"/> method to find an example.
58 /// </remarks>
59 /// <seealso cref="DbManager.AddDataProvider(DataProviderBase)">AddDataManager Method</seealso>
60 /// <param name="command">The <see cref="IDbCommand"/> referencing the stored procedure for which the parameter
61 /// information is to be derived. The derived parameters will be populated into the
62 /// Parameters of this command.</param>
63 public override bool DeriveParameters(IDbCommand command)
64 {
65 SqlCommandBuilder.DeriveParameters((SqlCommand)command);
66
67 #if !MONO
68 foreach (SqlParameter p in command.Parameters)
69 {
70 // We have to clear UDT type names.
71 // Otherwise it will fail with error
72 // "Database name is not allowed with a table-valued parameter"
73 // but this is exactly the way how they are discovered.
74 //
75 if (p.SqlDbType == SqlDbType.Structured)
76 {
77 var firstDot = p.TypeName.IndexOf('.');
78 if (firstDot >= 0)
79 p.TypeName = p.TypeName.Substring(firstDot + 1);
80 }
81 }
82 #endif
83
84 return true;
85 }
86
87 public override void PrepareCommand(ref CommandType commandType, ref string commandText, ref IDbDataParameter[] commandParameters)
88 {
89 base.PrepareCommand(ref commandType, ref commandText, ref commandParameters);
90
91 if (commandParameters == null)
92 return;
93
94 foreach (var p in commandParameters)
95 {
96 var val = p.Value;
97
98 if (val == null || !val.GetType().IsArray || val is byte[] || val is char[])
99 continue;
100
101 var dt = new DataTable();
102
103 dt.Columns.Add("column_value", val.GetType().GetElementType());
104
105 dt.BeginLoadData();
106
107 foreach (object o in (Array)val)
108 {
109 var row = dt.NewRow();
110 row[0] = o;
111 dt.Rows.Add(row);
112 }
113
114 dt.EndLoadData();
115
116 p.Value = dt;
117 }
118 }
119
120 public override void SetUserDefinedType(IDbDataParameter parameter, string typeName)
121 {
122 #if !MONO
123 if (!(parameter is SqlParameter))
124 throw new ArgumentException("SqlParameter expected.", "parameter");
125
126 ((SqlParameter)parameter).TypeName = typeName;
127 #else
128 throw new NotSupportedException();
129 #endif
130 }
131
132 public override object Convert(object value, ConvertType convertType)
133 {
134 switch (convertType)
135 {
136 case ConvertType.ExceptionToErrorNumber:
137 if (value is SqlException)
138 return ((SqlException)value).Number;
139 break;
140 }
141
142 return SqlProvider.Convert(value, convertType);
143 }
144
145 public override DataExceptionType ConvertErrorNumberToDataExceptionType(int number)
146 {
147 switch (number)
148 {
149 case 1205: return DataExceptionType.Deadlock;
150 case -2: return DataExceptionType.Timeout;
151 case 547: return DataExceptionType.ForeignKeyViolation;
152 case 2601: return DataExceptionType.UniqueIndexViolation;
153 case 2627: return DataExceptionType.ConstraintViolation;
154 }
155
156 return DataExceptionType.Undefined;
157 }
158
159 /// <summary>
160 /// Returns connection type.
161 /// </summary>
162 /// <remarks>
163 /// See the <see cref="DbManager.AddDataProvider(DataProviderBase)"/> method to find an example.
164 /// </remarks>
165 /// <seealso cref="DbManager.AddDataProvider(DataProviderBase)">AddDataManager Method</seealso>
166 /// <value>An instance of the <see cref="Type"/> class.</value>
167 public override Type ConnectionType
168 {
169 get { return typeof(SqlConnection); }
170 }
171
172 public const string NameString = DataProvider.ProviderName.MsSql;
173
174 /// <summary>
175 /// Returns the data provider name.
176 /// </summary>
177 /// <remarks>
178 /// See the <see cref="DbManager.AddDataProvider(DataProviderBase)"/> method to find an example.
179 /// </remarks>
180 /// <seealso cref="DbManager.AddDataProvider(DataProviderBase)">AddDataProvider Method</seealso>
181 /// <value>Data provider name.</value>
182 public override string Name
183 {
184 get { return NameString; }
185 }
186
187 public override ISqlProvider CreateSqlProvider()
188 {
189 return new MsSql2005SqlProvider();
190 }
191
192 public override int MaxParameters
193 {
194 get { return 2100 - 20; }
195 }
196
197 public override int MaxBatchSize
198 {
199 get { return 65536; }
200 }
201
202 public override bool IsMarsEnabled(IDbConnection conn)
203 {
204 if (conn.ConnectionString != null)
205 {
206 return conn.ConnectionString.Split(';')
207 .Select(s => s.Split('='))
208 .Where (s => s.Length == 2 && s[0].Trim().ToLower() == "multipleactiveresultsets")
209 .Select(s => s[1].Trim().ToLower())
210 .Any (s => s == "true" || s == "1" || s == "yes");
211 }
212
213 return false;
214 }
215
216 #region GetDataReader
217
218 public override IDataReader GetDataReader(MappingSchema schema, IDataReader dataReader)
219 {
220 return dataReader is SqlDataReader?
221 new SqlDataReaderEx((SqlDataReader)dataReader):
222 base.GetDataReader(schema, dataReader);
223 }
224
225 class SqlDataReaderEx : DataReaderEx<SqlDataReader>
226 {
227 public SqlDataReaderEx(SqlDataReader rd): base(rd)
228 {
229 }
230
231 public override DateTimeOffset GetDateTimeOffset(int i)
232 {
233 #if !MONO
234 return DataReader.GetDateTimeOffset(i);
235 #else
236 throw new NotSupportedException();
237 #endif
238 }
239 }
240
241 #endregion
242
243 public override int InsertBatch<T>(
244 DbManager db,
245 string insertText,
246 IEnumerable<T> collection,
247 MemberMapper[] members,
248 int maxBatchSize,
249 DbManager.ParameterProvider<T> getParameters)
250 {
251 if (db.Transaction != null)
252 return base.InsertBatch(db, insertText, collection, members, maxBatchSize, getParameters);
253
254 var idx = insertText.IndexOf('\n');
255 var tbl = insertText.Substring(0, idx).Substring("INSERT INTO ".Length).TrimEnd('\r');
256 var rd = new BulkCopyReader(members, collection);
257 var bc = new SqlBulkCopy((SqlConnection)db.Connection)
258 {
259 BatchSize = maxBatchSize,
260 DestinationTableName = tbl,
261 };
262
263 foreach (var memberMapper in members)
264 bc.ColumnMappings.Add(new SqlBulkCopyColumnMapping(memberMapper.Ordinal, memberMapper.Name));
265
266 bc.WriteToServer(rd);
267
268 return rd.Count;
269 }
270
271 class BulkCopyReader : IDataReader
272 {
273 readonly MemberMapper[] _members;
274 readonly IEnumerable _collection;
275 readonly IEnumerator _enumerator;
276
277 public int Count;
278
279 public BulkCopyReader(MemberMapper[] members, IEnumerable collection)
280 {
281 _members = members;
282 _collection = collection;
283 _enumerator = _collection.GetEnumerator();
284 }
285
286 #region Implementation of IDisposable
287
288 public void Dispose()
289 {
290 }
291
292 #endregion
293
294 #region Implementation of IDataRecord
295
296 public string GetName(int i)
297 {
298 return _members[i].Name;
299 }
300
301 public Type GetFieldType(int i)
302 {
303 return _members[i].Type;
304 }
305
306 public object GetValue(int i)
307 {
308 return _members[i].GetValue(_enumerator.Current);
309 }
310
311 public int FieldCount
312 {
313 get { return _members.Length; }
314 }
315
316 public long GetBytes(int i, long fieldOffset, byte[] buffer, int bufferoffset, int length)
317 {
318 throw new NotImplementedException();
319 }
320
321 public long GetChars(int i, long fieldoffset, char[] buffer, int bufferoffset, int length)
322 {
323 throw new NotImplementedException();
324 }
325
326 public string GetDataTypeName(int i) { throw new NotImplementedException(); }
327 public int GetValues (object[] values) { throw new NotImplementedException(); }
328 public int GetOrdinal (string name) { throw new NotImplementedException(); }
329 public bool GetBoolean (int i) { throw new NotImplementedException(); }
330 public byte GetByte (int i) { throw new NotImplementedException(); }
331 public char GetChar (int i) { throw new NotImplementedException(); }
332 public Guid GetGuid (int i) { throw new NotImplementedException(); }
333 public short GetInt16 (int i) { throw new NotImplementedException(); }
334 public int GetInt32 (int i) { throw new NotImplementedException(); }
335 public long GetInt64 (int i) { throw new NotImplementedException(); }
336 public float GetFloat (int i) { throw new NotImplementedException(); }
337 public double GetDouble (int i) { throw new NotImplementedException(); }
338 public string GetString (int i) { throw new NotImplementedException(); }
339 public decimal GetDecimal (int i) { throw new NotImplementedException(); }
340 public DateTime GetDateTime (int i) { throw new NotImplementedException(); }
341 public IDataReader GetData (int i) { throw new NotImplementedException(); }
342 public bool IsDBNull (int i) { throw new NotImplementedException(); }
343
344 object IDataRecord.this[int i]
345 {
346 get { throw new NotImplementedException(); }
347 }
348
349 object IDataRecord.this[string name]
350 {
351 get { throw new NotImplementedException(); }
352 }
353
354 #endregion
355
356 #region Implementation of IDataReader
357
358 public void Close()
359 {
360 throw new NotImplementedException();
361 }
362
363 public DataTable GetSchemaTable()
364 {
365 throw new NotImplementedException();
366 }
367
368 public bool NextResult()
369 {
370 throw new NotImplementedException();
371 }
372
373 public bool Read()
374 {
375 var b = _enumerator.MoveNext();
376
377 if (b)
378 Count++;
379
380 return b;
381 }
382
383 public int Depth
384 {
385 get { throw new NotImplementedException(); }
386 }
387
388 public bool IsClosed
389 {
390 get { throw new NotImplementedException(); }
391 }
392
393 public int RecordsAffected
394 {
395 get { throw new NotImplementedException(); }
396 }
397
398 #endregion
399 }
400
401 public override void SetParameterValue(IDbDataParameter parameter, object value)
402 {
403 if (value is sbyte)
404 {
405 parameter.Value = (byte)(sbyte)value;
406 }
407 else if (value is ushort)
408 {
409 parameter.Value = (short)(ushort)value;
410 }
411 else if (value is uint)
412 {
413 parameter.Value = (int)(uint)value;
414 }
415 else if (value is ulong)
416 {
417 parameter.Value = (long)(ulong)value;
418 }
419 else if (value is string)
420 {
421 parameter.Value = value;
422 if (parameter.DbType == DbType.String && ((string)value).Length == 0) parameter.Size = 1;
423 }
424 else
425 {
426 base.SetParameterValue(parameter, value);
427 }
428 }
429 }
430 }