1 //---------------------------------------------------------------------
2 // <copyright file="EntityContainerRelationshipSet.cs" company="Microsoft">
3 // Copyright (c) Microsoft Corporation. All rights reserved.
7 // @backupOwner Microsoft
8 //---------------------------------------------------------------------
10 namespace System
.Data
.EntityModel
.SchemaObjectModel
12 using System
.Collections
.Generic
;
13 using System
.Data
.Entity
;
14 using System
.Data
.Metadata
.Edm
;
15 using System
.Diagnostics
;
19 /// Represents an RelationshipSet element.
21 internal abstract class EntityContainerRelationshipSet
: SchemaElement
24 private IRelationship _relationship
;
25 string _unresolvedRelationshipTypeName
;
29 /// Constructs an EntityContainerRelationshipSet
31 /// <param name="parentElement">Reference to the schema element.</param>
32 public EntityContainerRelationshipSet( EntityContainer parentElement
)
33 : base( parentElement
)
37 public override string FQName
41 return this.ParentElement
.Name
+ "." + this.Name
;
45 internal IRelationship Relationship
53 Debug
.Assert(value != null, "relationship can never be set to null");
54 _relationship
= value;
58 protected abstract bool HasEnd( string role
);
59 protected abstract void AddEnd( IRelationshipEnd relationshipEnd
, EntityContainerEntitySet entitySet
);
60 internal abstract IEnumerable
<EntityContainerRelationshipSetEnd
> Ends { get; }
63 /// The method that is called when an Association attribute is encountered.
65 /// <param name="reader">An XmlReader positioned at the Association attribute.</param>
66 protected void HandleRelationshipTypeNameAttribute( XmlReader reader
)
68 Debug
.Assert( reader
!= null );
69 ReturnValue
<string> value = HandleDottedNameAttribute( reader
, _unresolvedRelationshipTypeName
, Strings
.PropertyTypeAlreadyDefined
);
70 if ( value.Succeeded
)
72 _unresolvedRelationshipTypeName
= value.Value
;
78 /// Used during the resolve phase to resolve the type name to the object that represents that type
80 internal override void ResolveTopLevelNames()
82 base.ResolveTopLevelNames();
84 if ( _relationship
== null )
87 if ( !Schema
.ResolveTypeName( this, _unresolvedRelationshipTypeName
, out element
) )
92 _relationship
= element
as IRelationship
;
93 if ( _relationship
== null )
95 AddError( ErrorCode
.InvalidPropertyType
, EdmSchemaErrorSeverity
.Error
,
96 System
.Data
.Entity
.Strings
.InvalidRelationshipSetType(element
.Name
) );
101 foreach ( EntityContainerRelationshipSetEnd end
in Ends
)
103 end
.ResolveTopLevelNames();
107 internal override void ResolveSecondLevelNames()
109 base.ResolveSecondLevelNames();
110 foreach (EntityContainerRelationshipSetEnd end
in Ends
)
112 end
.ResolveSecondLevelNames();
117 /// Do all validation for this element here, and delegate to all sub elements
119 internal override void Validate()
125 // check out the ends
126 foreach ( EntityContainerRelationshipSetEnd end
in Ends
)
132 // Enabling Association between subtypes in case of Referential Constraints, since
133 // CSD is blocked on this. We need to make a long term call about whether we should
134 // really allow this. Bug #520216
135 //foreach (ReferentialConstraint constraint in Relationship.Constraints)
137 // IRelationshipEnd dependentEnd = constraint.DependentRole.End;
138 // EntityContainerRelationshipSetEnd setEnd = GetEnd(dependentEnd.Name);
139 // Debug.Assert(setEnd != null);
140 // //Make sure that the EntityType of the dependant role in a referential constraint
141 // //covers the whole EntitySet( i.e. not a subtype of the EntitySet's type).
142 // if (!setEnd.EntitySet.EntityType.IsOfType(constraint.DependentRole.End.Type))
144 // AddError(ErrorCode.InvalidDependentRoleType, EdmSchemaErrorSeverity.Error,
145 // System.Data.Entity.Strings.InvalidDependentRoleType(dependentEnd.Type.FQName, dependentEnd.Name,
146 // dependentEnd.Parent.FQName, setEnd.EntitySet.Name, setEnd.ParentElement.Name));
150 // Validate Number of ends is correct
152 // No ends are missing, becuase we infered all missing ends
153 // No extra ends are there because the names have been matched, and an extra name will have caused an error
155 // looks like no count validation needs to be done
160 /// Adds any ends that need to be infered
162 private void InferEnds()
164 Debug
.Assert( Relationship
!= null );
166 foreach ( IRelationshipEnd relationshipEnd
in Relationship
.Ends
)
168 if ( ! HasEnd( relationshipEnd
.Name
) )
170 EntityContainerEntitySet entitySet
= InferEntitySet(relationshipEnd
);
171 if (entitySet
!= null)
173 // we don't have this end, we need to add it
174 AddEnd(relationshipEnd
, entitySet
);
182 /// For the given relationship end, find the EntityContainer Property that will work for the extent
184 /// <param name="relationshipEnd">The relationship end of the RelationshipSet that needs and extent</param>
185 /// <returns>Null is none could be found, or the EntityContainerProperty that is the valid extent</returns>
186 private EntityContainerEntitySet
InferEntitySet( IRelationshipEnd relationshipEnd
)
188 Debug
.Assert(relationshipEnd
!= null, "relationshipEnd parameter is null");
190 List
<EntityContainerEntitySet
> possibleExtents
= new List
<EntityContainerEntitySet
>();
191 foreach ( EntityContainerEntitySet
set in ParentElement
.EntitySets
)
193 if ( relationshipEnd
.Type
.IsOfType( set.EntityType
) )
195 possibleExtents
.Add( set );
199 if ( possibleExtents
.Count
== 1 )
201 return possibleExtents
[0];
203 else if ( possibleExtents
.Count
== 0 )
206 AddError( ErrorCode
.MissingExtentEntityContainerEnd
, EdmSchemaErrorSeverity
.Error
,
207 System
.Data
.Entity
.Strings
.MissingEntityContainerEnd(relationshipEnd
.Name
, FQName
) );
212 AddError( ErrorCode
.AmbiguousEntityContainerEnd
, EdmSchemaErrorSeverity
.Error
,
213 System
.Data
.Entity
.Strings
.AmbiguousEntityContainerEnd(relationshipEnd
.Name
, FQName
) );
221 /// The parent element as an EntityContainer
223 internal new EntityContainer ParentElement
227 return (EntityContainer
)( base.ParentElement
);