e1806d8a65785437760a35188fa4c8806b1c9b33
[mono.git] / mcs / class / referencesource / System.Data.Entity / System / Data / EntityModel / SchemaObjectModel / RelationshipEnd.cs
1 //---------------------------------------------------------------------
2 // <copyright file="RelationshipEnd.cs" company="Microsoft">
3 //      Copyright (c) Microsoft Corporation.  All rights reserved.
4 // </copyright>
5 //
6 // @owner       Microsoft
7 // @backupOwner Microsoft
8 //---------------------------------------------------------------------
9
10 namespace System.Data.EntityModel.SchemaObjectModel
11 {
12     using System.Collections.Generic;
13     using System.Data.Metadata.Edm;
14     using System.Diagnostics;
15     using System.Xml;
16
17     /// <summary>
18     /// Represents an End element in a relationship
19     /// </summary>
20     internal sealed class RelationshipEnd : SchemaElement, IRelationshipEnd
21     {
22         private string _unresolvedType;
23         private RelationshipMultiplicity? _multiplicity;
24         private SchemaEntityType _type;
25         private List<OnOperation> _operations;
26
27         /// <summary>
28         /// construct a Relationship End
29         /// </summary>
30         /// <param name="relationship"></param>
31         public RelationshipEnd(Relationship relationship)
32             : base(relationship)
33         {
34         }
35
36         /// <summary>
37         /// Type of the End
38         /// </summary>
39         public SchemaEntityType Type
40         {
41             get
42             {
43                 return _type;
44             }
45             private set
46             {
47                 _type = value;
48             }
49         }
50
51         /// <summary>
52         /// Multiplicity of the End
53         /// </summary>
54         public RelationshipMultiplicity? Multiplicity
55         {
56             get
57             {
58                 return _multiplicity;
59             }
60             set
61             {
62                 _multiplicity = value;
63             }
64         }
65
66         /// <summary>
67         /// The On&lt;Operation&gt;s defined for the End
68         /// </summary>
69         public ICollection<OnOperation> Operations
70         {
71             get
72             {
73                 if (_operations == null)
74                     _operations = new List<OnOperation>();
75                 return _operations;
76             }
77         }
78
79         /// <summary>
80         /// do whole element resolution
81         /// </summary>
82         internal override void ResolveTopLevelNames()
83         {
84             base.ResolveTopLevelNames();
85
86             if (Type == null && _unresolvedType != null)
87             {
88                 SchemaType element;
89                 if (!Schema.ResolveTypeName(this, _unresolvedType, out element))
90                 {
91                     return;
92                 }
93
94                 Type = element as SchemaEntityType;
95                 if (Type == null)
96                 {
97                     AddError(ErrorCode.InvalidRelationshipEndType, EdmSchemaErrorSeverity.Error,
98                         System.Data.Entity.Strings.InvalidRelationshipEndType(ParentElement.Name, element.FQName));
99                 }
100             }
101         }
102
103         internal override void Validate()
104         {
105             base.Validate();
106
107             // Check if the end has multiplicity as many, it cannot have any operation behaviour
108             if (Multiplicity == RelationshipMultiplicity.Many && Operations.Count != 0)
109             {
110                 AddError(ErrorCode.EndWithManyMultiplicityCannotHaveOperationsSpecified,
111                          EdmSchemaErrorSeverity.Error,
112                          System.Data.Entity.Strings.EndWithManyMultiplicityCannotHaveOperationsSpecified(this.Name, ParentElement.FQName));
113
114                 
115                 
116             }
117             
118             // if there is no RefConstraint in Association and multiplicity is null
119             if (this.ParentElement.Constraints.Count == 0 && Multiplicity == null)
120             {
121                 AddError(ErrorCode.EndWithoutMultiplicity,
122                          EdmSchemaErrorSeverity.Error,
123                          System.Data.Entity.Strings.EndWithoutMultiplicity(this.Name, ParentElement.FQName));
124             }
125         }
126
127         /// <summary>
128         /// Do simple validation across attributes
129         /// </summary>
130         protected override void HandleAttributesComplete()
131         {
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);
135
136             base.HandleAttributesComplete();
137         }
138         
139         protected override bool ProhibitAttribute(string namespaceUri, string localName)
140         {
141             if (base.ProhibitAttribute(namespaceUri, localName))
142             {
143                 return true;
144             }
145
146             if (namespaceUri == null && localName == XmlConstants.Name)
147             {
148                 return false;
149             }
150             return false;
151         }
152         protected override bool HandleAttribute(XmlReader reader)
153         {
154             if (base.HandleAttribute(reader))
155             {
156                 return true;
157             }
158             else if (CanHandleAttribute(reader, XmlConstants.Multiplicity))
159             {
160                 HandleMultiplicityAttribute(reader);
161                 return true;
162             }
163             else if (CanHandleAttribute(reader, XmlConstants.Role))
164             {
165                 HandleNameAttribute(reader);
166                 return true;
167             }
168             else if (CanHandleAttribute(reader, XmlConstants.TypeElement))
169             {
170                 HandleTypeAttribute(reader);
171                 return true;
172             }
173
174             return false;
175         }
176
177         protected override bool HandleElement(XmlReader reader)
178         {
179             if (base.HandleElement(reader))
180             {
181                 return true;
182             }
183             else if (CanHandleElement(reader, XmlConstants.OnDelete))
184             {
185                 HandleOnDeleteElement(reader);
186                 return true;
187             }
188             return false;
189         }
190
191         /// <summary>
192         /// Handle the Type attribute
193         /// </summary>
194         /// <param name="reader">reader positioned at Type attribute</param>
195         private void HandleTypeAttribute(XmlReader reader)
196         {
197             Debug.Assert(reader != null);
198
199             string type;
200             if (!Utils.GetDottedName(this.Schema, reader, out type))
201                 return;
202
203             _unresolvedType = type;
204         }
205
206         /// <summary>
207         /// Handle the Multiplicity attribute
208         /// </summary>
209         /// <param name="reader">reader positioned at Type attribute</param>
210         private void HandleMultiplicityAttribute(XmlReader reader)
211         {
212             Debug.Assert(reader != null);
213             RelationshipMultiplicity multiplicity;
214             if (!TryParseMultiplicity(reader.Value, out multiplicity))
215             {
216                 AddError(ErrorCode.InvalidMultiplicity, EdmSchemaErrorSeverity.Error, reader, System.Data.Entity.Strings.InvalidRelationshipEndMultiplicity(ParentElement.Name, reader.Value));
217             }
218             _multiplicity = multiplicity;
219         }
220
221         /// <summary>
222         /// Handle an OnDelete element
223         /// </summary>
224         /// <param name="reader">reader positioned at the element</param>
225         private void HandleOnDeleteElement(XmlReader reader)
226         {
227             HandleOnOperationElement(reader, Operation.Delete);
228         }
229
230         /// <summary>
231         /// Handle an On&lt;Operation&gt; element
232         /// </summary>
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)
236         {
237             Debug.Assert(reader != null);
238
239             foreach (OnOperation other in Operations)
240             {
241                 if (other.Operation == operation)
242                     AddError(ErrorCode.InvalidOperation, EdmSchemaErrorSeverity.Error, reader, System.Data.Entity.Strings.DuplicationOperation(reader.Name));
243             }
244
245             OnOperation onOperation = new OnOperation(this, operation);
246             onOperation.Parse(reader);
247             _operations.Add(onOperation);
248         }
249
250
251
252         /// <summary>
253         /// The parent element as an IRelationship
254         /// </summary>
255         internal new IRelationship ParentElement
256         {
257             get
258             {
259                 return (IRelationship)(base.ParentElement);
260             }
261         }
262
263         /// <summary>
264         /// Create a new Multiplicity object from a string
265         /// </summary>
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)
270         {
271             switch (value)
272             {
273                 case "0..1":
274                     multiplicity = RelationshipMultiplicity.ZeroOrOne;
275                     return true;
276                 case "1":
277                     multiplicity = RelationshipMultiplicity.One;
278                     return true;
279                 case "*":
280                     multiplicity = RelationshipMultiplicity.Many;
281                     return true;
282                 default:
283                     multiplicity = (RelationshipMultiplicity)(- 1);
284                     return false;
285             }
286         }
287     }
288 }