1 //---------------------------------------------------------------------
2 // <copyright file="ViewKeyConstraint.cs" company="Microsoft">
3 // Copyright (c) Microsoft Corporation. All rights reserved.
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
;
20 // Class representing a key constraint on the view cell relations
21 internal class ViewKeyConstraint
: KeyConstraint
<ViewCellRelation
, ViewCellSlot
>
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
)
34 // effects: Returns the cell corresponding to this constraint
37 get { return CellRelation.Cell; }
42 internal bool Implies(ViewKeyConstraint second
)
44 if (false == Object
.ReferenceEquals(CellRelation
, second
.CellRelation
))
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
))
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
);
95 // The subsetting holds when referential constraints are taken into account
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
);
119 cSetKey
= ExtentKey
.GetKeyForRelationType(cSetPrefix
, (AssociationType
)cSet
.ElementType
);
122 string message
= Strings
.ViewGen_KeyConstraint_Violation(
124 ViewCellSlot
.SlotsToUserString(rightKeyConstraint
.KeySlots
, false /*isFromCside*/),
125 tableKey
.ToUserString(),
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();
142 foreach (ViewKeyConstraint rightConstraint
in rightKeyConstraints
)
144 string keyMsg
= ViewCellSlot
.SlotsToUserString(rightConstraint
.KeySlots
, true /*isFromCside*/);
145 if (isFirst
== false)
147 keyBuilder
.Append("; ");
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
);
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
);
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
,
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
);