Code:
/ Dotnetfx_Vista_SP2 / Dotnetfx_Vista_SP2 / 8.0.50727.4016 / DEVDIV / depot / DevDiv / releases / Orcas / QFE / ndp / fx / src / DataEntity / System / Data / Objects / ELinq / InitializerFacet.cs / 2 / InitializerFacet.cs
//----------------------------------------------------------------------
//
// Copyright (c) Microsoft Corporation. All rights reserved.
//
//
// @owner [....]
//---------------------------------------------------------------------
using System.Data.Metadata.Edm;
using System.Collections.Generic;
using System.Linq.Expressions;
using System.Reflection;
using System.Diagnostics;
using System.Linq;
using System.Collections;
using System.Data.Objects.DataClasses;
using System.Threading;
using System.Globalization;
using System.Security.Permissions;
using System.Security;
using System.Data.Common.Internal.Materialization;
using System.Data.Query.InternalTrees;
using System.Text;
namespace System.Data.Objects.ELinq
{
///
/// Facet encapsulating information necessary to initialize a LINQ projection
/// result.
///
internal abstract class InitializerMetadata : IEquatable
{
internal readonly Type ClrType;
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 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));
}
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);
}
public override int GetHashCode()
{
return ClrType.GetHashCode();
}
///
/// 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.
///
protected virtual bool IsStructurallyEquivalent(InitializerMetadata other)
{
return true;
}
///
/// Produces an expression initializing an instance of ClrType (given emitters for input
/// columns)
///
internal abstract Expression Emit(Translator translator, List propertyTranslatorResults);
///
/// Yields expected types for input columns. Null values are returned for children
/// whose type is irrelevant to the initializer.
///
internal abstract IEnumerable GetChildTypes();
///
/// return a list of propertyReader expressions from an array of translator results.
///
///
///
protected static List GetPropertyReaders(List propertyTranslatorResults)
{
List propertyReaders = propertyTranslatorResults.Select(s => s.Expression).ToList();
return propertyReaders;
}
///
/// Implementation of IGrouping that can be initialized using the standard
/// initializer pattern supported by ELinq
///
/// Type of key
/// Type of record
private class Grouping : IGrouping
{
public Grouping(K key, IEnumerable group)
{
_key = key;
_group = group;
}
private readonly K _key;
private readonly IEnumerable _group;
public K Key
{
get { return _key; }
}
public IEnumerable Group
{
get { return _group; }
}
IEnumerator IEnumerable.GetEnumerator()
{
if (null == _group)
{
yield break;
}
foreach (T member in _group)
{
yield return member;
}
}
System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()
{
return ((IEnumerable)this).GetEnumerator();
}
}
///
/// Metadata for grouping initializer.
///
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 propertyTranslatorResults)
{
// Create expression of the form:
// new Grouping(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(children[0], children[1])
Expression newGrouping = Expression.Convert(Expression.New(constructor, GetPropertyReaders(propertyTranslatorResults)), this.ClrType);
return newGrouping;
}
internal override IEnumerable 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);
}
}
///
/// Metadata for anonymous type materialization.
///
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.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 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));
// _newExpression with members rebound to constants (used for security check)
Expression constantProjection = Expression.New(_newExpression.Constructor,
propertyTranslatorResults.Select(child => (Expression)Expression.Constant(TypeSystem.GetDefaultValue(child.Expression.Type), child.Expression.Type)));
translator.RegisterUserExpression(constantProjection);
// condition
return newProjection;
}
internal override IEnumerable 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())
{
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 propertyReaders)
{
// ignore sentinel column
return base.Emit(translator, new List());
}
internal override IEnumerable GetChildTypes()
{
// ignore sentinel column
yield return null;
}
}
///
/// Metadata for standard projection initializers.
///
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 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].Expression;
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);
Expression constantProjection = Expression.MemberInit(_initExpression.NewExpression, constantMemberBindings);
translator.RegisterUserExpression(constantProjection);
return newProjection;
}
internal override IEnumerable 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);
}
}
}
///
/// Metadata for entity collection initializer.
///
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; } }
///
/// Make sure the other metadata instance generates the same property
/// (otherwise, we get incorrect behavior where multiple nav props return
/// the same type)
///
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 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 CreateEntityCollection(Shaper state, IEntityWithRelationships owner, Coordinator coordinator, string relationshipName, string targetRoleName)
where T : class, IEntityWithRelationships
{
if (null == owner)
{
return null;
}
else
{
EntityCollection result = owner.RelationshipManager.GetRelatedCollection(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 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()
{
if (!this.ClrType.IsGenericType || !typeof(EntityCollection<>).Equals(ClrType.GetGenericTypeDefinition()))
{
throw EntityUtil.InvalidOperation(System.Data.Entity.Strings.ELinq_UnexpectedTypeForNavigationProperty(
_navigationProperty,
typeof(EntityCollection<>),
ClrType));
}
Type elementType = this.ClrType.GetGenericArguments()[0];
return elementType;
}
}
}
internal enum InitializerMetadataKind
{
Grouping,
ProjectionNew,
ProjectionInitializer,
EntityCollection,
}
}
// File provided for Reference Use Only by Microsoft Corporation (c) 2007.
//----------------------------------------------------------------------
//
// Copyright (c) Microsoft Corporation. All rights reserved.
//
//
// @owner [....]
//---------------------------------------------------------------------
using System.Data.Metadata.Edm;
using System.Collections.Generic;
using System.Linq.Expressions;
using System.Reflection;
using System.Diagnostics;
using System.Linq;
using System.Collections;
using System.Data.Objects.DataClasses;
using System.Threading;
using System.Globalization;
using System.Security.Permissions;
using System.Security;
using System.Data.Common.Internal.Materialization;
using System.Data.Query.InternalTrees;
using System.Text;
namespace System.Data.Objects.ELinq
{
///
/// Facet encapsulating information necessary to initialize a LINQ projection
/// result.
///
internal abstract class InitializerMetadata : IEquatable
{
internal readonly Type ClrType;
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 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));
}
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);
}
public override int GetHashCode()
{
return ClrType.GetHashCode();
}
///
/// 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.
///
protected virtual bool IsStructurallyEquivalent(InitializerMetadata other)
{
return true;
}
///
/// Produces an expression initializing an instance of ClrType (given emitters for input
/// columns)
///
internal abstract Expression Emit(Translator translator, List propertyTranslatorResults);
///
/// Yields expected types for input columns. Null values are returned for children
/// whose type is irrelevant to the initializer.
///
internal abstract IEnumerable GetChildTypes();
///
/// return a list of propertyReader expressions from an array of translator results.
///
///
///
protected static List GetPropertyReaders(List propertyTranslatorResults)
{
List propertyReaders = propertyTranslatorResults.Select(s => s.Expression).ToList();
return propertyReaders;
}
///
/// Implementation of IGrouping that can be initialized using the standard
/// initializer pattern supported by ELinq
///
/// Type of key
/// Type of record
private class Grouping : IGrouping
{
public Grouping(K key, IEnumerable group)
{
_key = key;
_group = group;
}
private readonly K _key;
private readonly IEnumerable _group;
public K Key
{
get { return _key; }
}
public IEnumerable Group
{
get { return _group; }
}
IEnumerator IEnumerable.GetEnumerator()
{
if (null == _group)
{
yield break;
}
foreach (T member in _group)
{
yield return member;
}
}
System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()
{
return ((IEnumerable)this).GetEnumerator();
}
}
///
/// Metadata for grouping initializer.
///
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 propertyTranslatorResults)
{
// Create expression of the form:
// new Grouping(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(children[0], children[1])
Expression newGrouping = Expression.Convert(Expression.New(constructor, GetPropertyReaders(propertyTranslatorResults)), this.ClrType);
return newGrouping;
}
internal override IEnumerable 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);
}
}
///
/// Metadata for anonymous type materialization.
///
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.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 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));
// _newExpression with members rebound to constants (used for security check)
Expression constantProjection = Expression.New(_newExpression.Constructor,
propertyTranslatorResults.Select(child => (Expression)Expression.Constant(TypeSystem.GetDefaultValue(child.Expression.Type), child.Expression.Type)));
translator.RegisterUserExpression(constantProjection);
// condition
return newProjection;
}
internal override IEnumerable 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())
{
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 propertyReaders)
{
// ignore sentinel column
return base.Emit(translator, new List());
}
internal override IEnumerable GetChildTypes()
{
// ignore sentinel column
yield return null;
}
}
///
/// Metadata for standard projection initializers.
///
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 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].Expression;
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);
Expression constantProjection = Expression.MemberInit(_initExpression.NewExpression, constantMemberBindings);
translator.RegisterUserExpression(constantProjection);
return newProjection;
}
internal override IEnumerable 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);
}
}
}
///
/// Metadata for entity collection initializer.
///
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; } }
///
/// Make sure the other metadata instance generates the same property
/// (otherwise, we get incorrect behavior where multiple nav props return
/// the same type)
///
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 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 CreateEntityCollection(Shaper state, IEntityWithRelationships owner, Coordinator coordinator, string relationshipName, string targetRoleName)
where T : class, IEntityWithRelationships
{
if (null == owner)
{
return null;
}
else
{
EntityCollection result = owner.RelationshipManager.GetRelatedCollection(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 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()
{
if (!this.ClrType.IsGenericType || !typeof(EntityCollection<>).Equals(ClrType.GetGenericTypeDefinition()))
{
throw EntityUtil.InvalidOperation(System.Data.Entity.Strings.ELinq_UnexpectedTypeForNavigationProperty(
_navigationProperty,
typeof(EntityCollection<>),
ClrType));
}
Type elementType = this.ClrType.GetGenericArguments()[0];
return elementType;
}
}
}
internal enum InitializerMetadataKind
{
Grouping,
ProjectionNew,
ProjectionInitializer,
EntityCollection,
}
}
// File provided for Reference Use Only by Microsoft Corporation (c) 2007.
Link Menu

This book is available now!
Buy at Amazon US or
Buy at Amazon UK
- ArrayListCollectionBase.cs
- FastEncoder.cs
- Frame.cs
- Int32CollectionConverter.cs
- XmlSchemaAttributeGroup.cs
- BitConverter.cs
- XmlSigningNodeWriter.cs
- ListBoxDesigner.cs
- SqlIdentifier.cs
- TextRangeEditLists.cs
- EndpointDiscoveryBehavior.cs
- DynamicDataExtensions.cs
- IntSecurity.cs
- AudioBase.cs
- ObsoleteAttribute.cs
- NamedPermissionSet.cs
- DeflateStream.cs
- MapPathBasedVirtualPathProvider.cs
- ColorTransform.cs
- HeaderedItemsControl.cs
- AmbientLight.cs
- StateBag.cs
- PersistenceTypeAttribute.cs
- ListViewHitTestInfo.cs
- ClientTargetCollection.cs
- XslTransform.cs
- WebBrowserNavigatingEventHandler.cs
- SafeCertificateStore.cs
- BindingExpressionBase.cs
- Animatable.cs
- XmlDownloadManager.cs
- TypedRowHandler.cs
- HostAdapter.cs
- httpapplicationstate.cs
- PrimaryKeyTypeConverter.cs
- XmlSchemaAttribute.cs
- SuppressMessageAttribute.cs
- SiteMapNodeItemEventArgs.cs
- HttpCookieCollection.cs
- RequestedSignatureDialog.cs
- Timer.cs
- Cursor.cs
- WizardForm.cs
- RewritingPass.cs
- BidPrivateBase.cs
- DocumentViewerBase.cs
- StrokeIntersection.cs
- WebPartCatalogAddVerb.cs
- WebProxyScriptElement.cs
- UpdatePanelTriggerCollection.cs
- ColumnTypeConverter.cs
- DictionaryBase.cs
- Point3DConverter.cs
- ThemeInfoAttribute.cs
- CrossSiteScriptingValidation.cs
- FloaterBaseParaClient.cs
- ListViewInsertEventArgs.cs
- ParameterBuilder.cs
- SelectionProcessor.cs
- DataBindingCollection.cs
- Vector3DCollectionValueSerializer.cs
- _NetworkingPerfCounters.cs
- _TLSstream.cs
- StringUtil.cs
- TagNameToTypeMapper.cs
- DisplayInformation.cs
- JavaScriptSerializer.cs
- HttpStreamXmlDictionaryReader.cs
- WorkflowDesignerColors.cs
- FactoryId.cs
- XamlToRtfParser.cs
- DataGridToolTip.cs
- Transactions.cs
- NavigationWindowAutomationPeer.cs
- ErrorFormatterPage.cs
- TraceSection.cs
- ServicePointManagerElement.cs
- ProviderConnectionPointCollection.cs
- StrokeCollectionDefaultValueFactory.cs
- DataRelationCollection.cs
- DBConnection.cs
- Peer.cs
- DictationGrammar.cs
- GridViewSortEventArgs.cs
- AssemblyAttributesGoHere.cs
- PointAnimationClockResource.cs
- WebReferenceCollection.cs
- propertytag.cs
- EqualityArray.cs
- ControlAdapter.cs
- DataKeyArray.cs
- XmlSchemaDocumentation.cs
- Selection.cs
- Vector3DValueSerializer.cs
- UpdatePanel.cs
- PathSegment.cs
- ValuePatternIdentifiers.cs
- ViewStateException.cs
- HandleRef.cs
- ProviderCommandInfoUtils.cs