internal static string GenerateUpdateSql(DbUpdateCommandTree tree, out List<DbParameter> parameters) { StringBuilder commandText = new StringBuilder(CommandTextBuilderInitialCapacity); ExpressionTranslator translator = new ExpressionTranslator(commandText, tree, null != tree.Returning); bool first = true; commandText.Append("UPDATE "); tree.Target.Expression.Accept(translator); commandText.AppendLine(); // set c1 = ..., c2 = ..., ... commandText.Append("SET "); foreach (DbSetClause setClause in tree.SetClauses) { if (first) { first = false; } else { commandText.Append(", "); } setClause.Property.Accept(translator); commandText.Append(" = "); setClause.Value.Accept(translator); translator.RegisterMemberValue(setClause.Property, setClause.Value); } if (first) { // If first is still true, it indicates there were no set // clauses. Introduce a fake set clause so that: // - we acquire the appropriate locks // - server-gen columns (e.g. timestamp) get recomputed EntitySetBase table = ((DbScanExpression)tree.Target.Expression).Target; // hope this column isn't indexed to not waste power EdmMember someColumn = table.ElementType.Members.Last(x => !IsStoreGenerated(x)); commandText.AppendFormat("{0} = {0}", GenerateMemberSql(someColumn)); } commandText.AppendLine(); // where c1 = ..., c2 = ... commandText.Append("WHERE "); tree.Predicate.Accept(translator); commandText.AppendLine(); // generate returning sql GenerateReturningSql(commandText, tree, translator, tree.Returning); parameters = translator.Parameters; return commandText.ToString(); }
internal static string GenerateUpdateSql(DbUpdateCommandTree tree, SqlVersion sqlVersion, out List<SqlParameter> parameters) { const string dummySetParameter = "@p"; StringBuilder commandText = new StringBuilder(s_commandTextBuilderInitialCapacity); ExpressionTranslator translator = new ExpressionTranslator(commandText, tree, null != tree.Returning, sqlVersion); if (tree.SetClauses.Count == 0) { commandText.AppendLine("declare " + dummySetParameter + " int"); } // update [schemaName].[tableName] commandText.Append("update "); tree.Target.Expression.Accept(translator); commandText.AppendLine(); // set c1 = ..., c2 = ..., ... bool first = true; commandText.Append("set "); foreach (DbSetClause setClause in tree.SetClauses) { if (first) { first = false; } else { commandText.Append(", "); } setClause.Property.Accept(translator); commandText.Append(" = "); setClause.Value.Accept(translator); } if (first) { // If first is still true, it indicates there were no set // clauses. Introduce a fake set clause so that: // - we acquire the appropriate locks // - server-gen columns (e.g. timestamp) get recomputed // // We use the following pattern: // // update Foo // set @p = 0 // where ... commandText.Append(dummySetParameter + " = 0"); } commandText.AppendLine(); // where c1 = ..., c2 = ... commandText.Append("where "); tree.Predicate.Accept(translator); commandText.AppendLine(); // generate returning sql GenerateReturningSql(commandText, tree, null, translator, tree.Returning, false); parameters = translator.Parameters; return commandText.ToString(); }
internal static string GenerateUpdateSql(DbUpdateCommandTree tree, out List<DbParameter> parameters) { StringBuilder commandText = new StringBuilder(s_commandTextBuilderInitialCapacity); ExpressionTranslator translator = new ExpressionTranslator(commandText, tree, null != tree.Returning); // update [schemaName].[tableName] commandText.Append("update "); tree.Target.Expression.Accept(translator); commandText.AppendLine(); // set c1 = ..., c2 = ..., ... bool first = true; commandText.Append("set "); foreach (DbSetClause setClause in tree.SetClauses) { if (first) { first = false; } else { commandText.Append(", "); } setClause.Property.Accept(translator); commandText.Append(" = "); setClause.Value.Accept(translator); } if (first) { // If first is still true, it indicates there were no set // clauses. Introduce a fake set clause so that: // - we acquire the appropriate locks // - server-gen columns (e.g. timestamp) get recomputed // // We use the following pattern: // // update SomeTable // set @i = 0 // where ... DbParameter parameter = translator.CreateParameter( default(Int32), TypeUsage.CreateDefaultTypeUsage(PrimitiveType.GetEdmPrimitiveType(PrimitiveTypeKind.Int32))); commandText.Append(parameter.ParameterName); commandText.Append(" = 0"); } commandText.AppendLine(); // where c1 = ..., c2 = ... commandText.Append("where "); tree.Predicate.Accept(translator); commandText.AppendLine(); // generate returning sql GenerateReturningSql(commandText, tree, translator, tree.Returning); parameters = translator.Parameters; return commandText.ToString(); }
protected virtual void VisitUpdateCommandTree(DbUpdateCommandTree updateTree) { EntityUtil.CheckArgumentNull(updateTree, "updateTree"); this.VisitExpressionBindingPre(updateTree.Target); this.VisitModificationClauses(updateTree.SetClauses); this.VisitExpression(updateTree.Predicate); if (updateTree.Returning != null) { this.VisitExpression(updateTree.Returning); } this.VisitExpressionBindingPost(updateTree.Target); }
/// <summary> /// This method is added as a part of the fix for bug 13533 /// In this method we try to see from the command tree whether there is any /// updatable column(Property) available on the table(EntityType) private static bool GetUpdatableColumn(DbUpdateCommandTree tree, out string updatableColumnName) { var result = false; updatableColumnName = ""; var entityType = (EntityType)tree.Target.VariableType.EdmType; foreach (var edmProperty in entityType.Properties) { if (entityType.KeyMembers.Contains(edmProperty.Name)) { // continue if it is a primary key continue; } if (rowversionString == edmProperty.TypeUsage.EdmType.Name) { // if the property is of type rowversion then we continue checking the next item in the list continue; } // check whether the property is a identity type if (edmProperty.TypeUsage.Facets.Contains(storeGeneratedPatternString)) { var fct = edmProperty.TypeUsage.Facets.GetValue(storeGeneratedPatternString, false); if (StoreGeneratedPattern.Identity == (StoreGeneratedPattern)fct.Value) { // continue to check for the next property if the current property is a identity continue; } } //if the column is found then return the column name string updatableColumnName = edmProperty.Name; result = true; break; } return result; }
internal static string[] GenerateUpdateSql(DbUpdateCommandTree tree, out List<DbParameter> parameters, bool isLocalProvider) { var commandTexts = new List<String>(); var commandText = new StringBuilder(s_commandTextBuilderInitialCapacity); var translator = new ExpressionTranslator(commandText, tree, null != tree.Returning, isLocalProvider); // update [schemaName].[tableName] commandText.Append("update "); tree.Target.Expression.Accept(translator); commandText.AppendLine(); // set c1 = ..., c2 = ..., ... var first = true; commandText.Append("set "); foreach (DbSetClause setClause in tree.SetClauses) { if (first) { first = false; } else { commandText.Append(", "); } setClause.Property.Accept(translator); commandText.Append(" = "); setClause.Value.Accept(translator); } if (first) { // If first is still true, it indicates there were no set // clauses. // - we acquire the appropriate locks // - server-gen columns (e.g. timestamp) get recomputed // // Bug fix #13533 : A fake update DML updating some column item // with the same value as before to acquire the lock on the table // while updating some columns in another table. This happens when // both the table are dependent on an entity and the members of entity // which is mapped to one table is being updated and the other table // needs to be locked for consistancy. string updatableColumnName; if (GetUpdatableColumn(tree, out updatableColumnName)) { commandText.Append("["); commandText.Append(CommonUtils.EscapeSquareBraceNames(updatableColumnName)); commandText.Append("] "); commandText.Append(" = "); commandText.Append("["); commandText.Append(CommonUtils.EscapeSquareBraceNames(updatableColumnName)); commandText.Append("] "); } else { // Throw some meaningful error throw ADP1.Update( EntityRes.GetString(EntityRes.UpdateStatementCannotBeGeneratedForAcquiringLock), null); } } commandText.AppendLine(); // where c1 = ..., c2 = ... commandText.Append("where "); tree.Predicate.Accept(translator); commandText.AppendLine(); commandTexts.Add(commandText.ToString()); commandText.Length = 0; // generate returning sql GenerateReturningSql(commandText, tree, translator, tree.Returning); if (!String.IsNullOrEmpty(commandText.ToString())) { commandTexts.Add(commandText.ToString()); } parameters = translator.Parameters; return commandTexts.ToArray(); }
public SqlUpdateGenerator(DbUpdateCommandTree commandTree) { _commandTree = commandTree; }
private DbModificationCommandTree RebuildCommandTree(DbModificationCommandTree originalTree, Dictionary<DbSetClause, DbSetClause> clauseMappings) { if (clauseMappings.Count == 0) { return originalTree; } DbModificationCommandTree result; Debug.Assert(originalTree.CommandTreeKind == DbCommandTreeKind.Insert || originalTree.CommandTreeKind == DbCommandTreeKind.Update, "Set clauses specified for a modification tree that is not an update or insert tree?"); if (originalTree.CommandTreeKind == DbCommandTreeKind.Insert) { DbInsertCommandTree insertTree = (DbInsertCommandTree)originalTree; result = new DbInsertCommandTree(insertTree.MetadataWorkspace, insertTree.DataSpace, insertTree.Target, ReplaceClauses(insertTree.SetClauses, clauseMappings).AsReadOnly(), insertTree.Returning); } else { DbUpdateCommandTree updateTree = (DbUpdateCommandTree)originalTree; result = new DbUpdateCommandTree(updateTree.MetadataWorkspace, updateTree.DataSpace, updateTree.Target, updateTree.Predicate, ReplaceClauses(updateTree.SetClauses, clauseMappings).AsReadOnly(), updateTree.Returning); } return result; }
/// <summary> /// Builds an update command. /// </summary> /// <param name="oldRow">Old value of the row being updated.</param> /// <param name="newRow">New value for the row being updated.</param> /// <param name="processor">Context for the table containing row.</param> /// <returns>Update command.</returns> internal UpdateCommand BuildUpdateCommand(PropagatorResult oldRow, PropagatorResult newRow, TableChangeProcessor processor) { // If we're updating a row, the row may not need to be touched (e.g., no concurrency validation required) bool rowMustBeTouched = false; DbExpressionBinding target = GetTarget(processor); // Create set clauses and returning parameter Dictionary<int, string> outputIdentifiers; DbExpression returning; List<DbModificationClause> setClauses = new List<DbModificationClause>(); foreach (DbModificationClause clause in BuildSetClauses( target, newRow, oldRow, processor, /* insertMode */ false, out outputIdentifiers, out returning, ref rowMustBeTouched)) { setClauses.Add(clause); } // Construct predicate identifying the row to modify DbExpression predicate = BuildPredicate(target, oldRow, newRow, processor, ref rowMustBeTouched); if (0 == setClauses.Count) { if (rowMustBeTouched) { List<IEntityStateEntry> stateEntries = new List<IEntityStateEntry>(); stateEntries.AddRange(SourceInterpreter.GetAllStateEntries( oldRow, m_translator, processor.Table)); stateEntries.AddRange(SourceInterpreter.GetAllStateEntries( newRow, m_translator, processor.Table)); if (stateEntries.All(it => (it.State == EntityState.Unchanged))) { rowMustBeTouched = false; } } // Determine if there is nothing to do (i.e., no values to set, // no computed columns, and no concurrency validation required) if (!rowMustBeTouched) { return null; } } // Initialize DML command tree DbUpdateCommandTree commandTree = new DbUpdateCommandTree(m_translator.MetadataWorkspace, DataSpace.SSpace, target, predicate, setClauses.AsReadOnly(), returning); // Create command UpdateCommand command = new DynamicUpdateCommand(processor, m_translator, ModificationOperator.Update, oldRow, newRow, commandTree, outputIdentifiers); return command; }
protected virtual void VisitUpdateCommandTree(DbUpdateCommandTree updateTree) { //Contract.Requires(updateTree != null); VisitExpressionBindingPre(updateTree.Target); VisitModificationClauses(updateTree.SetClauses); VisitExpression(updateTree.Predicate); if (updateTree.Returning != null) { VisitExpression(updateTree.Returning); } VisitExpressionBindingPost(updateTree.Target); }