internal virtual CollectionColumnMap CreateColumnMapFromReaderAndClrType( DbDataReader reader, Type type, MetadataWorkspace workspace) { ConstructorInfo declaredConstructor = type.GetDeclaredConstructor(); if (type.IsAbstract() || (ConstructorInfo)null == declaredConstructor && !type.IsValueType()) { throw new InvalidOperationException(Strings.ObjectContext_InvalidTypeForStoreQuery((object)type)); } List <Tuple <MemberAssignment, int, EdmProperty> > source1 = new List <Tuple <MemberAssignment, int, EdmProperty> >(); foreach (PropertyInfo propertyInfo in type.GetInstanceProperties().Select <PropertyInfo, PropertyInfo>((Func <PropertyInfo, PropertyInfo>)(p => p.GetPropertyInfoForSet()))) { Type type1 = Nullable.GetUnderlyingType(propertyInfo.PropertyType); if ((object)type1 == null) { type1 = propertyInfo.PropertyType; } Type type2 = type1; Type type3 = type2.IsEnum() ? type2.GetEnumUnderlyingType() : propertyInfo.PropertyType; int ordinal; EdmType modelEdmType; if (ColumnMapFactory.TryGetColumnOrdinalFromReader(reader, propertyInfo.Name, out ordinal) && workspace.TryDetermineCSpaceModelType(type3, out modelEdmType) && (Helper.IsScalarType(modelEdmType) && propertyInfo.CanWriteExtended()) && (propertyInfo.GetIndexParameters().Length == 0 && (MethodInfo)null != propertyInfo.Setter())) { source1.Add(Tuple.Create <MemberAssignment, int, EdmProperty>(Expression.Bind((MemberInfo)propertyInfo, (Expression)Expression.Parameter(propertyInfo.PropertyType, "placeholder")), ordinal, new EdmProperty(propertyInfo.Name, TypeUsage.Create(modelEdmType)))); } } MemberInfo[] memberInfoArray = new MemberInfo[source1.Count]; MemberBinding[] memberBindingArray = new MemberBinding[source1.Count]; ColumnMap[] properties = new ColumnMap[source1.Count]; EdmProperty[] edmPropertyArray = new EdmProperty[source1.Count]; int index = 0; foreach (IGrouping <int, Tuple <MemberAssignment, int, EdmProperty> > source2 in (IEnumerable <IGrouping <int, Tuple <MemberAssignment, int, EdmProperty> > >)source1.GroupBy <Tuple <MemberAssignment, int, EdmProperty>, int>((Func <Tuple <MemberAssignment, int, EdmProperty>, int>)(tuple => tuple.Item2)).OrderBy <IGrouping <int, Tuple <MemberAssignment, int, EdmProperty> >, int>((Func <IGrouping <int, Tuple <MemberAssignment, int, EdmProperty> >, int>)(tuple => tuple.Key))) { if (source2.Count <Tuple <MemberAssignment, int, EdmProperty> >() != 1) { throw new InvalidOperationException(Strings.ObjectContext_TwoPropertiesMappedToSameColumn((object)reader.GetName(source2.Key), (object)string.Join(", ", source2.Select <Tuple <MemberAssignment, int, EdmProperty>, string>((Func <Tuple <MemberAssignment, int, EdmProperty>, string>)(tuple => tuple.Item3.Name)).ToArray <string>()))); } Tuple <MemberAssignment, int, EdmProperty> tuple1 = source2.Single <Tuple <MemberAssignment, int, EdmProperty> >(); MemberAssignment memberAssignment = tuple1.Item1; int columnPos = tuple1.Item2; EdmProperty edmProperty = tuple1.Item3; memberInfoArray[index] = memberAssignment.Member; memberBindingArray[index] = (MemberBinding)memberAssignment; properties[index] = (ColumnMap) new ScalarColumnMap(edmProperty.TypeUsage, edmProperty.Name, 0, columnPos); edmPropertyArray[index] = edmProperty; ++index; } MemberInitExpression initExpression = Expression.MemberInit((ConstructorInfo)null == declaredConstructor ? Expression.New(type) : Expression.New(declaredConstructor), memberBindingArray); InitializerMetadata projectionInitializer = InitializerMetadata.CreateProjectionInitializer((EdmItemCollection)workspace.GetItemCollection(DataSpace.CSpace), initExpression); RowType rowType = new RowType((IEnumerable <EdmProperty>)edmPropertyArray, projectionInitializer); RecordColumnMap recordColumnMap = new RecordColumnMap(TypeUsage.Create((EdmType)rowType), "DefaultTypeProjection", properties, (SimpleColumnMap)null); return((CollectionColumnMap) new SimpleCollectionColumnMap(rowType.GetCollectionType().TypeUsage, rowType.Name, (ColumnMap)recordColumnMap, (SimpleColumnMap[])null, (SimpleColumnMap[])null)); }
internal override ColumnMap Visit(RecordColumnMap columnMap, VarMap replacementVarMap) { SimpleColumnMap nullSentinel = columnMap.NullSentinel; if (nullSentinel != null) { nullSentinel = (SimpleColumnMap)nullSentinel.Accept <ColumnMap, VarMap>((ColumnMapVisitorWithResults <ColumnMap, VarMap>) this, replacementVarMap); } ColumnMap[] properties = this.VisitList <ColumnMap>(columnMap.Properties, replacementVarMap); return((ColumnMap) new RecordColumnMap(columnMap.Type, columnMap.Name, properties, nullSentinel)); }
/// <summary> /// RecordColumnMap /// </summary> /// <param name="columnMap"> </param> /// <param name="replacementVarMap"> </param> /// <returns> </returns> internal override ColumnMap Visit(RecordColumnMap columnMap, VarMap replacementVarMap) { var newNullability = columnMap.NullSentinel; if (null != newNullability) { newNullability = (SimpleColumnMap)newNullability.Accept(this, replacementVarMap); } var fieldList = VisitList(columnMap.Properties, replacementVarMap); return(new RecordColumnMap(columnMap.Type, columnMap.Name, fieldList, newNullability)); }
internal override void Visit(RecordColumnMap columnMap, Dump dumper) { using (new Dump.AutoXml(dumper, "Record", Dump.ColumnMapDumper.GetAttributes((ColumnMap)columnMap))) { if (columnMap.NullSentinel != null) { using (new Dump.AutoXml(dumper, "nullSentinel")) columnMap.NullSentinel.Accept <Dump>((ColumnMapVisitor <Dump>) this, dumper); } this.VisitList <ColumnMap>(columnMap.Properties, dumper); } }
/// <summary> /// RecordColumnMap /// </summary> internal override void Visit(RecordColumnMap columnMap, Dump dumper) { using (new AutoXml(dumper, "Record", GetAttributes(columnMap))) { if (columnMap.NullSentinel != null) { using (new AutoXml(dumper, "nullSentinel")) { columnMap.NullSentinel.Accept(this, dumper); } } VisitList(columnMap.Properties, dumper); } }
// <summary> // Build the collectionColumnMap from a store datareader, a type and an entitySet. // </summary> internal virtual CollectionColumnMap CreateColumnMapFromReaderAndType( DbDataReader storeDataReader, EdmType edmType, EntitySet entitySet, Dictionary <string, FunctionImportReturnTypeStructuralTypeColumnRenameMapping> renameList) { Debug.Assert( Helper.IsEntityType(edmType) || null == entitySet, "The specified non-null EntitySet is incompatible with the EDM type specified."); // Next, build the ColumnMap directly from the edmType and entitySet provided. var propertyColumnMaps = GetColumnMapsForType(storeDataReader, edmType, renameList); ColumnMap elementColumnMap = null; // NOTE: We don't have a null sentinel here, because the stored proc won't // return one anyway; we'll just presume the data's always there. if (Helper.IsRowType(edmType)) { elementColumnMap = new RecordColumnMap(TypeUsage.Create(edmType), edmType.Name, propertyColumnMaps, null); } else if (Helper.IsComplexType(edmType)) { elementColumnMap = new ComplexTypeColumnMap(TypeUsage.Create(edmType), edmType.Name, propertyColumnMaps, null); } else if (Helper.IsScalarType(edmType)) { if (storeDataReader.FieldCount != 1) { throw new EntityCommandExecutionException(Strings.ADP_InvalidDataReaderFieldCountForScalarType); } elementColumnMap = new ScalarColumnMap(TypeUsage.Create(edmType), edmType.Name, 0, 0); } else if (Helper.IsEntityType(edmType)) { elementColumnMap = CreateEntityTypeElementColumnMap( storeDataReader, edmType, entitySet, propertyColumnMaps, null /*renameList*/); } else { Debug.Assert(false, "unexpected edmType?"); } CollectionColumnMap collection = new SimpleCollectionColumnMap( edmType.GetCollectionType().TypeUsage, edmType.Name, elementColumnMap, null, null); return(collection); }
internal virtual CollectionColumnMap CreateColumnMapFromReaderAndClrType( DbDataReader reader, Type type, MetadataWorkspace workspace) { DebugCheck.NotNull(reader); DebugCheck.NotNull(type); DebugCheck.NotNull(workspace); // we require a default constructor var constructor = type.GetDeclaredConstructor(); if (type.IsAbstract() || (null == constructor && !type.IsValueType())) { throw new InvalidOperationException(Strings.ObjectContext_InvalidTypeForStoreQuery(type)); } // build a LINQ expression used by result assembly to create results var memberInfo = new List <Tuple <MemberAssignment, int, EdmProperty> >(); foreach (var prop in type.GetInstanceProperties() .Select(p => p.GetPropertyInfoForSet())) { // for enums unwrap the type if nullable var propertyUnderlyingType = Nullable.GetUnderlyingType(prop.PropertyType) ?? prop.PropertyType; var propType = propertyUnderlyingType.IsEnum() ? propertyUnderlyingType.GetEnumUnderlyingType() : prop.PropertyType; EdmType modelType; int ordinal; if (TryGetColumnOrdinalFromReader(reader, prop.Name, out ordinal) && workspace.TryDetermineCSpaceModelType(propType, out modelType) && (Helper.IsScalarType(modelType)) && prop.CanWriteExtended() && prop.GetIndexParameters().Length == 0 && null != prop.Setter()) { memberInfo.Add( Tuple.Create( Expression.Bind(prop, Expression.Parameter(prop.PropertyType, "placeholder")), ordinal, new EdmProperty(prop.Name, TypeUsage.Create(modelType)))); } } // initialize members in the order in which they appear in the reader var members = new MemberInfo[memberInfo.Count]; var memberBindings = new MemberBinding[memberInfo.Count]; var propertyMaps = new ColumnMap[memberInfo.Count]; var modelProperties = new EdmProperty[memberInfo.Count]; var i = 0; foreach (var memberGroup in memberInfo.GroupBy(tuple => tuple.Item2).OrderBy(tuple => tuple.Key)) { // make sure that a single column isn't contributing to multiple properties if (memberGroup.Count() != 1) { throw new InvalidOperationException( Strings.ObjectContext_TwoPropertiesMappedToSameColumn( reader.GetName(memberGroup.Key), String.Join(", ", memberGroup.Select(tuple => tuple.Item3.Name).ToArray()))); } var member = memberGroup.Single(); var assignment = member.Item1; var ordinal = member.Item2; var modelProp = member.Item3; members[i] = assignment.Member; memberBindings[i] = assignment; propertyMaps[i] = new ScalarColumnMap(modelProp.TypeUsage, modelProp.Name, 0, ordinal); modelProperties[i] = modelProp; i++; } var newExpr = null == constructor?Expression.New(type) : Expression.New(constructor); var init = Expression.MemberInit(newExpr, memberBindings); var initMetadata = InitializerMetadata.CreateProjectionInitializer( (EdmItemCollection)workspace.GetItemCollection(DataSpace.CSpace), init); // column map (a collection of rows with InitializerMetadata markup) var rowType = new RowType(modelProperties, initMetadata); var rowMap = new RecordColumnMap( TypeUsage.Create(rowType), "DefaultTypeProjection", propertyMaps, null); CollectionColumnMap collectionMap = new SimpleCollectionColumnMap( rowType.GetCollectionType().TypeUsage, rowType.Name, rowMap, null, null); return(collectionMap); }