从数据库中检索自动增量数并根据该数更新子行

问题描述

我在更新父行和子行时遇到问题,当我插入新的父行并从数据库中检索新 ID 时,我需要基于此更新子行 parentId,但没有这样做,因为我认为我正在使用合并方法。反映主数据表的变化。

我试图创建一个简单的例子来解释我的问题和我使用的方法

这里是数据库架构:

CREATE TABLE ParentTable
(  
  ID int IDENTITY(1,1) PRIMARY KEY,ParentName varchar(100)  
)   



CREATE TABLE ChildTable  
(  
  ID int IDENTITY(1,ParentId int FOREIGN KEY REFERENCES ParentTable(id),ChildName varchar(100)  
)   


GO
CREATE PROCEDURE [dbo].[sp_INSERT_ParentTable] @ParentName NVarChar(100),@GetScopeIdentity SmallInt = 0 OUTPUT AS 
BEGIN
   SET
      NOCOUNT 
      ON 
      INSERT INTO ParentTable (ParentName) VALUES ( @ParentName);

      SET @GetScopeIdentity = ScopE_IDENTITY() RETURN @GetScopeIdentity 
END



GO
CREATE PROCEDURE [dbo].[sp_INSERT_ChildTable] @ParentId int,@ChildName NVarChar(100),@GetScopeIdentity SmallInt = 0 OUTPUT AS 
BEGIN
   SET
      NOCOUNT 
      ON 
      INSERT INTO ChildTable(ParentId,ChildName) VALUES ( @ParentId,@ChildName);

      SET @GetScopeIdentity = ScopE_IDENTITY() RETURN @GetScopeIdentity 
END


-- resetting tables 
TruncATE TABLE ChildTable;
DELETE FROM ParentTable;
DBCC CHECKIDENT (ParentTable,RESEED,0);


INSERT INTO ParentTable (ParentName) VALUES ('Parent 1');
INSERT INTO ParentTable (ParentName) VALUES ('Parent 2');

INSERT INTO ChildTable(ParentId,ChildName) VALUES (1,'Child 1');
INSERT INTO ChildTable(ParentId,'Child 2');

INSERT INTO ChildTable(ParentId,ChildName) VALUES (2,'Child 3');
INSERT INTO ChildTable(ParentId,'Child 4');

这是我正在使用的代码

    private static readonly string ConnectionString = "Server=.;Database=DbTest;User Id=sa;Password=;";

    private static void AddParentRowFromDatabase()
    {
        using var sqlConnection = new sqlConnection(ConnectionString);

        using sqlCommand command = sqlConnection.CreateCommand();
        command.CommandText = "INSERT INTO ParentTable (ParentName) VALUES (@ParentName);";
        command.Parameters.Add("@ParentName",sqlDbType.NVarChar);

        sqlConnection.open();

        // this row id should be Now 3 because by default we are adding only two parent 
        // but notice that the dataset and DataTable doesn't kNow that we added this row 
        command.Parameters["@ParentName"].Value = "Added From Database Parent.";
        command.ExecuteNonQuery();
    }

    private static void Main(string[] args)
    {
        var connection = new sqlConnection(ConnectionString);

        var dataset = new DataSet();

        // Creating ParentTable Adapter and preparing its InsertCommand 
        var parentTableAdapter = new sqlDataAdapter("Select Id,ParentName from ParentTable",connection)
        {
            MissingSchemaAction = MissingSchemaAction.AddWithKey,AcceptChangesDuringUpdate = false
        };
        parentTableAdapter.RowUpdated += (sender,e) =>
        {
            if (e.StatementType != StatementType.Insert) return;
            e.Status = UpdateStatus.SkipCurrentRow;
        };

        var parentInsertCommand = new sqlCommand("sp_INSERT_ParentTable",connection) {CommandType = CommandType.StoredProcedure};
        parentInsertCommand.Parameters.Add(new sqlParameter("@ParentName",sqlDbType.NVarChar) {SourceColumn = "ParentName"});
        parentInsertCommand.Parameters.Add(new sqlParameter("@GetScopeIdentity",sqlDbType.Int) {SourceColumn = "Id",Direction = ParameterDirection.Output});
        parentInsertCommand.UpdatedRowSource = UpdateRowSource.OutputParameters;
        parentTableAdapter.InsertCommand = parentInsertCommand;
        // Here we just retrieve the structure as my real project and later I call fill method when I need it
        parentTableAdapter.FillSchema(dataset,SchemaType.Mapped,"ParentTable");

        // Creating ChildTable Adapter and preparing its InsertCommand 
        var childTableAdapter = new sqlDataAdapter("Select Id,ParentId,ChildName from ChildTable",AcceptChangesDuringUpdate = false
        };
        childTableAdapter.RowUpdated += (sender,e) =>
        {
            if (e.StatementType != StatementType.Insert) return;
            e.Status = UpdateStatus.SkipCurrentRow;
        };

        var childInsertCommand = new sqlCommand("sp_INSERT_ChildTable",connection) {CommandType = CommandType.StoredProcedure};
        childInsertCommand.Parameters.Add(new sqlParameter("@ParentId",sqlDbType.Int) {SourceColumn = "ParentId"});
        childInsertCommand.Parameters.Add(new sqlParameter("@ChildName",sqlDbType.NVarChar) {SourceColumn = "ChildName"});
        childInsertCommand.Parameters.Add(new sqlParameter("@GetScopeIdentity",Direction = ParameterDirection.Output});
        childInsertCommand.UpdatedRowSource = UpdateRowSource.OutputParameters;
        childTableAdapter.InsertCommand = childInsertCommand;
        // Here we just retrieve the structure as my real project and later I call fill method when I need it
        childTableAdapter.FillSchema(dataset,"ChildTable");

        // Here we create datarelation and passing true for creating constraints 
        var datarelation = new datarelation("ParentTable:ChildTable",dataset.Tables["ParentTable"].Columns["ID"],dataset.Tables["ChildTable"].Columns["ParentId"],true);
        dataset.Relations.Add(datarelation);

        // So wherever id in parent changes the child rows also changes 
        datarelation.ChildKeyConstraint.UpdateRule = Rule.Cascade;

        // Now we fill the tables from database 
        parentTableAdapter.Fill(dataset,"ParentTable");
        childTableAdapter.Fill(dataset,"ChildTable");

        Console.WriteLine("Dumping ParentTable content");
        Print_results(dataset.Tables["ParentTable"]);

        Console.WriteLine("Dumping ChildTable content");
        Print_results(dataset.Tables["ChildTable"]);

        Console.ReadLine();

        // Now lets act like we are on another pc and add some rows to the parentTable some our parentTable object doesn't kNow the real current row id
        Console.WriteLine("Adding some data from database.");
        AddParentRowFromDatabase(); // here we adding only one row it's id should be 3

        // Now lets add a parent with child rows using our adapters 
        DaTarow newParentRow = dataset.Tables["ParentTable"].NewRow();
        newParentRow["ParentName"] = "Parent Added from DataAdapter";
        dataset.Tables["ParentTable"].Rows.Add(newParentRow);

        // adding child rows 
        // child 1
        DaTarow newChildRow1 = dataset.Tables["ChildTable"].NewRow();
        newChildRow1["ParentId"] = newParentRow["ID"];
        newChildRow1["ChildName"] = "Child Added from DataAdapter 1 should be linked with parentId 4";
        // child 2
        DaTarow newChildRow2 = dataset.Tables["ChildTable"].NewRow();
        newChildRow2["ParentId"] = newParentRow["ID"];
        newChildRow2["ChildName"] = "Child Added from DataAdapter 2 should be linked with parentid 4";

        dataset.Tables["ChildTable"].Rows.Add(newChildRow1);
        dataset.Tables["ChildTable"].Rows.Add(newChildRow2);

        // Now lets review what we got 
        // the new added parent Id in the memory is 3 
        // but when we use the adapter it should update the row and change the id value to 4 because there is a row with id 3 
        // what I need after that to update the child rows ParentId column with the new retrieved id value 

        DataTable parentTableChanges = dataset.Tables["ParentTable"].GetChanges();

        DataTable childTableChanges = dataset.Tables["ChildTable"].GetChanges();

        parentTableAdapter.Update(parentTableChanges);

        dataset.Tables["ParentTable"].Merge(parentTableChanges); // merge updated id to the parent table

        childTableAdapter.Update(childTableChanges);

        dataset.Tables["ChildTable"].Merge(childTableChanges); // merge updated id to the parent table

        // Now if we dump child rows we should see the new added childs but with the new retreived ParentId which is 4 

        Print_results(dataset.Tables["ParentTable"]);

        Print_results(dataset.Tables["ChildTable"]);

        Console.ReadLine();
    }

    private static void Print_results(DataTable data)
    {
        Console.WriteLine();
        var colWidths = new Dictionary<string,int>();

        foreach (DataColumn col in data.Columns)
        {
            Console.Write(col.ColumnName);
            int maxLabelSize = data.Rows.OfType<DaTarow>()
                .Select(m => (m.Field<object>(col.ColumnName)?.ToString() ?? "").Length)
                .OrderByDescending(m => m).FirstOrDefault();

            colWidths.Add(col.ColumnName,maxLabelSize);
            for (var i = 0; i < maxLabelSize - col.ColumnName.Length + 10; i++) Console.Write(" ");
        }

        Console.WriteLine();

        foreach (DaTarow daTarow in data.Rows)
        {
            for (var j = 0; j < daTarow.ItemArray.Length; j++)
            {
                Console.Write(daTarow.ItemArray[j]);
                for (var i = 0; i < colWidths[data.Columns[j].ColumnName] - daTarow.ItemArray[j].ToString().Length + 10; i++) Console.Write(" ");
            }

            Console.WriteLine();
        }

        Console.WriteLine("End of the table.\n\n");
    }

我希望我很清楚。有人知道更好的方法吗?

感谢帮助

解决方法

暂无找到可以解决该程序问题的有效方法,小编努力寻找整理中!

如果你已经找到好的解决方法,欢迎将解决方案带上本链接一起发送给小编。

小编邮箱:dio#foxmail.com (将#修改为@)