1 //---------------------------------------------------------------------
2 // <copyright file="RelationshipEnd.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.Metadata.Edm;
14 using System.Diagnostics;
18 /// Represents an End element in a relationship
20 internal sealed class RelationshipEnd : SchemaElement, IRelationshipEnd
22 private string _unresolvedType;
23 private RelationshipMultiplicity? _multiplicity;
24 private SchemaEntityType _type;
25 private List<OnOperation> _operations;
28 /// construct a Relationship End
30 /// <param name="relationship"></param>
31 public RelationshipEnd(Relationship relationship)
39 public SchemaEntityType Type
52 /// Multiplicity of the End
54 public RelationshipMultiplicity? Multiplicity
62 _multiplicity = value;
67 /// The On<Operation>s defined for the End
69 public ICollection<OnOperation> Operations
73 if (_operations == null)
74 _operations = new List<OnOperation>();
80 /// do whole element resolution
82 internal override void ResolveTopLevelNames()
84 base.ResolveTopLevelNames();
86 if (Type == null && _unresolvedType != null)
89 if (!Schema.ResolveTypeName(this, _unresolvedType, out element))
94 Type = element as SchemaEntityType;
97 AddError(ErrorCode.InvalidRelationshipEndType, EdmSchemaErrorSeverity.Error,
98 System.Data.Entity.Strings.InvalidRelationshipEndType(ParentElement.Name, element.FQName));
103 internal override void Validate()
107 // Check if the end has multiplicity as many, it cannot have any operation behaviour
108 if (Multiplicity == RelationshipMultiplicity.Many && Operations.Count != 0)
110 AddError(ErrorCode.EndWithManyMultiplicityCannotHaveOperationsSpecified,
111 EdmSchemaErrorSeverity.Error,
112 System.Data.Entity.Strings.EndWithManyMultiplicityCannotHaveOperationsSpecified(this.Name, ParentElement.FQName));
118 // if there is no RefConstraint in Association and multiplicity is null
119 if (this.ParentElement.Constraints.Count == 0 && Multiplicity == null)
121 AddError(ErrorCode.EndWithoutMultiplicity,
122 EdmSchemaErrorSeverity.Error,
123 System.Data.Entity.Strings.EndWithoutMultiplicity(this.Name, ParentElement.FQName));
128 /// Do simple validation across attributes
130 protected override void HandleAttributesComplete()
132 // set up the default name in before validating anythig that might want to display it in an error message;
133 if (Name == null && _unresolvedType != null)
134 Name = Utils.ExtractTypeName(Schema.DataModel, _unresolvedType);
136 base.HandleAttributesComplete();
139 protected override bool ProhibitAttribute(string namespaceUri, string localName)
141 if (base.ProhibitAttribute(namespaceUri, localName))
146 if (namespaceUri == null && localName == XmlConstants.Name)
152 protected override bool HandleAttribute(XmlReader reader)
154 if (base.HandleAttribute(reader))
158 else if (CanHandleAttribute(reader, XmlConstants.Multiplicity))
160 HandleMultiplicityAttribute(reader);
163 else if (CanHandleAttribute(reader, XmlConstants.Role))
165 HandleNameAttribute(reader);
168 else if (CanHandleAttribute(reader, XmlConstants.TypeElement))
170 HandleTypeAttribute(reader);
177 protected override bool HandleElement(XmlReader reader)
179 if (base.HandleElement(reader))
183 else if (CanHandleElement(reader, XmlConstants.OnDelete))
185 HandleOnDeleteElement(reader);
192 /// Handle the Type attribute
194 /// <param name="reader">reader positioned at Type attribute</param>
195 private void HandleTypeAttribute(XmlReader reader)
197 Debug.Assert(reader != null);
200 if (!Utils.GetDottedName(this.Schema, reader, out type))
203 _unresolvedType = type;
207 /// Handle the Multiplicity attribute
209 /// <param name="reader">reader positioned at Type attribute</param>
210 private void HandleMultiplicityAttribute(XmlReader reader)
212 Debug.Assert(reader != null);
213 RelationshipMultiplicity multiplicity;
214 if (!TryParseMultiplicity(reader.Value, out multiplicity))
216 AddError(ErrorCode.InvalidMultiplicity, EdmSchemaErrorSeverity.Error, reader, System.Data.Entity.Strings.InvalidRelationshipEndMultiplicity(ParentElement.Name, reader.Value));
218 _multiplicity = multiplicity;
222 /// Handle an OnDelete element
224 /// <param name="reader">reader positioned at the element</param>
225 private void HandleOnDeleteElement(XmlReader reader)
227 HandleOnOperationElement(reader, Operation.Delete);
231 /// Handle an On<Operation> element
233 /// <param name="reader">reader positioned at the element</param>
234 /// <param name="operation">the kind of operation being handled</param>
235 private void HandleOnOperationElement(XmlReader reader, Operation operation)
237 Debug.Assert(reader != null);
239 foreach (OnOperation other in Operations)
241 if (other.Operation == operation)
242 AddError(ErrorCode.InvalidOperation, EdmSchemaErrorSeverity.Error, reader, System.Data.Entity.Strings.DuplicationOperation(reader.Name));
245 OnOperation onOperation = new OnOperation(this, operation);
246 onOperation.Parse(reader);
247 _operations.Add(onOperation);
253 /// The parent element as an IRelationship
255 internal new IRelationship ParentElement
259 return (IRelationship)(base.ParentElement);
264 /// Create a new Multiplicity object from a string
266 /// <param name="value">string containing Multiplicity definition</param>
267 /// <param name="multiplicity">new multiplicity object (null if there were errors)</param>
268 /// <returns>try if the string was parsable, false otherwise</returns>
269 private static bool TryParseMultiplicity(string value, out RelationshipMultiplicity multiplicity)
274 multiplicity = RelationshipMultiplicity.ZeroOrOne;
277 multiplicity = RelationshipMultiplicity.One;
280 multiplicity = RelationshipMultiplicity.Many;
283 multiplicity = (RelationshipMultiplicity)(- 1);