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
- TreeNode.cs
- HttpCachePolicy.cs
- DbCommandTree.cs
- DataGridViewCheckBoxColumn.cs
- RTLAwareMessageBox.cs
- Camera.cs
- SourceFileBuildProvider.cs
- HttpCachePolicy.cs
- httpserverutility.cs
- Region.cs
- DataGridViewUtilities.cs
- TypeContext.cs
- DesignerCatalogPartChrome.cs
- CaseInsensitiveOrdinalStringComparer.cs
- MdImport.cs
- HtmlAnchor.cs
- QueryComponents.cs
- Compiler.cs
- AstTree.cs
- TdsParser.cs
- Font.cs
- FormsAuthenticationConfiguration.cs
- CompilerLocalReference.cs
- UriScheme.cs
- UnsafeNativeMethods.cs
- LinqDataSourceInsertEventArgs.cs
- IntegerValidator.cs
- NameValueCollection.cs
- PropertyValueChangedEvent.cs
- DefaultValueMapping.cs
- PageAsyncTask.cs
- HttpModuleActionCollection.cs
- PrimaryKeyTypeConverter.cs
- RtType.cs
- HttpFormatExtensions.cs
- ProviderCollection.cs
- XmlStringTable.cs
- DateTimePickerDesigner.cs
- SocketStream.cs
- Triangle.cs
- TypeBuilderInstantiation.cs
- ObjectComplexPropertyMapping.cs
- HostingMessageProperty.cs
- SpellerHighlightLayer.cs
- XmlTypeMapping.cs
- BrowserDefinition.cs
- CreateUserWizard.cs
- MaskedTextBox.cs
- Compilation.cs
- ItemAutomationPeer.cs
- XPathDocument.cs
- RequestCachingSection.cs
- NamespaceQuery.cs
- ValidationErrorCollection.cs
- UserCancellationException.cs
- SmiContext.cs
- BlobPersonalizationState.cs
- BamlReader.cs
- MtomMessageEncodingElement.cs
- TextMarkerSource.cs
- RelationshipDetailsRow.cs
- SymmetricCryptoHandle.cs
- XmlILCommand.cs
- Helper.cs
- _OSSOCK.cs
- TemplateBuilder.cs
- ColorTransformHelper.cs
- PolyLineSegment.cs
- XmlBaseReader.cs
- XPathNavigatorKeyComparer.cs
- InternalTypeHelper.cs
- StyleTypedPropertyAttribute.cs
- IItemContainerGenerator.cs
- LambdaCompiler.Binary.cs
- ReliableMessagingVersionConverter.cs
- AccessControlEntry.cs
- WizardPanel.cs
- WebPartDisplayModeEventArgs.cs
- OdbcEnvironmentHandle.cs
- RelatedEnd.cs
- RtfToken.cs
- DrawingImage.cs
- AttachedPropertyBrowsableForChildrenAttribute.cs
- Visual3D.cs
- XmlAttributeHolder.cs
- ObfuscationAttribute.cs
- CounterSet.cs
- ToolStripManager.cs
- wgx_sdk_version.cs
- CurrentChangingEventManager.cs
- GridSplitter.cs
- ComponentManagerBroker.cs
- CodeMethodInvokeExpression.cs
- LineServices.cs
- BackStopAuthenticationModule.cs
- _TimerThread.cs
- CopyAttributesAction.cs
- DigitalSignature.cs
- TriState.cs
- SqlNamer.cs