1 //---------------------------------------------------------------------
2 // <copyright file="AssociationSetMetadata.cs" company="Microsoft">
3 // Copyright (c) Microsoft Corporation. All rights reserved.
7 // @backupOwner Microsoft
8 //---------------------------------------------------------------------
10 using System.Data.Metadata.Edm;
11 using System.Data.Common.Utils;
12 using System.Data.Common.CommandTrees;
13 using System.Collections.Generic;
15 namespace System.Data.Mapping.Update.Internal
18 /// Encapsulates information about ends of an association set needed to correctly
19 /// interpret updates.
21 internal sealed class AssociationSetMetadata
24 /// Gets association ends that must be modified if the association
25 /// is changed (e.g. the mapping of the association is conditioned
26 /// on some property of the end)
28 internal readonly Set<AssociationEndMember> RequiredEnds;
30 /// Gets association ends that may be implicitly modified as a result
31 /// of changes to the association (e.g. collocated entity with server
34 internal readonly Set<AssociationEndMember> OptionalEnds;
36 /// Gets association ends whose values may influence the association
37 /// (e.g. where there is a ReferentialIntegrity or "foreign key" constraint)
39 internal readonly Set<AssociationEndMember> IncludedValueEnds;
41 /// true iff. there are interesting ends for this association set.
45 get { return 0 < RequiredEnds.Count || 0 < OptionalEnds.Count || 0 < IncludedValueEnds.Count; }
49 /// Initialize Metadata for an AssociationSet
51 internal AssociationSetMetadata(Set<EntitySet> affectedTables, AssociationSet associationSet, MetadataWorkspace workspace)
53 // If there is only 1 table, there can be no ambiguity about the "destination" of a relationship, so such
54 // sets are not typically required.
55 bool isRequired = 1 < affectedTables.Count;
57 // determine the ends of the relationship
58 var ends = associationSet.AssociationSetEnds;
60 // find collocated entities
61 foreach (EntitySet table in affectedTables)
63 // Find extents influencing the table
64 var influencingExtents = MetadataHelper.GetInfluencingEntitySetsForTable(table, workspace);
66 foreach (EntitySet influencingExtent in influencingExtents)
68 foreach (var end in ends)
70 // If the extent is an end of the relationship and we haven't already added it to the
72 if (end.EntitySet.EdmEquals(influencingExtent))
76 AddEnd(ref RequiredEnds, end.CorrespondingAssociationEndMember);
78 else if (null == RequiredEnds || !RequiredEnds.Contains(end.CorrespondingAssociationEndMember))
80 AddEnd(ref OptionalEnds, end.CorrespondingAssociationEndMember);
87 // fix Required and Optional sets
88 FixSet(ref RequiredEnds);
89 FixSet(ref OptionalEnds);
91 // for associations with referential constraints, the principal end is always interesting
92 // since its key values may take precedence over the key values of the dependent end
93 foreach (ReferentialConstraint constraint in associationSet.ElementType.ReferentialConstraints)
95 // FromRole is the principal end in the referential constraint
96 AssociationEndMember principalEnd = (AssociationEndMember)constraint.FromRole;
98 if (!RequiredEnds.Contains(principalEnd) &&
99 !OptionalEnds.Contains(principalEnd))
101 AddEnd(ref IncludedValueEnds, principalEnd);
105 FixSet(ref IncludedValueEnds);
109 /// Initialize given required ends.
111 internal AssociationSetMetadata(IEnumerable<AssociationEndMember> requiredEnds)
113 if (requiredEnds.Any())
115 RequiredEnds = new Set<AssociationEndMember>(requiredEnds);
117 FixSet(ref RequiredEnds);
118 FixSet(ref OptionalEnds);
119 FixSet(ref IncludedValueEnds);
122 static private void AddEnd(ref Set<AssociationEndMember> set, AssociationEndMember element)
126 set = new Set<AssociationEndMember>();
131 static private void FixSet(ref Set<AssociationEndMember> set)
135 set = Set<AssociationEndMember>.Empty;