1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168
|
//---------------------------------------------------------------------
// <copyright file="NavigationProperty.cs" company="Microsoft">
// Copyright (c) Microsoft Corporation. All rights reserved.
// </copyright>
//
// @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
{
/// <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>();
}
}
}
|