private bool CheckConstraintWhenParentChildMapped( Cell cell, ErrorLog errorLog, AssociationEndMember parentEnd, ConfigViewGenerator config) { bool flag = true; if (parentEnd.RelationshipMultiplicity == RelationshipMultiplicity.Many) { ErrorLog.Record record = new ErrorLog.Record(ViewGenErrorCode.ForeignKeyUpperBoundMustBeOne, Strings.ViewGen_Foreign_Key_UpperBound_MustBeOne((object)this.ToUserString(), (object)cell.CQuery.Extent.Name, (object)parentEnd.Name), cell, string.Empty); errorLog.AddEntry(record); flag = false; } if (!MemberPath.AreAllMembersNullable(this.ChildColumns) && parentEnd.RelationshipMultiplicity != RelationshipMultiplicity.One) { ErrorLog.Record record = new ErrorLog.Record(ViewGenErrorCode.ForeignKeyLowerBoundMustBeOne, Strings.ViewGen_Foreign_Key_LowerBound_MustBeOne((object)this.ToUserString(), (object)cell.CQuery.Extent.Name, (object)parentEnd.Name), cell, string.Empty); errorLog.AddEntry(record); flag = false; } if (config.IsNormalTracing && flag) { Trace.WriteLine("Foreign key mapped to relationship " + cell.CQuery.Extent.Name); } return(flag); }
internal InputForComputingCellGroups( EntityContainerMapping containerMapping, ConfigViewGenerator config) { this.ContainerMapping = containerMapping; this.Config = config; }
// requires: constraint.ChildColumns form a key in // constraint.ChildTable (actually they should subsume the primary key) private void GuaranteeForeignKeyConstraintInCSpace(QueryRewriter childRewriter, QueryRewriter parentRewriter, ErrorLog errorLog, ConfigViewGenerator config) { ViewgenContext childContext = childRewriter.ViewgenContext; ViewgenContext parentContext = parentRewriter.ViewgenContext; CellTreeNode cNode = childRewriter.BasicView; CellTreeNode pNode = parentRewriter.BasicView; FragmentQueryProcessor qp = FragmentQueryProcessor.Merge(childContext.RightFragmentQP, parentContext.RightFragmentQP); bool cImpliesP = qp.IsContainedIn(cNode.RightFragmentQuery, pNode.RightFragmentQuery); if (false == cImpliesP) { // Foreign key constraint not being ensured in C-space string childExtents = LeftCellWrapper.GetExtentListAsUserString(cNode.GetLeaves()); string parentExtents = LeftCellWrapper.GetExtentListAsUserString(pNode.GetLeaves()); string message = System.Data.Entity.Strings.ViewGen_Foreign_Key_Not_Guaranteed_InCSpace( ToUserString()); // Add all wrappers into allWrappers Set <LeftCellWrapper> allWrappers = new Set <LeftCellWrapper>(pNode.GetLeaves()); allWrappers.AddRange(cNode.GetLeaves()); ErrorLog.Record record = new ErrorLog.Record(true, ViewGenErrorCode.ForeignKeyNotGuaranteedInCSpace, message, allWrappers, String.Empty); errorLog.AddEntry(record); } }
// effects: Shrinks the domain of members whose types can be enumerated - currently it applies // only to boolean type as for enums we don't restrict enum values to specified members only. // For example NOT(False, True, Null) for a boolean domain should be removed internal void ReduceEnumerableDomainToEnumeratedValues(ConfigViewGenerator config) { // Go through the two maps ReduceEnumerableDomainToEnumeratedValues(m_conditionDomainMap, config, m_edmItemCollection); ReduceEnumerableDomainToEnumeratedValues(m_nonConditionDomainMap, config, m_edmItemCollection); }
internal QueryRewriter(EdmType generatedType, ViewgenContext context, ViewGenMode typesGenerationMode) { Debug.Assert(typesGenerationMode != ViewGenMode.GenerateAllViews); _typesGenerationMode = typesGenerationMode; _context = context; _generatedType = generatedType; _domainMap = context.MemberMaps.LeftDomainMap; _config = context.Config; _identifiers = context.CqlIdentifiers; _qp = new RewritingProcessor<Tile<FragmentQuery>>(new DefaultTileProcessor<FragmentQuery>(context.LeftFragmentQP)); _extentPath = new MemberPath(context.Extent); _keyAttributes = new List<MemberPath>(MemberPath.GetKeyMembers(context.Extent, _domainMap)); // populate _fragmentQueries and _views foreach (var leftCellWrapper in _context.AllWrappersForExtent) { var query = leftCellWrapper.FragmentQuery; Tile<FragmentQuery> tile = CreateTile(query); _fragmentQueries.Add(query); _views.Add(tile); } Debug.Assert(_views.Count > 0); AdjustMemberDomainsForUpdateViews(); // must be done after adjusting domains _domainQuery = GetDomainQuery(FragmentQueries, generatedType); _usedViews = new HashSet<FragmentQuery>(); }
internal QueryRewriter( EdmType generatedType, ViewgenContext context, ViewGenMode typesGenerationMode) { this._typesGenerationMode = typesGenerationMode; this._context = context; this._generatedType = generatedType; this._domainMap = context.MemberMaps.LeftDomainMap; this._config = context.Config; this._identifiers = context.CqlIdentifiers; this._qp = new RewritingProcessor <Tile <FragmentQuery> >((TileProcessor <Tile <FragmentQuery> >) new DefaultTileProcessor <FragmentQuery>((TileQueryProcessor <FragmentQuery>)context.LeftFragmentQP)); this._extentPath = new MemberPath(context.Extent); this._keyAttributes = new List <MemberPath>(MemberPath.GetKeyMembers(context.Extent, this._domainMap)); foreach (LeftCellWrapper leftCellWrapper in this._context.AllWrappersForExtent) { FragmentQuery fragmentQuery = leftCellWrapper.FragmentQuery; Tile <FragmentQuery> tile = (Tile <FragmentQuery>)QueryRewriter.CreateTile(fragmentQuery); this._fragmentQueries.Add(fragmentQuery); this._views.Add(tile); } this.AdjustMemberDomainsForUpdateViews(); this._domainQuery = this.GetDomainQuery(this.FragmentQueries, generatedType); this._usedViews = new HashSet <FragmentQuery>(); }
internal static void ThrowMappingException(ErrorLog errorLog, ConfigViewGenerator config) { InternalMappingException exception = new InternalMappingException(errorLog.ToUserString(), errorLog); if (config.IsNormalTracing) { exception.ErrorLog.PrintTrace(); } throw exception; }
internal static void ThrowMappingException(ErrorLog.Record errorRecord, ConfigViewGenerator config) { InternalMappingException exception = new InternalMappingException(errorRecord.ToUserString(), errorRecord); if (config.IsNormalTracing) { exception.ErrorLog.PrintTrace(); } throw exception; }
internal static void ThrowMappingException(ErrorLog errorLog, ConfigViewGenerator config) { InternalMappingException mappingException = new InternalMappingException(errorLog.ToUserString(), errorLog); if (config.IsNormalTracing) { mappingException.ErrorLog.PrintTrace(); } throw mappingException; }
internal MemberDomainMap( ViewTarget viewTarget, bool isValidationEnabled, IEnumerable <Cell> extentCells, EdmItemCollection edmItemCollection, ConfigViewGenerator config, Dictionary <EntityType, Set <EntityType> > inheritanceGraph) { this.m_conditionDomainMap = new Dictionary <MemberPath, Set <Constant> >(MemberPath.EqualityComparer); this.m_edmItemCollection = edmItemCollection; Dictionary <MemberPath, Set <Constant> > dictionary = viewTarget != ViewTarget.UpdateView ? Domain.ComputeConstantDomainSetsForSlotsInQueryViews(extentCells, this.m_edmItemCollection, isValidationEnabled) : Domain.ComputeConstantDomainSetsForSlotsInUpdateViews(extentCells, this.m_edmItemCollection); foreach (Cell extentCell in extentCells) { foreach (MemberRestriction memberRestriction in extentCell.GetLeftQuery(viewTarget).GetConjunctsFromWhereClause()) { MemberPath memberPath = memberRestriction.RestrictedMemberSlot.MemberPath; Set <Constant> set; if (!dictionary.TryGetValue(memberPath, out set)) { set = Domain.DeriveDomainFromMemberPath(memberPath, edmItemCollection, isValidationEnabled); } if (set.Contains(Constant.Null) || !memberRestriction.Domain.Values.All <Constant>((Func <Constant, bool>)(conditionConstant => conditionConstant.Equals((object)Constant.NotNull)))) { if (set.Count <= 0 || !set.Contains(Constant.Null) && memberRestriction.Domain.Values.Contains <Constant>(Constant.Null)) { ExceptionHelpers.ThrowMappingException(new ErrorLog.Record(ViewGenErrorCode.InvalidCondition, Strings.ViewGen_InvalidCondition((object)memberPath.PathToString(new bool?(false))), extentCell, string.Empty), config); } if (!memberPath.IsAlwaysDefined(inheritanceGraph)) { set.Add(Constant.Undefined); } this.AddToDomainMap(memberPath, (IEnumerable <Constant>)set); } } } this.m_nonConditionDomainMap = new Dictionary <MemberPath, Set <Constant> >(MemberPath.EqualityComparer); foreach (Cell extentCell in extentCells) { foreach (MemberProjectedSlot allQuerySlot in extentCell.GetLeftQuery(viewTarget).GetAllQuerySlots()) { MemberPath memberPath = allQuerySlot.MemberPath; if (!this.m_conditionDomainMap.ContainsKey(memberPath) && !this.m_nonConditionDomainMap.ContainsKey(memberPath)) { Set <Constant> set = Domain.DeriveDomainFromMemberPath(memberPath, this.m_edmItemCollection, true); if (!memberPath.IsAlwaysDefined(inheritanceGraph)) { set.Add(Constant.Undefined); } Set <Constant> iconstants = Domain.ExpandNegationsInDomain((IEnumerable <Constant>)set, (IEnumerable <Constant>)set); this.m_nonConditionDomainMap.Add(memberPath, (Set <Constant>) new MemberDomainMap.CellConstantSetInfo(iconstants)); } } } }
internal void CheckConstraint( Set <Cell> cells, QueryRewriter childRewriter, QueryRewriter parentRewriter, ErrorLog errorLog, ConfigViewGenerator config) { if (!this.IsConstraintRelevantForCells((IEnumerable <Cell>)cells)) { return; } if (config.IsNormalTracing) { Trace.WriteLine(string.Empty); Trace.WriteLine(string.Empty); Trace.Write("Checking: "); Trace.WriteLine((object)this); } if (childRewriter == null && parentRewriter == null) { return; } if (childRewriter == null) { ErrorLog.Record record = new ErrorLog.Record(ViewGenErrorCode.ForeignKeyMissingTableMapping, Strings.ViewGen_Foreign_Key_Missing_Table_Mapping((object)this.ToUserString(), (object)this.ChildTable.Name), (IEnumerable <LeftCellWrapper>)parentRewriter.UsedCells, string.Empty); errorLog.AddEntry(record); } else if (parentRewriter == null) { ErrorLog.Record record = new ErrorLog.Record(ViewGenErrorCode.ForeignKeyMissingTableMapping, Strings.ViewGen_Foreign_Key_Missing_Table_Mapping((object)this.ToUserString(), (object)this.ParentTable.Name), (IEnumerable <LeftCellWrapper>)childRewriter.UsedCells, string.Empty); errorLog.AddEntry(record); } else { if (this.CheckIfConstraintMappedToForeignKeyAssociation(childRewriter, parentRewriter, cells)) { return; } int count = errorLog.Count; if (this.IsForeignKeySuperSetOfPrimaryKeyInChildTable()) { this.GuaranteeForeignKeyConstraintInCSpace(childRewriter, parentRewriter, errorLog); } else { this.GuaranteeMappedRelationshipForForeignKey(childRewriter, parentRewriter, (IEnumerable <Cell>)cells, errorLog, config); } if (count != errorLog.Count) { return; } this.CheckForeignKeyColumnOrder(cells, errorLog); } }
internal static Constant GetDefaultValueForMemberPath( MemberPath memberPath, IEnumerable <LeftCellWrapper> wrappersForErrorReporting, ConfigViewGenerator config) { Constant defaultConstant = (Constant)null; if (!Domain.TryGetDefaultValueForMemberPath(memberPath, out defaultConstant)) { ExceptionHelpers.ThrowMappingException(new ErrorLog.Record(ViewGenErrorCode.NoDefaultValue, Strings.ViewGen_No_Default_Value((object)memberPath.Extent.Name, (object)memberPath.PathToString(new bool?(false))), wrappersForErrorReporting, string.Empty), config); } return(defaultConstant); }
internal static Constant GetDefaultValueForMemberPath(MemberPath memberPath, IEnumerable <LeftCellWrapper> wrappersForErrorReporting, ConfigViewGenerator config) { Constant defaultValue = null; if (!Domain.TryGetDefaultValueForMemberPath(memberPath, out defaultValue)) { string message = Strings.ViewGen_No_Default_Value(memberPath.Extent.Name, memberPath.PathToString(false)); ErrorLog.Record record = new ErrorLog.Record(true, ViewGenErrorCode.NoDefaultValue, message, wrappersForErrorReporting, String.Empty); ExceptionHelpers.ThrowMappingException(record, config); } return(defaultValue); }
/// <summary> /// This method compiles all the user defined query views in the <paramref name="entityContainerMapping"/>. /// </summary> private static void CompileUserDefinedQueryViews(StorageEntityContainerMapping entityContainerMapping, Dictionary <EntitySetBase, GeneratedView> userDefinedQueryViewsDict, Dictionary <OfTypeQVCacheKey, GeneratedView> userDefinedQueryViewsOfTypeDict, IList <EdmSchemaError> errors) { ConfigViewGenerator config = new ConfigViewGenerator(); foreach (StorageSetMapping setMapping in entityContainerMapping.AllSetMaps) { if (setMapping.QueryView != null) { GeneratedView generatedView; if (!userDefinedQueryViewsDict.TryGetValue(setMapping.Set, out generatedView)) { // Parse the view so that we will get back any errors in the view. if (GeneratedView.TryParseUserSpecifiedView(setMapping, setMapping.Set.ElementType, setMapping.QueryView, true, // includeSubtypes entityContainerMapping.StorageMappingItemCollection, config, /*out*/ errors, out generatedView)) { // Add first QueryView userDefinedQueryViewsDict.Add(setMapping.Set, generatedView); } // Add all type-specific QueryViews foreach (OfTypeQVCacheKey key in setMapping.GetTypeSpecificQVKeys()) { Debug.Assert(key.First.Equals(setMapping.Set)); if (GeneratedView.TryParseUserSpecifiedView(setMapping, key.Second.First, // type setMapping.GetTypeSpecificQueryView(key), key.Second.Second, // includeSubtypes entityContainerMapping.StorageMappingItemCollection, config, /*out*/ errors, out generatedView)) { userDefinedQueryViewsOfTypeDict.Add(key, generatedView); } } } } } }
// requires: IsForeignKeySuperSetOfPrimaryKeyInChildTable() is false // effects: Given that both the ChildColumns in this and the // primaryKey of ChildTable are mapped. Return true iff no error occurred private bool CheckConstraintWhenParentChildMapped( Cell cell, ErrorLog errorLog, AssociationEndMember parentEnd, ConfigViewGenerator config) { var ok = true; // The foreign key constraint has been mapped to a // relationship. Check if the multiplicities are consistent // If all columns in the child table (corresponding to // the constraint) are nullable, the parent end can be // 0..1 or 1..1. Else if must be 1..1 if (parentEnd.RelationshipMultiplicity == RelationshipMultiplicity.Many) { // Parent should at most one since we are talking // about foreign keys here var message = Strings.ViewGen_Foreign_Key_UpperBound_MustBeOne( ToUserString(), cell.CQuery.Extent.Name, parentEnd.Name); var record = new ErrorLog.Record(ViewGenErrorCode.ForeignKeyUpperBoundMustBeOne, message, cell, String.Empty); errorLog.AddEntry(record); ok = false; } if (MemberPath.AreAllMembersNullable(ChildColumns) == false && parentEnd.RelationshipMultiplicity != RelationshipMultiplicity.One) { // Some column in the constraint in the child table // is non-nullable and lower bound is not 1 var message = Strings.ViewGen_Foreign_Key_LowerBound_MustBeOne( ToUserString(), cell.CQuery.Extent.Name, parentEnd.Name); var record = new ErrorLog.Record(ViewGenErrorCode.ForeignKeyLowerBoundMustBeOne, message, cell, String.Empty); errorLog.AddEntry(record); ok = false; } if (config.IsNormalTracing && ok) { Trace.WriteLine("Foreign key mapped to relationship " + cell.CQuery.Extent.Name); } return(ok); }
// requires: IsForeignKeySuperSetOfPrimaryKeyInChildTable() is false // and primaryKeys of ChildTable are not mapped in cell. cell // corresponds to an association set. parentSet is the set // corresponding to the end that we are looking at // effects: Checks if the constraint is correctly maintained in // C-space via an association set (being a subset of the // corresponding entitySet) private bool CheckConstraintWhenOnlyParentMapped(Cell cell, EntitySet parentSet, AssociationSet assocSet, AssociationEndMember endMember, QueryRewriter childRewriter, QueryRewriter parentRewriter, ConfigViewGenerator config) { ViewgenContext childContext = childRewriter.ViewgenContext; ViewgenContext parentContext = parentRewriter.ViewgenContext; CellTreeNode pNode = parentRewriter.BasicView; Debug.Assert(pNode != null); RoleBoolean endRoleBoolean = new RoleBoolean(assocSet.AssociationSetEnds[endMember.Name]); // use query in pNode as a factory to create a bool expression for the endRoleBoolean BoolExpression endCondition = pNode.RightFragmentQuery.Condition.Create(endRoleBoolean); FragmentQuery cNodeQuery = FragmentQuery.Create(pNode.RightFragmentQuery.Attributes, endCondition); FragmentQueryProcessor qp = FragmentQueryProcessor.Merge(childContext.RightFragmentQP, parentContext.RightFragmentQP); bool cImpliesP = qp.IsContainedIn(cNodeQuery, pNode.RightFragmentQuery); return(cImpliesP); }
private static void ReduceEnumerableDomainToEnumeratedValues( Dictionary <MemberPath, Set <Constant> > domainMap, ConfigViewGenerator config, EdmItemCollection edmItemCollection) { foreach (MemberPath key in domainMap.Keys) { if (MetadataHelper.HasDiscreteDomain(key.EdmType)) { Set <Constant> set1 = Domain.DeriveDomainFromMemberPath(key, edmItemCollection, true); Set <Constant> set2 = domainMap[key].Difference((IEnumerable <Constant>)set1); set2.Remove(Constant.Undefined); if (set2.Count > 0) { if (config.IsNormalTracing) { Helpers.FormatTraceLine("Changed domain of {0} from {1} - subtract {2}", (object)key, (object)domainMap[key], (object)set2); } domainMap[key].Subtract((IEnumerable <Constant>)set2); } } } }
// effects: Fixes the domains of variables in this as specified in FixEnumerableDomains private static void ReduceEnumerableDomainToEnumeratedValues( Dictionary <MemberPath, CellConstantSet> domainMap, ConfigViewGenerator config, EdmItemCollection edmItemCollection) { foreach (var member in domainMap.Keys) { if (MetadataHelper.HasDiscreteDomain(member.EdmType) == false) { continue; } var domain = Domain.DeriveDomainFromMemberPath(member, edmItemCollection, true /* leaveDomainUnbounded */); var extra = domainMap[member].Difference(domain); extra.Remove(Constant.Undefined); if (extra.Count > 0) { // domainMap has extra members -- we should get rid of them if (config.IsNormalTracing) { Helpers.FormatTraceLine("Changed domain of {0} from {1} - subtract {2}", member, domainMap[member], extra); } domainMap[member].Subtract(extra); } } }
// requires: constraint.ChildColumns form a key in // constraint.ChildTable (actually they should subsume the primary key) private void GuaranteeForeignKeyConstraintInCSpace(QueryRewriter childRewriter, QueryRewriter parentRewriter, ErrorLog errorLog, ConfigViewGenerator config) { ViewgenContext childContext = childRewriter.ViewgenContext; ViewgenContext parentContext = parentRewriter.ViewgenContext; CellTreeNode cNode = childRewriter.BasicView; CellTreeNode pNode = parentRewriter.BasicView; FragmentQueryProcessor qp = FragmentQueryProcessor.Merge(childContext.RightFragmentQP, parentContext.RightFragmentQP); bool cImpliesP = qp.IsContainedIn(cNode.RightFragmentQuery, pNode.RightFragmentQuery); if (false == cImpliesP) { // Foreign key constraint not being ensured in C-space string childExtents = LeftCellWrapper.GetExtentListAsUserString(cNode.GetLeaves()); string parentExtents = LeftCellWrapper.GetExtentListAsUserString(pNode.GetLeaves()); string message = System.Data.Entity.Strings.ViewGen_Foreign_Key_Not_Guaranteed_InCSpace( ToUserString()); // Add all wrappers into allWrappers Set<LeftCellWrapper> allWrappers = new Set<LeftCellWrapper>(pNode.GetLeaves()); allWrappers.AddRange(cNode.GetLeaves()); ErrorLog.Record record = new ErrorLog.Record(true, ViewGenErrorCode.ForeignKeyNotGuaranteedInCSpace, message, allWrappers, String.Empty); errorLog.AddEntry(record); } }
// requires: IsForeignKeySuperSetOfPrimaryKeyInChildTable() is false // effects: Given that both the ChildColumns in this and the // primaryKey of ChildTable are mapped. Return true iff no error occurred private bool CheckConstraintWhenParentChildMapped( Cell cell, ErrorLog errorLog, AssociationEndMember parentEnd, ConfigViewGenerator config) { var ok = true; // The foreign key constraint has been mapped to a // relationship. Check if the multiplicities are consistent // If all columns in the child table (corresponding to // the constraint) are nullable, the parent end can be // 0..1 or 1..1. Else if must be 1..1 if (parentEnd.RelationshipMultiplicity == RelationshipMultiplicity.Many) { // Parent should at most one since we are talking // about foreign keys here var message = Strings.ViewGen_Foreign_Key_UpperBound_MustBeOne( ToUserString(), cell.CQuery.Extent.Name, parentEnd.Name); var record = new ErrorLog.Record(ViewGenErrorCode.ForeignKeyUpperBoundMustBeOne, message, cell, String.Empty); errorLog.AddEntry(record); ok = false; } if (MemberPath.AreAllMembersNullable(ChildColumns) == false && parentEnd.RelationshipMultiplicity != RelationshipMultiplicity.One) { // Some column in the constraint in the child table // is non-nullable and lower bound is not 1 var message = Strings.ViewGen_Foreign_Key_LowerBound_MustBeOne( ToUserString(), cell.CQuery.Extent.Name, parentEnd.Name); var record = new ErrorLog.Record(ViewGenErrorCode.ForeignKeyLowerBoundMustBeOne, message, cell, String.Empty); errorLog.AddEntry(record); ok = false; } if (config.IsNormalTracing && ok) { Trace.WriteLine("Foreign key mapped to relationship " + cell.CQuery.Extent.Name); } return ok; }
// effects: Ensures that there is a relationship mapped into the C-space for some cell in m_cellGroup. Else // adds an error to errorLog private void GuaranteeMappedRelationshipForForeignKey( QueryRewriter childRewriter, QueryRewriter parentRewriter, IEnumerable<Cell> cells, ErrorLog errorLog, ConfigViewGenerator config) { var childContext = childRewriter.ViewgenContext; var parentContext = parentRewriter.ViewgenContext; // Find a cell where this foreign key is mapped as a relationship var prefix = new MemberPath(ChildTable); var primaryKey = ExtentKey.GetPrimaryKeyForEntityType(prefix, ChildTable.ElementType); var primaryKeyFields = primaryKey.KeyFields; var foundCell = false; var foundValidParentColumnsForForeignKey = false; //we need to find only one, dont error on any one check being false List<ErrorLog.Record> errorListForInvalidParentColumnsForForeignKey = null; foreach (var cell in cells) { if (cell.SQuery.Extent.Equals(ChildTable) == false) { continue; } // The childtable is mapped to a relationship in the C-space in cell // Check that all the columns of the foreign key and the primary key in the child table are mapped to some // property in the C-space var parentEnd = GetRelationEndForColumns(cell, ChildColumns); if (parentEnd != null && CheckParentColumnsForForeignKey(cell, cells, parentEnd, ref errorListForInvalidParentColumnsForForeignKey) == false) { // Not an error unless we find no valid case continue; } else { foundValidParentColumnsForForeignKey = true; } var childEnd = GetRelationEndForColumns(cell, primaryKeyFields); Debug.Assert( childEnd == null || parentEnd != childEnd, "Ends are same => PKey and child columns are same - code should gone to other method"); // Note: If both of them are not-null, they are mapped to the // same association set -- since we checked that particular cell if (childEnd != null && parentEnd != null && FindEntitySetForColumnsMappedToEntityKeys(cells, primaryKeyFields) != null) { foundCell = true; CheckConstraintWhenParentChildMapped(cell, errorLog, parentEnd, config); break; // Done processing for the foreign key - either it was mapped correctly or it was not } else if (parentEnd != null) { // At this point, we know cell corresponds to an association set var assocSet = (AssociationSet)cell.CQuery.Extent; var parentSet = MetadataHelper.GetEntitySetAtEnd(assocSet, parentEnd); foundCell = CheckConstraintWhenOnlyParentMapped(assocSet, parentEnd, childRewriter, parentRewriter); if (foundCell) { break; } } } //CheckParentColumnsForForeignKey has returned no matches, Error. if (!foundValidParentColumnsForForeignKey) { Debug.Assert( errorListForInvalidParentColumnsForForeignKey != null && errorListForInvalidParentColumnsForForeignKey.Count > 0); foreach (var errorRecord in errorListForInvalidParentColumnsForForeignKey) { errorLog.AddEntry(errorRecord); } return; } if (foundCell == false) { // No cell found -- Declare error var message = Strings.ViewGen_Foreign_Key_Missing_Relationship_Mapping(ToUserString()); IEnumerable<LeftCellWrapper> parentWrappers = GetWrappersFromContext(parentContext, ParentTable); IEnumerable<LeftCellWrapper> childWrappers = GetWrappersFromContext(childContext, ChildTable); var bothExtentWrappers = new Set<LeftCellWrapper>(parentWrappers); bothExtentWrappers.AddRange(childWrappers); var record = new ErrorLog.Record( ViewGenErrorCode.ForeignKeyMissingRelationshipMapping, message, bothExtentWrappers, String.Empty); errorLog.AddEntry(record); } }
// effects: Checks that this foreign key constraints for all the // tables are being ensured on the C-side as well. If not, adds // errors to the errorLog internal void CheckConstraint( Set<Cell> cells, QueryRewriter childRewriter, QueryRewriter parentRewriter, ErrorLog errorLog, ConfigViewGenerator config) { if (IsConstraintRelevantForCells(cells) == false) { // if the constraint does not deal with any cell in this group, ignore it return; } if (config.IsNormalTracing) { Trace.WriteLine(String.Empty); Trace.WriteLine(String.Empty); Trace.Write("Checking: "); Trace.WriteLine(this); } if (childRewriter == null && parentRewriter == null) { // Neither table is mapped - so we are fine return; } // If the child table has not been mapped, we used to say that we // are fine. However, if we have SPerson(pid) and SAddress(aid, // pid), where pid is an FK into SPerson, we are in trouble if // SAddress is not mapped - SPerson could get deleted. So we // check for it as well // if the parent table is not mapped, we also have a problem if (childRewriter == null) { var message = Strings.ViewGen_Foreign_Key_Missing_Table_Mapping( ToUserString(), ChildTable.Name); // Get the cells from the parent table var record = new ErrorLog.Record( ViewGenErrorCode.ForeignKeyMissingTableMapping, message, parentRewriter.UsedCells, String.Empty); errorLog.AddEntry(record); return; } if (parentRewriter == null) { var message = Strings.ViewGen_Foreign_Key_Missing_Table_Mapping( ToUserString(), ParentTable.Name); // Get the cells from the child table var record = new ErrorLog.Record( ViewGenErrorCode.ForeignKeyMissingTableMapping, message, childRewriter.UsedCells, String.Empty); errorLog.AddEntry(record); return; } // Note: we do not check if the parent columns correspond to the // table's keys - metadata checks for that //First check if the FK is covered by Foreign Key Association //If we find this, we don't need to check for independent associations. If user maps the Fk to both FK and independent associations, //the regular round tripping validation will catch the error. if (CheckIfConstraintMappedToForeignKeyAssociation(childRewriter, parentRewriter, cells)) { return; } // Check if the foreign key in the child table corresponds to the primary key, i.e., if // the foreign key (e.g., pid, pid2) is a superset of the actual key members (e.g., pid), it means // that the foreign key is also the primary key for this table -- so we can propagate the queries upto C-Space // rather than doing the cell check var initialErrorLogSize = errorLog.Count; if (IsForeignKeySuperSetOfPrimaryKeyInChildTable()) { GuaranteeForeignKeyConstraintInCSpace(childRewriter, parentRewriter, errorLog); } else { GuaranteeMappedRelationshipForForeignKey(childRewriter, parentRewriter, cells, errorLog, config); } if (initialErrorLogSize == errorLog.Count) { // Check if the order of columns in foreign key correponds to the // mappings in m_cellGroup, e.g., if <pid1, pid2> in SAddress is // a foreign key into <pid1, pid2> of the SPerson table, make // sure that this order is preserved through the mappings in m_cellGroup CheckForeignKeyColumnOrder(cells, errorLog); } }
internal static Constant GetDefaultValueForMemberPath(MemberPath memberPath, IEnumerable<LeftCellWrapper> wrappersForErrorReporting, ConfigViewGenerator config) { Constant defaultValue = null; if (!Domain.TryGetDefaultValueForMemberPath(memberPath, out defaultValue)) { string message = Strings.ViewGen_No_Default_Value(memberPath.Extent.Name, memberPath.PathToString(false)); ErrorLog.Record record = new ErrorLog.Record(true, ViewGenErrorCode.NoDefaultValue, message, wrappersForErrorReporting, String.Empty); ExceptionHelpers.ThrowMappingException(record, config); } return defaultValue; }
// effects: Creates a map with all the condition member constants // from extentCells. viewtarget determines whether the view is an // update or query view internal MemberDomainMap(ViewTarget viewTarget, bool isValidationEnabled, IEnumerable<Cell> extentCells, EdmItemCollection edmItemCollection, ConfigViewGenerator config, Dictionary<EntityType, Set<EntityType>> inheritanceGraph) { m_conditionDomainMap = new Dictionary<MemberPath, CellConstantSet>(MemberPath.EqualityComparer); m_edmItemCollection = edmItemCollection; Dictionary<MemberPath, CellConstantSet> domainMap = null; if (viewTarget == ViewTarget.UpdateView) { domainMap = Domain.ComputeConstantDomainSetsForSlotsInUpdateViews(extentCells, m_edmItemCollection); } else { domainMap = Domain.ComputeConstantDomainSetsForSlotsInQueryViews(extentCells, m_edmItemCollection, isValidationEnabled); } foreach (Cell cell in extentCells) { CellQuery cellQuery = cell.GetLeftQuery(viewTarget); // Get the atoms from cellQuery and only keep the ones that // are condition members foreach (MemberRestriction condition in cellQuery.GetConjunctsFromWhereClause()) { // Note: TypeConditions are created using OneOfTypeConst and // scalars are created using OneOfScalarConst MemberPath memberPath = condition.RestrictedMemberSlot.MemberPath; Debug.Assert(condition is ScalarRestriction || condition is TypeRestriction, "Unexpected restriction"); // Take the narrowed domain from domainMap, if any CellConstantSet domainValues; if (!domainMap.TryGetValue(memberPath, out domainValues)) { domainValues = Domain.DeriveDomainFromMemberPath(memberPath, edmItemCollection, isValidationEnabled); } //Don't count conditions that are satisfied through IsNull=false if (!domainValues.Contains(Constant.Null)) { //multiple values of condition represent disjunction in conditions (not currently supported) // if there is any condition constant that is NotNull if (condition.Domain.Values.All(conditionConstant => (conditionConstant.Equals(Constant.NotNull)))) { continue; } //else there is atleast one condition value that is allowed, continue view generation } //------------------------------------------ //| Nullable | IsNull | Test case | //| T | T | T | //| T | F | T | //| F | T | F | //| F | F | T | //------------------------------------------ //IsNull condition on a member that is non nullable is an invalid condition if (domainValues.Count <= 0 || (!domainValues.Contains(Constant.Null) && condition.Domain.Values.Contains(Constant.Null))) { string message = System.Data.Entity.Strings.ViewGen_InvalidCondition(memberPath.PathToString(false)); ErrorLog.Record record = new ErrorLog.Record(true, ViewGenErrorCode.InvalidCondition, message, cell, String.Empty); ExceptionHelpers.ThrowMappingException(record, config); } if (memberPath.IsAlwaysDefined(inheritanceGraph) == false) { domainValues.Add(Constant.Undefined); } AddToDomainMap(memberPath, domainValues); } } // Fill up the domains for the remaining slots as well m_nonConditionDomainMap = new Dictionary<MemberPath, CellConstantSet>(MemberPath.EqualityComparer); foreach (Cell cell in extentCells) { CellQuery cellQuery = cell.GetLeftQuery(viewTarget); // Get the atoms from cellQuery and only keep the ones that // are condition members foreach (MemberProjectedSlot slot in cellQuery.GetAllQuerySlots()) { MemberPath member = slot.MemberPath; if (m_conditionDomainMap.ContainsKey(member) == false && m_nonConditionDomainMap.ContainsKey(member) == false) { CellConstantSet memberSet = Domain.DeriveDomainFromMemberPath(member, m_edmItemCollection, true /* Regardless of validation, leave the domain unbounded because this is not a condition member */); if (member.IsAlwaysDefined(inheritanceGraph) == false) { // nonConditionMember may belong to subclass memberSet.Add(Constant.Undefined); } memberSet = Domain.ExpandNegationsInDomain(memberSet, memberSet); m_nonConditionDomainMap.Add(member, new CellConstantSetInfo(memberSet, slot)); } } } }
// effects: Fixes the domains of variables in this as specified in FixEnumerableDomains private static void ReduceEnumerableDomainToEnumeratedValues(ViewTarget target, Dictionary<MemberPath, CellConstantSet> domainMap, ConfigViewGenerator config, EdmItemCollection edmItemCollection) { foreach (MemberPath member in domainMap.Keys) { if (MetadataHelper.HasDiscreteDomain(member.EdmType) == false) { continue; } CellConstantSet domain = Domain.DeriveDomainFromMemberPath(member, edmItemCollection, true /* leaveDomainUnbounded */); CellConstantSet extra = domainMap[member].Difference(domain); extra.Remove(Constant.Undefined); if (extra.Count > 0) { // domainMap has extra members -- we should get rid of them if (config.IsNormalTracing) { Helpers.FormatTraceLine("Changed domain of {0} from {1} - subtract {2}", member, domainMap[member], extra); } domainMap[member].Subtract(extra); } } }
// effects: Shrinks the domain of members whose types can be enumerated - currently it applies // only to boolean type as for enums we don't restrict enum values to specified members only. // For example NOT(False, True, Null) for a boolean domain should be removed internal void ReduceEnumerableDomainToEnumeratedValues(ViewTarget target, ConfigViewGenerator config) { // Go through the two maps ReduceEnumerableDomainToEnumeratedValues(target, m_conditionDomainMap, config, m_edmItemCollection); ReduceEnumerableDomainToEnumeratedValues(target, m_nonConditionDomainMap, config, m_edmItemCollection); }
internal MemberDomainMap( ViewTarget viewTarget, bool isValidationEnabled, IEnumerable <Cell> extentCells, EdmItemCollection edmItemCollection, ConfigViewGenerator config, Dictionary <EntityType, Set <EntityType> > inheritanceGraph) { m_conditionDomainMap = new Dictionary <MemberPath, CellConstantSet>(MemberPath.EqualityComparer); m_edmItemCollection = edmItemCollection; Dictionary <MemberPath, CellConstantSet> domainMap = null; if (viewTarget == ViewTarget.UpdateView) { domainMap = Domain.ComputeConstantDomainSetsForSlotsInUpdateViews(extentCells, m_edmItemCollection); } else { domainMap = Domain.ComputeConstantDomainSetsForSlotsInQueryViews(extentCells, m_edmItemCollection, isValidationEnabled); } foreach (var cell in extentCells) { var cellQuery = cell.GetLeftQuery(viewTarget); // Get the atoms from cellQuery and only keep the ones that // are condition members foreach (var condition in cellQuery.GetConjunctsFromWhereClause()) { // Note: TypeConditions are created using OneOfTypeConst and // scalars are created using OneOfScalarConst var memberPath = condition.RestrictedMemberSlot.MemberPath; Debug.Assert( condition is ScalarRestriction || condition is TypeRestriction, "Unexpected restriction"); // Take the narrowed domain from domainMap, if any CellConstantSet domainValues; if (!domainMap.TryGetValue(memberPath, out domainValues)) { domainValues = Domain.DeriveDomainFromMemberPath(memberPath, edmItemCollection, isValidationEnabled); } //Don't count conditions that are satisfied through IsNull=false if (!domainValues.Contains(Constant.Null)) { //multiple values of condition represent disjunction in conditions (not currently supported) // if there is any condition constant that is NotNull if (condition.Domain.Values.All(conditionConstant => (conditionConstant.Equals(Constant.NotNull)))) { continue; } //else there is atleast one condition value that is allowed, continue view generation } //------------------------------------------ //| Nullable | IsNull | Test case | //| T | T | T | //| T | F | T | //| F | T | F | //| F | F | T | //------------------------------------------ //IsNull condition on a member that is non nullable is an invalid condition if (domainValues.Count <= 0 || (!domainValues.Contains(Constant.Null) && condition.Domain.Values.Contains(Constant.Null))) { var message = Strings.ViewGen_InvalidCondition(memberPath.PathToString(false)); var record = new ErrorLog.Record(ViewGenErrorCode.InvalidCondition, message, cell, String.Empty); ExceptionHelpers.ThrowMappingException(record, config); } if (memberPath.IsAlwaysDefined(inheritanceGraph) == false) { domainValues.Add(Constant.Undefined); } AddToDomainMap(memberPath, domainValues); } } // Fill up the domains for the remaining slots as well m_nonConditionDomainMap = new Dictionary <MemberPath, CellConstantSet>(MemberPath.EqualityComparer); foreach (var cell in extentCells) { var cellQuery = cell.GetLeftQuery(viewTarget); // Get the atoms from cellQuery and only keep the ones that // are condition members foreach (var slot in cellQuery.GetAllQuerySlots()) { var member = slot.MemberPath; if (m_conditionDomainMap.ContainsKey(member) == false && m_nonConditionDomainMap.ContainsKey(member) == false) { var memberSet = Domain.DeriveDomainFromMemberPath( member, m_edmItemCollection, true /* Regardless of validation, leave the domain unbounded because this is not a condition member */); if (member.IsAlwaysDefined(inheritanceGraph) == false) { // nonConditionMember may belong to subclass memberSet.Add(Constant.Undefined); } memberSet = Domain.ExpandNegationsInDomain(memberSet, memberSet); m_nonConditionDomainMap.Add(member, new CellConstantSetInfo(memberSet)); } } } }
internal void ReduceEnumerableDomainToEnumeratedValues(ConfigViewGenerator config) { MemberDomainMap.ReduceEnumerableDomainToEnumeratedValues(this.m_conditionDomainMap, config, this.m_edmItemCollection); MemberDomainMap.ReduceEnumerableDomainToEnumeratedValues(this.m_nonConditionDomainMap, config, this.m_edmItemCollection); }
// requires: IsForeignKeySuperSetOfPrimaryKeyInChildTable() is false // and primaryKeys of ChildTable are not mapped in cell. cell // corresponds to an association set. parentSet is the set // corresponding to the end that we are looking at // effects: Checks if the constraint is correctly maintained in // C-space via an association set (being a subset of the // corresponding entitySet) private bool CheckConstraintWhenOnlyParentMapped(Cell cell, EntitySet parentSet, AssociationSet assocSet, AssociationEndMember endMember, QueryRewriter childRewriter, QueryRewriter parentRewriter, ConfigViewGenerator config) { ViewgenContext childContext = childRewriter.ViewgenContext; ViewgenContext parentContext = parentRewriter.ViewgenContext; CellTreeNode pNode = parentRewriter.BasicView; Debug.Assert(pNode != null); RoleBoolean endRoleBoolean = new RoleBoolean(assocSet.AssociationSetEnds[endMember.Name]); // use query in pNode as a factory to create a bool expression for the endRoleBoolean BoolExpression endCondition = pNode.RightFragmentQuery.Condition.Create(endRoleBoolean); FragmentQuery cNodeQuery = FragmentQuery.Create(pNode.RightFragmentQuery.Attributes, endCondition); FragmentQueryProcessor qp = FragmentQueryProcessor.Merge(childContext.RightFragmentQP, parentContext.RightFragmentQP); bool cImpliesP = qp.IsContainedIn(cNodeQuery, pNode.RightFragmentQuery); return cImpliesP; }
private void GuaranteeMappedRelationshipForForeignKey( QueryRewriter childRewriter, QueryRewriter parentRewriter, IEnumerable <Cell> cells, ErrorLog errorLog, ConfigViewGenerator config) { ViewgenContext viewgenContext1 = childRewriter.ViewgenContext; ViewgenContext viewgenContext2 = parentRewriter.ViewgenContext; IEnumerable <MemberPath> keyFields = ExtentKey.GetPrimaryKeyForEntityType(new MemberPath((EntitySetBase)this.ChildTable), this.ChildTable.ElementType).KeyFields; bool flag1 = false; bool flag2 = false; List <ErrorLog.Record> errorList = (List <ErrorLog.Record>)null; foreach (Cell cell in cells) { if (cell.SQuery.Extent.Equals((object)this.ChildTable)) { AssociationEndMember relationEndForColumns = ForeignConstraint.GetRelationEndForColumns(cell, this.ChildColumns); if (relationEndForColumns == null || this.CheckParentColumnsForForeignKey(cell, cells, relationEndForColumns, ref errorList)) { flag2 = true; if (ForeignConstraint.GetRelationEndForColumns(cell, keyFields) != null && relationEndForColumns != null && ForeignConstraint.FindEntitySetForColumnsMappedToEntityKeys(cells, keyFields).Count > 0) { flag1 = true; this.CheckConstraintWhenParentChildMapped(cell, errorLog, relationEndForColumns, config); break; } if (relationEndForColumns != null) { AssociationSet extent = (AssociationSet)cell.CQuery.Extent; MetadataHelper.GetEntitySetAtEnd(extent, relationEndForColumns); flag1 = ForeignConstraint.CheckConstraintWhenOnlyParentMapped(extent, relationEndForColumns, childRewriter, parentRewriter); if (flag1) { break; } } } } } if (!flag2) { foreach (ErrorLog.Record record in errorList) { errorLog.AddEntry(record); } } else { if (flag1) { return; } string message = Strings.ViewGen_Foreign_Key_Missing_Relationship_Mapping((object)this.ToUserString()); IEnumerable <LeftCellWrapper> wrappersFromContext1 = (IEnumerable <LeftCellWrapper>)ForeignConstraint.GetWrappersFromContext(viewgenContext2, (EntitySetBase)this.ParentTable); IEnumerable <LeftCellWrapper> wrappersFromContext2 = (IEnumerable <LeftCellWrapper>)ForeignConstraint.GetWrappersFromContext(viewgenContext1, (EntitySetBase)this.ChildTable); Set <LeftCellWrapper> set = new Set <LeftCellWrapper>(wrappersFromContext1); set.AddRange(wrappersFromContext2); ErrorLog.Record record = new ErrorLog.Record(ViewGenErrorCode.ForeignKeyMissingRelationshipMapping, message, (IEnumerable <LeftCellWrapper>)set, string.Empty); errorLog.AddEntry(record); } }
internal InputForComputingCellGroups(StorageEntityContainerMapping containerMapping, ConfigViewGenerator config) { ContainerMapping = containerMapping; Config = config; }
// effects: Ensures that there is a relationship mapped into the C-space for some cell in m_cellGroup. Else // adds an error to errorLog private void GuaranteeMappedRelationshipForForeignKey( QueryRewriter childRewriter, QueryRewriter parentRewriter, IEnumerable <Cell> cells, ErrorLog errorLog, ConfigViewGenerator config) { var childContext = childRewriter.ViewgenContext; var parentContext = parentRewriter.ViewgenContext; // Find a cell where this foreign key is mapped as a relationship var prefix = new MemberPath(ChildTable); var primaryKey = ExtentKey.GetPrimaryKeyForEntityType(prefix, ChildTable.ElementType); var primaryKeyFields = primaryKey.KeyFields; var foundCell = false; var foundValidParentColumnsForForeignKey = false; //we need to find only one, dont error on any one check being false List <ErrorLog.Record> errorListForInvalidParentColumnsForForeignKey = null; foreach (var cell in cells) { if (cell.SQuery.Extent.Equals(ChildTable) == false) { continue; } // The childtable is mapped to a relationship in the C-space in cell // Check that all the columns of the foreign key and the primary key in the child table are mapped to some // property in the C-space var parentEnd = GetRelationEndForColumns(cell, ChildColumns); if (parentEnd != null && CheckParentColumnsForForeignKey(cell, cells, parentEnd, ref errorListForInvalidParentColumnsForForeignKey) == false) { // Not an error unless we find no valid case continue; } else { foundValidParentColumnsForForeignKey = true; } var childEnd = GetRelationEndForColumns(cell, primaryKeyFields); Debug.Assert( childEnd == null || parentEnd != childEnd, "Ends are same => PKey and child columns are same - code should gone to other method"); // Note: If both of them are not-null, they are mapped to the // same association set -- since we checked that particular cell if (childEnd != null && parentEnd != null && FindEntitySetForColumnsMappedToEntityKeys(cells, primaryKeyFields) != null) { foundCell = true; CheckConstraintWhenParentChildMapped(cell, errorLog, parentEnd, config); break; // Done processing for the foreign key - either it was mapped correctly or it was not } else if (parentEnd != null) { // At this point, we know cell corresponds to an association set var assocSet = (AssociationSet)cell.CQuery.Extent; var parentSet = MetadataHelper.GetEntitySetAtEnd(assocSet, parentEnd); foundCell = CheckConstraintWhenOnlyParentMapped(assocSet, parentEnd, childRewriter, parentRewriter); if (foundCell) { break; } } } //CheckParentColumnsForForeignKey has returned no matches, Error. if (!foundValidParentColumnsForForeignKey) { Debug.Assert( errorListForInvalidParentColumnsForForeignKey != null && errorListForInvalidParentColumnsForForeignKey.Count > 0); foreach (var errorRecord in errorListForInvalidParentColumnsForForeignKey) { errorLog.AddEntry(errorRecord); } return; } if (foundCell == false) { // No cell found -- Declare error var message = Strings.ViewGen_Foreign_Key_Missing_Relationship_Mapping(ToUserString()); IEnumerable <LeftCellWrapper> parentWrappers = GetWrappersFromContext(parentContext, ParentTable); IEnumerable <LeftCellWrapper> childWrappers = GetWrappersFromContext(childContext, ChildTable); var bothExtentWrappers = new Set <LeftCellWrapper>(parentWrappers); bothExtentWrappers.AddRange(childWrappers); var record = new ErrorLog.Record( ViewGenErrorCode.ForeignKeyMissingRelationshipMapping, message, bothExtentWrappers, String.Empty); errorLog.AddEntry(record); } }
// effects: Checks that this foreign key constraints for all the // tables are being ensured on the C-side as well. If not, adds // errors to the errorLog internal void CheckConstraint( Set <Cell> cells, QueryRewriter childRewriter, QueryRewriter parentRewriter, ErrorLog errorLog, ConfigViewGenerator config) { if (IsConstraintRelevantForCells(cells) == false) { // if the constraint does not deal with any cell in this group, ignore it return; } if (config.IsNormalTracing) { Trace.WriteLine(String.Empty); Trace.WriteLine(String.Empty); Trace.Write("Checking: "); Trace.WriteLine(this); } if (childRewriter == null && parentRewriter == null) { // Neither table is mapped - so we are fine return; } // If the child table has not been mapped, we used to say that we // are fine. However, if we have SPerson(pid) and SAddress(aid, // pid), where pid is an FK into SPerson, we are in trouble if // SAddress is not mapped - SPerson could get deleted. So we // check for it as well // if the parent table is not mapped, we also have a problem if (childRewriter == null) { var message = Strings.ViewGen_Foreign_Key_Missing_Table_Mapping( ToUserString(), ChildTable.Name); // Get the cells from the parent table var record = new ErrorLog.Record( ViewGenErrorCode.ForeignKeyMissingTableMapping, message, parentRewriter.UsedCells, String.Empty); errorLog.AddEntry(record); return; } if (parentRewriter == null) { var message = Strings.ViewGen_Foreign_Key_Missing_Table_Mapping( ToUserString(), ParentTable.Name); // Get the cells from the child table var record = new ErrorLog.Record( ViewGenErrorCode.ForeignKeyMissingTableMapping, message, childRewriter.UsedCells, String.Empty); errorLog.AddEntry(record); return; } // Note: we do not check if the parent columns correspond to the // table's keys - metadata checks for that //First check if the FK is covered by Foreign Key Association //If we find this, we don't need to check for independent associations. If user maps the Fk to both FK and independent associations, //the regular round tripping validation will catch the error. if (CheckIfConstraintMappedToForeignKeyAssociation(childRewriter, parentRewriter, cells)) { return; } // Check if the foreign key in the child table corresponds to the primary key, i.e., if // the foreign key (e.g., pid, pid2) is a superset of the actual key members (e.g., pid), it means // that the foreign key is also the primary key for this table -- so we can propagate the queries upto C-Space // rather than doing the cell check var initialErrorLogSize = errorLog.Count; if (IsForeignKeySuperSetOfPrimaryKeyInChildTable()) { GuaranteeForeignKeyConstraintInCSpace(childRewriter, parentRewriter, errorLog); } else { GuaranteeMappedRelationshipForForeignKey(childRewriter, parentRewriter, cells, errorLog, config); } if (initialErrorLogSize == errorLog.Count) { // Check if the order of columns in foreign key correponds to the // mappings in m_cellGroup, e.g., if <pid1, pid2> in SAddress is // a foreign key into <pid1, pid2> of the SPerson table, make // sure that this order is preserved through the mappings in m_cellGroup CheckForeignKeyColumnOrder(cells, errorLog); } }