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

Копия текущей версии из github
author cin
date Thu, 27 Mar 2014 21:46:09 +0400
parents
children 1e85f66cf767
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Source/Data/DataProvider/SqlDataProviderBase.cs	Thu Mar 27 21:46:09 2014 +0400
@@ -0,0 +1,430 @@
+using System;
+using System.Collections;
+using System.Collections.Generic;
+using System.Data;
+using System.Data.Common;
+using System.Data.SqlClient;
+using System.Linq;
+
+using SqlException = System.Data.SqlClient.SqlException;
+using SqlParameter = System.Data.SqlClient.SqlParameter;
+
+namespace BLToolkit.Data.DataProvider
+{
+	using Mapping;
+	using Sql.SqlProvider;
+
+	/// <summary>
+	/// Implements access to the Data Provider for SQL Server.
+	/// </summary>
+	/// <remarks>
+	/// See the <see cref="DbManager.AddDataProvider(DataProviderBase)"/> method to find an example.
+	/// </remarks>
+	/// <seealso cref="DbManager.AddDataProvider(DataProviderBase)">AddDataManager Method</seealso>
+	public abstract class SqlDataProviderBase : DataProviderBase
+	{
+		/// <summary>
+		/// Creates the database connection object.
+		/// </summary>
+		/// <remarks>
+		/// See the <see cref="DbManager.AddDataProvider(DataProviderBase)"/> method to find an example.
+		/// </remarks>
+		/// <seealso cref="DbManager.AddDataProvider(DataProviderBase)">AddDataManager Method</seealso>
+		/// <returns>The database connection object.</returns>
+		public override IDbConnection CreateConnectionObject()
+		{
+			return new SqlConnection();
+		}
+
+		/// <summary>
+		/// Creates the data adapter object.
+		/// </summary>
+		/// <remarks>
+		/// See the <see cref="DbManager.AddDataProvider(DataProviderBase)"/> method to find an example.
+		/// </remarks>
+		/// <seealso cref="DbManager.AddDataProvider(DataProviderBase)">AddDataManager Method</seealso>
+		/// <returns>A data adapter object.</returns>
+		public override DbDataAdapter CreateDataAdapterObject()
+		{
+			return new SqlDataAdapter();
+		}
+
+		/// <summary>
+		/// Populates the specified <see cref="IDbCommand"/> object's Parameters collection with 
+		/// parameter information for the stored procedure specified in the <see cref="IDbCommand"/>.
+		/// </summary>
+		/// <remarks>
+		/// See the <see cref="DbManager.AddDataProvider(DataProviderBase)"/> method to find an example.
+		/// </remarks>
+		/// <seealso cref="DbManager.AddDataProvider(DataProviderBase)">AddDataManager Method</seealso>
+		/// <param name="command">The <see cref="IDbCommand"/> referencing the stored procedure for which the parameter
+		/// information is to be derived. The derived parameters will be populated into the 
+		/// Parameters of this command.</param>
+		public override bool DeriveParameters(IDbCommand command)
+		{
+			SqlCommandBuilder.DeriveParameters((SqlCommand)command);
+			
+#if !MONO
+			foreach (SqlParameter p in command.Parameters)
+			{
+				// We have to clear UDT type names.
+				// Otherwise it will fail with error
+				// "Database name is not allowed with a table-valued parameter"
+				// but this is exactly the way how they are discovered.
+				//
+				if (p.SqlDbType == SqlDbType.Structured)
+				{
+					var firstDot = p.TypeName.IndexOf('.');
+					if (firstDot >= 0)
+						p.TypeName = p.TypeName.Substring(firstDot + 1);
+				}
+			}
+#endif
+
+			return true;
+		}
+
+		public override void PrepareCommand(ref CommandType commandType, ref string commandText, ref IDbDataParameter[] commandParameters)
+		{
+			base.PrepareCommand(ref commandType, ref commandText, ref commandParameters);
+
+			if (commandParameters == null)
+				return;
+
+			foreach (var p in commandParameters)
+			{
+				var val = p.Value;
+
+				if (val == null || !val.GetType().IsArray || val is byte[] || val is char[])
+					continue;
+
+				var dt = new DataTable();
+
+				dt.Columns.Add("column_value", val.GetType().GetElementType());
+
+				dt.BeginLoadData();
+
+				foreach (object o in (Array)val)
+				{
+					var row = dt.NewRow();
+					row[0] = o;
+					dt.Rows.Add(row);
+				}
+
+				dt.EndLoadData();
+
+				p.Value = dt;
+			}
+		}
+
+		public override void SetUserDefinedType(IDbDataParameter parameter, string typeName)
+		{
+#if !MONO
+			if (!(parameter is SqlParameter))
+				throw new ArgumentException("SqlParameter expected.", "parameter");
+
+			((SqlParameter)parameter).TypeName = typeName;
+#else
+			throw new NotSupportedException();
+#endif
+		}
+
+		public override object Convert(object value, ConvertType convertType)
+		{
+			switch (convertType)
+			{
+				case ConvertType.ExceptionToErrorNumber:
+					if (value is SqlException)
+						return ((SqlException)value).Number;
+					break;
+			}
+
+			return SqlProvider.Convert(value, convertType);
+		}
+
+		public override DataExceptionType ConvertErrorNumberToDataExceptionType(int number)
+		{
+			switch (number)
+			{
+				case 1205: return DataExceptionType.Deadlock;
+				case   -2: return DataExceptionType.Timeout;
+				case  547: return DataExceptionType.ForeignKeyViolation;
+				case 2601: return DataExceptionType.UniqueIndexViolation;
+				case 2627: return DataExceptionType.ConstraintViolation;
+			}
+
+			return DataExceptionType.Undefined;
+		}
+
+		/// <summary>
+		/// Returns connection type.
+		/// </summary>
+		/// <remarks>
+		/// See the <see cref="DbManager.AddDataProvider(DataProviderBase)"/> method to find an example.
+		/// </remarks>
+		/// <seealso cref="DbManager.AddDataProvider(DataProviderBase)">AddDataManager Method</seealso>
+		/// <value>An instance of the <see cref="Type"/> class.</value>
+		public override Type ConnectionType
+		{
+			get { return typeof(SqlConnection); }
+		}
+
+		public const string NameString = DataProvider.ProviderName.MsSql;
+
+		/// <summary>
+		/// Returns the data provider name.
+		/// </summary>
+		/// <remarks>
+		/// See the <see cref="DbManager.AddDataProvider(DataProviderBase)"/> method to find an example.
+		/// </remarks>
+		/// <seealso cref="DbManager.AddDataProvider(DataProviderBase)">AddDataProvider Method</seealso>
+		/// <value>Data provider name.</value>
+		public override string Name
+		{
+			get { return NameString; }
+		}
+
+		public override ISqlProvider CreateSqlProvider()
+		{
+			return new MsSql2005SqlProvider();
+		}
+
+		public override int MaxParameters
+		{
+			get { return 2100 - 20; }
+		}
+
+		public override int MaxBatchSize
+		{
+			get { return 65536; }
+		}
+
+		public override bool IsMarsEnabled(IDbConnection conn)
+		{
+			if (conn.ConnectionString != null)
+			{
+				return conn.ConnectionString.Split(';')
+					.Select(s => s.Split('='))
+					.Where (s => s.Length == 2 && s[0].Trim().ToLower() == "multipleactiveresultsets")
+					.Select(s => s[1].Trim().ToLower())
+					.Any   (s => s == "true" || s == "1" || s == "yes");
+			}
+
+			return false;
+		}
+
+		#region GetDataReader
+
+		public override IDataReader GetDataReader(MappingSchema schema, IDataReader dataReader)
+		{
+			return dataReader is SqlDataReader?
+				new SqlDataReaderEx((SqlDataReader)dataReader):
+				base.GetDataReader(schema, dataReader);
+		}
+
+		class SqlDataReaderEx : DataReaderEx<SqlDataReader>
+		{
+			public SqlDataReaderEx(SqlDataReader rd): base(rd)
+			{
+			}
+
+			public override DateTimeOffset GetDateTimeOffset(int i)
+			{
+#if !MONO
+				return DataReader.GetDateTimeOffset(i);
+#else
+				throw new NotSupportedException();
+#endif
+			}
+		}
+
+		#endregion
+
+		public override int InsertBatch<T>(
+			DbManager                      db,
+			string                         insertText,
+			IEnumerable<T>                 collection,
+			MemberMapper[]                 members,
+			int                            maxBatchSize,
+			DbManager.ParameterProvider<T> getParameters)
+		{
+			if (db.Transaction != null)
+				return base.InsertBatch(db, insertText, collection, members, maxBatchSize, getParameters);
+
+			var idx = insertText.IndexOf('\n');
+			var tbl = insertText.Substring(0, idx).Substring("INSERT INTO ".Length).TrimEnd('\r');
+			var rd  = new BulkCopyReader(members, collection);
+			var bc  = new SqlBulkCopy((SqlConnection)db.Connection)
+			{
+				BatchSize            = maxBatchSize,
+				DestinationTableName = tbl,
+			};
+
+			foreach (var memberMapper in members)
+				bc.ColumnMappings.Add(new SqlBulkCopyColumnMapping(memberMapper.Ordinal, memberMapper.Name));
+
+			bc.WriteToServer(rd);
+
+			return rd.Count;
+		}
+
+		class BulkCopyReader : IDataReader
+		{
+			readonly MemberMapper[] _members;
+			readonly IEnumerable    _collection;
+			readonly IEnumerator    _enumerator;
+
+			public int Count;
+
+			public BulkCopyReader(MemberMapper[] members, IEnumerable collection)
+			{
+				_members    = members;
+				_collection = collection;
+				_enumerator = _collection.GetEnumerator();
+			}
+
+			#region Implementation of IDisposable
+
+			public void Dispose()
+			{
+			}
+
+			#endregion
+
+			#region Implementation of IDataRecord
+
+			public string GetName(int i)
+			{
+				return _members[i].Name;
+			}
+
+			public Type GetFieldType(int i)
+			{
+				return _members[i].Type;
+			}
+
+			public object GetValue(int i)
+			{
+				return _members[i].GetValue(_enumerator.Current);
+			}
+
+			public int FieldCount
+			{
+				get { return _members.Length; }
+			}
+
+			public long GetBytes(int i, long fieldOffset, byte[] buffer, int bufferoffset, int length)
+			{
+				throw new NotImplementedException();
+			}
+
+			public long GetChars(int i, long fieldoffset, char[] buffer, int bufferoffset, int length)
+			{
+				throw new NotImplementedException();
+			}
+
+			public string      GetDataTypeName(int i)           { throw new NotImplementedException(); }
+			public int         GetValues      (object[] values) { throw new NotImplementedException(); }
+			public int         GetOrdinal     (string name)     { throw new NotImplementedException(); }
+			public bool        GetBoolean     (int i)           { throw new NotImplementedException(); }
+			public byte        GetByte        (int i)           { throw new NotImplementedException(); }
+			public char        GetChar        (int i)           { throw new NotImplementedException(); }
+			public Guid        GetGuid        (int i)           { throw new NotImplementedException(); }
+			public short       GetInt16       (int i)           { throw new NotImplementedException(); }
+			public int         GetInt32       (int i)           { throw new NotImplementedException(); }
+			public long        GetInt64       (int i)           { throw new NotImplementedException(); }
+			public float       GetFloat       (int i)           { throw new NotImplementedException(); }
+			public double      GetDouble      (int i)           { throw new NotImplementedException(); }
+			public string      GetString      (int i)           { throw new NotImplementedException(); }
+			public decimal     GetDecimal     (int i)           { throw new NotImplementedException(); }
+			public DateTime    GetDateTime    (int i)           { throw new NotImplementedException(); }
+			public IDataReader GetData        (int i)           { throw new NotImplementedException(); }
+			public bool        IsDBNull       (int i)           { throw new NotImplementedException(); }
+
+			object IDataRecord.this[int i]
+			{
+				get { throw new NotImplementedException(); }
+			}
+
+			object IDataRecord.this[string name]
+			{
+				get { throw new NotImplementedException(); }
+			}
+
+			#endregion
+
+			#region Implementation of IDataReader
+
+			public void Close()
+			{
+				throw new NotImplementedException();
+			}
+
+			public DataTable GetSchemaTable()
+			{
+				throw new NotImplementedException();
+			}
+
+			public bool NextResult()
+			{
+				throw new NotImplementedException();
+			}
+
+			public bool Read()
+			{
+				var b = _enumerator.MoveNext();
+
+				if (b)
+					Count++;
+
+				return b;
+			}
+
+			public int Depth
+			{
+				get { throw new NotImplementedException(); }
+			}
+
+			public bool IsClosed
+			{
+				get { throw new NotImplementedException(); }
+			}
+
+			public int RecordsAffected
+			{
+				get { throw new NotImplementedException(); }
+			}
+
+			#endregion
+		}
+
+		public override void SetParameterValue(IDbDataParameter parameter, object value)
+		{
+			if (value is sbyte)
+			{
+				parameter.Value = (byte)(sbyte)value;
+			}
+			else if (value is ushort)
+			{
+				parameter.Value = (short)(ushort)value;
+			}
+			else if (value is uint)
+			{
+				parameter.Value = (int)(uint)value;
+			}
+			else if (value is ulong)
+			{
+				parameter.Value = (long)(ulong)value;
+			}
+			else if (value is string)
+			{
+				parameter.Value = value;
+				if (parameter.DbType == DbType.String && ((string)value).Length == 0) parameter.Size = 1;
+			}
+			else
+			{
+				base.SetParameterValue(parameter, value);
+			}
+		}
+	}
+}