diff Source/DataAccess/DataAccessor.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/DataAccess/DataAccessor.cs	Thu Mar 27 21:46:09 2014 +0400
@@ -0,0 +1,711 @@
+using System;
+using System.Collections;
+using System.Collections.Generic;
+using System.Data;
+using System.Data.SqlTypes;
+using System.Diagnostics;
+using System.IO;
+using System.Reflection;
+using System.Xml;
+#if !SILVERLIGHT
+using System.Xml.Linq;
+#endif
+
+namespace BLToolkit.DataAccess
+{
+	using Aspects;
+	using Common;
+	using Data;
+	using Data.DataProvider;
+	using Mapping;
+	using Patterns;
+	using Properties;
+	using Reflection;
+	using TypeBuilder;
+
+	[DataAccessor, DebuggerStepThrough]
+	public abstract class DataAccessor : DataAccessorBase
+	{
+		#region Constructors
+
+		protected DataAccessor()
+		{
+		}
+
+		protected DataAccessor(DbManager dbManager)
+			: base(dbManager)
+		{
+		}
+
+		protected DataAccessor(DbManager dbManager, bool dispose)
+			: base(dbManager, dispose)
+		{
+		}
+
+		#endregion
+
+		#region CreateInstance
+
+		public static DataAccessor CreateInstance(Type type)
+		{
+			return (DataAccessor)Activator.CreateInstance(TypeFactory.GetType(type));
+		}
+
+		public static DataAccessor CreateInstance(Type type, InitContext context)
+		{
+			return (DataAccessor)Activator.CreateInstance(TypeFactory.GetType(type), context);
+		}
+
+		public static DataAccessor CreateInstance(Type type, DbManager dbManager)
+		{
+			return CreateInstance(type, dbManager, false);
+		}
+
+		public static DataAccessor CreateInstance(
+			Type type,
+			InitContext context,
+			DbManager dbManager)
+		{
+			return CreateInstance(type, context, dbManager, false);
+		}
+
+		public static DataAccessor CreateInstance(Type type, DbManager dbManager, bool dispose)
+		{
+			var da = CreateInstance(type);
+
+			da.SetDbManager(dbManager, dispose);
+
+			return da;
+		}
+
+		public static DataAccessor CreateInstance(
+			Type type,
+			InitContext context,
+			DbManager dbManager,
+			bool dispose)
+		{
+			var da = CreateInstance(type, context);
+
+			da.SetDbManager(dbManager, dispose);
+
+			return da;
+		}
+
+		public static T CreateInstance<T>() where T : DataAccessor
+		{
+			return TypeFactory.CreateInstance<T>();
+		}
+
+		public static T CreateInstance<T>(DbManager dbManager)
+			where T : DataAccessor
+		{
+			return CreateInstance<T>(dbManager, false);
+		}
+
+		public static T CreateInstance<T>(DbManager dbManager, bool dispose)
+			where T : DataAccessor
+		{
+			var da = TypeFactory.CreateInstance<T>();
+
+			da.SetDbManager(dbManager, dispose);
+
+			return da;
+		}
+
+		#endregion
+
+		#region Protected Members
+
+		#region Parameters
+
+		[NoInterception]
+		protected virtual string GetQueryParameterName(DbManager db, string paramName)
+		{
+			return (string)db.DataProvider.Convert(paramName, ConvertType.NameToQueryParameter);
+		}
+
+		[NoInterception]
+		protected virtual string GetSpParameterName(DbManager db, string paramName)
+		{
+			return (string)db.DataProvider.Convert(paramName, db.GetConvertTypeToParameter());
+		}
+
+		[NoInterception]
+		protected virtual IDbDataParameter[] PrepareParameters(DbManager db, object[] parameters)
+		{
+			return db.PrepareParameters(parameters);
+		}
+
+		[NoInterception]
+		protected virtual IDbDataParameter GetParameter(DbManager db, string paramName)
+		{
+			var p = db.Parameter(paramName);
+
+			if (p == null)
+			{
+				// This usually means that the parameter name is incorrect.
+				//
+				throw new DataAccessException(string.Format(
+					Resources.DataAccessot_ParameterNotFound, paramName));
+			}
+
+			// Input parameter mapping make no sence.
+			//
+			Debug.WriteLineIf(p.Direction == ParameterDirection.Input,
+				string.Format("'{0}.{1}' is an input parameter.",
+					db.Command.CommandText, paramName));
+
+			return p;
+		}
+
+		[NoInterception]
+		protected virtual IDbDataParameter[] CreateParameters(
+			DbManager                 db,
+			object                    obj,
+			string[]                  outputParameters,
+			string[]                  inputOutputParameters,
+			string[]                  ignoreParameters,
+			params IDbDataParameter[] commandParameters)
+		{
+			return db.CreateParameters(obj, outputParameters,
+				inputOutputParameters, ignoreParameters, commandParameters);
+		}
+
+		[NoInterception]
+		protected virtual IDbDataParameter[] CreateParameters(
+			DbManager                 db,
+			DataRow                   dataRow,
+			string[]                  outputParameters,
+			string[]                  inputOutputParameters,
+			string[]                  ignoreParameters,
+			params IDbDataParameter[] commandParameters)
+		{
+			return db.CreateParameters(dataRow, outputParameters,
+				inputOutputParameters, ignoreParameters, commandParameters);
+		}
+
+		[NoInterception]
+		protected virtual string PrepareSqlQuery(DbManager db, int queryID, int uniqueID, string sqlQuery)
+		{
+			return sqlQuery;
+		}
+
+		#endregion
+
+		#region ExecuteDictionary
+
+		protected void ExecuteDictionary(
+			DbManager             db,
+			IDictionary           dictionary,
+			Type                  objectType,
+			Type                  keyType,
+			string                methodName)
+		{
+			var isIndex = TypeHelper.IsSameOrParent(typeof(CompoundValue), keyType);
+			var mms     = new SqlQuery(Extensions).GetKeyFieldList(db, objectType);
+
+			if (mms.Length == 0)
+				throw new DataAccessException(string.Format(
+					Resources.DataAccessor_UnknownIndex,
+					GetType().Name, methodName));
+
+			if (mms.Length > 1 && keyType != typeof(object) && !isIndex)
+				throw new DataAccessException(string.Format(
+					Resources.DataAccessor_InvalidKeyType,
+					GetType().Name, methodName));
+
+			if (isIndex || mms.Length > 1)
+			{
+				var fields = new string[mms.Length];
+
+				for (var i = 0; i < mms.Length; i++)
+					fields[i] = mms[i].MemberName;
+
+				db.ExecuteDictionary(dictionary, new MapIndex(fields), objectType, null);
+			}
+			else
+			{
+				db.ExecuteDictionary(dictionary, mms[0].MemberName, objectType, null);
+			}
+		}
+
+		protected void ExecuteDictionary<TValue>(
+			DbManager                          db,
+			IDictionary<CompoundValue, TValue> dictionary,
+			Type                               objectType,
+			string                             methodName)
+		{
+			var mms = new SqlQuery(Extensions).GetKeyFieldList(db, objectType);
+
+			if (mms.Length == 0)
+				throw new DataAccessException(string.Format(
+					Resources.DataAccessor_UnknownIndex,
+					GetType().Name, methodName));
+
+			var fields = new string[mms.Length];
+
+			for (var i = 0; i < mms.Length; i++)
+				fields[i] = mms[i].MemberName;
+
+			db.ExecuteDictionary(dictionary, new MapIndex(fields), objectType, null);
+		}
+
+		protected void ExecuteDictionary<TKey, TValue>(
+			DbManager                 db,
+			IDictionary<TKey, TValue> dictionary,
+			Type                      objectType,
+			string                    methodName)
+		{
+			var mms = new SqlQuery(Extensions).GetKeyFieldList(db, objectType);
+
+			if (mms.Length == 0)
+				throw new DataAccessException(string.Format(
+					Resources.DataAccessor_UnknownIndex,
+					GetType().Name, methodName));
+
+			if (mms.Length != 1)
+				throw new DataAccessException(string.Format(
+					Resources.DataAccessor_IndexIsComplex,
+					GetType().Name, methodName));
+
+			db.ExecuteDictionary(dictionary, mms[0].MemberName, objectType, null);
+		}
+
+		protected void ExecuteScalarDictionary(
+			DbManager             db,
+			IDictionary           dictionary,
+			Type                  objectType,
+			Type                  keyType,
+			string                methodName,
+			NameOrIndexParameter  scalarField,
+			Type                  elementType)
+		{
+			var isIndex = TypeHelper.IsSameOrParent(typeof(CompoundValue), keyType);
+			var mms     = new SqlQuery(Extensions).GetKeyFieldList(db, objectType);
+
+			if (mms.Length == 0)
+				throw new DataAccessException(string.Format(
+					Resources.DataAccessor_UnknownIndex,
+					GetType().Name, methodName));
+
+			if (mms.Length > 1 && keyType != typeof(object) && !isIndex)
+				throw new DataAccessException(string.Format(
+					Resources.DataAccessor_InvalidKeyType,
+					GetType().Name, methodName));
+
+			if (isIndex || mms.Length > 1)
+			{
+				var fields = new string[mms.Length];
+
+				for (var i = 0; i < mms.Length; i++)
+					fields[i] = mms[i].Name;
+
+				db.ExecuteScalarDictionary(dictionary, new MapIndex(fields), scalarField, elementType);
+			}
+			else
+			{
+				db.ExecuteScalarDictionary(
+					dictionary,
+					mms[0].Name,
+					keyType,
+					scalarField,
+					elementType);
+			}
+		}
+
+		#endregion
+
+		#region ExecuteEnumerable
+
+		protected IEnumerable<T> ExecuteEnumerable<T>(DbManager db, Type objectType, bool disposeDbManager)
+		{
+			try
+			{
+				using (var rd = db.ExecuteReader())
+				{
+					if (rd.Read())
+					{
+						var dest   = MappingSchema.GetObjectMapper(objectType);
+						var source = MappingSchema.CreateDataReaderMapper(rd);
+
+						var ctx = new InitContext
+						{
+							MappingSchema = MappingSchema,
+							ObjectMapper  = dest,
+							DataSource    = source,
+							SourceObject  = rd
+						};
+
+						var index   = MappingSchema.GetIndex(source, dest);
+						var mappers = ctx.MappingSchema.GetValueMappers(source, dest, index);
+
+						do
+						{
+							var destObject = (T)dest.CreateInstance(ctx);
+
+							if (ctx.StopMapping)
+								yield return destObject;
+
+							var smDest = destObject as ISupportMapping;
+
+							if (smDest != null)
+							{
+								smDest.BeginMapping(ctx);
+
+								if (ctx.StopMapping)
+									yield return destObject;
+							}
+
+							MappingSchema.MapInternal(source, rd, dest, destObject, index, mappers);
+
+							if (smDest != null)
+								smDest.EndMapping(ctx);
+
+							yield return destObject;
+						} while (rd.Read());
+					}
+				}
+			}
+			finally
+			{
+				if (disposeDbManager)
+					db.Dispose();
+			}
+		}
+
+		protected IEnumerable ExecuteEnumerable(DbManager db, Type objectType, bool disposeDbManager)
+		{
+			var ms = db.MappingSchema;
+
+			if (disposeDbManager)
+			{
+				using (db)
+				using (var rd = db.ExecuteReader())
+					while (rd.Read())
+						yield return ms.MapDataReaderToObject(rd, objectType);
+			}
+			else
+			{
+				using (var rd = db.ExecuteReader())
+					while (rd.Read())
+						yield return ms.MapDataReaderToObject(rd, objectType);
+			}
+		}
+
+		#endregion
+
+		#region Convert
+
+		#region Primitive Types
+
+		[CLSCompliant(false)]
+		[NoInterception]
+		protected virtual SByte ConvertToSByte(DbManager db, object value, object parameter)
+		{
+			return db.MappingSchema.ConvertToSByte(value);
+		}
+
+		[NoInterception]
+		protected virtual Int16 ConvertToInt16(DbManager db, object value, object parameter)
+		{
+			return db.MappingSchema.ConvertToInt16(value);
+		}
+
+		[NoInterception]
+		protected virtual Int32 ConvertToInt32(DbManager db, object value, object parameter)
+		{
+			return db.MappingSchema.ConvertToInt32(value);
+		}
+
+		[NoInterception]
+		protected virtual Int64 ConvertToInt64(DbManager db, object value, object parameter)
+		{
+			return db.MappingSchema.ConvertToInt64(value);
+		}
+
+		[NoInterception]
+		protected virtual Byte ConvertToByte(DbManager db, object value, object parameter)
+		{
+			return db.MappingSchema.ConvertToByte(value);
+		}
+
+		[CLSCompliant(false)]
+		[NoInterception]
+		protected virtual UInt16 ConvertToUInt16(DbManager db, object value, object parameter)
+		{
+			return db.MappingSchema.ConvertToUInt16(value);
+		}
+
+		[CLSCompliant(false)]
+		[NoInterception]
+		protected virtual UInt32 ConvertToUInt32(DbManager db, object value, object parameter)
+		{
+			return db.MappingSchema.ConvertToUInt32(value);
+		}
+
+		[CLSCompliant(false)]
+		[NoInterception]
+		protected virtual UInt64 ConvertToUInt64(DbManager db, object value, object parameter)
+		{
+			return db.MappingSchema.ConvertToUInt64(value);
+		}
+
+		[NoInterception]
+		protected virtual Char ConvertToChar(DbManager db, object value, object parameter)
+		{
+			return db.MappingSchema.ConvertToChar(value);
+		}
+
+		[NoInterception]
+		protected virtual Single ConvertToSingle(DbManager db, object value, object parameter)
+		{
+			return db.MappingSchema.ConvertToSingle(value);
+		}
+
+		[NoInterception]
+		protected virtual Double ConvertToDouble(DbManager db, object value, object parameter)
+		{
+			return db.MappingSchema.ConvertToDouble(value);
+		}
+
+		[NoInterception]
+		protected virtual Boolean ConvertToBoolean(DbManager db, object value, object parameter)
+		{
+			return db.MappingSchema.ConvertToBoolean(value);
+		}
+
+		#endregion
+
+		#region Simple Types
+
+		[NoInterception]
+		protected virtual String ConvertToString(DbManager db, object value, object parameter)
+		{
+			return db.MappingSchema.ConvertToString(value);
+		}
+
+		[NoInterception]
+		protected virtual DateTime ConvertToDateTime(DbManager db, object value, object parameter)
+		{
+			return db.MappingSchema.ConvertToDateTime(value);
+		}
+
+		[NoInterception]
+		protected virtual DateTimeOffset ConvertToDateTimeOffset(DbManager db, object value, object parameter)
+		{
+			return db.MappingSchema.ConvertToDateTimeOffset(value);
+		}
+
+		[NoInterception]
+		protected virtual System.Data.Linq.Binary ConvertToLinqBinary(DbManager db, object value, object parameter)
+		{
+			return db.MappingSchema.ConvertToLinqBinary(value);
+		}
+
+		[NoInterception]
+		protected virtual Decimal ConvertToDecimal(DbManager db, object value, object parameter)
+		{
+			return db.MappingSchema.ConvertToDecimal(value);
+		}
+
+		[NoInterception]
+		protected virtual Guid ConvertToGuid(DbManager db, object value, object parameter)
+		{
+			return db.MappingSchema.ConvertToGuid(value);
+		}
+
+		[NoInterception]
+		protected virtual Stream ConvertToStream(DbManager db, object value, object parameter)
+		{
+			return db.MappingSchema.ConvertToStream(value);
+		}
+
+		[NoInterception]
+		protected virtual XmlReader ConvertToXmlReader(DbManager db, object value, object parameter)
+		{
+			return db.MappingSchema.ConvertToXmlReader(value);
+		}
+
+		[NoInterception]
+		protected virtual XmlDocument ConvertToXmlDocument(DbManager db, object value, object parameter)
+		{
+			return db.MappingSchema.ConvertToXmlDocument(value);
+		}
+
+#if !SILVERLIGHT
+		[NoInterception]
+        protected virtual XElement ConvertToXElement(DbManager db, object value, object parameter)
+        {
+            return db.MappingSchema.ConvertToXElement(value);
+        }
+#endif
+
+        [NoInterception]
+		protected virtual Byte[] ConvertToByteArray(DbManager db, object value, object parameter)
+		{
+			return db.MappingSchema.ConvertToByteArray(value);
+		}
+
+		[NoInterception]
+		protected virtual Char[] ConvertToCharArray(DbManager db, object value, object parameter)
+		{
+			return db.MappingSchema.ConvertToCharArray(value);
+		}
+
+		#endregion
+
+		#region SqlTypes
+
+		[NoInterception]
+		protected virtual SqlByte ConvertToSqlByte(DbManager db, object value, object parameter)
+		{
+			return db.MappingSchema.ConvertToSqlByte(value);
+		}
+
+		[NoInterception]
+		protected virtual SqlInt16 ConvertToSqlInt16(DbManager db, object value, object parameter)
+		{
+			return db.MappingSchema.ConvertToSqlInt16(value);
+		}
+
+		[NoInterception]
+		protected virtual SqlInt32 ConvertToSqlInt32(DbManager db, object value, object parameter)
+		{
+			return db.MappingSchema.ConvertToSqlInt32(value);
+		}
+
+		[NoInterception]
+		protected virtual SqlInt64 ConvertToSqlInt64(DbManager db, object value, object parameter)
+		{
+			return db.MappingSchema.ConvertToSqlInt64(value);
+		}
+
+		[NoInterception]
+		protected virtual SqlSingle ConvertToSqlSingle(DbManager db, object value, object parameter)
+		{
+			return db.MappingSchema.ConvertToSqlSingle(value);
+		}
+
+		[NoInterception]
+		protected virtual SqlBoolean ConvertToSqlBoolean(DbManager db, object value, object parameter)
+		{
+			return db.MappingSchema.ConvertToSqlBoolean(value);
+		}
+
+		[NoInterception]
+		protected virtual SqlDouble ConvertToSqlDouble(DbManager db, object value, object parameter)
+		{
+			return db.MappingSchema.ConvertToSqlDouble(value);
+		}
+
+		[NoInterception]
+		protected virtual SqlDateTime ConvertToSqlDateTime(DbManager db, object value, object parameter)
+		{
+			return db.MappingSchema.ConvertToSqlDateTime(value);
+		}
+
+		[NoInterception]
+		protected virtual SqlDecimal ConvertToSqlDecimal(DbManager db, object value, object parameter)
+		{
+			return db.MappingSchema.ConvertToSqlDecimal(value);
+		}
+
+		[NoInterception]
+		protected virtual SqlMoney ConvertToSqlMoney(DbManager db, object value, object parameter)
+		{
+			return db.MappingSchema.ConvertToSqlMoney(value);
+		}
+
+		[NoInterception]
+		protected virtual SqlGuid ConvertToSqlGuid(DbManager db, object value, object parameter)
+		{
+			return db.MappingSchema.ConvertToSqlGuid(value);
+		}
+
+		[NoInterception]
+		protected virtual SqlString ConvertToSqlString(DbManager db, object value, object parameter)
+		{
+			return db.MappingSchema.ConvertToSqlString(value);
+		}
+
+		#endregion
+
+		#region General case
+
+		[NoInterception]
+		protected virtual object ConvertChangeType(
+			DbManager db,
+			object    value,
+			Type      conversionType,
+			object    parameter)
+		{
+			return db.MappingSchema.ConvertChangeType(value, conversionType);
+		}
+
+		#endregion
+		
+		#endregion
+
+		#region IsNull
+
+		/// <summary>
+		/// Reserved for internal BLToolkit use.
+		/// </summary>
+		public interface INullableInternal
+		{
+			bool IsNull { [MustImplement(false, false)] get; }
+		}
+
+		[NoInterception]
+		protected virtual bool IsNull(
+			DbManager db,
+			object    value,
+			object    parameter)
+		{
+			// Speed up for scalar and nullable types.
+			//
+			switch (System.Convert.GetTypeCode(value))
+			{
+				// null, DBNull.Value, Nullable<T> without a value.
+				//
+				case TypeCode.Empty:
+				case TypeCode.DBNull:
+					return true;
+
+				case TypeCode.Object:
+					break;
+
+				// int, byte, string, DateTime and other primitives except Guid.
+				// Also Nullable<T> with a value.
+				//
+				default:
+					return false;
+			}
+
+			// Speed up for SqlTypes.
+			//
+			var nullable = value as INullable;
+			if (nullable != null)
+				return nullable.IsNull;
+
+			// All other types which have 'IsNull' property but does not implement 'INullable' interface.
+			// For example: 'Oracle.DataAccess.Types.OracleDecimal'.
+			//
+			// For types without 'IsNull' property the return value is always false.
+			//
+			var nullableInternal = (INullableInternal)DuckTyping.Implement(typeof(INullableInternal), value);
+
+			return nullableInternal.IsNull;
+		}
+
+		#endregion
+
+		protected virtual SqlQueryAttribute GetSqlQueryAttribute(MethodInfo methodInfo)
+		{
+			var attrs = methodInfo.GetCustomAttributes(typeof(SqlQueryAttribute), true);
+			return (SqlQueryAttribute)attrs[0];
+		}
+
+		#endregion
+	}
+}