Пример #1
0
        public void TestTypeMapperPropertyMappingViaPropertyNameWithMapAttribute()
        {
            // Setup
            var propertyName = "PropertyString";

            TypeMapper.Add <TypeMapCacheTestClass>(propertyName, DbType.StringFixedLength);

            // Act
            var actual   = TypeMapCache.Get <TypeMapCacheTestClass>(propertyName);
            var expected = DbType.String;

            // Assert
            Assert.AreEqual(expected, actual);
        }
Пример #2
0
        public void Cleanup()
        {
            ClassMapper.Clear();
            PropertyMapper.Clear();
            PrimaryMapper.Clear();
            IdentityMapper.Clear();
            TypeMapper.Clear();
            //PropertyHandlerMapper.Clear();
            PropertyValueAttributeMapper.Clear();

            ClassMappedNameCache.Flush();
            PropertyCache.Flush();
            PrimaryCache.Flush();
            IdentityCache.Flush();
            TypeMapCache.Flush();
            //PropertyHandlerMapper.Clear();
            PropertyValueAttributeCache.Flush();
        }
Пример #3
0
        public void TestTypeMapperPropertyMappingViaExpressionWithMapAttribute()
        {
            // Setup
            TypeMapper.Add <TypeMapperTestClass>(e => e.PropertyString, DbType.StringFixedLength);

            // Act
            var actual   = TypeMapper.Get <TypeMapperTestClass>(e => e.PropertyString);
            var expected = DbType.StringFixedLength;

            // Assert
            Assert.AreEqual(expected, actual);

            // Act
            actual   = TypeMapCache.Get <TypeMapperTestClass>(e => e.PropertyString);
            expected = DbType.String;

            // Assert
            Assert.AreEqual(expected, actual);
        }
Пример #4
0
        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
            }));
        }
Пример #5
0
        public void TestTypeMapperPropertyMappingViaFieldWithMapAttribute()
        {
            // Setup
            var field = new Field("PropertyString");

            TypeMapper.Add <TypeMapperTestClass>(field, DbType.StringFixedLength);

            // Act
            var actual   = TypeMapper.Get <TypeMapperTestClass>(field);
            var expected = DbType.StringFixedLength;

            // Assert
            Assert.AreEqual(expected, actual);

            // Act
            actual   = TypeMapCache.Get <TypeMapperTestClass>(field);
            expected = DbType.String;

            // Assert
            Assert.AreEqual(expected, actual);
        }
Пример #6
0
 /// <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));
                }
            }
        }
Пример #8
0
        /// <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());
        }
Пример #9
0
        /// <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;
            }

            // Validate, make sure to only have the proper operation
            if (queryField.Operation != Operation.Equal)
            {
                throw new InvalidOperationException($"Operation must only be '{nameof(Operation.Equal)}' when calling the 'Execute' methods.");
            }

            // 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 = m_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 == m_bytesType)
                    {
                        dbType = DbType.Binary;
                    }
                }
            }

            #endregion

            // Create the parameter
            command.Parameters.Add(command.CreateParameter(queryField.Parameter.Name, value, dbType));
        }
Пример #10
0
        /// <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));
            }
        }
Пример #11
0
 public void Cleanup()
 {
     TypeMapper.Clear();
     TypeMapCache.Flush();
 }
Пример #12
0
        /// <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));
        }