private static int UpdateAll(IConnectionProvider conn, IEntity rootEntity, DbRelation recursiveRelation, UpdateList setExpressions, int beginAtLevel, int endAtLevel) { // Stop condition: rowsAffected == 0 int totalRowsAffected = 0; bool isLocalConn = !conn.IsOpen; try { if (isLocalConn) conn.BeginTransaction(); // We need to perform COUNT at least once to determine whether rowsAffacted returned by UPDATE can be trusted. RowsAffectedCredibility trustRowsAffected = RowsAffectedCredibility.NotDetermined; bool reachedEndLevel = false; int level = beginAtLevel; do { // Dependening on DBMS configuration, update statements may automatically return the number of rows affected. int rowsAffectedReturnedByEngine = UpdateAtLevel(conn, rootEntity, recursiveRelation, setExpressions, level); // We need to perform manual counting for as long as rows affected cannot be trusted. int? manualNodeCount = CountNodesAtLevelIfRowsAffectedCannotBeTrusted(conn, rootEntity, trustRowsAffected, recursiveRelation, level); // Evaluation which determines whether rows affected may be trusted takes place only once, ie. if not yet determined. bool evaluateRowsAffectedCredibility = (trustRowsAffected == RowsAffectedCredibility.NotDetermined) && (manualNodeCount.HasValue); if (evaluateRowsAffectedCredibility) { bool engineCountMatchesManualCount = (rowsAffectedReturnedByEngine == manualNodeCount.Value); trustRowsAffected = (engineCountMatchesManualCount) ? RowsAffectedCredibility.Trusted : RowsAffectedCredibility.Untrusted; } // Manual node count is null if we have determined that rows affected value returned by engine is credible. int rowsUpdatedInCurrentLevel = manualNodeCount ?? rowsAffectedReturnedByEngine; totalRowsAffected += rowsUpdatedInCurrentLevel; // Inspect stop condition before level variable is increased. reachedEndLevel = IsEndLevelReached(endAtLevel, level, rowsUpdatedInCurrentLevel); // Next level. level++; } while (!reachedEndLevel); if (isLocalConn) conn.CommitTransaction(); } finally { if (isLocalConn) conn.CloseConnection(); } return totalRowsAffected; }
private static int UpdateWithLeafFilter(IConnectionProvider conn, IEntity rootEntity, DbRelation recursiveRelation, UpdateList setExpressions, SearchCondition leafFilter, int beginAtLevel, int endAtLevel) { // Stop condition: final level reached (tree depth is measured). // It's possible that at some intermediate levels no records satisfy the specified criteria. // Nevertheless, the algorithm must proceed to the next level where it might find matching records. // This behavior simulates the behavior of recursive CTEs. int totalRowsAffected = 0; bool isLocalConn = !conn.IsOpen; try { if (isLocalConn) conn.BeginTransaction(); endAtLevel = GetEndLevel(conn, rootEntity, recursiveRelation, endAtLevel); bool reachedEndLevel = false; int level = beginAtLevel; do { UpdateStatement updateAtLevel = CreateUpdateLevelStatement(rootEntity, recursiveRelation, setExpressions, leafFilter, level); totalRowsAffected += updateAtLevel.Execute(conn); reachedEndLevel = (level >= endAtLevel); level++; } while (!reachedEndLevel); if (isLocalConn) conn.CommitTransaction(); } finally { if (isLocalConn) conn.CloseConnection(); } return totalRowsAffected; }