/// <summary> /// This is an internal API that supports the Entity Framework Core infrastructure and not subject to /// the same compatibility standards as public APIs. It may be changed or removed without notice in /// any release. You should only use it directly in your code with extreme caution and knowing that /// doing so can result in application failures when updating to a new Entity Framework Core release. /// </summary> public override IRelationalValueBufferFactory CreateValueBufferFactory( IRelationalValueBufferFactoryFactory relationalValueBufferFactoryFactory, DbDataReader dataReader) { Check.NotNull(relationalValueBufferFactoryFactory, nameof(relationalValueBufferFactoryFactory)); Check.NotNull(dataReader, nameof(dataReader)); var readerColumns = Enumerable .Range(0, dataReader.FieldCount) .Select( i => new { Name = dataReader.GetName(i), Ordinal = i }) .ToList(); var types = new TypeMaterializationInfo[SelectExpression.Projection.Count]; for (var i = 0; i < SelectExpression.Projection.Count; i++) { if (SelectExpression.Projection[i] is ColumnExpression columnExpression) { var columnName = columnExpression.Name; if (columnName != null) { var readerColumn = readerColumns.SingleOrDefault( c => string.Equals(columnName, c.Name, StringComparison.OrdinalIgnoreCase)); if (readerColumn == null) { throw new InvalidOperationException(RelationalStrings.FromSqlMissingColumn(columnName)); } types[i] = new TypeMaterializationInfo( columnExpression.Type, columnExpression.Property, Dependencies.TypeMappingSource, fromLeftOuterJoin: false, readerColumn.Ordinal); } } } return(relationalValueBufferFactoryFactory.Create(types)); }
private static Expression CreateGetValueExpression( Expression dataReaderExpression, int index, TypeMaterializationInfo materializationInfo, bool detailedErrorsEnabled, bool box = true) { var getMethod = materializationInfo.Mapping.GetDataReaderMethod(); index = materializationInfo.Index == -1 ? index : materializationInfo.Index; var indexExpression = Expression.Constant(index); Expression valueExpression = Expression.Call( getMethod.DeclaringType != typeof(DbDataReader) ? Expression.Convert(dataReaderExpression, getMethod.DeclaringType) : dataReaderExpression, getMethod, indexExpression); valueExpression = materializationInfo.Mapping.CustomizeDataReaderExpression(valueExpression); var converter = materializationInfo.Mapping.Converter; if (converter != null) { if (valueExpression.Type != converter.ProviderClrType) { valueExpression = Expression.Convert(valueExpression, converter.ProviderClrType); } valueExpression = ReplacingExpressionVisitor.Replace( converter.ConvertFromProviderExpression.Parameters.Single(), valueExpression, converter.ConvertFromProviderExpression.Body); } if (valueExpression.Type != materializationInfo.ModelClrType) { valueExpression = Expression.Convert(valueExpression, materializationInfo.ModelClrType); } var exceptionParameter = Expression.Parameter(typeof(Exception), name: "e"); var property = materializationInfo.Property; if (detailedErrorsEnabled) { var catchBlock = Expression .Catch( exceptionParameter, Expression.Call( _throwReadValueExceptionMethod .MakeGenericMethod(valueExpression.Type), exceptionParameter, Expression.Call( dataReaderExpression, _getFieldValueMethod.MakeGenericMethod(typeof(object)), indexExpression), Expression.Constant(property, typeof(IPropertyBase)))); valueExpression = Expression.TryCatch(valueExpression, catchBlock); } if (box && valueExpression.Type.GetTypeInfo().IsValueType) { valueExpression = Expression.Convert(valueExpression, typeof(object)); } if (property?.IsNullable != false || property.DeclaringEntityType.BaseType != null || materializationInfo.IsFromLeftOuterJoin != false) { valueExpression = Expression.Condition( Expression.Call(dataReaderExpression, _isDbNullMethod, indexExpression), Expression.Default(valueExpression.Type), valueExpression); } return(valueExpression); }
/// <summary> /// Determines whether the specified object is equal to the current object. /// </summary> /// <param name="other">The object to compare with the current object.</param> /// <returns><see langword="true" /> if the specified object is equal to the current object; otherwise, <see langword="false" />.</returns> protected virtual bool Equals(TypeMaterializationInfo other) => ProviderClrType == other.ProviderClrType && ModelClrType == other.ModelClrType && Equals(Mapping, other.Mapping) && Equals(Property, other.Property) && IsNullable == other.IsNullable;