169 lines
6.8 KiB
C#
169 lines
6.8 KiB
C#
|
//---------------------------------------------------------------------
|
||
|
// <copyright file="NavigationProperty.cs" company="Microsoft">
|
||
|
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||
|
// </copyright>
|
||
|
//
|
||
|
// @owner [....]
|
||
|
// @backupOwner [....]
|
||
|
//---------------------------------------------------------------------
|
||
|
using System.Collections.Generic;
|
||
|
using System.Data.Common;
|
||
|
using System.Diagnostics;
|
||
|
using System.Threading;
|
||
|
using System.Linq;
|
||
|
|
||
|
namespace System.Data.Metadata.Edm
|
||
|
{
|
||
|
/// <summary>
|
||
|
/// Represent the edm navigation property class
|
||
|
/// </summary>
|
||
|
public sealed class NavigationProperty : EdmMember
|
||
|
{
|
||
|
#region Constructors
|
||
|
/// <summary>
|
||
|
/// Initializes a new instance of the navigation property class
|
||
|
/// </summary>
|
||
|
/// <param name="name">name of the navigation property</param>
|
||
|
/// <param name="typeUsage">TypeUsage object containing the navigation property type and its facets</param>
|
||
|
/// <exception cref="System.ArgumentNullException">Thrown if name or typeUsage arguments are null</exception>
|
||
|
/// <exception cref="System.ArgumentException">Thrown if name argument is empty string</exception>
|
||
|
internal NavigationProperty(string name, TypeUsage typeUsage)
|
||
|
: base(name, typeUsage)
|
||
|
{
|
||
|
EntityUtil.CheckStringArgument(name, "name");
|
||
|
EntityUtil.GenericCheckArgumentNull(typeUsage, "typeUsage");
|
||
|
_accessor = new NavigationPropertyAccessor(name);
|
||
|
}
|
||
|
|
||
|
/// <summary>
|
||
|
/// Initializes a new OSpace instance of the property class
|
||
|
/// </summary>
|
||
|
/// <param name="name">name of the property</param>
|
||
|
/// <param name="typeUsage">TypeUsage object containing the property type and its facets</param>
|
||
|
/// <param name="propertyInfo">for the property</param>
|
||
|
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
|
||
|
|
||
|
/// <summary>
|
||
|
/// Returns the kind of the type
|
||
|
/// </summary>
|
||
|
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;
|
||
|
|
||
|
/// <summary>Store the handle, allowing the PropertyInfo/MethodInfo/Type references to be GC'd</summary>
|
||
|
internal readonly System.RuntimeMethodHandle PropertyGetterHandle;
|
||
|
|
||
|
/// <summary>cached dynamic methods to access the property values from a CLR instance</summary>
|
||
|
private readonly NavigationPropertyAccessor _accessor;
|
||
|
#endregion
|
||
|
|
||
|
/// <summary>
|
||
|
/// Gets/Sets the relationship type that this navigation property operates on
|
||
|
/// </summary>
|
||
|
/// <exception cref="System.InvalidOperationException">Thrown if the NavigationProperty instance is in ReadOnly state</exception>
|
||
|
[MetadataProperty(BuiltInTypeKind.RelationshipType, false)]
|
||
|
public RelationshipType RelationshipType
|
||
|
{
|
||
|
get
|
||
|
{
|
||
|
return _relationshipType;
|
||
|
}
|
||
|
internal set
|
||
|
{
|
||
|
_relationshipType = value;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/// <summary>
|
||
|
/// Gets/Sets the to relationship end member in the navigation
|
||
|
/// </summary>
|
||
|
/// <exception cref="System.InvalidOperationException">Thrown if the NavigationProperty instance is in ReadOnly state</exception>
|
||
|
[MetadataProperty(BuiltInTypeKind.RelationshipEndMember, false)]
|
||
|
public RelationshipEndMember ToEndMember
|
||
|
{
|
||
|
get
|
||
|
{
|
||
|
return _toEndMember;
|
||
|
}
|
||
|
internal set
|
||
|
{
|
||
|
_toEndMember = value;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/// <summary>
|
||
|
/// Gets/Sets the from relationship end member in the navigation
|
||
|
/// </summary>
|
||
|
/// <exception cref="System.InvalidOperationException">Thrown if the NavigationProperty instance is in ReadOnly state</exception>
|
||
|
[MetadataProperty(BuiltInTypeKind.RelationshipEndMember, false)]
|
||
|
public RelationshipEndMember FromEndMember
|
||
|
{
|
||
|
get
|
||
|
{
|
||
|
return _fromEndMember;
|
||
|
}
|
||
|
internal set
|
||
|
{
|
||
|
_fromEndMember = value;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
internal NavigationPropertyAccessor Accessor
|
||
|
{
|
||
|
get { return _accessor; }
|
||
|
}
|
||
|
|
||
|
/// <summary>
|
||
|
/// 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.
|
||
|
/// </summary>
|
||
|
/// <returns>Foreign key properties</returns>
|
||
|
public IEnumerable<EdmProperty> 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<EdmProperty>(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<EdmProperty>();
|
||
|
}
|
||
|
}
|
||
|
}
|