/// <summary> /// Given the type in the target space and the member name in the source space, /// get the corresponding member in the target space /// For e.g. consider a Conceptual Type 'Foo' with a member 'Bar' and a CLR type /// 'XFoo' with a member 'YBar'. If one has a reference to Foo one can /// invoke GetMember(Foo,"YBar") to retrieve the member metadata for bar /// </summary> /// <param name="type">The type in the target perspective</param> /// <param name="memberName">the name of the member in the source perspective</param> /// <param name="ignoreCase">Whether to do case-sensitive member look up or not</param> /// <param name="outMember">returns the member in target space, if a match is found</param> internal virtual bool TryGetMember(StructuralType type, String memberName, bool ignoreCase, out EdmMember outMember) { EntityUtil.CheckArgumentNull(type, "type"); EntityUtil.CheckStringArgument(memberName, "memberName"); outMember = null; return(type.Members.TryGetValue(memberName, ignoreCase, out outMember)); }
private void AddScalarMember(Type type, PropertyInfo clrProperty, StructuralType ospaceType, EdmProperty cspaceProperty, EdmType propertyType) { Debug.Assert(type != null, "type != null"); Debug.Assert(clrProperty != null, "clrProperty != null"); Debug.Assert(clrProperty.CanRead && clrProperty.CanWrite, "The clr property has to have a setter and a getter."); Debug.Assert(ospaceType != null, "ospaceType != null"); Debug.Assert(cspaceProperty != null, "cspaceProperty != null"); Debug.Assert(propertyType != null, "propertyType != null"); Debug.Assert(Helper.IsScalarType(propertyType), "Property has to be primitive or enum."); var cspaceType = cspaceProperty.DeclaringType; bool isKeyMember = Helper.IsEntityType(cspaceType) && ((EntityType)cspaceType).KeyMemberNames.Contains(clrProperty.Name); // the property is nullable only if it is not a key and can actually be set to null (i.e. is not a value type or is a nullable value type) bool nullableFacetValue = !isKeyMember && (!clrProperty.PropertyType.IsValueType || Nullable.GetUnderlyingType(clrProperty.PropertyType) != null); EdmProperty ospaceProperty = new EdmProperty( cspaceProperty.Name, TypeUsage.Create(propertyType, new FacetValues { Nullable = nullableFacetValue }), clrProperty, type.TypeHandle); if (isKeyMember) { ((EntityType)ospaceType).AddKeyMember(ospaceProperty); } else { ospaceType.AddMember(ospaceProperty); } }
private bool TryFindAndCreateEnumProperties(Type type, StructuralType cspaceType, StructuralType ospaceType, PropertyInfo[] clrProperties, List <Action> referenceResolutionListForCurrentType) { var typeClosureToTrack = new List <KeyValuePair <EdmProperty, PropertyInfo> >(); foreach (EdmProperty cspaceProperty in cspaceType.GetDeclaredOnlyMembers <EdmProperty>().Where(p => Helper.IsEnumType(p.TypeUsage.EdmType))) { PropertyInfo clrProperty = clrProperties.FirstOrDefault(p => MemberMatchesByConvention(p, cspaceProperty)); if (clrProperty != null) { typeClosureToTrack.Add(new KeyValuePair <EdmProperty, PropertyInfo>(cspaceProperty, clrProperty)); } else { string message = Strings.Validator_OSpace_Convention_MissingRequiredProperty(cspaceProperty.Name, type.FullName); SessionData.LoadMessageLogger.LogLoadMessage(message, cspaceType); return(false); } } foreach (var typeToTrack in typeClosureToTrack) { TrackClosure(typeToTrack.Value.PropertyType); // prevent the lifting of these closure variables var ot = ospaceType; var cp = typeToTrack.Key; var clrp = typeToTrack.Value; referenceResolutionListForCurrentType.Add(() => CreateAndAddEnumProperty(type, ot, cp, clrp)); } return(true); }
/// <summary> /// Creates an Enum property based on <paramref name="clrProperty"/>and adds it to the parent structural type. /// </summary> /// <param name="type">CLR type owning <paramref name="clrProperty"/>.</param> /// <param name="ospaceType">OSpace type the created property will be added to.</param> /// <param name="cspaceProperty">Corresponding property from CSpace.</param> /// <param name="clrProperty">CLR property used to build an Enum property.</param> private void CreateAndAddEnumProperty(Type type, StructuralType ospaceType, EdmProperty cspaceProperty, PropertyInfo clrProperty) { EdmType propertyType; if (SessionData.CspaceToOspace.TryGetValue(cspaceProperty.TypeUsage.EdmType, out propertyType)) { if (clrProperty.CanRead && clrProperty.CanWrite) { AddScalarMember(type, clrProperty, ospaceType, cspaceProperty, propertyType); } else { string message = SessionData.LoadMessageLogger.CreateErrorMessageWithTypeSpecificLoadLogs( Strings.Validator_OSpace_Convention_ScalarPropertyMissginGetterOrSetter(clrProperty.Name, type.FullName, type.Assembly.FullName), cspaceProperty.TypeUsage.EdmType); SessionData.EdmItemErrors.Add(new EdmItemError(message, ospaceType)); } } else { string message = SessionData.LoadMessageLogger.CreateErrorMessageWithTypeSpecificLoadLogs( Strings.Validator_OSpace_Convention_MissingOSpaceType(cspaceProperty.TypeUsage.EdmType.FullName), cspaceProperty.TypeUsage.EdmType); SessionData.EdmItemErrors.Add(new EdmItemError(message, ospaceType)); } }
private bool TryCreateMembers(Type type, StructuralType cspaceType, StructuralType ospaceType, List <Action> referenceResolutionListForCurrentType) { BindingFlags flags = cspaceType.BaseType == null ? RootEntityPropertyReflectionBindingFlags : PropertyReflectionBindingFlags; PropertyInfo[] clrProperties = type.GetProperties(flags); // required properties scalar properties first if (!TryFindAndCreatePrimitiveProperties(type, cspaceType, ospaceType, clrProperties)) { return(false); } if (!TryFindAndCreateEnumProperties(type, cspaceType, ospaceType, clrProperties, referenceResolutionListForCurrentType)) { return(false); } if (!TryFindComplexProperties(type, cspaceType, ospaceType, clrProperties, referenceResolutionListForCurrentType)) { return(false); } if (!TryFindNavigationProperties(type, cspaceType, ospaceType, clrProperties, referenceResolutionListForCurrentType)) { return(false); } return(true); }
/// <summary> /// Creates a structural OSpace type based on CLR type and CSpace type. /// </summary> /// <param name="type">CLR type.</param> /// <param name="cspaceType">CSpace Type</param> /// <param name="newOSpaceType">OSpace type created based on CLR <paramref name="type"/> and <paramref name="cspaceType"/></param> /// <returns><c>true</c> if the type was created successfully. Otherwise <c>false</c>.</returns> private bool TryCreateStructuralType(Type type, StructuralType cspaceType, out EdmType newOSpaceType) { Debug.Assert(type != null, "type != null"); Debug.Assert(cspaceType != null, "cspaceType != null"); List <Action> referenceResolutionListForCurrentType = new List <Action>(); newOSpaceType = null; Debug.Assert(TypesMatchByConvention(type, cspaceType), "The types passed as parameters don't match by convention."); StructuralType ospaceType; if (Helper.IsEntityType(cspaceType)) { ospaceType = new ClrEntityType(type, cspaceType.NamespaceName, cspaceType.Name); } else { Debug.Assert(Helper.IsComplexType(cspaceType), "Invalid type attribute encountered"); ospaceType = new ClrComplexType(type, cspaceType.NamespaceName, cspaceType.Name); } if (cspaceType.BaseType != null) { if (TypesMatchByConvention(type.BaseType, cspaceType.BaseType)) { TrackClosure(type.BaseType); referenceResolutionListForCurrentType.Add( () => ospaceType.BaseType = ResolveBaseType((StructuralType)cspaceType.BaseType, type)); } else { string message = Strings.Validator_OSpace_Convention_BaseTypeIncompatible(type.BaseType.FullName, type.FullName, cspaceType.BaseType.FullName); SessionData.LoadMessageLogger.LogLoadMessage(message, cspaceType); return(false); } } // Load the properties for this type if (!TryCreateMembers(type, (StructuralType)cspaceType, ospaceType, referenceResolutionListForCurrentType)) { return(false); } // Add this to the known type map so we won't try to load it again SessionData.TypesInLoading.Add(type.FullName, ospaceType); // we only add the referenceResolution to the list unless we structrually matched this type foreach (var referenceResolution in referenceResolutionListForCurrentType) { this._referenceResolutions.Add(referenceResolution); } newOSpaceType = ospaceType; return(true); }
private void CreateAndAddNavigationProperty(StructuralType cspaceType, StructuralType ospaceType, NavigationProperty cspaceProperty, PropertyInfo clrProperty) { EdmType ospaceRelationship; if (SessionData.CspaceToOspace.TryGetValue(cspaceProperty.RelationshipType, out ospaceRelationship)) { Debug.Assert(ospaceRelationship is StructuralType, "Structural type expected."); bool foundTarget = false; EdmType targetType = null; if (Helper.IsCollectionType(cspaceProperty.TypeUsage.EdmType)) { EdmType findType; foundTarget = SessionData.CspaceToOspace.TryGetValue((StructuralType)((CollectionType)cspaceProperty.TypeUsage.EdmType).TypeUsage.EdmType, out findType); if (foundTarget) { Debug.Assert(findType is StructuralType, "Structural type expected."); targetType = findType.GetCollectionType(); } } else { EdmType findType; foundTarget = SessionData.CspaceToOspace.TryGetValue((StructuralType)cspaceProperty.TypeUsage.EdmType, out findType); if (foundTarget) { Debug.Assert(findType is StructuralType, "Structural type expected."); targetType = findType; } } Debug.Assert(foundTarget, "Since the relationship will only be created if it can find the types for both ends, we will never fail to find one of the ends"); NavigationProperty navigationProperty = new NavigationProperty(cspaceProperty.Name, TypeUsage.Create(targetType), clrProperty); navigationProperty.RelationshipType = (RelationshipType)ospaceRelationship; // we can use First because o-space relationships are created directly from // c-space relationship navigationProperty.ToEndMember = (RelationshipEndMember)((RelationshipType)ospaceRelationship).Members.First(e => e.Name == cspaceProperty.ToEndMember.Name); navigationProperty.FromEndMember = (RelationshipEndMember)((RelationshipType)ospaceRelationship).Members.First(e => e.Name == cspaceProperty.FromEndMember.Name); ospaceType.AddMember(navigationProperty); } else { EntityTypeBase missingType = cspaceProperty.RelationshipType.RelationshipEndMembers.Select(e => ((RefType)e.TypeUsage.EdmType).ElementType).First(e => e != cspaceType); string message = SessionData.LoadMessageLogger.CreateErrorMessageWithTypeSpecificLoadLogs( Strings.Validator_OSpace_Convention_RelationshipNotLoaded(cspaceProperty.RelationshipType.FullName, missingType.FullName), missingType); SessionData.EdmItemErrors.Add(new EdmItemError(message, ospaceType)); } }
/// <summary> /// Get the number of members the base type has. If the base type is not a structural type or has no /// members, it returns 0 /// </summary> /// <returns>The number of members in the base type</returns> private int GetBaseTypeMemberCount() { // The count of members is what in this collection plus base type's member collection StructuralType baseType = _declaringType.BaseType as StructuralType; if (baseType != null) { return(baseType.Members.Count); } return(0); }
private EdmType ResolveBaseType(StructuralType baseCSpaceType, Type type) { EdmType ospaceType; bool foundValue = SessionData.CspaceToOspace.TryGetValue(baseCSpaceType, out ospaceType); if (!foundValue) { string message = SessionData.LoadMessageLogger.CreateErrorMessageWithTypeSpecificLoadLogs( Strings.Validator_OSpace_Convention_BaseTypeNotLoaded(type, baseCSpaceType), baseCSpaceType); SessionData.EdmItemErrors.Add(new EdmItemError(message, ospaceType)); } Debug.Assert(!foundValue || ospaceType is StructuralType, "Structural type expected (if found)."); return(ospaceType); }
private bool TryFindNavigationProperties(Type type, StructuralType cspaceType, StructuralType ospaceType, PropertyInfo[] clrProperties, List <Action> referenceResolutionListForCurrentType) { List <KeyValuePair <NavigationProperty, PropertyInfo> > typeClosureToTrack = new List <KeyValuePair <NavigationProperty, PropertyInfo> >(); foreach (NavigationProperty cspaceProperty in cspaceType.GetDeclaredOnlyMembers <NavigationProperty>()) { PropertyInfo clrProperty = clrProperties.FirstOrDefault(p => NonPrimitiveMemberMatchesByConvention(p, cspaceProperty)); if (clrProperty != null) { bool needsSetter = cspaceProperty.ToEndMember.RelationshipMultiplicity != RelationshipMultiplicity.Many; if (clrProperty.CanRead && (!needsSetter || clrProperty.CanWrite)) { typeClosureToTrack.Add( new KeyValuePair <NavigationProperty, PropertyInfo>( cspaceProperty, clrProperty)); } } else { string message = Strings.Validator_OSpace_Convention_MissingRequiredProperty( cspaceProperty.Name, type.FullName); SessionData.LoadMessageLogger.LogLoadMessage(message, cspaceType); return(false); } } foreach (var typeToTrack in typeClosureToTrack) { TrackClosure(typeToTrack.Value.PropertyType); // keep from lifting these closure variables var ct = cspaceType; var ot = ospaceType; var cp = typeToTrack.Key; var clrp = typeToTrack.Value; referenceResolutionListForCurrentType.Add(() => CreateAndAddNavigationProperty(ct, ot, cp, clrp)); } return(true); }
/// <summary> /// Find the index of an item /// </summary> /// <param name="item">The item whose index is to be looked for</param> /// <returns>The index of the found item, -1 if not found</returns> public override int IndexOf(EdmMember item) { // Try to get it from this collection, if found, then the relative index needs to be added with the number // of members in the base type to get the absolute index int relativeIndex = base.IndexOf(item); if (relativeIndex != -1) { return(relativeIndex + GetBaseTypeMemberCount()); } // Try to find it in the base type StructuralType baseType = _declaringType.BaseType as StructuralType; if (baseType != null) { return(baseType.Members.IndexOf(item)); } return(-1); }
/// <summary> /// Given the type in the target space and the member name in the source space, /// get the corresponding member in the target space /// For e.g. consider a Conceptual Type Foo with a member bar and a CLR type /// XFoo with a member YBar. If one has a reference to Foo one can /// invoke GetMember(Foo,"YBar") to retrieve the member metadata for bar /// </summary> /// <param name="type">The type in the target perspective</param> /// <param name="memberName">the name of the member in the source perspective</param> /// <param name="ignoreCase">true for case-insensitive lookup</param> /// <param name="outMember">returns the edmMember if a match is found</param> /// <returns>true if a match is found, otherwise false</returns> internal override bool TryGetMember(StructuralType type, String memberName, bool ignoreCase, out EdmMember outMember) { outMember = null; Map map = null; if (this.MetadataWorkspace.TryGetMap(type, DataSpace.OCSpace, out map)) { ObjectTypeMapping objectTypeMap = map as ObjectTypeMapping; if (objectTypeMap != null) { ObjectMemberMapping objPropertyMapping = objectTypeMap.GetMemberMapForClrMember(memberName, ignoreCase); if (null != objPropertyMapping) { outMember = objPropertyMapping.EdmMember; return(true); } } } return(false); }
/// <summary> /// Resolves enum type property. /// </summary> /// <param name="declaringType">The type to add the declared property to.</param> /// <param name="clrProperty">Property to resolve.</param> private void ResolveEnumTypeProperty(StructuralType declaringType, PropertyInfo clrProperty) { Debug.Assert(declaringType != null, "type != null"); Debug.Assert(clrProperty != null, "clrProperty != null"); Debug.Assert( (Nullable.GetUnderlyingType(clrProperty.PropertyType) ?? clrProperty.PropertyType).IsEnum, "This method should be called for enums only"); EdmType propertyType; if (!TryGetLoadedType(clrProperty.PropertyType, out propertyType) || !Helper.IsEnumType(propertyType)) { SessionData.EdmItemErrors.Add( new EdmItemError( System.Data.Entity.Strings.Validator_OSpace_ScalarPropertyNotPrimitive( clrProperty.Name, clrProperty.DeclaringType.FullName, clrProperty.PropertyType.FullName), null)); } else { var edmScalarPropertyAttribute = (EdmScalarPropertyAttribute)clrProperty.GetCustomAttributes(typeof(EdmScalarPropertyAttribute), false).Single(); EdmProperty enumProperty = new EdmProperty( clrProperty.Name, TypeUsage.Create(propertyType, new FacetValues() { Nullable = edmScalarPropertyAttribute.IsNullable }), clrProperty, declaringType.ClrType.TypeHandle); declaringType.AddMember(enumProperty); if (declaringType.BuiltInTypeKind == BuiltInTypeKind.EntityType && edmScalarPropertyAttribute.EntityKeyProperty) { ((EntityType)declaringType).AddKeyMember(enumProperty); } } }
private void CreateAndAddComplexType(Type type, StructuralType ospaceType, EdmProperty cspaceProperty, PropertyInfo clrProperty) { EdmType propertyType; if (SessionData.CspaceToOspace.TryGetValue((StructuralType)cspaceProperty.TypeUsage.EdmType, out propertyType)) { Debug.Assert(propertyType is StructuralType, "Structural type expected."); EdmProperty property = new EdmProperty(cspaceProperty.Name, TypeUsage.Create(propertyType, new FacetValues { Nullable = false }), clrProperty, type.TypeHandle); ospaceType.AddMember(property); } else { string message = SessionData.LoadMessageLogger.CreateErrorMessageWithTypeSpecificLoadLogs( Strings.Validator_OSpace_Convention_MissingOSpaceType(cspaceProperty.TypeUsage.EdmType.FullName), cspaceProperty.TypeUsage.EdmType); SessionData.EdmItemErrors.Add(new EdmItemError(message, ospaceType)); } }
/// <summary> /// Validate an StructuralType object /// </summary> /// <param name="item">The StructuralType object to validate</param> /// <param name="errors">An error collection for adding validation errors</param> /// <param name="validatedItems">A dictionary keeping track of items that have been validated</param> private void ValidateStructuralType(StructuralType item, List <EdmItemError> errors, HashSet <MetadataItem> validatedItems) { ValidateEdmType(item, errors, validatedItems); // Just validate each member, the collection already guaranteed that there aren't any nulls in the collection Dictionary <string, EdmMember> allMembers = new Dictionary <string, EdmMember>(); foreach (EdmMember member in item.Members) { // Check if the base type already has a member of the same name EdmMember baseMember = null; if (allMembers.TryGetValue(member.Name, out baseMember)) { AddError(errors, new EdmItemError(System.Data.Entity.Strings.Validator_BaseTypeHasMemberOfSameName, item)); } else { allMembers.Add(member.Name, member); } InternalValidate(member, errors, validatedItems); } }
private bool TryFindAndCreatePrimitiveProperties(Type type, StructuralType cspaceType, StructuralType ospaceType, PropertyInfo[] clrProperties) { foreach (EdmProperty cspaceProperty in cspaceType.GetDeclaredOnlyMembers <EdmProperty>().Where(p => Helper.IsPrimitiveType(p.TypeUsage.EdmType))) { PropertyInfo clrProperty = clrProperties.FirstOrDefault(p => MemberMatchesByConvention(p, cspaceProperty)); if (clrProperty != null) { PrimitiveType propertyType; if (TryGetPrimitiveType(clrProperty.PropertyType, out propertyType)) { if (clrProperty.CanRead && clrProperty.CanWrite) { AddScalarMember(type, clrProperty, ospaceType, cspaceProperty, propertyType); } else { string message = Strings.Validator_OSpace_Convention_ScalarPropertyMissginGetterOrSetter(clrProperty.Name, type.FullName, type.Assembly.FullName); SessionData.LoadMessageLogger.LogLoadMessage(message, cspaceType); return(false); } } else { string message = Strings.Validator_OSpace_Convention_NonPrimitiveTypeProperty(clrProperty.Name, type.FullName, clrProperty.PropertyType.FullName); SessionData.LoadMessageLogger.LogLoadMessage(message, cspaceType); return(false); } } else { string message = Strings.Validator_OSpace_Convention_MissingRequiredProperty(cspaceProperty.Name, type.FullName); SessionData.LoadMessageLogger.LogLoadMessage(message, cspaceType); return(false); } } return(true); }
private void ResolveComplexTypeProperty(StructuralType type, PropertyInfo clrProperty) { // Load the property type and create a new property object EdmType propertyType; // If the type could not be loaded it's definitely not a complex type, so that's an error // If it could be loaded but is not a complex type that's an error as well if (!TryGetLoadedType(clrProperty.PropertyType, out propertyType) || propertyType.BuiltInTypeKind != BuiltInTypeKind.ComplexType) { // This property does not need to be validated further, just add to the errors collection and continue with the next property // This failure will cause an exception to be thrown later during validation of all of the types SessionData.EdmItemErrors.Add(new EdmItemError(System.Data.Entity.Strings.Validator_OSpace_ComplexPropertyNotComplex(clrProperty.Name, clrProperty.DeclaringType.FullName, clrProperty.PropertyType.FullName), null)); } else { EdmProperty newProperty = new EdmProperty(clrProperty.Name, TypeUsage.Create(propertyType, new FacetValues { Nullable = false }), clrProperty, type.ClrType.TypeHandle); type.AddMember(newProperty); } }
/// <summary> /// The method returns the underlying CLR type for the specified OSpace type argument. /// If the DataSpace of the parameter is not OSpace, the method returns false and sets /// the out parameter to null. /// </summary> /// <param name="objectSpaceType">The OSpace type to look up</param> /// <param name="clrType">The CLR type of the OSpace argument</param> /// <returns>true on success, false on failure</returns> public bool TryGetClrType(StructuralType objectSpaceType, out Type clrType) { return(ObjectItemCollection.TryGetClrType((EdmType)objectSpaceType, out clrType)); }
/// <summary> /// The method returns the underlying CLR type for the specified OSpace type argument. /// If the DataSpace of the parameter is not OSpace, an ArgumentException is thrown. /// </summary> /// <param name="objectSpaceType">The OSpace type to look up</param> /// <returns>The CLR type of the OSpace argument</returns> public Type GetClrType(StructuralType objectSpaceType) { return(ObjectItemCollection.GetClrType((EdmType)objectSpaceType)); }
internal void ResolveNavigationProperty(StructuralType declaringType, PropertyInfo propertyInfo) { Debug.Assert(propertyInfo.IsDefined(typeof(EdmRelationshipNavigationPropertyAttribute), false), "The property must have navigation property defined"); // EdmScalarPropertyAttribute, EdmComplexPropertyAttribute and EdmRelationshipNavigationPropertyAttribute // are all EdmPropertyAttributes that we need to process. If the current property is not an EdmPropertyAttribute // we will just ignore it and skip to the next property. object[] relationshipPropertyAttributes = propertyInfo.GetCustomAttributes(typeof(EdmRelationshipNavigationPropertyAttribute), false); Debug.Assert(relationshipPropertyAttributes.Length == 1, "There should be exactly one property for every navigation property"); // The only valid return types from navigation properties are: // (1) EntityType // (2) CollectionType containing valid EntityType // If TryGetLoadedType returned false, it could mean that we couldn't validate any part of the type, or it could mean that it's a generic // where the main generic type was validated, but the generic type parameter was not. We can't tell the difference, so just fail // with the same error message in both cases. The user will have to figure out which part of the type is wrong. // We can't just rely on checking for a generic because it can lead to a scenario where we report that the type parameter is invalid // when really it's the main generic type. That is more confusing than reporting the full name and letting the user determine the problem. EdmType propertyType; if (!TryGetLoadedType(propertyInfo.PropertyType, out propertyType) || !(propertyType.BuiltInTypeKind == BuiltInTypeKind.EntityType || propertyType.BuiltInTypeKind == BuiltInTypeKind.CollectionType)) { // Once an error is detected the property does not need to be validated further, just add to the errors // collection and continue with the next property. The failure will cause an exception to be thrown later during validation of all of the types. SessionData.EdmItemErrors.Add(new EdmItemError(System.Data.Entity.Strings.Validator_OSpace_InvalidNavPropReturnType(propertyInfo.Name, propertyInfo.DeclaringType.FullName, propertyInfo.PropertyType.FullName), null)); return; } // else we have a valid EntityType or CollectionType that contains EntityType. ResolveNonSchemaType enforces that a collection type // must contain an EntityType, and if it doesn't, propertyType will be null here. If propertyType is EntityType or CollectionType we know it is valid // Expecting EdmRelationshipNavigationPropertyAttribute to have AllowMultiple=False, so only look at first element in the attribute array EdmRelationshipNavigationPropertyAttribute attribute = (EdmRelationshipNavigationPropertyAttribute)relationshipPropertyAttributes[0]; EdmMember member = null; EdmType type; if (SessionData.TypesInLoading.TryGetValue(attribute.RelationshipNamespaceName + "." + attribute.RelationshipName, out type) && Helper.IsAssociationType(type)) { AssociationType relationshipType = (AssociationType)type; if (relationshipType != null) { // The return value of this property has been verified, so create the property now NavigationProperty navigationProperty = new NavigationProperty(propertyInfo.Name, TypeUsage.Create(propertyType), propertyInfo); navigationProperty.RelationshipType = relationshipType; member = navigationProperty; if (relationshipType.Members[0].Name == attribute.TargetRoleName) { navigationProperty.ToEndMember = (RelationshipEndMember)relationshipType.Members[0]; navigationProperty.FromEndMember = (RelationshipEndMember)relationshipType.Members[1]; } else if (relationshipType.Members[1].Name == attribute.TargetRoleName) { navigationProperty.ToEndMember = (RelationshipEndMember)relationshipType.Members[1]; navigationProperty.FromEndMember = (RelationshipEndMember)relationshipType.Members[0]; } else { SessionData.EdmItemErrors.Add(new EdmItemError(System.Data.Entity.Strings.TargetRoleNameInNavigationPropertyNotValid( propertyInfo.Name, propertyInfo.DeclaringType.FullName, attribute.TargetRoleName, attribute.RelationshipName), navigationProperty)); member = null; } if (member != null && ((RefType)navigationProperty.FromEndMember.TypeUsage.EdmType).ElementType.ClrType != declaringType.ClrType) { SessionData.EdmItemErrors.Add(new EdmItemError(System.Data.Entity.Strings.NavigationPropertyRelationshipEndTypeMismatch( declaringType.FullName, navigationProperty.Name, relationshipType.FullName, navigationProperty.FromEndMember.Name, ((RefType)navigationProperty.FromEndMember.TypeUsage.EdmType).ElementType.ClrType), navigationProperty)); member = null; } } } else { SessionData.EdmItemErrors.Add(new EdmItemError(System.Data.Entity.Strings.RelationshipNameInNavigationPropertyNotValid( propertyInfo.Name, propertyInfo.DeclaringType.FullName, attribute.RelationshipName), declaringType)); } if (member != null) { declaringType.AddMember(member); } }
/// <summary> /// Load all the property metadata of the given type /// </summary> /// <param name="type">The CLR entity type</param> /// <param name="structuralType">The type where properties are loaded</param> /// <param name="context"></param> private void LoadPropertiesFromType(StructuralType structuralType) { // Look at both public, internal, and private instanced properties declared at this type, inherited members // are not looked at. Internal and private properties are also looked at because they are also schematized fields PropertyInfo[] properties = structuralType.ClrType.GetProperties(PropertyReflectionBindingFlags); foreach (PropertyInfo property in properties) { EdmMember newMember = null; bool isEntityKeyProperty = false; //used for EdmScalarProperties only // EdmScalarPropertyAttribute, EdmComplexPropertyAttribute and EdmRelationshipNavigationPropertyAttribute // are all EdmPropertyAttributes that we need to process. If the current property is not an EdmPropertyAttribute // we will just ignore it and skip to the next property. if (property.IsDefined(typeof(EdmRelationshipNavigationPropertyAttribute), false)) { // keep the loop var from being lifted PropertyInfo pi = property; _unresolvedNavigationProperties.Add(() => ResolveNavigationProperty(structuralType, pi)); } else if (property.IsDefined(typeof(EdmScalarPropertyAttribute), false)) { if ((Nullable.GetUnderlyingType(property.PropertyType) ?? property.PropertyType).IsEnum) { TrackClosure(property.PropertyType); PropertyInfo local = property; AddTypeResolver(() => ResolveEnumTypeProperty(structuralType, local)); } else { newMember = LoadScalarProperty(structuralType.ClrType, property, out isEntityKeyProperty); } } else if (property.IsDefined(typeof(EdmComplexPropertyAttribute), false)) { TrackClosure(property.PropertyType); // keep loop var from being lifted PropertyInfo local = property; AddTypeResolver(() => ResolveComplexTypeProperty(structuralType, local)); } if (newMember == null) { // Property does not have one of the following attributes: // EdmScalarPropertyAttribute, EdmComplexPropertyAttribute, EdmRelationshipNavigationPropertyAttribute // This means its an unmapped property and can be ignored. // Or there were error encountered while loading the properties continue; } // Add the property object to the type structuralType.AddMember(newMember); // Add to the entity's collection of key members // Do this here instead of in the if condition above for scalar properties because // we want to make sure the AddMember call above did not fail before updating the key members if (Helper.IsEntityType(structuralType) && isEntityKeyProperty) { ((EntityType)structuralType).AddKeyMember(newMember); } } }
/// <summary> /// Change the declaring type without doing fixup in the member collection /// </summary> internal void ChangeDeclaringTypeWithoutCollectionFixup(StructuralType newDeclaringType) { _declaringType = newDeclaringType; }
/// <summary> /// The constructor for constructing the collection with the given items /// </summary> /// <param name="declaringType">The type that has this member collection</param> /// <param name="items">The items to populate the collection</param> /// <exception cref="System.ArgumentNullException">Thrown if the declaring type is null</exception> public MemberCollection(StructuralType declaringType, IEnumerable <EdmMember> items) : base(items) { Debug.Assert(declaringType != null, "This member collection must belong to a declaring type"); _declaringType = declaringType; }
// This way this collection works is that it has storage for members on the current type and access to // members in the base types. As of that requirement, MemberCollection has a reference back to the declaring // type that owns this collection. Whenever MemberCollection is asked to do a look by name, it looks at the // current collection, if it doesn't find it, then it ask for it from the declaring type's base type's // MemberCollection. Because of this order, members in derived types hide members in the base type if they // have the same name. For look up by index, base type members have lower index then current type's members. // Add/Update/Remove operations on this collection is only allowed for members owned by this MemberCollection // and not allowed for members owned by MemberCollections in the base types. For example, if the caller tries // to remove a member by ordinal which is within the base type's member ordinal range, it throws an exception. // Hence, base type members are in a sense "readonly" to this MemberCollection. When enumerating all the // members, the enumeration starts from members in the root type in the inheritance chain. With this special // enumeration requirement, we have a specialized enumerator class for this MemberCollection. See the // Enumerator class for details on how it works. #region Constructors /// <summary> /// Default constructor for constructing an empty collection /// </summary> /// <param name="declaringType">The type that has this member collection</param> /// <exception cref="System.ArgumentNullException">Thrown if the declaring type is null</exception> public MemberCollection(StructuralType declaringType) : this(declaringType, null) { }