Mercurial > pub > bltoolkit
view Source/Data/DataProvider/DataProviderBase.cs @ 9:1e85f66cf767 default tip
update bltoolkit
author | nickolay |
---|---|
date | Thu, 05 Apr 2018 20:53:26 +0300 |
parents | f990fcb411a9 |
children |
line wrap: on
line source
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; } } }