Ejemplo n.º 1
0
        /// <summary>
        /// Gets a delegate that is used to convert the <see cref="DbDataReader"/> object into data entity object.
        /// </summary>
        /// <typeparam name="TEntity">The data entity object to convert to.</typeparam>
        /// <param name="reader">The <see cref="DbDataReader"/> to be converted.</param>
        /// <returns>An instance of data entity object.</returns>
        public static DataReaderToDataEntityDelegate <TEntity> GetDataReaderToDataEntityDelegate <TEntity>(DbDataReader reader)
            where TEntity : class
        {
            var entityType    = typeof(TEntity);
            var dynamicMethod = new DynamicMethod(StringConstant.DynamicMethod,
                                                  entityType,
                                                  new[] { typeof(DbDataReader) },
                                                  typeof(Assembly).GetTypeInfo().Module,
                                                  true);
            var ilGenerator      = dynamicMethod.GetILGenerator();
            var fieldDefinitions = FieldDefinitionCache.Get <TEntity>(Command.Query);

            // Declare IL Variables
            ilGenerator.DeclareLocal(entityType);
            ilGenerator.DeclareLocal(typeof(object));

            // Create instance of the object type
            ilGenerator.Emit(OpCodes.Newobj, entityType.GetTypeInfo().GetConstructor(Type.EmptyTypes));
            ilGenerator.Emit(OpCodes.Stloc, 0);

            // Matching the fields
            var fields = Enumerable.Range(0, reader.FieldCount)
                         .Select(reader.GetName)
                         .Select(n => n.ToLower())
                         .ToList();
            var matchedCount = 0;

            // Iterate the properties
            PropertyCache.Get <TEntity>(Command.Query)
            .Where(property => property.PropertyInfo.CanWrite)
            .ToList()
            .ForEach(property =>
            {
                var mappedName      = property.GetMappedName().ToLower();
                var fieldDefinition = fieldDefinitions?.FirstOrDefault(fd => fd.Name.ToLower() == mappedName);
                var ordinal         = fields.IndexOf(mappedName);
                if (ordinal >= 0)
                {
                    EmitDataReaderToDataEntityMapping <TEntity>(ilGenerator, ordinal, property, fieldDefinition);
                    matchedCount++;
                }
            });

            // Throw an error if there are no matching atleast one
            if (matchedCount == 0)
            {
                throw new NoMatchedFieldsException($"There is no matching fields between the result set of the data reader and the type '{typeof(TEntity).FullName}'.");
            }

            // Return the TEntity instance value
            ilGenerator.Emit(OpCodes.Ldloc, 0);
            ilGenerator.Emit(OpCodes.Ret);

            // Create a delegate
            return((DataReaderToDataEntityDelegate <TEntity>)dynamicMethod.CreateDelegate(typeof(DataReaderToDataEntityDelegate <TEntity>)));
        }
Ejemplo n.º 2
0
        /// <summary>
        /// Returns the list of the bindings for the entity.
        /// </summary>
        /// <typeparam name="TEntity">The target entity type.</typeparam>
        /// <param name="newEntityExpression">The new entity expression.</param>
        /// <param name="readerParameterExpression">The data reader parameter.</param>
        /// <param name="readerFields">The list of fields to be bound from the data reader.</param>
        /// <returns>The enumerable list of member assignment and bindings.</returns>
        private static IEnumerable <MemberAssignment> GetMemberAssignments <TEntity>(Expression newEntityExpression,
                                                                                     ParameterExpression readerParameterExpression, IEnumerable <DataReaderFieldDefinition> readerFields)
            where TEntity : class
        {
            // Initialize variables
            var memberAssignments = new List <MemberAssignment>();
            var dataReaderType    = typeof(DbDataReader);
            var tableFields       = FieldDefinitionCache.Get <TEntity>();
            var isStrict          = TypeMapper.ConversionType == ConversionType.Default;

            // Iterate each properties
            foreach (var property in PropertyCache.Get <TEntity>().Where(property => property.PropertyInfo.CanWrite))
            {
                // Gets the mapped name and the ordinal
                var mappedName = property.GetMappedName().ToLower();
                var ordinal    = readerFields?.Select(f => f.Name).ToList().IndexOf(mappedName);

                // Process only if there is a correct ordinal
                if (ordinal >= 0)
                {
                    // Variables needed for the iteration
                    var tableField           = tableFields?.FirstOrDefault(f => f.Name.ToLower() == mappedName);
                    var readerField          = readerFields.First(f => f.Name.ToLower() == mappedName);
                    var isTableFieldNullable = tableField == null || tableField?.IsNullable == true;
                    var underlyingType       = Nullable.GetUnderlyingType(property.PropertyInfo.PropertyType);
                    var propertyType         = underlyingType ?? property.PropertyInfo.PropertyType;
                    var convertType          = readerField.Type;
                    var isConversionNeeded   = readerField.Type != propertyType;

                    // Get the correct method info, if the reader.Get<Type> is not found, then use the default GetValue() method
                    var readerGetValueMethod = dataReaderType.GetTypeInfo().GetMethod(string.Concat("Get", readerField.Type.Name));
                    if (readerGetValueMethod == null)
                    {
                        // Single value is throwing an exception in GetString(), skip it and use the GetValue() instead
                        if (isStrict == false && readerField.Type != typeof(Single))
                        {
                            readerGetValueMethod = dataReaderType.GetTypeInfo().GetMethod(string.Concat("Get", propertyType.Name));
                        }

                        // If present, then use the property type, otherwise, use the object
                        if (readerGetValueMethod != null)
                        {
                            convertType = propertyType;
                        }
                        else
                        {
                            readerGetValueMethod = dataReaderType.GetTypeInfo().GetMethod("GetValue");
                            convertType          = typeof(object);
                        }

                        // Force the conversion flag
                        isConversionNeeded = true;
                    }

                    // Expressions
                    var ordinalExpression = Expression.Constant(ordinal);
                    var valueExpression   = (Expression)null;

                    // Check for nullables
                    if (isTableFieldNullable == true)
                    {
                        var isDbNullExpression = Expression.Call(readerParameterExpression, dataReaderType.GetTypeInfo().GetMethod("IsDBNull"), ordinalExpression);

                        // True expression
                        var trueExpression = (Expression)null;
                        if (underlyingType != null && underlyingType.GetTypeInfo().IsValueType == true)
                        {
                            trueExpression = Expression.New(typeof(Nullable <>).MakeGenericType(propertyType));
                        }
                        else
                        {
                            trueExpression = Expression.Default(propertyType);
                        }

                        // False expression
                        var falseExpression = (Expression)Expression.Call(readerParameterExpression, readerGetValueMethod, ordinalExpression);

                        // Only if there are conversions, execute the logics inside
                        if (isConversionNeeded == true)
                        {
                            if (isStrict == true)
                            {
                                falseExpression = Expression.Convert(falseExpression, propertyType);
                            }
                            else
                            {
                                // Variables needed
                                var targetInstance  = (Expression)null;
                                var targetMethod    = (MethodInfo)null;
                                var targetParameter = (Expression)null;

                                // Identify if the target type is 'Guid'
                                if (propertyType == typeof(Guid) && readerField.Type == typeof(string))
                                {
                                    // This is Guid.Parse()
                                    targetMethod    = typeof(Guid).GetTypeInfo().GetMethod("Parse", new[] { typeof(string) });
                                    targetInstance  = null;
                                    targetParameter = falseExpression;
                                }
                                else if (propertyType == typeof(string) && readerField.Type == typeof(Guid))
                                {
                                    // This is Guid.ToString()
                                    targetMethod    = typeof(Guid).GetTypeInfo().GetMethod("ToString", new Type[0]);
                                    targetInstance  = falseExpression;
                                    targetParameter = null;
                                }
                                else
                                {
                                    // This System.Convert.To<Type>()
                                    targetMethod    = typeof(Convert).GetTypeInfo().GetMethod(string.Concat("To", propertyType.Name), new[] { convertType });
                                    targetInstance  = null;
                                    targetParameter = falseExpression;
                                }

                                // If there are methods found from System.Convert(), then use it, otherwise use the normal
                                if (targetMethod != null)
                                {
                                    if (targetParameter == null)
                                    {
                                        falseExpression = Expression.Call(targetInstance, targetMethod);
                                    }
                                    else
                                    {
                                        falseExpression = Expression.Call(targetInstance, targetMethod, targetParameter);
                                    }
                                }
                                else
                                {
                                    // There are coersion problem on certain types (i.e: Guid-to-String (vice versa))
                                    falseExpression = Expression.Convert(falseExpression, propertyType);
                                }
                            }
                        }
                        if (underlyingType != null && underlyingType.GetTypeInfo().IsValueType == true)
                        {
                            var nullableConstructorExpression = typeof(Nullable <>).MakeGenericType(propertyType).GetTypeInfo().GetConstructor(new[] { propertyType });
                            falseExpression = Expression.New(nullableConstructorExpression, falseExpression);
                        }

                        // Set the value
                        valueExpression = Expression.Condition(isDbNullExpression, trueExpression, falseExpression);
                    }
                    else
                    {
                        // Call the actual Get<Type>/GetValue method by ordinal
                        valueExpression = Expression.Call(readerParameterExpression,
                                                          readerGetValueMethod,
                                                          ordinalExpression);

                        // Convert to correct type if necessary
                        if (isConversionNeeded == true)
                        {
                            valueExpression = Expression.Convert(valueExpression, propertyType);
                        }

                        // Set for the 'Nullable' property
                        if (underlyingType != null && underlyingType.GetTypeInfo().IsValueType == true)
                        {
                            var nullableConstructorExpression = typeof(Nullable <>).MakeGenericType(propertyType).GetTypeInfo().GetConstructor(new[] { propertyType });
                            valueExpression = Expression.New(nullableConstructorExpression, valueExpression);
                        }
                    }

                    // Set the actual property value
                    memberAssignments.Add(Expression.Bind(property.PropertyInfo, valueExpression));
                }
            }

            // Return the result
            return(memberAssignments);
        }
Ejemplo n.º 3
0
        /// <summary>
        /// Returns the list of the bindings for the entity.
        /// </summary>
        /// <typeparam name="TEntity">The target entity type.</typeparam>
        /// <param name="newEntityExpression">The new entity expression.</param>
        /// <param name="readerParameterExpression">The data reader parameter.</param>
        /// <param name="readerFields">The list of fields to be bound from the data reader.</param>
        /// <returns>The enumerable list of member assignment and bindings.</returns>
        private static IEnumerable <MemberAssignment> GetMemberAssignments <TEntity>(Expression newEntityExpression,
                                                                                     ParameterExpression readerParameterExpression, IEnumerable <DataReaderFieldDefinition> readerFields)
            where TEntity : class
        {
            // Initialize variables
            var memberAssignments = new List <MemberAssignment>();
            var dataReaderType    = typeof(DbDataReader);
            var tableFields       = FieldDefinitionCache.Get <TEntity>();
            var properties        = PropertyCache.Get <TEntity>(Command.Query)
                                    .Where(property => property.PropertyInfo.CanWrite)
                                    .ToList();

            // Iterate each properties
            properties?.ForEach(property =>
            {
                // Gets the mapped name and the ordinal
                var mappedName = property.GetMappedName().ToLower();
                var ordinal    = readerFields?.Select(f => f.Name).ToList().IndexOf(mappedName);

                // Process only if there is a correct ordinal
                if (ordinal >= 0)
                {
                    // Variables needed for the iteration
                    var tableField           = tableFields?.FirstOrDefault(f => f.Name.ToLower() == mappedName);
                    var readerField          = readerFields.First(f => f.Name.ToLower() == mappedName);
                    var isTableFieldNullable = tableField == null || tableField?.IsNullable == true;
                    var underlyingType       = Nullable.GetUnderlyingType(property.PropertyInfo.PropertyType);
                    var propertyType         = underlyingType ?? property.PropertyInfo.PropertyType;
                    var isConversionNeeded   = readerField?.Type != propertyType;

                    // Get the correct method info, if the reader.Get<Type> is not found, then use the default GetValue
                    var readerGetValueMethod = dataReaderType.GetMethod(string.Concat("Get", readerField?.Type.Name));
                    if (readerGetValueMethod == null)
                    {
                        readerGetValueMethod = dataReaderType.GetMethod(string.Concat("Get", propertyType.Name)) ??
                                               dataReaderType.GetMethod("GetValue");
                        isConversionNeeded = true; // Force
                    }

                    // Expressions
                    var ordinalExpression = Expression.Constant(ordinal);
                    var valueExpression   = (Expression)null;

                    // Check for nullables
                    if (isTableFieldNullable == true)
                    {
                        var isDbNullExpression = Expression.Call(readerParameterExpression, dataReaderType.GetMethod("IsDBNull"), ordinalExpression);

                        // True expression
                        var trueExpression = (Expression)null;
                        if (underlyingType != null && underlyingType.IsValueType == true)
                        {
                            trueExpression = Expression.New(typeof(Nullable <>).MakeGenericType(propertyType));
                        }
                        else
                        {
                            trueExpression = Expression.Default(propertyType);
                        }

                        // False expression
                        var falseExpression = (Expression)Expression.Call(readerParameterExpression, readerGetValueMethod, ordinalExpression);
                        if (isConversionNeeded == true)
                        {
                            falseExpression = Expression.Convert(falseExpression, propertyType);
                        }
                        if (underlyingType != null && underlyingType.IsValueType == true)
                        {
                            var nullableConstructorExpression = typeof(Nullable <>).MakeGenericType(propertyType).GetConstructor(new[] { propertyType });
                            falseExpression = Expression.New(nullableConstructorExpression, falseExpression);
                        }

                        // Set the value
                        valueExpression = Expression.Condition(isDbNullExpression, trueExpression, falseExpression);
                    }
                    else
                    {
                        // Call the actual Get<Type>/GetValue method by ordinal
                        valueExpression = Expression.Call(readerParameterExpression,
                                                          readerGetValueMethod,
                                                          ordinalExpression);

                        // Convert to correct type if necessary
                        if (isConversionNeeded == true)
                        {
                            valueExpression = Expression.Convert(valueExpression, propertyType);
                        }

                        // Set for the 'Nullable' property
                        if (underlyingType != null && underlyingType.IsValueType == true)
                        {
                            var nullableConstructorExpression = typeof(Nullable <>).MakeGenericType(propertyType).GetConstructor(new[] { propertyType });
                            valueExpression = Expression.New(nullableConstructorExpression, valueExpression);
                        }
                    }

                    // Set the actual property value
                    memberAssignments.Add(Expression.Bind(property.PropertyInfo, valueExpression));
                }
            });

            // Return the result
            return(memberAssignments);
        }