/// <summary> /// Constructs a join propagator. /// </summary> /// <param name="left">Result of propagating changes in the left input to the join</param> /// <param name="right">Result of propagating changes in the right input to the join</param> /// <param name="node">Join operator in update mapping view over which to propagate changes</param> /// <param name="parent">Handler of propagation for the entire update mapping view</param> internal JoinPropagator(ChangeNode left, ChangeNode right, DbJoinExpression node, Propagator parent) { EntityUtil.CheckArgumentNull(left, "left"); EntityUtil.CheckArgumentNull(right, "right"); EntityUtil.CheckArgumentNull(node, "node"); EntityUtil.CheckArgumentNull(parent, "parent"); m_left = left; m_right = right; m_joinExpression = node; m_parent = parent; Debug.Assert(DbExpressionKind.LeftOuterJoin == node.ExpressionKind || DbExpressionKind.InnerJoin == node.ExpressionKind, "(Update/JoinPropagagtor/JoinEvaluator) " + "caller must ensure only left outer and inner joins are requested"); // Retrieve propagation rules for the join type of the expression. if (DbExpressionKind.InnerJoin == m_joinExpression.ExpressionKind) { m_insertRules = s_innerJoinInsertRules; m_deleteRules = s_innerJoinDeleteRules; } else { m_insertRules = s_leftOuterJoinInsertRules; m_deleteRules = s_leftOuterJoinDeleteRules; } // Figure out key selectors involved in the equi-join (if it isn't an equi-join, we don't support it) JoinConditionVisitor.GetKeySelectors(node.JoinCondition, out m_leftKeySelectors, out m_rightKeySelectors); // Find the key selector expressions in the left and right placeholders m_leftPlaceholderKey = ExtractKey(m_left.Placeholder, m_leftKeySelectors, m_parent); m_rightPlaceholderKey = ExtractKey(m_right.Placeholder, m_rightKeySelectors, m_parent); }
/// <summary> /// Determine properties from the left and right inputs to an equi-join participating /// in predicate. /// </summary> /// <remarks> /// The property definitions returned are 'aligned'. If the join predicate reads: /// <code> /// a = b AND c = d AND e = f /// </code> /// then the output is as follows: /// <code> /// leftProperties = {a, c, e} /// rightProperties = {b, d, f} /// </code> /// See Walker class for an explanation of this coding pattern. /// </remarks> static internal void GetKeySelectors(DbExpression joinCondition, out ReadOnlyCollection <DbExpression> leftKeySelectors, out ReadOnlyCollection <DbExpression> rightKeySelectors) { EntityUtil.CheckArgumentNull(joinCondition, "joinCondition"); // Constructs a new predicate visitor, which implements a visitor for expression nodes // and returns no values. This visitor instead builds up a list of properties as leaves // of the join predicate are visited. JoinConditionVisitor visitor = new JoinConditionVisitor(); // Walk the predicate using the predicate visitor. joinCondition.Accept(visitor); // Retrieve properties discovered visiting predicate leaf nodes. leftKeySelectors = visitor.m_leftKeySelectors.AsReadOnly(); rightKeySelectors = visitor.m_rightKeySelectors.AsReadOnly(); Debug.Assert(leftKeySelectors.Count == rightKeySelectors.Count, "(Update/JoinPropagator) The equi-join must have an equal number of left and right properties"); }