Esempio n. 1
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
            }));
        }
Esempio n. 2
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));
        }