Updates referencesource to .NET 4.7
[mono-project.git] / mcs / class / referencesource / System.Data.Entity / System / Data / EntityModel / SchemaObjectModel / EntityContainerRelationshipSet.cs
blobdca3bc5e3c3ff784dc4c7c85a258cb0a3e2d4e80
1 //---------------------------------------------------------------------
2 // <copyright file="EntityContainerRelationshipSet.cs" company="Microsoft">
3 // Copyright (c) Microsoft Corporation. All rights reserved.
4 // </copyright>
5 //
6 // @owner Microsoft
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;
16 using System.Xml;
18 /// <summary>
19 /// Represents an RelationshipSet element.
20 /// </summary>
21 internal abstract class EntityContainerRelationshipSet : SchemaElement
24 private IRelationship _relationship;
25 string _unresolvedRelationshipTypeName;
28 /// <summary>
29 /// Constructs an EntityContainerRelationshipSet
30 /// </summary>
31 /// <param name="parentElement">Reference to the schema element.</param>
32 public EntityContainerRelationshipSet( EntityContainer parentElement )
33 : base( parentElement )
37 public override string FQName
39 get
41 return this.ParentElement.Name + "." + this.Name;
45 internal IRelationship Relationship
47 get
49 return _relationship;
51 set
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; }
62 /// <summary>
63 /// The method that is called when an Association attribute is encountered.
64 /// </summary>
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;
77 /// <summary>
78 /// Used during the resolve phase to resolve the type name to the object that represents that type
79 /// </summary>
80 internal override void ResolveTopLevelNames()
82 base.ResolveTopLevelNames();
84 if ( _relationship == null )
86 SchemaType element;
87 if ( !Schema.ResolveTypeName( this, _unresolvedRelationshipTypeName, out element ) )
89 return;
92 _relationship = element as IRelationship;
93 if ( _relationship == null )
95 AddError( ErrorCode.InvalidPropertyType, EdmSchemaErrorSeverity.Error,
96 System.Data.Entity.Strings.InvalidRelationshipSetType(element.Name ) );
97 return;
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();
116 /// <summary>
117 /// Do all validation for this element here, and delegate to all sub elements
118 /// </summary>
119 internal override void Validate()
121 base.Validate();
123 InferEnds();
125 // check out the ends
126 foreach ( EntityContainerRelationshipSetEnd end in Ends )
128 end.Validate();
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))
143 // {
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));
147 // }
150 // Validate Number of ends is correct
151 // What we know:
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
159 /// <summary>
160 /// Adds any ends that need to be infered
161 /// </summary>
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);
181 /// <summary>
182 /// For the given relationship end, find the EntityContainer Property that will work for the extent
183 /// </summary>
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 )
205 // no matchs
206 AddError( ErrorCode.MissingExtentEntityContainerEnd, EdmSchemaErrorSeverity.Error,
207 System.Data.Entity.Strings.MissingEntityContainerEnd(relationshipEnd.Name, FQName ) );
209 else
211 // abmigous
212 AddError( ErrorCode.AmbiguousEntityContainerEnd, EdmSchemaErrorSeverity.Error,
213 System.Data.Entity.Strings.AmbiguousEntityContainerEnd(relationshipEnd.Name, FQName ) );
216 return null;
220 /// <summary>
221 /// The parent element as an EntityContainer
222 /// </summary>
223 internal new EntityContainer ParentElement
227 return (EntityContainer)( base.ParentElement );