private static string GetRowTypeIdentityFromProperties( IEnumerable <EdmProperty> properties, InitializerMetadata initializerMetadata) { StringBuilder builder = new StringBuilder("rowtype["); if (properties != null) { int num = 0; foreach (EdmProperty property in properties) { if (num > 0) { builder.Append(","); } builder.Append("("); builder.Append(property.Name); builder.Append(","); property.TypeUsage.BuildIdentity(builder); builder.Append(")"); ++num; } } builder.Append("]"); if (initializerMetadata != null) { builder.Append(",").Append(initializerMetadata.Identity); } return(builder.ToString()); }
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 InitializerMetadata GetCanonicalInitializerMetadata( InitializerMetadata metadata) { if (this._getCanonicalInitializerMetadataMemoizer == null) { Interlocked.CompareExchange <Memoizer <InitializerMetadata, InitializerMetadata> >(ref this._getCanonicalInitializerMetadataMemoizer, new Memoizer <InitializerMetadata, InitializerMetadata>((Func <InitializerMetadata, InitializerMetadata>)(m => m), (IEqualityComparer <InitializerMetadata>)EqualityComparer <InitializerMetadata> .Default), (Memoizer <InitializerMetadata, InitializerMetadata>)null); } return(this._getCanonicalInitializerMetadataMemoizer.Evaluate(metadata)); }
internal static RowType CreateRowType( IEnumerable <KeyValuePair <string, TypeUsage> > columns, InitializerMetadata initializerMetadata) { List <EdmProperty> edmPropertyList = new List <EdmProperty>(); foreach (KeyValuePair <string, TypeUsage> column in columns) { edmPropertyList.Add(new EdmProperty(column.Key, column.Value)); } return(new RowType((IEnumerable <EdmProperty>)edmPropertyList, initializerMetadata)); }
internal RowType(IEnumerable <EdmProperty> properties, InitializerMetadata initializerMetadata) : base(RowType.GetRowTypeIdentityFromProperties(RowType.CheckProperties(properties), initializerMetadata), "Transient", ~DataSpace.OSpace) { if (properties != null) { foreach (EdmProperty property in properties) { this.AddProperty(property); } } this._initializerMetadata = initializerMetadata; this.SetReadOnly(); }
internal void Append(string prefix, TypeUsage type) { if (type == null) { return; } InitializerMetadata initializerMetadata; if (InitializerMetadata.TryGetInitializerMetadata(type, out initializerMetadata)) { initializerMetadata.AppendColumnMapKey(this); } this.Append(prefix, type.EdmType); }
/// <summary> /// Given an InitializerMetadata instance, returns the canonical version of that instance. /// This allows us to avoid compiling materialization delegates repeatedly for the same /// pattern. /// </summary> internal InitializerMetadata GetCanonicalInitializerMetadata(InitializerMetadata metadata) { if (null == _getCanonicalInitializerMetadataMemoizer) { // We memoize the identity function because the first evaluation of the function establishes // the canonical 'reference' for the initializer metadata with a particular 'value'. Interlocked.CompareExchange(ref _getCanonicalInitializerMetadataMemoizer, new Memoizer <InitializerMetadata, InitializerMetadata>( m => m, EqualityComparer <InitializerMetadata> .Default), null); } // check if an equivalent has already been registered InitializerMetadata canonical = _getCanonicalInitializerMetadataMemoizer.Evaluate(metadata); return(canonical); }
internal void Append(string prefix, TypeUsage type) { if (null != type) { // LINQ has anonymous types that aren't going to show up in our // metadata workspace, and we don't want to hydrate a record when // we need an anonymous type. LINQ solves this by annotating the // edmType with some additional information, which we'll pick up // here. InitializerMetadata initializer; if (InitializerMetadata.TryGetInitializerMetadata(type, out initializer)) { initializer.AppendColumnMapKey(this); } Append(prefix, type.EdmType); } }
/// <summary> /// Initializes a RowType with the given members and initializer metadata /// </summary> internal RowType(IEnumerable<EdmProperty> properties, InitializerMetadata initializerMetadata) : base(GetRowTypeIdentityFromProperties(CheckProperties(properties), initializerMetadata), EdmConstants.TransientNamespace, (DataSpace)(-1)) { // Initialize the properties. if (null != properties) { foreach (EdmProperty property in properties) { this.AddProperty(property); } } _initializerMetadata = initializerMetadata; // Row types are immutable, so now that we're done initializing, set it // to be read-only. SetReadOnly(); }
/// <summary> /// Initializes a RowType with the given members and initializer metadata /// </summary> internal RowType(IEnumerable <EdmProperty> properties, InitializerMetadata initializerMetadata) : base(GetRowTypeIdentityFromProperties(CheckProperties(properties), initializerMetadata), EdmConstants.TransientNamespace, (DataSpace)(-1)) { // Initialize the properties. if (null != properties) { foreach (EdmProperty property in properties) { this.AddProperty(property); } } _initializerMetadata = initializerMetadata; // Row types are immutable, so now that we're done initializing, set it // to be read-only. SetReadOnly(); }
/// <summary> /// Given an InitializerMetadata instance, returns the canonical version of that instance. /// This allows us to avoid compiling materialization delegates repeatedly for the same /// pattern. /// </summary> internal InitializerMetadata GetCanonicalInitializerMetadata(InitializerMetadata metadata) { if (null == _getCanonicalInitializerMetadataMemoizer) { // We memoize the identity function because the first evaluation of the function establishes // the canonical 'reference' for the initializer metadata with a particular 'value'. Interlocked.CompareExchange(ref _getCanonicalInitializerMetadataMemoizer, new Memoizer<InitializerMetadata, InitializerMetadata>( m => m, EqualityComparer<InitializerMetadata>.Default), null); } // check if an equivalent has already been registered InitializerMetadata canonical = _getCanonicalInitializerMetadataMemoizer.Evaluate(metadata); return canonical; }
// <summary> // Calculates the row type identity that would result from // a given set of properties. // </summary> // <param name="properties"> The properties that determine the row type's structure </param> // <param name="initializerMetadata"> Metadata describing materialization of this row type </param> // <returns> A string that identifies the row type </returns> private static string GetRowTypeIdentityFromProperties(IEnumerable<EdmProperty> properties, InitializerMetadata initializerMetadata) { // The row type identity is formed as follows: // "rowtype[" + a comma-separated list of property identities + "]" var identity = new StringBuilder("rowtype["); if (null != properties) { var i = 0; // For each property, append the type name and facets. foreach (var property in properties) { if (i > 0) { identity.Append(","); } identity.Append("("); identity.Append(property.Name); identity.Append(","); property.TypeUsage.BuildIdentity(identity); identity.Append(")"); i++; } } identity.Append("]"); if (null != initializerMetadata) { identity.Append(",").Append(initializerMetadata.Identity); } return identity.ToString(); }
/// <summary> /// Requires: a public type with a public, default constructor. Returns a column map initializing the type /// and all properties of the type with a public setter taking a primitive type and having a corresponding /// column in the reader. /// </summary> internal static CollectionColumnMap CreateColumnMapFromReaderAndClrType(DbDataReader reader, Type type, MetadataWorkspace workspace) { Debug.Assert(null != reader); Debug.Assert(null != type); Debug.Assert(null != workspace); // we require a default constructor ConstructorInfo constructor = type.GetConstructor(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance, null, Type.EmptyTypes, null); if (type.IsAbstract || (null == constructor && !type.IsValueType)) { throw EntityUtil.InvalidOperation( Strings.ObjectContext_InvalidTypeForStoreQuery(type)); } // build a LINQ expression used by result assembly to create results var memberInfo = new List <Tuple <MemberAssignment, int, EdmProperty> >(); foreach (PropertyInfo prop in type.GetProperties(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance)) { // for enums unwrap the type if nullable var propertyUnderlyingType = Nullable.GetUnderlyingType(prop.PropertyType) ?? prop.PropertyType; Type propType = propertyUnderlyingType.IsEnum ? propertyUnderlyingType.GetEnumUnderlyingType() : prop.PropertyType; EdmType modelType; int ordinal; if (TryGetColumnOrdinalFromReader(reader, prop.Name, out ordinal) && MetadataHelper.TryDetermineCSpaceModelType(propType, workspace, out modelType) && (Helper.IsScalarType(modelType)) && prop.CanWrite && prop.GetIndexParameters().Length == 0 && null != prop.GetSetMethod(/* nonPublic */ true)) { 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 MemberInfo[] members = new MemberInfo[memberInfo.Count]; MemberBinding[] memberBindings = new MemberBinding[memberInfo.Count]; ColumnMap[] propertyMaps = new ColumnMap[memberInfo.Count]; EdmProperty[] modelProperties = new EdmProperty[memberInfo.Count]; int 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 EntityUtil.InvalidOperation(Strings.ObjectContext_TwoPropertiesMappedToSameColumn( reader.GetName(memberGroup.Key), String.Join(", ", memberGroup.Select(tuple => tuple.Item3.Name).ToArray()))); } var member = memberGroup.Single(); MemberAssignment assignment = member.Item1; int ordinal = member.Item2; EdmProperty modelProp = member.Item3; members[i] = assignment.Member; memberBindings[i] = assignment; propertyMaps[i] = new ScalarColumnMap(modelProp.TypeUsage, modelProp.Name, 0, ordinal); modelProperties[i] = modelProp; i++; } NewExpression newExpr = null == constructor?Expression.New(type) : Expression.New(constructor); MemberInitExpression init = Expression.MemberInit(newExpr, memberBindings); InitializerMetadata initMetadata = InitializerMetadata.CreateProjectionInitializer( (EdmItemCollection)workspace.GetItemCollection(DataSpace.CSpace), init, members); // column map (a collection of rows with InitializerMetadata markup) RowType rowType = new RowType(modelProperties, initMetadata); RecordColumnMap rowMap = new RecordColumnMap(TypeUsage.Create(rowType), "DefaultTypeProjection", propertyMaps, null); CollectionColumnMap collectionMap = new SimpleCollectionColumnMap(rowType.GetCollectionType().TypeUsage, rowType.Name, rowMap, null, null); return(collectionMap); }
internal void ValidateInitializerMetadata(InitializerMetadata metadata) { DebugCheck.NotNull(metadata); InitializerMetadata existingMetadata; if (_initializers != null && _initializers.TryGetValue(metadata.ClrType, out existingMetadata)) { // Verify the initializers are compatible. if (!metadata.Equals(existingMetadata)) { throw new NotSupportedException( Strings.ELinq_UnsupportedHeterogeneousInitializers( DescribeClrType(metadata.ClrType))); } } else { // Register the metadata so that subsequent initializers for this type can be verified. if (_initializers == null) { _initializers = new Dictionary<Type, InitializerMetadata>(); } _initializers.Add(metadata.ClrType, metadata); } }
private static DbNewInstanceExpression CreateNewRowExpression( List<KeyValuePair<string, DbExpression>> columns, InitializerMetadata initializerMetadata) { var propertyValues = new List<DbExpression>(columns.Count); var properties = new List<EdmProperty>(columns.Count); for (var i = 0; i < columns.Count; i++) { var column = columns[i]; propertyValues.Add(column.Value); properties.Add(new EdmProperty(column.Key, column.Value.ResultType)); } var rowType = new RowType(properties, initializerMetadata); var typeUsage = TypeUsage.Create(rowType); return typeUsage.New(propertyValues); }
internal static RowType CreateRowType(IEnumerable <KeyValuePair <string, TypeUsage> > columns, InitializerMetadata initializerMetadata) { var rowElements = new List <EdmProperty>(); foreach (var kvp in columns) { rowElements.Add(new EdmProperty(kvp.Key, kvp.Value)); } return(new RowType(rowElements, initializerMetadata)); }
/// <summary> /// Calculates the row type identity that would result from /// a given set of properties. /// </summary> /// <param name="properties">The properties that determine the row type's structure</param> /// <param name="initializerMetadata">Metadata describing materialization of this row type</param> /// <returns>A string that identifies the row type</returns> private static string GetRowTypeIdentityFromProperties(IEnumerable <EdmProperty> properties, InitializerMetadata initializerMetadata) { // The row type identity is formed as follows: // "rowtype[" + a comma-separated list of property identities + "]" StringBuilder identity = new StringBuilder("rowtype["); if (null != properties) { int i = 0; // For each property, append the type name and facets. foreach (EdmProperty property in properties) { if (i > 0) { identity.Append(","); } identity.Append("("); identity.Append(property.Name); identity.Append(","); property.TypeUsage.BuildIdentity(identity); identity.Append(")"); i++; } } identity.Append("]"); if (null != initializerMetadata) { identity.Append(",").Append(initializerMetadata.Identity); } return(identity.ToString()); }
internal void ValidateInitializerMetadata(InitializerMetadata metadata) { Debug.Assert(null != metadata); InitializerMetadata existingMetadata; if (_initializers != null && _initializers.TryGetValue(metadata.ClrType, out existingMetadata)) { // Verify the initializers are compatible. if (!metadata.Equals(existingMetadata)) { throw EntityUtil.NotSupported(System.Data.Entity.Strings.ELinq_UnsupportedHeterogeneousInitializers( ExpressionConverter.DescribeClrType(metadata.ClrType))); } } else { // Register the metadata so that subsequent initializers for this type can be verified. if (_initializers == null) { _initializers = new Dictionary<Type, InitializerMetadata>(); } _initializers.Add(metadata.ClrType, metadata); } }