Updates referencesource to .NET 4.7
[mono.git] / mcs / class / referencesource / System.Data.Entity / System / Data / EntityModel / SchemaObjectModel / Relationship.cs
1 //---------------------------------------------------------------------
2 // <copyright file="Relationship.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.Data.Objects.DataClasses;
15     using System.Diagnostics;
16     using System.Xml;
17
18     /// <summary>
19     /// Represents an Association element
20     /// </summary>
21     internal sealed class Relationship : SchemaType, IRelationship
22     {
23         private RelationshipKind _relationshipKind;
24         private RelationshipEndCollection _ends;
25         private List<ReferentialConstraint> _constraints;
26         private bool _isForeignKey;
27
28         /// <summary>
29         /// Construct a Relationship object
30         /// </summary>
31         /// <param name="parent">the parent</param>
32         /// <param name="kind">the kind of relationship</param>
33         public Relationship(Schema parent, RelationshipKind kind)
34         : base(parent)
35         {
36             RelationshipKind = kind;
37
38             if (Schema.DataModel == SchemaDataModelOption.EntityDataModel)
39             {
40                 _isForeignKey = false;
41                 OtherContent.Add(Schema.SchemaSource);
42             }
43             else if (Schema.DataModel == SchemaDataModelOption.ProviderDataModel)
44             {
45                 _isForeignKey = true;
46             }
47         }
48
49
50         /// <summary>
51         /// List of Ends defined for this Association
52         /// </summary>
53         public IList<IRelationshipEnd> Ends
54         {
55             get
56             {
57                 if ( _ends == null )
58                     _ends = new RelationshipEndCollection();
59                 return _ends;
60             }
61         }
62
63         /// <summary>
64         /// Returns the list of constraints on this relation
65         /// </summary>
66         public IList<ReferentialConstraint> Constraints
67         {
68             get
69             {
70                 if (_constraints == null)
71                 {
72                     _constraints = new List<ReferentialConstraint>();
73                 }
74                 return _constraints;
75             }
76         }
77
78         public bool TryGetEnd( string roleName, out IRelationshipEnd end )
79         {
80             return _ends.TryGetEnd( roleName, out end );
81         }
82
83
84         /// <summary>
85         /// Is this an Association
86         /// </summary>
87         public RelationshipKind RelationshipKind
88         {
89             get
90             {
91                 return _relationshipKind;
92             }
93             private set
94             {
95                 _relationshipKind = value;
96             }
97         }
98
99         /// <summary>
100         /// Is this a foreign key (aka foreign key) relationship?
101         /// </summary>
102         public bool IsForeignKey
103         {
104             get { return _isForeignKey; }
105         }
106
107         /// <summary>
108         /// do whole element validation
109         /// </summary>
110         /// <returns></returns>
111         internal override void Validate()
112         {
113             base.Validate();
114
115             bool foundOperations = false;
116             foreach ( RelationshipEnd end in Ends )
117             {
118                 end.Validate();
119                 if ( RelationshipKind == RelationshipKind.Association )
120                 {
121                     if ( end.Operations.Count > 0 )
122                     {
123                         if ( foundOperations )
124                             end.AddError( ErrorCode.InvalidOperation, EdmSchemaErrorSeverity.Error, System.Data.Entity.Strings.InvalidOperationMultipleEndsInAssociation);
125                         foundOperations = true;
126                     }
127                 }
128             }
129
130             if (Constraints.Count == 0)
131             {
132                 if (this.Schema.DataModel == SchemaDataModelOption.ProviderDataModel)
133                 {
134                     AddError(ErrorCode.MissingConstraintOnRelationshipType,
135                              EdmSchemaErrorSeverity.Error,
136                              System.Data.Entity.Strings.MissingConstraintOnRelationshipType(FQName));
137                 }
138             }
139             else
140             {
141                 foreach (ReferentialConstraint constraint in Constraints)
142                 {
143                     constraint.Validate();
144                 }
145             }
146         }
147
148         /// <summary>
149         /// do whole element resolution
150         /// </summary>
151         internal override void ResolveTopLevelNames()
152         {
153             base.ResolveTopLevelNames();
154
155             foreach ( RelationshipEnd end in Ends )
156                 end.ResolveTopLevelNames();
157
158             foreach (ReferentialConstraint referentialConstraint in Constraints)
159             {
160                 referentialConstraint.ResolveTopLevelNames();
161             }
162         }
163
164         protected override bool HandleElement(XmlReader reader)
165         {
166             if (base.HandleElement(reader))
167             {
168                 return true;
169             }
170             else if (CanHandleElement(reader, XmlConstants.End))
171             {
172                 HandleEndElement(reader);
173                 return true;
174             }
175             else if (CanHandleElement(reader, XmlConstants.ReferentialConstraint))
176             {
177                 HandleConstraintElement(reader);
178                 return true;
179             }
180             return false;
181         }
182
183         /// <summary>
184         /// handle the End child element
185         /// </summary>
186         /// <param name="reader">XmlReader positioned at the end element</param>
187         private void HandleEndElement(XmlReader reader)
188         {
189             Debug.Assert(reader != null);
190             RelationshipEnd end = new RelationshipEnd(this);
191             end.Parse(reader);
192
193             if (Ends.Count == 2)
194             {
195                 AddError( ErrorCode.InvalidAssociation, EdmSchemaErrorSeverity.Error, System.Data.Entity.Strings.TooManyAssociationEnds(FQName ) );
196                 return;
197             }
198
199             Ends.Add(end);
200         }
201
202         /// <summary>
203         /// handle the constraint element
204         /// </summary>
205         /// <param name="reader">XmlReader positioned at the constraint element</param>
206         private void HandleConstraintElement(XmlReader reader)
207         {
208             Debug.Assert(reader != null);
209
210             ReferentialConstraint constraint = new ReferentialConstraint(this);
211             constraint.Parse(reader);
212             this.Constraints.Add(constraint);
213
214             if (this.Schema.DataModel == SchemaDataModelOption.EntityDataModel && this.Schema.SchemaVersion >= XmlConstants.EdmVersionForV2)
215             {
216                 // in V2, referential constraint implies foreign key
217                 _isForeignKey = true;
218             }
219         }
220
221     }
222 }