Mercurial > pub > bltoolkit
diff Source/Data/DataProvider/DataProviderBase.cs @ 0:f990fcb411a9
Копия текущей версии из github
author | cin |
---|---|
date | Thu, 27 Mar 2014 21:46:09 +0400 |
parents | |
children |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Source/Data/DataProvider/DataProviderBase.cs Thu Mar 27 21:46:09 2014 +0400 @@ -0,0 +1,513 @@ +using System; +using System.Collections.Generic; +using System.Data; +using System.Data.Common; +using System.Data.Linq; +using System.Linq; + +namespace BLToolkit.Data.DataProvider +{ + using Common; + using Mapping; + using Sql.SqlProvider; + + /// <summary> + /// The <b>DataProviderBase</b> is a class that provides specific data provider information + /// for the <see cref="DbManager"/> class. + /// </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 partial class DataProviderBase : IMappingSchemaProvider + { + #region Abstract Properties + + /// <summary> + /// Returns an actual type of the connection object used by this instance of the <see cref="DbManager"/>. + /// </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 abstract Type ConnectionType { get; } + + /// <summary> + /// Returns the data manager name. + /// </summary> + /// <remarks> + /// See the <see cref="DbManager.AddDataProvider(DataProviderBase)"/> method to find an example. + /// </remarks> + /// <seealso cref="DbManager.AddDataProvider(DataProviderBase)">AddDataManager Method</seealso> + /// <value>The data manager name.</value> + public abstract string Name { get; } + + private string _uniqueName; + /// <summary> + /// Same as <see cref="Name"/>, but may be overridden to add two or more providers of same type. + /// </summary> + public string UniqueName + { + get { return _uniqueName ?? Name; } + internal set { _uniqueName = value; } + } + + #endregion + + #region Abstract Methods + + /// <summary> + /// Creates a new instance of the <see cref="IDbConnection"/>. + /// </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 <see cref="IDbConnection"/> object.</returns> + public abstract IDbConnection CreateConnectionObject(); + + /// <summary> + /// Creates a new connection object with same connection string. + /// </summary> + /// <param name="connection">A connection object used as prototype.</param> + /// <returns>New connection instance.</returns> + public virtual IDbConnection CloneConnection(IDbConnection connection) + { + if (connection == null) + throw new ArgumentNullException("connection"); + + var cloneable = connection as ICloneable; + + if (cloneable != null) + return (IDbConnection)cloneable.Clone(); + + var newConnection = CreateConnectionObject(); + + // This is definitelly not enought when PersistSecurityInfo set to false. + // + newConnection.ConnectionString = connection.ConnectionString; + + return newConnection; + } + + /// <summary> + /// Creates an instance of the <see cref="DbDataAdapter"/>. + /// </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 <see cref="DbDataAdapter"/> object.</returns> + public abstract DbDataAdapter CreateDataAdapterObject(); + + /// <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> + /// <returns>true - parameters can be derive.</returns> + public abstract bool DeriveParameters(IDbCommand command); + + #endregion + + #region Factory methods + + public virtual IDbCommand CreateCommandObject(IDbConnection connection) + { + return connection.CreateCommand(); + } + + public virtual IDbDataParameter CreateParameterObject(IDbCommand command) + { + return command.CreateParameter(); + } + + #endregion + + #region IDbDataParameter methods + + public virtual IDbDataParameter GetParameter( + IDbCommand command, + NameOrIndexParameter nameOrIndex) + { + return (IDbDataParameter)(nameOrIndex.ByName ? + command.Parameters[nameOrIndex.Name] : command.Parameters[nameOrIndex.Index]); + } + + public virtual void AttachParameter( + IDbCommand command, + IDbDataParameter parameter) + { + command.Parameters.Add(parameter); + } + + public virtual void SetUserDefinedType(IDbDataParameter parameter, string typeName) + { + throw new NotSupportedException(Name + " data provider does not support UDT."); + } + + public virtual bool IsValueParameter(IDbDataParameter parameter) + { + return parameter.Direction != ParameterDirection.ReturnValue; + } + + public virtual IDbDataParameter CloneParameter(IDbDataParameter parameter) + { + return (IDbDataParameter)((ICloneable)parameter).Clone(); + } + + public virtual bool InitParameter(IDbDataParameter parameter) + { + return false; + } + + #endregion + + #region Virtual Members + + /// <summary> + /// Open an <see cref="IDataReader"/> into the given RefCursor object + /// </summary> + /// <param name="refCursor">The refcursor to open an <see cref="IDataReader"/> to</param> + /// <returns>The <see cref="IDataReader"/> into the refcursor</returns> + public virtual IDataReader GetRefCursorDataReader(object refCursor) + { + throw new NotSupportedException("Operation not supported on this DataProvider"); + } + + public virtual object Convert(object value, ConvertType convertType) + { + return SqlProvider.Convert(value, convertType); + } + + public virtual DataExceptionType ConvertErrorNumberToDataExceptionType(int number) + { + return DataExceptionType.Undefined; + } + + public virtual void InitDbManager(DbManager dbManager) + { + var schema = MappingSchema; + + if (schema != null) + dbManager.MappingSchema = schema; + } + + /// <summary> + /// One time initialization from a configuration file. + /// </summary> + /// <param name="attributes">Provider specific attributes.</param> + public virtual void Configure(System.Collections.Specialized.NameValueCollection attributes) + { + } + + public virtual MappingSchema MappingSchema { get; set; } + + public virtual void PrepareCommand(ref CommandType commandType, ref string commandText, ref IDbDataParameter[] commandParameters) + { + /* + if (commandParameters != null) foreach (var p in commandParameters) + { + if (p.Value is System.Data.Linq.Binary) + { + var arr = ((System.Data.Linq.Binary)p.Value).ToArray(); + + p.Value = arr; + p.DbType = DbType.Binary; + p.Size = arr.Length; + } + } + */ + } + + public virtual bool CanReuseCommand(IDbCommand command, CommandType newCommandType) + { + return true; + } + + public virtual int ExecuteArray(IDbCommand command, int iterations) + { + // save parameter values + var parameters = command.Parameters + .OfType<IDbDataParameter>() + .Select(param => new + { + Parameter = param, + Value = param.Value as Array + }) + .ToArray(); + + var outParameters = parameters + .Where(p => + p.Parameter.Direction == ParameterDirection.InputOutput || + p.Parameter.Direction == ParameterDirection.Output) + .ToArray(); + + // validate parameter values + foreach (var p in parameters) + { + if (p.Value == null) + { + throw new InvalidOperationException("ExecuteArray requires that all " + + "parameter values are arrays. Parameter name: " + p.Parameter.ParameterName); + } + + if (p.Value.GetLength(0) != iterations) + { + throw new InvalidOperationException("ExecuteArray requires that array sizes are " + + "equal to the number of iterations. Parameter name: " + p.Parameter.ParameterName); + } + } + + try + { + // run iterations + int rowsAffected = 0; + for (int iteration = 0; iteration < iterations; iteration++) + { + // copy input parameter values + foreach (var param in parameters) + { + SetParameterValue(param.Parameter, param.Value.GetValue(iteration)); + } + + rowsAffected += command.ExecuteNonQuery(); + + // return output parameter values + foreach (var param in outParameters) + { + var outputValue = param.Parameter.Value; + param.Value.SetValue(outputValue, iteration); + } + } + + return rowsAffected; + } + finally + { + // restore parameter values + foreach (var param in parameters) + { + param.Parameter.Value = param.Value; + } + } + } + + public virtual string GetSequenceQuery(string sequenceName) + { + return null; + } + + public virtual string NextSequenceQuery(string sequenceName) + { + return null; + } + + public virtual string GetReturningInto(string columnName) + { + return null; + } + + public virtual void SetParameterValue(IDbDataParameter parameter, object value) + { + if (value is System.Data.Linq.Binary) + { + var arr = ((System.Data.Linq.Binary)value).ToArray(); + + parameter.Value = arr; + parameter.DbType = DbType.Binary; + parameter.Size = arr.Length; + } + else + parameter.Value = value; + } + + public abstract ISqlProvider CreateSqlProvider(); + + private ISqlProvider _sqlProvider; + protected ISqlProvider SqlProvider + { + get { return _sqlProvider ?? (_sqlProvider = CreateSqlProvider()); } + } + + public virtual IDataReader GetDataReader(MappingSchema schema, IDataReader dataReader) + { + return dataReader; + } + + public virtual IDataReader GetDataReader(IDbCommand command, CommandBehavior commandBehavior) + { + return command.ExecuteReader(commandBehavior); + } + + public virtual bool ParameterNamesEqual(string paramName1, string paramName2) + { + // default implementation is case-insensitive, because if we make it + // case-sensitive and don't overload it in all existing providers - client code may break + return string.Equals(paramName1, paramName2, StringComparison.OrdinalIgnoreCase); + } + + public virtual DbType GetDbType(Type systemType) + { + if (systemType == typeof(Binary) || systemType == typeof(byte[])) + return DbType.Binary; + + return DbType.Object; + } + + public virtual bool IsMarsEnabled(IDbConnection conn) + { + return false; + } + + public virtual string ProviderName { get { return ConnectionType.Namespace; } } + public virtual int MaxParameters { get { return 100; } } + public virtual int MaxBatchSize { get { return 65536; } } + public virtual string EndOfSql { get { return ";"; } } + + #endregion + + #region DataReaderEx + + protected class DataReaderBase<T> : IDataReader + where T: IDataReader + { + public readonly T DataReader; + + protected DataReaderBase(T rd) + { + DataReader = rd; + } + + #region Implementation of IDisposable + + public void Dispose() + { + DataReader.Dispose(); + } + + #endregion + + #region Implementation of IDataRecord + + public string GetName (int i) { return DataReader.GetName (i); } + public string GetDataTypeName(int i) { return DataReader.GetDataTypeName(i); } + public Type GetFieldType (int i) { return DataReader.GetFieldType (i); } + // GetValue method is virtual since it can be overridden by some data provider + // (For instance, OdbDataProvider uses special methodes for clob data fetching) + public virtual object GetValue (int i) { return DataReader.GetValue (i); } + public int GetValues (object[] values) { return DataReader.GetValues (values); } + public int GetOrdinal (string name) { return DataReader.GetOrdinal (name); } + public bool GetBoolean (int i) { return DataReader.GetBoolean (i); } + public byte GetByte (int i) { return DataReader.GetByte (i); } + public char GetChar (int i) { return DataReader.GetChar (i); } + public Guid GetGuid (int i) { return DataReader.GetGuid (i); } + public short GetInt16 (int i) { return DataReader.GetInt16 (i); } + public int GetInt32 (int i) { return DataReader.GetInt32 (i); } + public long GetInt64 (int i) { return DataReader.GetInt64 (i); } + public float GetFloat (int i) { return DataReader.GetFloat (i); } + public double GetDouble (int i) { return DataReader.GetDouble (i); } + public string GetString (int i) { return DataReader.GetString (i); } + public decimal GetDecimal (int i) { return DataReader.GetDecimal (i); } + public DateTime GetDateTime (int i) { return DataReader.GetDateTime (i); } + public IDataReader GetData (int i) { return DataReader.GetData (i); } + public bool IsDBNull (int i) { return DataReader.IsDBNull (i); } + + public int FieldCount { get { return DataReader.FieldCount; } } + + object IDataRecord.this[int i] { get { return DataReader[i]; } } + object IDataRecord.this[string name] { get { return DataReader[name]; } } + + public long GetBytes(int i, long fieldOffset, byte[] buffer, int bufferoffset, int length) + { + return DataReader.GetBytes(i, fieldOffset, buffer, bufferoffset, length); + } + + public long GetChars(int i, long fieldoffset, char[] buffer, int bufferoffset, int length) + { + return DataReader.GetChars(i, fieldoffset, buffer, bufferoffset, length); + } + + #endregion + + #region Implementation of IDataReader + + public void Close () { DataReader.Close (); } + public DataTable GetSchemaTable() { return DataReader.GetSchemaTable(); } + public bool NextResult () { return DataReader.NextResult (); } + public bool Read () { return DataReader.Read (); } + public int Depth { get { return DataReader.Depth; } } + public bool IsClosed { get { return DataReader.IsClosed; } } + public int RecordsAffected { get { return DataReader.RecordsAffected; } } + + #endregion + } + + protected abstract class DataReaderEx<T> : DataReaderBase<T>, IDataReaderEx + where T: IDataReader + { + protected DataReaderEx(T rd) : base(rd) + { + } + + #region Implementation of IDataReaderEx + + public abstract DateTimeOffset GetDateTimeOffset(int i); + + #endregion + } + + #endregion + + #region InsertBatch + + public virtual int InsertBatchWithIdentity<T>( + DbManager db, + string insertText, + IEnumerable<T> collection, + MemberMapper[] members, + int maxBatchSize, + DbManager.ParameterProvider<T> getParameters) + { + throw new NotImplementedException("Insert batch with identity is not implemented!"); + } + + public virtual int InsertBatch<T>( + DbManager db, + string insertText, + IEnumerable<T> collection, + MemberMapper[] members, + int maxBatchSize, + DbManager.ParameterProvider<T> getParameters) + { + db.SetCommand(insertText); + return db.ExecuteForEach(collection, members, maxBatchSize, getParameters); + } + + #endregion + + protected int ExecuteSqlList(DbManager db, IEnumerable<string> sqlList) + { + var cnt = 0; + + foreach (string sql in sqlList) + { + cnt += db.SetCommand(sql).ExecuteNonQuery(); + } + + return cnt; + } + + public virtual DbType GetParameterDbType(DbType dbType) + { + return dbType; + } + } +}