/// <summary> /// Tells Insight the custom serializer to use when serializing all instances of type T. /// </summary> /// <typeparam name="T">The type that is being serialized.</typeparam> /// <param name="serializer">The serializer to use.</param> public static void Serialize <T>(IDbObjectSerializer serializer) { AddRule(new DbSerializationRule() { FieldType = typeof(T), Mode = SerializationMode.Custom, Serializer = serializer }); }
/// <summary> /// Tells Insight the SerializationMode to use when serializing the given member of type T. /// </summary> /// <typeparam name="T">The type containing the object to be serialized.</typeparam> /// <param name="fieldName">The name of the field.</param> /// <param name="serializer">The serializer to use.</param> public static void Serialize <T>(string fieldName, IDbObjectSerializer serializer) { AddRule(new DbSerializationRule() { RecordType = typeof(T), FieldName = fieldName, Mode = SerializationMode.Custom, Serializer = serializer }); }
/// <summary> /// Initializes a new instance of the FieldMapping class. /// </summary> /// <param name="pathToMember">The path to the member.</param> /// <param name="member">The member that is bound.</param> /// <param name="serializer">The serializer for the mapping.</param> public FieldMapping(string pathToMember, ClassPropInfo member, IDbObjectSerializer serializer) { PathToMember = pathToMember; Member = member; Serializer = serializer; Prefix = ClassPropInfo.GetMemberPrefix(pathToMember); IsDeep = (Prefix != null); }
/// <summary> /// Look up a DbType from a .Net type. /// </summary> /// <param name="type">The type of object to look up.</param> /// <param name="serializer">The serializer that has been detected for the field.</param> /// <param name="parameterType">The expected sql parameter type. Used as the default.</param> /// <returns>The equivalent DbType.</returns> private static DbType LookupDbType(Type type, IDbObjectSerializer serializer, DbType parameterType) { DbType sqlType; // if the serializer can serialize it, then it's a string if (serializer != null && serializer.CanSerialize(type, parameterType)) { return(serializer.GetSerializedDbType(type, parameterType)); } // if the type is nullable, get the underlying type var nullUnderlyingType = Nullable.GetUnderlyingType(type); if (nullUnderlyingType != null) { type = nullUnderlyingType; } // if it's an enum, get the underlying type if (type.GetTypeInfo().IsEnum) { type = Enum.GetUnderlyingType(type); } // look up the type if (_typeToDbTypeMap.TryGetValue(type, out sqlType)) { return(sqlType); } // special cases for XmlDocument and XDocument if (type == typeof(XmlDocument)) { return(DbType.Xml); } if (type == typeof(XDocument)) { return(DbType.Xml); } // support for enumerables if (typeof(IEnumerable).IsAssignableFrom(type)) { // use -1 to denote its a list, hacky but will work on any DB return(DbTypeEnumerable); } // sql udts are udts if (TypeHelper.IsSqlUserDefinedType(type)) { return(DbType.Object); } // let's see if the type can be directly converted to the parameter type return(parameterType); }
/// <summary> /// Serializes an object. This is a stub method that reorders parameters. /// </summary> /// <param name="value">The value to serialize.</param> /// <param name="type">The type to serialize.</param> /// <param name="serializer">The serializer to use.</param> /// <returns>The serialized object.</returns> private static object SerializeObject(object value, Type type, IDbObjectSerializer serializer) { return(serializer.SerializeObject(type, value)); }
/// <summary> /// Serialize a value into a parameter. This is a stub method that reorders the stack. /// </summary> /// <param name="value">The value to serialize.</param> /// <param name="type">The type of the member.</param> /// <param name="serializer">The serializer to use.</param> /// <returns>The serialized value.</returns> private static object SerializeParameterValue(object value, Type type, IDbObjectSerializer serializer) { return(serializer.SerializeObject(type, value) ?? DBNull.Value); }
/// <summary> /// Serializes an object. This is a stub method that reorders parameters. /// </summary> /// <param name="value">The value to serialize.</param> /// <param name="type">The type to serialize.</param> /// <param name="serializer">The serializer to use.</param> /// <returns>The serialized object.</returns> private static object SerializeObject(object value, Type type, IDbObjectSerializer serializer) { return serializer.SerializeObject(type, value); }
/// <summary> /// Look up a DbType from a .Net type. /// </summary> /// <param name="type">The type of object to look up.</param> /// <param name="serializer">The serializer that has been detected for the field.</param> /// <param name="parameterType">The expected sql parameter type. Used as the default.</param> /// <returns>The equivalend DbType.</returns> private static DbType LookupDbType(Type type, IDbObjectSerializer serializer, DbType parameterType) { DbType sqlType; // if the serializer can serialize it, then it's a string if (serializer != null && serializer.CanSerialize(type, parameterType)) return serializer.GetSerializedDbType(type, parameterType); // if the type is nullable, get the underlying type var nullUnderlyingType = Nullable.GetUnderlyingType(type); if (nullUnderlyingType != null) type = nullUnderlyingType; // if it's an enum, get the underlying type if (type.IsEnum) type = Enum.GetUnderlyingType(type); // look up the type if (_typeToDbTypeMap.TryGetValue(type, out sqlType)) return sqlType; // special cases for XmlDocument and XDocument if (type == typeof(XmlDocument)) return DbType.Xml; if (type == typeof(XDocument)) return DbType.Xml; // support for enumerables if (typeof(IEnumerable).IsAssignableFrom(type)) { // use -1 to denote its a list, hacky but will work on any DB return DbTypeEnumerable; } // sql udts are udts if (TypeHelper.IsSqlUserDefinedType(type)) return DbType.Object; // let's see if the type can be directly converted to the parameter type return parameterType; }
/// <summary> /// Serialize a value into a parameter. This is a stub method that reorders the stack. /// </summary> /// <param name="value">The value to serialize.</param> /// <param name="type">The type of the member.</param> /// <param name="serializer">The serializer to use.</param> /// <returns>The serialized value.</returns> private static object SerializeParameterValue(object value, Type type, IDbObjectSerializer serializer) { return serializer.SerializeObject(type, value) ?? DBNull.Value; }
/// <summary> /// Emits the IL to convert a value to a target type. /// </summary> /// <param name="il">The IL generator to output to.</param> /// <param name="memberName">The name of the member being converted.</param> /// <param name="sourceType">The source type.</param> /// <param name="targetType">The target type.</param> /// <param name="serializer">The serializer to use to deserialize the value.</param> public static void EmitConvertValue(ILGenerator il, string memberName, Type sourceType, Type targetType, IDbObjectSerializer serializer) { // targetType - the target type we need to convert to // underlyingTargetType - if the target type is nullable, we need to look at the underlying target type // rawTargetType - if the underlying target type is enum, we need to look at the underlying target type for that // sourceType - this is the type of the data in the data set Type underlyingTargetType = Nullable.GetUnderlyingType(targetType) ?? targetType; // some labels that we need var finishLabel = il.DefineLabel(); Label isDbNullLabel = il.DefineLabel(); // if the value is DbNull, then we continue to the next item il.Emit(OpCodes.Dup); // dup value, stack => [target][value][value] il.Emit(OpCodes.Isinst, typeof(DBNull)); // isinst DBNull:value, stack => [target][value-as-object][DBNull or null] il.Emit(OpCodes.Brtrue_S, isDbNullLabel); // br.true isDBNull, stack => [target][value-as-object] // handle the special target types first if (targetType == typeof(char)) { // char il.EmitCall(OpCodes.Call, _readChar, null); } else if (targetType == typeof(char?)) { // char? il.EmitCall(OpCodes.Call, _readNullableChar, null); } else if (targetType == TypeHelper.LinqBinaryType) { // unbox sql byte arrays to Linq.Binary // before: stack => [target][object-value] // after: stack => [target][byte-array-value] il.Emit(OpCodes.Unbox_Any, typeof(byte[])); // stack is now [target][byte-array] // before: stack => [target][byte-array-value] // after: stack => [target][Linq.Binary-value] il.Emit(OpCodes.Newobj, TypeHelper.LinqBinaryCtor); } else if (targetType == typeof(XmlDocument)) { // special handler for XmlDocuments // before: stack => [target][object-value] il.Emit(OpCodes.Call, _readXmlDocument); // after: stack => [target][xmlDocument] } else if (targetType == typeof(XDocument)) { // special handler for XDocuments // before: stack => [target][object-value] il.Emit(OpCodes.Call, _readXDocument); // after: stack => [target][xDocument] } else if (serializer != null && serializer.CanDeserialize(sourceType, targetType)) { // we are getting a string from the database, but the target is not a string, and it's a reference type // assume the column is a serialized data type and that we want to deserialize it il.EmitLoadType(targetType); StaticFieldStorage.EmitLoad(il, serializer); il.Emit(OpCodes.Call, typeof(TypeConverterGenerator).GetMethod("DeserializeObject", BindingFlags.NonPublic | BindingFlags.Static)); il.Emit(OpCodes.Unbox_Any, targetType); } else if (underlyingTargetType.IsEnum && sourceType == typeof(string)) { var localString = il.DeclareLocal(typeof(string)); // if we are converting a string to an enum, then parse it. // see if the value from the database is a string. if so, we need to parse it. If not, we will just try to unbox it. il.Emit(OpCodes.Isinst, typeof(string)); // is string, stack => [target][string] il.Emit(OpCodes.Stloc, localString); // pop loc.2 (enum), stack => [target] // call enum.parse (type, value, true) il.EmitLoadType(underlyingTargetType); il.Emit(OpCodes.Ldloc, localString); // push enum, stack => [target][enum-type][string] il.Emit(OpCodes.Ldc_I4_1); // push true, stack => [target][enum-type][string][true] il.EmitCall(OpCodes.Call, _enumParse, null); // call Enum.Parse, stack => [target][enum-as-object] // Enum.Parse returns an object, which we need to unbox to the enum value il.Emit(OpCodes.Unbox_Any, underlyingTargetType); } else if (EmitConstructorConversion(il, sourceType, targetType)) { // target type can be constructed from source type } else { // this isn't a system value type, so unbox to the type the reader is giving us (this is a system type, hopefully) // now we have an unboxed sourceType il.Emit(OpCodes.Unbox_Any, sourceType); if (sourceType != targetType) { // attempt to convert the value to the target type if (!EmitConversionOrCoersion(il, sourceType, targetType)) { if (sourceType != targetType) { throw new InvalidOperationException(String.Format( CultureInfo.InvariantCulture, "Field {0} cannot be converted from {1} to {2}. Create a conversion constructor or conversion operator.", memberName, sourceType.AssemblyQualifiedName, targetType.AssemblyQualifiedName)); } } // if the target is nullable, then construct the nullable from the data if (Nullable.GetUnderlyingType(targetType) != null) il.Emit(OpCodes.Newobj, targetType.GetConstructor(new[] { underlyingTargetType })); } } ///////////////////////////////////////////////////////////////////// // convert DBNull to default of the given type il.Emit(OpCodes.Br_S, finishLabel); il.MarkLabel(isDbNullLabel); il.Emit(OpCodes.Pop); TypeHelper.EmitDefaultValue(il, targetType); il.MarkLabel(finishLabel); }
/// <summary> /// Deserializes an object. This is a stub method that just reorders the parameters. /// </summary> /// <param name="encoded">The encoded value.</param> /// <param name="type">The type to deserialize.</param> /// <param name="serializer">The serializer to use.</param> /// <returns>The deserialized object.</returns> private static object DeserializeObject(object encoded, Type type, IDbObjectSerializer serializer) { return serializer.DeserializeObject(type, encoded); }
/// <summary> /// Emits the IL to convert a value to a target type. /// </summary> /// <param name="il">The IL generator to output to.</param> /// <param name="memberName">The name of the member being converted.</param> /// <param name="sourceType">The source type.</param> /// <param name="targetType">The target type.</param> /// <param name="serializer">The serializer to use to deserialize the value.</param> public static void EmitConvertValue(ILGenerator il, string memberName, Type sourceType, Type targetType, IDbObjectSerializer serializer) { // targetType - the target type we need to convert to // underlyingTargetType - if the target type is nullable, we need to look at the underlying target type // rawTargetType - if the underlying target type is enum, we need to look at the underlying target type for that // sourceType - this is the type of the data in the data set Type underlyingTargetType = Nullable.GetUnderlyingType(targetType) ?? targetType; // some labels that we need var finishLabel = il.DefineLabel(); Label isDbNullLabel = il.DefineLabel(); // if the value is DbNull, then we continue to the next item il.Emit(OpCodes.Dup); // dup value, stack => [target][value][value] il.Emit(OpCodes.Isinst, typeof(DBNull)); // isinst DBNull:value, stack => [target][value-as-object][DBNull or null] il.Emit(OpCodes.Brtrue_S, isDbNullLabel); // br.true isDBNull, stack => [target][value-as-object] // handle the special target types first if (targetType == typeof(char)) { // char il.EmitCall(OpCodes.Call, _readChar, null); } else if (targetType == typeof(char?)) { // char? il.EmitCall(OpCodes.Call, _readNullableChar, null); } else if (targetType == TypeHelper.LinqBinaryType) { // unbox sql byte arrays to Linq.Binary // before: stack => [target][object-value] // after: stack => [target][byte-array-value] il.Emit(OpCodes.Unbox_Any, typeof(byte[])); // stack is now [target][byte-array] // before: stack => [target][byte-array-value] // after: stack => [target][Linq.Binary-value] il.Emit(OpCodes.Newobj, TypeHelper.LinqBinaryCtor); } else if (targetType == typeof(XmlDocument)) { // special handler for XmlDocuments // before: stack => [target][object-value] il.Emit(OpCodes.Call, _readXmlDocument); // after: stack => [target][xmlDocument] } else if (targetType == typeof(XDocument)) { // special handler for XDocuments // before: stack => [target][object-value] il.Emit(OpCodes.Call, _readXDocument); // after: stack => [target][xDocument] } else if (serializer != null && serializer.CanDeserialize(sourceType, targetType)) { // we are getting a string from the database, but the target is not a string, and it's a reference type // assume the column is a serialized data type and that we want to deserialize it il.EmitLoadType(targetType); StaticFieldStorage.EmitLoad(il, serializer); il.Emit(OpCodes.Call, typeof(TypeConverterGenerator).GetMethod("DeserializeObject", BindingFlags.NonPublic | BindingFlags.Static)); il.Emit(OpCodes.Unbox_Any, targetType); } else if (underlyingTargetType.IsEnum && sourceType == typeof(string)) { var localString = il.DeclareLocal(typeof(string)); // if we are converting a string to an enum, then parse it. // see if the value from the database is a string. if so, we need to parse it. If not, we will just try to unbox it. il.Emit(OpCodes.Isinst, typeof(string)); // is string, stack => [target][string] il.Emit(OpCodes.Stloc, localString); // pop loc.2 (enum), stack => [target] // call enum.parse (type, value, true) il.EmitLoadType(underlyingTargetType); il.Emit(OpCodes.Ldloc, localString); // push enum, stack => [target][enum-type][string] il.Emit(OpCodes.Ldc_I4_1); // push true, stack => [target][enum-type][string][true] il.EmitCall(OpCodes.Call, _enumParse, null); // call Enum.Parse, stack => [target][enum-as-object] // Enum.Parse returns an object, which we need to unbox to the enum value il.Emit(OpCodes.Unbox_Any, underlyingTargetType); } else if (EmitConstructorConversion(il, sourceType, targetType)) { // target type can be constructed from source type } else { // this isn't a system value type, so unbox to the type the reader is giving us (this is a system type, hopefully) // now we have an unboxed sourceType il.Emit(OpCodes.Unbox_Any, sourceType); if (sourceType != targetType) { // attempt to convert the value to the target type if (!EmitConversionOrCoersion(il, sourceType, targetType)) { if (sourceType != targetType) { throw new InvalidOperationException(String.Format( CultureInfo.InvariantCulture, "Field {0} cannot be converted from {1} to {2}. Create a conversion constructor or conversion operator.", memberName, sourceType.AssemblyQualifiedName, targetType.AssemblyQualifiedName)); } } // if the target is nullable, then construct the nullable from the data if (Nullable.GetUnderlyingType(targetType) != null) { il.Emit(OpCodes.Newobj, targetType.GetConstructor(new[] { underlyingTargetType })); } } } ///////////////////////////////////////////////////////////////////// // convert DBNull to default of the given type il.Emit(OpCodes.Br_S, finishLabel); il.MarkLabel(isDbNullLabel); il.Emit(OpCodes.Pop); TypeHelper.EmitDefaultValue(il, targetType); il.MarkLabel(finishLabel); }
/// <summary> /// Deserializes an object. This is a stub method that just reorders the parameters. /// </summary> /// <param name="encoded">The encoded value.</param> /// <param name="type">The type to deserialize.</param> /// <param name="serializer">The serializer to use.</param> /// <returns>The deserialized object.</returns> private static object DeserializeObject(object encoded, Type type, IDbObjectSerializer serializer) { return(serializer.DeserializeObject(type, encoded)); }