Updates referencesource to .NET 4.7
[mono-project.git] / mcs / class / referencesource / System.Data.Entity / System / Data / Mapping / ViewGeneration / Validation / ViewKeyConstraint.cs
bloba8898c241a3e02bb6d8a3aaf86ea1f435560a5b5
1 //---------------------------------------------------------------------
2 // <copyright file="ViewKeyConstraint.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.Mapping.ViewGeneration.Validation
12 using System.Collections.Generic;
13 using System.Data.Common.Utils;
14 using System.Data.Entity;
15 using System.Data.Mapping.ViewGeneration.Structures;
16 using System.Data.Mapping.ViewGeneration.Utils;
17 using System.Data.Metadata.Edm;
18 using System.Text;
20 // Class representing a key constraint on the view cell relations
21 internal class ViewKeyConstraint : KeyConstraint<ViewCellRelation, ViewCellSlot>
25 #region Constructor
26 // effects: Constructs a key constraint for the given relation and keyslots
27 internal ViewKeyConstraint(ViewCellRelation relation, IEnumerable<ViewCellSlot> keySlots) :
28 base(relation, keySlots, ProjectedSlot.EqualityComparer)
31 #endregion
33 #region Properties
34 // effects: Returns the cell corresponding to this constraint
35 internal Cell Cell
37 get { return CellRelation.Cell; }
39 #endregion
41 #region Methods
42 internal bool Implies(ViewKeyConstraint second)
44 if (false == Object.ReferenceEquals(CellRelation, second.CellRelation))
46 return false;
48 // Check if the slots in this key are a subset of slots in
49 // second. If it is a key in this e.g., <A.pid> then <A.pid,
50 // A.foo> is certainly a key as well
52 if (KeySlots.IsSubsetOf(second.KeySlots))
54 return true;
57 // Now check for subsetting taking referential constraints into account
58 // Check that each slot in KeySlots can be found in second.KeySlots if we take
59 // slot equivalence into account
61 Set<ViewCellSlot> secondKeySlots = new Set<ViewCellSlot>(second.KeySlots);
63 foreach (ViewCellSlot firstSlot in KeySlots)
65 bool found = false; // Need to find a match for firstSlot
67 foreach (ViewCellSlot secondSlot in secondKeySlots)
69 if (ProjectedSlot.EqualityComparer.Equals(firstSlot.SSlot, secondSlot.SSlot))
71 // S-side is the same. Check if C-side is the same as well. If so, remove it
72 // from secondKeySlots
73 // We have to check for C-side equivalence in terms of actual equality
74 // and equivalence via ref constraints. The former is needed since the
75 // S-side key slots would typically be mapped to the same C-side slot.
76 // The latter is needed since the same S-side key slot could be mapped
77 // into two slots on the C-side that are connected via a ref constraint
78 MemberPath path1 = firstSlot.CSlot.MemberPath;
79 MemberPath path2 = secondSlot.CSlot.MemberPath;
80 if (MemberPath.EqualityComparer.Equals(path1, path2) || path1.IsEquivalentViaRefConstraint(path2))
82 secondKeySlots.Remove(secondSlot);
83 found = true;
84 break;
88 if (found == false)
90 return false;
95 // The subsetting holds when referential constraints are taken into account
96 return true;
99 // effects: Given the fact that rightKeyConstraint is not implied by a
100 // leftSide key constraint, return a useful error message -- some S
101 // was not implied by the C key constraints
102 internal static ErrorLog.Record GetErrorRecord(ViewKeyConstraint rightKeyConstraint)
104 List<ViewCellSlot> keySlots = new List<ViewCellSlot>(rightKeyConstraint.KeySlots);
105 EntitySetBase table = keySlots[0].SSlot.MemberPath.Extent;
106 EntitySetBase cSet = keySlots[0].CSlot.MemberPath.Extent;
108 MemberPath tablePrefix = new MemberPath(table);
109 MemberPath cSetPrefix = new MemberPath(cSet);
111 ExtentKey tableKey = ExtentKey.GetPrimaryKeyForEntityType(tablePrefix, (EntityType)table.ElementType);
112 ExtentKey cSetKey = null;
113 if (cSet is EntitySet)
115 cSetKey = ExtentKey.GetPrimaryKeyForEntityType(cSetPrefix, (EntityType)cSet.ElementType);
117 else
119 cSetKey = ExtentKey.GetKeyForRelationType(cSetPrefix, (AssociationType)cSet.ElementType);
122 string message = Strings.ViewGen_KeyConstraint_Violation(
123 table.Name,
124 ViewCellSlot.SlotsToUserString(rightKeyConstraint.KeySlots, false /*isFromCside*/),
125 tableKey.ToUserString(),
126 cSet.Name,
127 ViewCellSlot.SlotsToUserString(rightKeyConstraint.KeySlots, true /*isFromCside*/),
128 cSetKey.ToUserString());
130 string debugMessage = StringUtil.FormatInvariant("PROBLEM: Not implied {0}", rightKeyConstraint);
131 return new ErrorLog.Record(true, ViewGenErrorCode.KeyConstraintViolation, message, rightKeyConstraint.CellRelation.Cell, debugMessage);
134 // effects: Given the fact that none of the rightKeyConstraint are not implied by a
135 // leftSide key constraint, return a useful error message (used for
136 // the Update requirement
137 internal static ErrorLog.Record GetErrorRecord(IEnumerable<ViewKeyConstraint> rightKeyConstraints)
139 ViewKeyConstraint rightKeyConstraint = null;
140 StringBuilder keyBuilder = new StringBuilder();
141 bool isFirst = true;
142 foreach (ViewKeyConstraint rightConstraint in rightKeyConstraints)
144 string keyMsg = ViewCellSlot.SlotsToUserString(rightConstraint.KeySlots, true /*isFromCside*/);
145 if (isFirst == false)
147 keyBuilder.Append("; ");
149 isFirst = false;
150 keyBuilder.Append(keyMsg);
151 rightKeyConstraint = rightConstraint;
154 List<ViewCellSlot> keySlots = new List<ViewCellSlot>(rightKeyConstraint.KeySlots);
155 EntitySetBase table = keySlots[0].SSlot.MemberPath.Extent;
156 EntitySetBase cSet = keySlots[0].CSlot.MemberPath.Extent;
158 MemberPath tablePrefix = new MemberPath(table);
159 ExtentKey tableKey = ExtentKey.GetPrimaryKeyForEntityType(tablePrefix, (EntityType)table.ElementType);
161 string message;
162 if (cSet is EntitySet)
164 message = System.Data.Entity.Strings.ViewGen_KeyConstraint_Update_Violation_EntitySet(keyBuilder.ToString(), cSet.Name,
165 tableKey.ToUserString(), table.Name);
167 else
169 //For a 1:* or 0..1:* association, the * side has to be mapped to the
170 //key properties of the table. Fior this specific case, we give out a specific message
171 //that is specific for this case.
172 AssociationSet associationSet = (AssociationSet)cSet;
173 AssociationEndMember endMember = Helper.GetEndThatShouldBeMappedToKey(associationSet.ElementType);
174 if(endMember != null)
176 message = System.Data.Entity.Strings.ViewGen_AssociationEndShouldBeMappedToKey(endMember.Name,
177 table.Name);
179 else
181 message = System.Data.Entity.Strings.ViewGen_KeyConstraint_Update_Violation_AssociationSet(cSet.Name,
182 tableKey.ToUserString(), table.Name);
186 string debugMessage = StringUtil.FormatInvariant("PROBLEM: Not implied {0}", rightKeyConstraint);
187 return new ErrorLog.Record(true, ViewGenErrorCode.KeyConstraintUpdateViolation, message, rightKeyConstraint.CellRelation.Cell, debugMessage);
189 #endregion