//---------------------------------------------------------------------
//
// Copyright (c) Microsoft Corporation. All rights reserved.
//
//
// @owner Microsoft
// @backupOwner Microsoft
//---------------------------------------------------------------------
using System.Collections.Generic;
using System.Data.Common;
using System.Diagnostics;
using System.Threading;
using System.Linq;
namespace System.Data.Metadata.Edm
{
///
/// Represent the edm navigation property class
///
public sealed class NavigationProperty : EdmMember
{
#region Constructors
///
/// Initializes a new instance of the navigation property class
///
/// name of the navigation property
/// TypeUsage object containing the navigation property type and its facets
/// Thrown if name or typeUsage arguments are null
/// Thrown if name argument is empty string
internal NavigationProperty(string name, TypeUsage typeUsage)
: base(name, typeUsage)
{
EntityUtil.CheckStringArgument(name, "name");
EntityUtil.GenericCheckArgumentNull(typeUsage, "typeUsage");
_accessor = new NavigationPropertyAccessor(name);
}
///
/// Initializes a new OSpace instance of the property class
///
/// name of the property
/// TypeUsage object containing the property type and its facets
/// for the property
internal NavigationProperty(string name, TypeUsage typeUsage, System.Reflection.PropertyInfo propertyInfo)
: this(name, typeUsage)
{
System.Diagnostics.Debug.Assert(name == propertyInfo.Name, "different PropertyName?");
if (null != propertyInfo)
{
System.Reflection.MethodInfo method;
method = propertyInfo.GetGetMethod();
PropertyGetterHandle = ((null != method) ? method.MethodHandle : default(System.RuntimeMethodHandle));
}
}
#endregion
///
/// Returns the kind of the type
///
public override BuiltInTypeKind BuiltInTypeKind { get { return BuiltInTypeKind.NavigationProperty; } }
#region Fields
internal const string RelationshipTypeNamePropertyName = "RelationshipType";
internal const string ToEndMemberNamePropertyName = "ToEndMember";
private RelationshipType _relationshipType;
private RelationshipEndMember _toEndMember;
private RelationshipEndMember _fromEndMember;
/// Store the handle, allowing the PropertyInfo/MethodInfo/Type references to be GC'd
internal readonly System.RuntimeMethodHandle PropertyGetterHandle;
/// cached dynamic methods to access the property values from a CLR instance
private readonly NavigationPropertyAccessor _accessor;
#endregion
///
/// Gets/Sets the relationship type that this navigation property operates on
///
/// Thrown if the NavigationProperty instance is in ReadOnly state
[MetadataProperty(BuiltInTypeKind.RelationshipType, false)]
public RelationshipType RelationshipType
{
get
{
return _relationshipType;
}
internal set
{
_relationshipType = value;
}
}
///
/// Gets/Sets the to relationship end member in the navigation
///
/// Thrown if the NavigationProperty instance is in ReadOnly state
[MetadataProperty(BuiltInTypeKind.RelationshipEndMember, false)]
public RelationshipEndMember ToEndMember
{
get
{
return _toEndMember;
}
internal set
{
_toEndMember = value;
}
}
///
/// Gets/Sets the from relationship end member in the navigation
///
/// Thrown if the NavigationProperty instance is in ReadOnly state
[MetadataProperty(BuiltInTypeKind.RelationshipEndMember, false)]
public RelationshipEndMember FromEndMember
{
get
{
return _fromEndMember;
}
internal set
{
_fromEndMember = value;
}
}
internal NavigationPropertyAccessor Accessor
{
get { return _accessor; }
}
///
/// Where the given navigation property is on the dependent end of a referential constraint,
/// returns the foreign key properties. Otherwise, returns an empty set. We will return the members in the order
/// of the principal end key properties.
///
/// Foreign key properties
public IEnumerable GetDependentProperties()
{
// Get the declared type
AssociationType associationType = (AssociationType)this.RelationshipType;
Debug.Assert(
associationType.ReferentialConstraints != null,
"ReferenceConstraints cannot be null");
if (associationType.ReferentialConstraints.Count > 0)
{
ReferentialConstraint rc = associationType.ReferentialConstraints[0];
RelationshipEndMember dependentEndMember = rc.ToRole;
if (dependentEndMember.EdmEquals(this.FromEndMember))
{
//Order the dependant properties in the order of principal end's key members.
var keyMembers = rc.FromRole.GetEntityType().KeyMembers;
var dependantProperties = new List(keyMembers.Count);
for (int i = 0; i < keyMembers.Count; i++)
{
dependantProperties.Add(rc.ToProperties[rc.FromProperties.IndexOf(((EdmProperty)keyMembers[i]))]);
}
return dependantProperties.AsReadOnly();
}
}
return Enumerable.Empty();
}
}
}