/// <summary> /// Creates a command parameter from the <see cref="QueryField"/> object. /// </summary> /// <param name="command">The command object to be used.</param> /// <param name="queryField">The value of <see cref="QueryField"/> object.</param> /// <param name="propertiesToSkip">The list of the properties to be skipped.</param> /// <param name="entityType">The type of the data entity.</param> internal static void CreateParameters(this IDbCommand command, QueryField queryField, IEnumerable <string> propertiesToSkip, Type entityType) { // Exclude those to be skipped if (propertiesToSkip?.Contains(queryField.Field.Name, StringComparer.OrdinalIgnoreCase) == true) { return; } // Get the values var value = queryField.Parameter.Value; var valueType = value?.GetType()?.GetUnderlyingType(); var dbType = (DbType?)null; #region PropertyHandler // Check the property handler var typeHandler = PropertyHandlerCache.Get <object>(valueType); if (typeHandler != null) { var classProperty = (ClassProperty)null; var setMethod = typeHandler.GetType().GetMethod("Set"); var returnType = setMethod.ReturnType; if (entityType != null) { classProperty = PropertyCache.Get(entityType, queryField.Field); } dbType = clientTypeToDbTypeResolver.Resolve(returnType); value = setMethod.Invoke(typeHandler, new[] { value, classProperty }); } #endregion #region DbType else { dbType = TypeMapCache.Get(valueType); // Check for the specialized types if (dbType == null) { if (valueType?.IsEnum == true) { dbType = DbType.String; } else if (valueType == StaticType.ByteArray) { dbType = DbType.Binary; } } } #endregion // Create the parameter command.Parameters.Add(command.CreateParameter(queryField.Parameter.Name, value, dbType)); }
public void TestWithoutMapping() { // Act var result = TypeMapCache.Get <TypeMapCacheTest>(); // Assert Assert.IsNull(result); }
public void TestClassMapDbTypeMappingWithMapAttribute() { // Act var actual = TypeMapCache.Get <ClassMapperTestWithAttributesClass>(e => e.PropertyString); var expected = DbType.String; // Assert Assert.AreEqual(expected, actual); }
public void TestFluentMapDbTypeMapping() { // Act var actual = TypeMapCache.Get <FluentMapperTestClass>(e => e.PropertyString); var expected = DbType.String; // Assert Assert.AreEqual(expected, actual); }
public void TestWithMapping() { // Setup TypeMapper.Add <TypeMapCacheTestClass>(DbType.Object); // Act var result = TypeMapCache.Get <TypeMapCacheTestClass>(); var expected = DbType.Object; // Assert Assert.AreEqual(expected, result); }
public void TestTypeMapperPropertyMappingViaExpressionWithMapAttribute() { // Setup TypeMapper.Add <TypeMapCacheTestClass>(e => e.PropertyString, DbType.StringFixedLength); // Act var actual = TypeMapCache.Get <TypeMapCacheTestClass>(e => e.PropertyString); var expected = DbType.String; // Assert Assert.AreEqual(expected, actual); }
public void TestClassMapDbTypeMappingOverride() { // Setup TypeMapper.Add <ClassMapperTestClass>(e => e.PropertyString, DbType.AnsiString, true); // Act var actual = TypeMapCache.Get <ClassMapperTestClass>(); var expected = DbType.AnsiString; // Assert Assert.AreEqual(expected, actual); }
public void TestFluentMapDbTypeMappingOverride() { // Setup FluentMapper .Entity <FluentMapperTestClass>() .DbType(e => e.PropertyString, DbType.AnsiString, true); // Act var actual = TypeMapCache.Get <FluentMapperTestClass>(e => e.PropertyString); var expected = DbType.AnsiString; // Assert Assert.AreEqual(expected, actual); }
public void TestTypeMapperPropertyMappingViaField() { // Setup var field = new Field("ColumnString"); TypeMapper.Add <TypeMapCacheTestClass>(field, DbType.StringFixedLength); // Act var actual = TypeMapCache.Get <TypeMapCacheTestClass>(field); var expected = DbType.StringFixedLength; // Assert Assert.AreEqual(expected, actual); }
public void TestTypeMapperPropertyMappingViaPropertyName() { // Setup var propertyName = "ColumnString"; TypeMapper.Add <TypeMapCacheTestClass>(propertyName, DbType.StringFixedLength); // Act var actual = TypeMapCache.Get <TypeMapCacheTestClass>(propertyName); var expected = DbType.StringFixedLength; // Assert Assert.AreEqual(expected, actual); }
public static Expression GetPlainTypeToDbParametersForNonEnumCompiledFunction(Expression commandParameterExpression, ClassProperty paramProperty, ClassProperty entityProperty, DbField dbField, Type valueType, Expression valueExpression) { // Automatic if (Converter.ConversionType == ConversionType.Automatic && dbField?.Type != null) { valueType = dbField.Type.GetUnderlyingType(); valueExpression = ConvertExpressionWithAutomaticConversion(valueExpression, valueType); } // DbType var dbType = (paramProperty == null ? null : TypeMapCache.Get(paramProperty.GetDeclaringType(), paramProperty.PropertyInfo)) ?? (entityProperty == null ? null : TypeMapCache.Get(entityProperty.GetDeclaringType(), entityProperty.PropertyInfo)); valueType ??= dbField?.Type.GetUnderlyingType(); if (dbType == null && valueType != null) { var resolver = new ClientTypeToDbTypeResolver(); dbType = valueType.GetDbType() ?? // type level, use TypeMapCache resolver.Resolve(valueType) ?? // type level, primitive mapping (dbField?.Type != null ? resolver.Resolve(dbField?.Type) : null); // Fallback to the database type } var dbTypeExpression = dbType == null?GetNullableTypeExpression(StaticType.DbType) : ConvertExpressionToNullableExpression(Expression.Constant(dbType), StaticType.DbType); // DbCommandExtension.CreateParameter var methodInfo = GetDbCommandCreateParameterMethod(); return(Expression.Call(methodInfo, new Expression[] { commandParameterExpression, Expression.Constant(paramProperty.GetMappedName()), ConvertExpressionToTypeExpression(valueExpression, StaticType.Object), dbTypeExpression })); }
/// <summary> /// Gets the corresponding <see cref="DbType"/> object. /// </summary> /// <param name="type">The target type.</param> /// <returns>The instance of the <see cref="DbType"/> object.</returns> public static DbType?GetDbType(this Type type) => type != null?TypeMapCache.Get(type.GetUnderlyingType()) : null;
/// <summary> /// Creates a parameter from object by mapping the property from the target entity type. /// </summary> /// <param name="command">The command object to be used.</param> /// <param name="param">The object to be used when creating the parameters.</param> /// <param name="propertiesToSkip">The list of the properties to be skipped.</param> /// <param name="entityType">The type of the data entity.</param> internal static void CreateParameters(this IDbCommand command, object param, IEnumerable <string> propertiesToSkip, Type entityType) { // Check for presence if (param == null) { return; } // Supporting the IDictionary<string, object> if (param is ExpandoObject || param is IDictionary <string, object> ) { CreateParameters(command, (IDictionary <string, object>)param, propertiesToSkip, entityType); } // Supporting the QueryField else if (param is QueryField) { CreateParameters(command, (QueryField)param, propertiesToSkip, entityType); } // Supporting the IEnumerable<QueryField> else if (param is IEnumerable <QueryField> ) { CreateParameters(command, (IEnumerable <QueryField>)param, propertiesToSkip, entityType); } // Supporting the QueryGroup else if (param is QueryGroup) { CreateParameters(command, (QueryGroup)param, propertiesToSkip, entityType); } // Otherwise, iterate the properties else { var type = param.GetType(); // Check the validity of the type if (type.IsGenericType && type.GetGenericTypeDefinition() == StaticType.Dictionary) { throw new InvalidParameterException("The supported type of dictionary object must be of type IDictionary<string, object>."); } // Variables for properties var properties = type.IsClassType() ? PropertyCache.Get(type) : type.GetClassProperties(); // Skip some properties if (propertiesToSkip != null) { properties = properties? .Where(p => propertiesToSkip?.Contains(p.PropertyInfo.Name, StringComparer.OrdinalIgnoreCase) == false); } // Iterate the properties foreach (var property in properties) { // Get the property vaues var name = property.GetMappedName(); var value = property.PropertyInfo.GetValue(param); var dbType = (DbType?)null; #region PropertyHandler // Check the property handler var propertyHandler = property.GetPropertyHandler(); if (propertyHandler != null) { var setMethod = propertyHandler.GetType().GetMethod("Set"); var returnType = setMethod.ReturnType; var classProperty = PropertyCache.Get(property.GetDeclaringType(), property.PropertyInfo); dbType = clientTypeToDbTypeResolver.Resolve(returnType); value = setMethod.Invoke(propertyHandler, new[] { value, classProperty }); } #endregion #region DbType else { // Check for the specialized first var propertyType = property.PropertyInfo.PropertyType.GetUnderlyingType(); if (propertyType?.IsEnum == true) { dbType = DbType.String; } else if (propertyType == StaticType.ByteArray) { dbType = DbType.Binary; } else { // Get property db type dbType = property.GetDbType(); // Ensure mapping based on the value type if (dbType == null && value != null) { dbType = TypeMapCache.Get(value.GetType().GetUnderlyingType()); } } } #endregion // Add the new parameter command.Parameters.Add(command.CreateParameter(name, value, dbType)); } } }
/// <summary> /// /// </summary> /// <param name="paramType"></param> /// <param name="entityType"></param> /// <param name="dbFields"></param> /// <returns></returns> internal static Action <DbCommand, object> GetPlainTypeToDbParametersCompiledFunction(Type paramType, Type entityType, IEnumerable <DbField> dbFields = null) { var commandParameterExpression = Expression.Parameter(StaticType.DbCommand, "command"); var entityParameterExpression = Expression.Parameter(StaticType.Object, "entity"); var entityExpression = ConvertExpressionToTypeExpression(entityParameterExpression, paramType); var methodInfo = GetDbCommandCreateParameterMethod(); var callExpressions = new List <Expression>(); var paramProperties = PropertyCache.Get(paramType); var entityProperties = PropertyCache.Get(entityType); // Iterate foreach (var paramProperty in paramProperties) { // Ensure it matching any params var entityProperty = entityProperties?.FirstOrDefault(e => string.Equals(e.GetMappedName(), paramProperty.GetMappedName(), StringComparison.OrdinalIgnoreCase) || string.Equals(e.PropertyInfo.Name, paramProperty.PropertyInfo.Name, StringComparison.OrdinalIgnoreCase)); // Variables var dbField = dbFields?.FirstOrDefault(df => string.Equals(df.Name, paramProperty.GetMappedName(), StringComparison.OrdinalIgnoreCase)); var valueExpression = (Expression)Expression.Property(entityExpression, paramProperty.PropertyInfo); var valueType = (entityProperty ?? paramProperty).PropertyInfo.PropertyType.GetUnderlyingType(); // PropertyHandler var handlerSetTuple = ConvertExpressionToPropertyHandlerSetExpressionTuple(valueExpression, paramProperty, valueType); if (handlerSetTuple.handlerSetReturnType != null) { valueExpression = handlerSetTuple.convertedExpression; valueType = handlerSetTuple.handlerSetReturnType; } // Automatic if (Converter.ConversionType == ConversionType.Automatic && dbField?.Type != null) { valueType = dbField.Type.GetUnderlyingType(); valueExpression = ConvertExpressionWithAutomaticConversion(valueExpression, valueType); } // DbType var dbType = (paramProperty == null ? null : TypeMapCache.Get(paramProperty.GetDeclaringType(), paramProperty.PropertyInfo)) ?? (entityProperty == null ? null : TypeMapCache.Get(entityProperty.GetDeclaringType(), entityProperty.PropertyInfo)); if (dbType == null && (valueType ??= dbField?.Type.GetUnderlyingType()) != null) { dbType = valueType.GetDbType() ?? // type level, use TypeMapCache new ClientTypeToDbTypeResolver().Resolve(valueType) ?? // type level, primitive mapping (valueType.IsEnum ? Converter.EnumDefaultDatabaseType : null); // use Converter.EnumDefaultDatabaseType } var dbTypeExpression = dbType == null?GetNullableTypeExpression(StaticType.DbType) : ConvertExpressionToNullableExpression(Expression.Constant(dbType), StaticType.DbType); // DbCommandExtension.CreateParameter var expression = Expression.Call(methodInfo, new Expression[] { commandParameterExpression, Expression.Constant(paramProperty.GetMappedName()), ConvertExpressionToTypeExpression(valueExpression, StaticType.Object), dbTypeExpression }); // DbCommand.Parameters.Add var parametersExpression = Expression.Property(commandParameterExpression, "Parameters"); var addExpression = Expression.Call(parametersExpression, GetDbParameterCollectionAddMethod(), expression); // Add callExpressions.Add(addExpression); } // Return return(Expression .Lambda <Action <DbCommand, object> >(Expression.Block(callExpressions), commandParameterExpression, entityParameterExpression) .Compile()); }
/// <summary> /// Create the command parameters from the <see cref="IDictionary{TKey, TValue}"/> object. /// </summary> /// <param name="command">The command object to be used.</param> /// <param name="dictionary">The parameters from the <see cref="Dictionary{TKey, TValue}"/> object.</param> /// <param name="propertiesToSkip">The list of the properties to be skipped.</param> /// <param name="entityType">The type of the data entity.</param> internal static void CreateParameters(this IDbCommand command, IDictionary <string, object> dictionary, IEnumerable <string> propertiesToSkip, Type entityType) { // Variables needed var kvps = dictionary.Where(kvp => propertiesToSkip?.Contains(kvp.Key, StringComparer.OrdinalIgnoreCase) != true); // Iterate the key value pairs foreach (var kvp in kvps) { var dbType = (DbType?)null; var value = kvp.Value; var valueType = (Type)null; var declaringType = entityType; var property = (PropertyInfo)null; // Cast the proper object and identify the properties if (kvp.Value is CommandParameter) { var commandParameter = (CommandParameter)kvp.Value; // Get the property and value property = commandParameter.MappedToType.GetProperty(kvp.Key); declaringType = commandParameter.MappedToType ?? property.DeclaringType; value = commandParameter.Value; // Set the value type valueType = value?.GetType()?.GetUnderlyingType(); } else { // In this area, it could be a 'dynamic' object valueType = kvp.Value?.GetType()?.GetUnderlyingType(); } // Get the property-level mapping if (property != null) { #region PropertyHandler // Check the property handler var propertyHandler = PropertyHandlerCache.Get <object>(declaringType, property); if (propertyHandler != null) { var setMethod = propertyHandler.GetType().GetMethod("Set"); var returnType = setMethod.ReturnType; var classProperty = PropertyCache.Get(declaringType, property); dbType = m_clientTypeToDbTypeResolver.Resolve(returnType); value = setMethod.Invoke(propertyHandler, new[] { value, classProperty }); } #endregion else { #region DbType dbType = TypeMapCache.Get(property.DeclaringType, property); // Check for the specialized types if (dbType == null) { if (valueType?.IsEnum == true) { dbType = DbType.String; } else if (valueType == m_bytesType) { dbType = DbType.Binary; } } #endregion } } // Add the parameter command.Parameters.Add(command.CreateParameter(kvp.Key, value, dbType)); } }
/// <summary> /// Create Parameter, the process will handle value conversion and type conversion. /// </summary> /// <param name="command">The command object to be used.</param> /// <param name="name">Entity property's name.</param> /// <param name="value">Entity property's value, maybe null.</param> /// <param name="classProperty"> /// The entity's class property information. <br /> /// If the parameter is a dictionary, it will be null, otherwise it will not be null. /// </param> /// <param name="dbField"> /// Used to get the actual field type information of the database to determine whether automatic type conversion is required. <br /> /// When the tableName is assigned, it will be based on the database field information obtained by the tableName, so this parameter will be null in most cases. /// </param> /// <param name="parameterDirection">The direction of the parameter.</param> /// <param name="fallbackType">Used when none of the above parameters can determine the value of Parameter.DbType.</param> /// <returns>An instance of the newly created parameter object.</returns> private static IDbDataParameter CreateParameter(IDbCommand command, string name, object value, ClassProperty classProperty, DbField dbField, ParameterDirection?parameterDirection, Type fallbackType) { /* * In some cases, the value type and the classProperty type will be inconsistent, Therefore, the type gives priority to value. * ex: in RepoDb.MySql.IntegrationTests.TestMySqlConnectionForQueryForMySqlMapAttribute * entity AttributeTable.Id = int * database completetable.Id = bigint(20) AUTO_INCREMENT * value id in connection.Query<AttributeTable>(id) is from connection.Insert<AttributeTable>(table) = ulong */ var valueType = (value?.GetType() ?? classProperty?.PropertyInfo.PropertyType).GetUnderlyingType(); // Enum if (valueType?.IsEnum == true && dbField != null) { value = ConvertEnumValueToType(value, dbField.Type); } /* * Try to get the propertyHandler, the order of the source of resolve is classProperty and valueType. * If the propertyHandler exists, the value and DbType are re-determined by the propertyHandler. */ var propertyHandler = classProperty?.GetPropertyHandler() ?? (valueType == null ? null : PropertyHandlerCache.Get <object>(valueType)); if (propertyHandler != null) { var propertyHandlerSetMethod = propertyHandler.GetType().GetMethod("Set"); value = propertyHandlerSetMethod.Invoke(propertyHandler, new[] { value, classProperty }); valueType = propertyHandlerSetMethod.ReturnType.GetUnderlyingType(); } /* * When the database field information exists and the field type definition is found to be different from the valueType, * if automatic type conversion is activated at this time, it will be processed. */ if (valueType != null && dbField != null && IsAutomaticConversion(dbField)) { var dbFieldType = dbField.Type.GetUnderlyingType(); if (dbFieldType != valueType) { if (value != null) { value = AutomaticConvert(value, valueType, dbFieldType); } valueType = dbFieldType; } } /* * Set DbType as much as possible, to avoid parameter misjudgment when Value is null. * order: * 1. attribute level, TypeMapAttribute define on class's property * 2. property level, assigned by TypeMapper.Add(entityType, property, dbType, ...) * 3. type level, use TypeMapCache, assigned by TypeMapper.Add(type, dbType, ...), not included Primitive mapping. * 4. type level, primitive mapping, included special type. ex: byte[] ...etc. * 5. if isEnum, use Converter.EnumDefaultDatabaseType. */ // if classProperty exists, try get dbType from attribute level or property level, // The reason for not using classProperty.GetDbType() is to avoid getting the type level mapping. var dbType = classProperty == null ? null : TypeMapCache.Get(classProperty.GetDeclaringType(), classProperty.PropertyInfo); if (dbType == null && (valueType ??= dbField?.Type.GetUnderlyingType() ?? fallbackType) != null) { dbType = valueType.GetDbType() ?? // type level, use TypeMapCache clientTypeToDbTypeResolver.Resolve(valueType) ?? // type level, primitive mapping (dbField?.Type != null ? clientTypeToDbTypeResolver.Resolve(dbField?.Type) : null); // fallback to the database type } if (dbType == null && valueType.IsEnum) { dbType = Converter.EnumDefaultDatabaseType; // use Converter.EnumDefaultDatabaseType } /* * Return the parameter */ return(command.CreateParameter(name, value, dbType, parameterDirection)); }