You've already forked linux-packaging-mono
							
							
		
			
				
	
	
		
			547 lines
		
	
	
		
			23 KiB
		
	
	
	
		
			C#
		
	
	
	
	
	
			
		
		
	
	
			547 lines
		
	
	
		
			23 KiB
		
	
	
	
		
			C#
		
	
	
	
	
	
| //---------------------------------------------------------------------
 | |
| // <copyright file="InitializerFacet.cs" company="Microsoft">
 | |
| //      Copyright (c) Microsoft Corporation.  All rights reserved.
 | |
| // </copyright>
 | |
| //
 | |
| // @owner  Microsoft
 | |
| //---------------------------------------------------------------------
 | |
| 
 | |
| namespace System.Data.Objects.ELinq
 | |
| {
 | |
|     using System.Collections.Generic;
 | |
|     using System.Data.Common;
 | |
|     using System.Data.Common.Internal.Materialization;
 | |
|     using System.Data.Metadata.Edm;
 | |
|     using System.Data.Objects.DataClasses;
 | |
|     using System.Data.Objects.Internal;
 | |
|     using System.Diagnostics;
 | |
|     using System.Globalization;
 | |
|     using System.Linq;
 | |
|     using System.Linq.Expressions;
 | |
|     using System.Reflection;
 | |
|     using System.Security;
 | |
|     using System.Security.Permissions;
 | |
|     using System.Threading;
 | |
| 
 | |
|     /// <summary>
 | |
|     /// Facet encapsulating information necessary to initialize a LINQ projection
 | |
|     /// result.
 | |
|     /// </summary>
 | |
|     internal abstract class InitializerMetadata : IEquatable<InitializerMetadata>
 | |
|     {
 | |
|         internal readonly Type ClrType;
 | |
|         internal static readonly MethodInfo UserExpressionMarker = typeof(InitializerMetadata).GetMethod("MarkAsUserExpression", BindingFlags.NonPublic | BindingFlags.Static);
 | |
|         private static long s_identifier;
 | |
|         internal readonly string Identity;
 | |
|         private static readonly string s_identifierPrefix = typeof(InitializerMetadata).Name;
 | |
| 
 | |
|         private InitializerMetadata(Type clrType)
 | |
|         {
 | |
|             Debug.Assert(null != clrType);
 | |
|             ClrType = clrType;
 | |
|             Identity = s_identifierPrefix + Interlocked.Increment(ref s_identifier).ToString(CultureInfo.InvariantCulture);
 | |
|         }
 | |
| 
 | |
|         // Gets the kind of this initializer (grouping, row, etc.)
 | |
|         internal abstract InitializerMetadataKind Kind { get; }
 | |
| 
 | |
|         // Attempts to retrieve the initializer facet from a type usage
 | |
|         internal static bool TryGetInitializerMetadata(TypeUsage typeUsage, out InitializerMetadata initializerMetadata)
 | |
|         {
 | |
|             initializerMetadata = null;
 | |
|             if (BuiltInTypeKind.RowType == typeUsage.EdmType.BuiltInTypeKind)
 | |
|             {
 | |
|                 initializerMetadata = ((RowType)typeUsage.EdmType).InitializerMetadata;
 | |
|             }
 | |
|             return null != initializerMetadata;
 | |
|         }
 | |
| 
 | |
|         // Initializes an initializer for an IGrouping return type
 | |
|         // Requires: resultType is IGrouping<T, K> instance.
 | |
|         internal static InitializerMetadata CreateGroupingInitializer(EdmItemCollection itemCollection, Type resultType)
 | |
|         {
 | |
|             return itemCollection.GetCanonicalInitializerMetadata(new GroupingInitializerMetadata(resultType));
 | |
|         }
 | |
| 
 | |
|         // Initializes an initializer for a MemberInit expression
 | |
|         internal static InitializerMetadata CreateProjectionInitializer(EdmItemCollection itemCollection, MemberInitExpression initExpression,
 | |
|             MemberInfo[] members)
 | |
|         {
 | |
|             return itemCollection.GetCanonicalInitializerMetadata(new ProjectionInitializerMetadata(initExpression, members));
 | |
|         }
 | |
| 
 | |
|         // Initializes an initializer for a New expression
 | |
|         internal static InitializerMetadata CreateProjectionInitializer(EdmItemCollection itemCollection, NewExpression newExpression)
 | |
|         {
 | |
|             return itemCollection.GetCanonicalInitializerMetadata(new ProjectionNewMetadata(newExpression));
 | |
|         }
 | |
| 
 | |
|         // Initializes an initializer for a New expression with no properties
 | |
|         internal static InitializerMetadata CreateEmptyProjectionInitializer(EdmItemCollection itemCollection, NewExpression newExpression)
 | |
|         {
 | |
|             return itemCollection.GetCanonicalInitializerMetadata(new EmptyProjectionNewMetadata(newExpression));
 | |
|         }
 | |
| 
 | |
|         // Creates metadata for entity collection materialization
 | |
|         internal static InitializerMetadata CreateEntityCollectionInitializer(EdmItemCollection itemCollection, Type type, NavigationProperty navigationProperty)
 | |
|         {
 | |
|             return itemCollection.GetCanonicalInitializerMetadata(new EntityCollectionInitializerMetadata(type, navigationProperty));
 | |
|         }
 | |
| 
 | |
|         private static T MarkAsUserExpression<T>(T value)
 | |
|         {
 | |
|             // No op. This is used as a marker inside of an expression tree to indicate
 | |
|             // that the input expression is not trusted.
 | |
|             return value;
 | |
|         }
 | |
| 
 | |
|         internal virtual void AppendColumnMapKey(ColumnMapKeyBuilder builder)
 | |
|         {
 | |
|             // by default, the type is sufficient (more information is needed for EntityCollection and initializers)
 | |
|             builder.Append("CLR-", this.ClrType);
 | |
|         }
 | |
| 
 | |
|         public override bool Equals(object obj)
 | |
|         {
 | |
|             Debug.Fail("use typed Equals method only");
 | |
|             return Equals(obj as InitializerMetadata);
 | |
|         }
 | |
| 
 | |
|         public bool Equals(InitializerMetadata other)
 | |
|         {
 | |
|             Debug.Assert(null != other, "must not use a null key");
 | |
|             if (object.ReferenceEquals(this, other)) { return true; }
 | |
|             if (this.Kind != other.Kind) { return false; }
 | |
|             if (!this.ClrType.Equals(other.ClrType)) { return false; }
 | |
|             return IsStructurallyEquivalent(other);
 | |
|         }
 | |
| 
 | |
|         [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA2303", Justification="ClrType is not expected to be an Embedded Interop Type.")]
 | |
|         public override int GetHashCode()
 | |
|         {
 | |
|             return ClrType.GetHashCode();
 | |
|         }
 | |
| 
 | |
|         /// <summary>
 | |
|         /// Requires: other has the same type as this and refers to the same CLR type
 | |
|         /// Determine whether this Metadata is compatible with the other based on record layout.
 | |
|         /// </summary>
 | |
|         protected virtual bool IsStructurallyEquivalent(InitializerMetadata other)
 | |
|         {
 | |
|             return true;
 | |
|         }
 | |
|         
 | |
|         /// <summary>
 | |
|         /// Produces an expression initializing an instance of ClrType (given emitters for input
 | |
|         /// columns)
 | |
|         /// </summary>
 | |
|         internal abstract Expression Emit(Translator translator, List<TranslatorResult> propertyTranslatorResults);
 | |
| 
 | |
|         /// <summary>
 | |
|         /// Yields expected types for input columns. Null values are returned for children
 | |
|         /// whose type is irrelevant to the initializer.
 | |
|         /// </summary>
 | |
|         internal abstract IEnumerable<Type> GetChildTypes();
 | |
| 
 | |
|         /// <summary>
 | |
|         /// return a list of propertyReader expressions from an array of translator results.
 | |
|         /// </summary>
 | |
|         /// <param name="propertyTranslatorResults"></param>
 | |
|         /// <returns></returns>
 | |
|         protected static List<Expression> GetPropertyReaders(List<TranslatorResult> propertyTranslatorResults)
 | |
|         {
 | |
|             List<Expression> propertyReaders = propertyTranslatorResults.Select(s => s.UnwrappedExpression).ToList();
 | |
|             return propertyReaders;
 | |
|         }
 | |
| 
 | |
|         /// <summary>
 | |
|         /// Implementation of IGrouping that can be initialized using the standard
 | |
|         /// initializer pattern supported by ELinq
 | |
|         /// </summary>
 | |
|         /// <typeparam name="K">Type of key</typeparam>
 | |
|         /// <typeparam name="T">Type of record</typeparam>
 | |
|         private class Grouping<K, T> : IGrouping<K, T>
 | |
|         {
 | |
|             public Grouping(K key, IEnumerable<T> group)
 | |
|             {
 | |
|                 _key = key;
 | |
|                 _group = group;
 | |
|             }
 | |
| 
 | |
|             private readonly K _key;
 | |
|             private readonly IEnumerable<T> _group;
 | |
| 
 | |
|             public K Key
 | |
|             {
 | |
|                 get { return _key; }
 | |
|             }
 | |
| 
 | |
|             public IEnumerable<T> Group
 | |
|             {
 | |
|                 get { return _group; }
 | |
|             }
 | |
| 
 | |
|             IEnumerator<T> IEnumerable<T>.GetEnumerator()
 | |
|             {
 | |
|                 if (null == _group)
 | |
|                 {
 | |
|                     yield break;
 | |
|                 }
 | |
|                 foreach (T member in _group)
 | |
|                 {
 | |
|                     yield return member;
 | |
|                 }
 | |
|             }
 | |
| 
 | |
|             System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()
 | |
|             {
 | |
|                 return ((IEnumerable<T>)this).GetEnumerator();
 | |
|             }
 | |
|         }
 | |
|         
 | |
|         /// <summary>
 | |
|         /// Metadata for grouping initializer.
 | |
|         /// </summary>
 | |
|         private class GroupingInitializerMetadata : InitializerMetadata
 | |
|         {
 | |
|             internal GroupingInitializerMetadata(Type type)
 | |
|                 : base(type)
 | |
|             {
 | |
|             }
 | |
| 
 | |
|             internal override InitializerMetadataKind Kind { get { return InitializerMetadataKind.Grouping; } }
 | |
| 
 | |
|             internal override Expression Emit(Translator translator, List<TranslatorResult> propertyTranslatorResults)
 | |
|             {
 | |
|                 // Create expression of the form:
 | |
|                 // new Grouping<K, T>(children[0], children[1])
 | |
| 
 | |
|                 // Collect information...
 | |
|                 Debug.Assert(ClrType.IsGenericType &&
 | |
|                     typeof(IGrouping<,>).Equals(ClrType.GetGenericTypeDefinition()));
 | |
|                 Debug.Assert(propertyTranslatorResults.Count == 2);
 | |
|                 Type keyType = this.ClrType.GetGenericArguments()[0];
 | |
|                 Type groupElementType = this.ClrType.GetGenericArguments()[1];
 | |
|                 Type groupType = typeof(Grouping<,>).MakeGenericType(keyType, groupElementType);
 | |
|                 ConstructorInfo constructor = groupType.GetConstructors().Single();
 | |
| 
 | |
|                 // new Grouping<K, T>(children[0], children[1])
 | |
|                 Expression newGrouping = Expression.Convert(Expression.New(constructor, GetPropertyReaders(propertyTranslatorResults)), this.ClrType);
 | |
| 
 | |
|                 return newGrouping;
 | |
|             }
 | |
| 
 | |
|             internal override IEnumerable<Type> GetChildTypes()
 | |
|             {
 | |
|                 // Collect information...
 | |
|                 Debug.Assert(ClrType.IsGenericType &&
 | |
|                     typeof(IGrouping<,>).Equals(ClrType.GetGenericTypeDefinition()));
 | |
|                 Type keyType = this.ClrType.GetGenericArguments()[0];
 | |
|                 Type groupElementType = this.ClrType.GetGenericArguments()[1];
 | |
| 
 | |
|                 // key
 | |
|                 yield return keyType;
 | |
|                 // group
 | |
|                 yield return typeof(IEnumerable<>).MakeGenericType(groupElementType);
 | |
|             }
 | |
|         }
 | |
| 
 | |
|         /// <summary>
 | |
|         /// Metadata for anonymous type materialization.
 | |
|         /// </summary>
 | |
|         private class ProjectionNewMetadata : InitializerMetadata
 | |
|         {
 | |
|             internal ProjectionNewMetadata(NewExpression newExpression)
 | |
|                 : base(newExpression.Type)
 | |
|             {
 | |
|                 Debug.Assert(null != newExpression);
 | |
|                 _newExpression = newExpression;
 | |
|             }
 | |
| 
 | |
|             private readonly NewExpression _newExpression;
 | |
| 
 | |
|             internal override InitializerMetadataKind Kind { get { return InitializerMetadataKind.ProjectionNew; } }
 | |
| 
 | |
|             protected override bool IsStructurallyEquivalent(InitializerMetadata other)
 | |
|             {                
 | |
|                 // caller must ensure the type matches                
 | |
|                 ProjectionNewMetadata otherProjection = (ProjectionNewMetadata)other;
 | |
|                 if (this._newExpression.Members == null && otherProjection._newExpression.Members == null)
 | |
|                 {
 | |
|                     return true;
 | |
|                 }
 | |
| 
 | |
|                 if (this._newExpression.Members == null || otherProjection._newExpression.Members == null)
 | |
|                 {
 | |
|                     return false;
 | |
|                 }
 | |
| 
 | |
|                 if (this._newExpression.Members.Count != otherProjection._newExpression.Members.Count)
 | |
|                 {
 | |
|                     return false;
 | |
|                 }
 | |
| 
 | |
|                 for (int i = 0; i < this._newExpression.Members.Count; i++)
 | |
|                 {
 | |
|                     MemberInfo thisMember = this._newExpression.Members[i];
 | |
|                     MemberInfo otherMember = otherProjection._newExpression.Members[i];
 | |
|                     if (!thisMember.Equals(otherMember))
 | |
|                     {
 | |
|                         return false;
 | |
|                     }
 | |
|                 }
 | |
| 
 | |
|                 return true;
 | |
|             }
 | |
| 
 | |
|             internal override Expression Emit(Translator translator, List<TranslatorResult> propertyTranslatorResults)
 | |
|             {
 | |
|                 // Create expression of the form:
 | |
|                 // _newExpression(children)
 | |
| 
 | |
|                 // (ClrType)null
 | |
|                 Expression nullProjection = Expression.Constant(null, this.ClrType);
 | |
| 
 | |
|                 // _newExpression with members rebound
 | |
|                 Expression newProjection = Expression.New(_newExpression.Constructor, GetPropertyReaders(propertyTranslatorResults));
 | |
| 
 | |
|                 // Indicate that this expression is provided by the user and should not be trusted.
 | |
|                 return Expression.Call(UserExpressionMarker.MakeGenericMethod(newProjection.Type), newProjection);
 | |
|             }
 | |
| 
 | |
|             internal override IEnumerable<Type> GetChildTypes()
 | |
|             {
 | |
|                 // return all argument types
 | |
|                 return _newExpression.Arguments.Select(arg => arg.Type);
 | |
|             }
 | |
| 
 | |
|             internal override void AppendColumnMapKey(ColumnMapKeyBuilder builder)
 | |
|             {
 | |
|                 base.AppendColumnMapKey(builder);
 | |
|                 builder.Append(_newExpression.Constructor.ToString());
 | |
|                 foreach (var member in _newExpression.Members ?? Enumerable.Empty<MemberInfo>())
 | |
|                 {
 | |
|                     builder.Append("DT", member.DeclaringType);
 | |
|                     builder.Append("." + member.Name);
 | |
|                 }
 | |
|             }
 | |
|         }
 | |
| 
 | |
|         private class EmptyProjectionNewMetadata : ProjectionNewMetadata
 | |
|         {
 | |
|             internal EmptyProjectionNewMetadata(NewExpression newExpression)
 | |
|                 : base(newExpression)
 | |
|             {
 | |
|             }
 | |
|             internal override Expression Emit(Translator translator, List<TranslatorResult> propertyReaders)
 | |
|             {
 | |
|                 // ignore sentinel column
 | |
|                 return base.Emit(translator, new List<TranslatorResult>());
 | |
|             }
 | |
|             internal override IEnumerable<Type> GetChildTypes()
 | |
|             {
 | |
|                 // ignore sentinel column
 | |
|                 yield return null;
 | |
|             }
 | |
|         }
 | |
| 
 | |
|         /// <summary>
 | |
|         /// Metadata for standard projection initializers.
 | |
|         /// </summary>
 | |
|         private class ProjectionInitializerMetadata : InitializerMetadata
 | |
|         {
 | |
|             internal ProjectionInitializerMetadata(MemberInitExpression initExpression, MemberInfo[] members)
 | |
|                 : base(initExpression.Type)
 | |
|             {
 | |
|                 Debug.Assert(null != initExpression);
 | |
|                 Debug.Assert(null != members);
 | |
|                 _initExpression = initExpression;
 | |
|                 _members = members;
 | |
|             }
 | |
| 
 | |
|             private readonly MemberInitExpression _initExpression;
 | |
|             private readonly MemberInfo[] _members;
 | |
| 
 | |
|             internal override InitializerMetadataKind Kind { get { return InitializerMetadataKind.ProjectionInitializer; } }
 | |
| 
 | |
|             protected override bool IsStructurallyEquivalent(InitializerMetadata other)
 | |
|             {
 | |
|                 // caller must ensure the type matches
 | |
|                 ProjectionInitializerMetadata otherProjection = (ProjectionInitializerMetadata)other;
 | |
|                 if (this._initExpression.Bindings.Count != otherProjection._initExpression.Bindings.Count)
 | |
|                 {
 | |
|                     return false;
 | |
|                 }
 | |
| 
 | |
|                 for (int i = 0; i < this._initExpression.Bindings.Count; i++)
 | |
|                 {
 | |
|                     MemberBinding thisBinding = this._initExpression.Bindings[i];
 | |
|                     MemberBinding otherBinding = otherProjection._initExpression.Bindings[i];
 | |
|                     if (!thisBinding.Member.Equals(otherBinding.Member))
 | |
|                     {
 | |
|                         return false;
 | |
|                     }
 | |
|                 }
 | |
| 
 | |
|                 return true;
 | |
|             }
 | |
| 
 | |
|             internal override Expression Emit(Translator translator, List<TranslatorResult> propertyReaders)
 | |
|             {
 | |
|                 // Create expression of the form:
 | |
|                 // _initExpression(children)
 | |
| 
 | |
|                 // create member bindings (where values are taken from children)
 | |
|                 MemberBinding[] memberBindings = new MemberBinding[_initExpression.Bindings.Count];
 | |
|                 MemberBinding[] constantMemberBindings = new MemberBinding[memberBindings.Length];
 | |
|                 for (int i = 0; i < memberBindings.Length; i++)
 | |
|                 {
 | |
|                     MemberBinding originalBinding = _initExpression.Bindings[i];
 | |
|                     Expression value = propertyReaders[i].UnwrappedExpression;
 | |
|                     MemberBinding newBinding = Expression.Bind(originalBinding.Member, value);
 | |
|                     MemberBinding constantBinding = Expression.Bind(originalBinding.Member, Expression.Constant(
 | |
|                         TypeSystem.GetDefaultValue(value.Type), value.Type));
 | |
|                     memberBindings[i] = newBinding;
 | |
|                     constantMemberBindings[i] = constantBinding;
 | |
|                 }
 | |
| 
 | |
|                 Expression newProjection = Expression.MemberInit(_initExpression.NewExpression, memberBindings);
 | |
| 
 | |
|                 // Indicate that this expression is provided by the user and should not be trusted.
 | |
|                 return Expression.Call(UserExpressionMarker.MakeGenericMethod(newProjection.Type), newProjection);
 | |
|             }
 | |
| 
 | |
|             internal override IEnumerable<Type> GetChildTypes()
 | |
|             {
 | |
|                 // return all argument types
 | |
|                 foreach (var binding in _initExpression.Bindings)
 | |
|                 {
 | |
|                     // determine member type
 | |
|                     Type memberType;
 | |
|                     string name;
 | |
|                     TypeSystem.PropertyOrField(binding.Member, out name, out memberType);
 | |
|                     yield return memberType;
 | |
|                 }
 | |
|             }
 | |
| 
 | |
|             internal override void AppendColumnMapKey(ColumnMapKeyBuilder builder)
 | |
|             {
 | |
|                 base.AppendColumnMapKey(builder);
 | |
|                 foreach (var binding in _initExpression.Bindings)
 | |
|                 {
 | |
|                     builder.Append(",", binding.Member.DeclaringType);
 | |
|                     builder.Append("." + binding.Member.Name);
 | |
|                 }
 | |
|             }
 | |
|         }
 | |
| 
 | |
|         /// <summary>
 | |
|         /// Metadata for entity collection initializer.
 | |
|         /// </summary>
 | |
|         private class EntityCollectionInitializerMetadata : InitializerMetadata
 | |
|         {
 | |
|             internal EntityCollectionInitializerMetadata(Type type, NavigationProperty navigationProperty)
 | |
|                 : base(type)
 | |
|             {
 | |
|                 Debug.Assert(null != navigationProperty);
 | |
|                 _navigationProperty = navigationProperty;
 | |
|             }
 | |
| 
 | |
|             private readonly NavigationProperty _navigationProperty;
 | |
| 
 | |
|             internal override InitializerMetadataKind Kind { get { return InitializerMetadataKind.EntityCollection; } }
 | |
| 
 | |
|             /// <summary>
 | |
|             /// Make sure the other metadata instance generates the same property
 | |
|             /// (otherwise, we get incorrect behavior where multiple nav props return
 | |
|             /// the same type)
 | |
|             /// </summary>
 | |
|             protected override bool IsStructurallyEquivalent(InitializerMetadata other)
 | |
|             {
 | |
|                 // caller must ensure the type matches
 | |
|                 EntityCollectionInitializerMetadata otherInitializer = (EntityCollectionInitializerMetadata)other;
 | |
|                 return this._navigationProperty.Equals(otherInitializer._navigationProperty);
 | |
|             }
 | |
| 
 | |
|             private static readonly MethodInfo s_createEntityCollectionMethod = typeof(EntityCollectionInitializerMetadata).GetMethod("CreateEntityCollection",
 | |
|                 BindingFlags.Static | BindingFlags.Public);
 | |
| 
 | |
|             internal override Expression Emit(Translator translator, List<TranslatorResult> propertyTranslatorResults)
 | |
|             {
 | |
|                 Debug.Assert(propertyTranslatorResults.Count > 1, "no properties?");
 | |
|                 Debug.Assert(propertyTranslatorResults[1] is CollectionTranslatorResult, "not a collection?");
 | |
| 
 | |
|                 Type elementType = GetElementType();
 | |
|                 MethodInfo createEntityCollectionMethod = s_createEntityCollectionMethod.MakeGenericMethod(elementType);
 | |
| 
 | |
|                 Expression shaper = Translator.Shaper_Parameter;
 | |
|                 Expression owner = propertyTranslatorResults[0].Expression;
 | |
| 
 | |
|                 CollectionTranslatorResult collectionResult = propertyTranslatorResults[1] as CollectionTranslatorResult;
 | |
| 
 | |
|                 Expression coordinator = collectionResult.ExpressionToGetCoordinator;
 | |
| 
 | |
|                 // CreateEntityCollection(shaper, owner, elements, relationshipName, targetRoleName)
 | |
|                 Expression result = Expression.Call(createEntityCollectionMethod,
 | |
|                     shaper, owner, coordinator, Expression.Constant(_navigationProperty.RelationshipType.FullName), Expression.Constant(_navigationProperty.ToEndMember.Name));
 | |
| 
 | |
|                 return result;
 | |
|             }
 | |
| 
 | |
|             public static EntityCollection<T> CreateEntityCollection<T>(Shaper state, IEntityWrapper wrappedOwner, Coordinator<T> coordinator, string relationshipName, string targetRoleName)
 | |
|                 where T : class
 | |
|             {
 | |
|                 if (null == wrappedOwner.Entity)
 | |
|                 {
 | |
|                     return null;
 | |
|                 }
 | |
|                 else
 | |
|                 {
 | |
|                     EntityCollection<T> result = wrappedOwner.RelationshipManager.GetRelatedCollection<T>(relationshipName, targetRoleName);
 | |
|                     // register a handler for deferred loading (when the nested result has been consumed)
 | |
|                     coordinator.RegisterCloseHandler((readerState, elements) => result.Load(elements, readerState.MergeOption));
 | |
|                     return result;
 | |
|                 }
 | |
|             }
 | |
| 
 | |
|             internal override IEnumerable<Type> GetChildTypes()
 | |
|             {
 | |
|                 Type elementType = GetElementType();
 | |
|                 yield return null; // defer in determining entity type...
 | |
|                 yield return typeof(IEnumerable<>).MakeGenericType(elementType);
 | |
|             }
 | |
| 
 | |
| 
 | |
|             internal override void AppendColumnMapKey(ColumnMapKeyBuilder builder)
 | |
|             {
 | |
|                 base.AppendColumnMapKey(builder);
 | |
|                 builder.Append(",NP" + _navigationProperty.Name);
 | |
|                 builder.Append(",AT", _navigationProperty.DeclaringType);
 | |
|             }
 | |
| 
 | |
|             private Type GetElementType()
 | |
|             {
 | |
|                 // POCO support requires that we allow ICollection<T> collections.  This allows a POCO collection
 | |
|                 // to be projected in a LINQ query.
 | |
|                 Type elementType;
 | |
|                 if (!EntityUtil.TryGetICollectionElementType(ClrType, out elementType))
 | |
|                 {
 | |
|                     throw EntityUtil.InvalidOperation(System.Data.Entity.Strings.ELinq_UnexpectedTypeForNavigationProperty(
 | |
|                         _navigationProperty,
 | |
|                         typeof(EntityCollection<>), typeof(ICollection<>),
 | |
|                         ClrType));
 | |
|                 }
 | |
|                 return elementType;
 | |
|             }            
 | |
|         }
 | |
|     }
 | |
| 
 | |
|     internal enum InitializerMetadataKind
 | |
|     {
 | |
|         Grouping,
 | |
|         ProjectionNew,
 | |
|         ProjectionInitializer,
 | |
|         EntityCollection,
 | |
|     }
 | |
| }
 |