protected override void PopulateWriterColumns(SqlWriteBuilder builder, RowChangingData cdata, bool includePrimaryKey)
        {
            base.PopulateWriterColumns(builder, cdata, includePrimaryKey);

            //change the Notes value during RetroDRY saving
            if (cdata.ModifiedRow is Customer cust)
            {
                builder.ChangeValue("Notes", ">" + cust.Notes);
            }
        }
        /// <summary>
        /// Add all non-key values from a diff row to a SqlWriteBuilder
        /// </summary>
        protected virtual void PopulateWriterColumns(SqlWriteBuilder builder, RowChangingData cdata, bool includePrimaryKey)
        {
            var customColValues = new Dictionary <string, object>(); //contents must be json compatible types

            //write to builder; write custom cols to temporary dictionary
            foreach (var coldef in cdata.TableDef.Cols)
            {
                if (coldef.IsComputed)
                {
                    continue;
                }
                if (!includePrimaryKey && coldef.Name == cdata.TableDef.PrimaryKeyColName)
                {
                    continue;
                }
                if (!cdata.DiffRow.Columns.TryGetValue(coldef.Name, out object value))
                {
                    continue;
                }
                if (coldef.IsCustom)
                {
                    customColValues[coldef.Name] = value;
                }
                else
                {
                    builder.AddNonKey(coldef.Name, coldef.WireType, value);
                }
            }

            //if any custom columns are to be written, include CustomValues column with old and new values/
            //Example: if custom cols A and B exist, and the current write only updates A, we still need to include the pristine value of B in the json
            if (customColValues.Any())
            {
                if (cdata.PristineRow != null)
                {
                    foreach (var coldef in cdata.TableDef.Cols.Where(c => c.IsCustom))
                    {
                        if (customColValues.ContainsKey(coldef.Name))
                        {
                            continue;                                           //don't overwrite old over new
                        }
                        customColValues[coldef.Name] = cdata.PristineRow.GetCustom(coldef.Name);
                    }
                }
                string json = CustomValuesToJson(cdata.TableDef, customColValues);
                builder.AddNonKey(CUSTOMCOLNAME, null, json, useJson: true);
            }
        }
        /// <summary>
        /// Insert or update a row
        /// </summary>
        /// <returns>database assigned parent key (only if changed) else null</returns>
        protected async Task <object> InsertUpdateRow(IDbConnection db, RowChangingData cdata)
        {
            if (cdata.DiffRow.Kind == DiffKind.NewRow)
            {
                var  builder      = new SqlInsertBuilder(SqlFlavor, CustomizeSqlStatement);
                bool dbAssignsKey = cdata.TableDef.DatabaseAssignsKey;
                PopulateWriterColumns(builder, cdata, !dbAssignsKey);
                if (cdata.TableDef.ParentKeyColumnName != null)
                {
                    builder.AddNonKey(cdata.TableDef.ParentKeyColumnName, null, cdata.ParentKey);
                }
                var newKeyValue = await builder.Execute(db, cdata.TableDef.SqlTableName, cdata.TableDef.PrimaryKeyColName, dbAssignsKey);

                //populate the new key value in Modified persiston's row
                if (newKeyValue != null)
                {
                    var rr = new RowRecurPoint()
                    {
                        TableDef = cdata.TableDef, Row = cdata.ModifiedRow
                    };
                    rr.SetPrimaryKey(newKeyValue);
                }
                return(newKeyValue);
            }
            if (cdata.DiffRow.Kind == DiffKind.Other)
            {
                var builder = new SqlUpdateBuilder(SqlFlavor, CustomizeSqlStatement);
                PopulateWriterColumns(builder, cdata, false);
                if (!cdata.DiffRow.Columns.TryGetValue(cdata.TableDef.PrimaryKeyColName, out object pkValue))
                {
                    throw new Exception($"Cannot update row in {cdata.TableDef.Name} because no primary key was found in diff");
                }
                if (builder.NonKeyCount > 0)
                {
                    await builder.Execute(db, cdata.TableDef.SqlTableName, cdata.TableDef.PrimaryKeyColName, pkValue);
                }
            }
            return(null);
        }
Beispiel #4
0
        /// <summary>
        /// Call ProcessRowF on all rows in the diff list, and recurse to all child tables.
        /// </summary>
        /// <param name="singleMainPristineRow">only set for top level call if there is a single main row</param>
        /// <param name="singleMainModifiedRow">only set for top level call if there is a single main row</param>
        protected async Task TraverseDiffList(TraversalData tdata, Row singleMainPristineRow, Row singleMainModifiedRow)
        {
            var pkField = tdata.TableDef.RowType.GetField(tdata.TableDef.PrimaryKeyColName);

            foreach (var row in tdata.DiffRowList)
            {
                if (!row.Columns.TryGetValue(tdata.TableDef.PrimaryKeyColName, out object rowKey))
                {
                    throw new Exception($"Diff row is missing primary key {tdata.TableDef.PrimaryKeyColName}");
                }

                //find pristine row
                Row pristineRow = singleMainPristineRow;
                if (tdata.PristineList != null && row.Kind != DiffKind.NewRow)
                {
                    int rowIdx = Utils.IndexOfPrimaryKeyMatch(tdata.PristineList, pkField, rowKey);
                    if (rowIdx >= 0)
                    {
                        pristineRow = tdata.PristineList[rowIdx] as Row;
                    }
                }

                //find modified row
                Row modifiedRow = singleMainModifiedRow;
                if (tdata.ModifiedList != null)
                {
                    int rowIdx = Utils.IndexOfPrimaryKeyMatch(tdata.ModifiedList, pkField, rowKey);
                    if (rowIdx >= 0)
                    {
                        modifiedRow = tdata.ModifiedList[rowIdx] as Row;
                    }
                }

                //callback to process row
                var cdata = new RowChangingData
                {
                    ParentKey   = tdata.ParentKey,
                    DiffRow     = row,
                    DiffRowList = tdata.DiffRowList,
                    TableDef    = tdata.TableDef,
                    PristineRow = pristineRow,
                    ModifiedRow = modifiedRow
                };
                (object newPK, bool doTraverseChildren) = await tdata.ProcessRowF?.Invoke(cdata);

                if (newPK != null)
                {
                    rowKey = newPK;
                }

                //skip child tables?
                if (!doTraverseChildren)
                {
                    continue;
                }

                //loop child tables of this row
                if (row.ChildTables != null)
                {
                    foreach (var child in row.ChildTables)
                    {
                        var childTableDef = child.Key;
                        var childRows     = child.Value;
                        var listField     = tdata.TableDef.RowType.GetField(childTableDef.Name);

                        //get pristine list
                        IList childPristineList = null;
                        if (pristineRow != null)
                        {
                            childPristineList = listField.GetValue(pristineRow) as IList;
                        }

                        //get modified list
                        IList childModifiedList = null;
                        if (modifiedRow != null)
                        {
                            childModifiedList = listField.GetValue(modifiedRow) as IList;
                        }

                        var childTdata = new TraversalData
                        {
                            ParentKey    = rowKey,
                            TableDef     = childTableDef,
                            DiffRowList  = childRows,
                            PristineList = childPristineList,
                            ModifiedList = childModifiedList,
                            ProcessRowF  = tdata.ProcessRowF
                        };
                        await TraverseDiffList(childTdata, null, null);
                    }
                }
            }
        }