예제 #1
0
        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);
        }
예제 #2
0
 /// <summary>
 ///     ScalarColumnMap
 /// </summary>
 internal override ColumnMap Visit(ScalarColumnMap columnMap, VarMap replacementVarMap)
 {
     return(new ScalarColumnMap(columnMap.Type, columnMap.Name, columnMap.CommandId, columnMap.ColumnPos));
 }