是否可以在服务器端的 Client/Server 场景中使用 SqlDataAdapter?

问题描述

首先:我们有一个应用程序主要围绕旧的 DataTable 类型构建。因此,我们无法切换到 e。 G。现在EF。这将是一个未来的项目。与此同时,我们需要构建一个新的基于服务器端 REST 的解决方案来替代旧的服务器逻辑。

问题: sqlDataAdapter.Update(DataTable) 不更新数据库中的数据:

  • 新记录:成功插入数据库
  • 修改记录:上面的 Update() 方法返回正确的计数,但更改不在 DB 中
  • 删除的记录:上面的 Update() 方法返回 0 计数,因此引发并发异常(这是数据适配器的设计,此处不正确)

推测原因:因为 DataTable 是由服务器应用程序根据客户端的请求获取的,但在它被写入数据库之前被传输到客户端并返回到服务器,sqlDataAdapter 似乎没有正确检测到它们的变化:

  1. 客户端请求数据
  2. 服务器从数据库获取数据
  3. 数据通过 REST 序列化传输到客户端
  4. 客户处理数据
  5. 更改的数据通过 REST 序列化传输到服务器
  6. 服务器实例化一个新的 sqlDataAdapter 实例,并在收到的数据上生成 sqlDataAdapter.Update()

数据完整性:

  • 每条记录的正确 RowState 出现在服务器端,当它生成 sqlDataAdapter.Update()
  • 出于效率原因,客户端仅将更改的记录传输到服务器
  • 所有的表都有一个 PK
  • 所有表都没有 FK 关系(这是/曾经是传统设计规则)

是否有可能以某种方式在“外部”数据上实现(服务器端)sqlDataAdapter.Update(),还是这种方法仅用于直接(客户端)更新原始数据的数据库

常见错误当然,我已经对这个问题进行了大量搜索,并注意正确填充 sql 命令属性


服务端代码部分:

public override int[] SaveDataTable(IEnumerable<DataTable> dataTables)
{
    var counts = new Queue<int>();
    using (_connection = new sqlConnection(ConnectionString))
    {
        _connection.open();
        var transaction = _connection.BeginTransaction();
        try
        {
            foreach (var table in dataTables)
            {
                //var command = new sqlCommand();
                var command = _connection.CreateCommand();
                using (command)
                {
                    command.Connection = _connection;
                    command.Transaction = transaction;
                    command.CommandText = Global.GetSelectStatement(table);
                    var dataAdapter = new sqlDataAdapter(command);
                    var cmdBuilder = new sqlCommandBuilder(dataAdapter);
                    dataAdapter.UpdateCommand = cmdBuilder.GetUpdateCommand();
                    dataAdapter.InsertCommand = cmdBuilder.GetInsertCommand();
                    dataAdapter.DeleteCommand = cmdBuilder.GetDeleteCommand();
                    //dataAdapter.SelectCommand = command;
                    //var dSet = new DataSet();
                    //dataAdapter.Fill(dSet);
                    //dataAdapter.Fill(table);
                    //dataAdapter.Fill(new DataTable());
                    //var clone = table.copy();
                    //clone.AcceptChanges();
                    //dataAdapter.Fill(clone);
                    counts.Enqueue(dataAdapter.Update(table));
                }
            }
            transaction.Commit();
        }
        catch (Exception)
        {
            transaction.Rollback(); //this may throw also
            throw;
        }
    }
    return counts.ToArray();
}

RowState = Modified

解决方法

好的,所以任务解决了。 SqlDataAdapter 的实现没有任何问题(当然评论中的改进建议除外)。

问题在于客户端应用程序代码总是调用 AcceptChanges() 以减少数据量。在将更改的数据发送到数据访问层之前,每行的 RowState 都用 DataRow.SetModified() 等“恢复”了

导致了SqlDataAdapter.Update()的问题。

当然这是合乎逻辑的,因为原来的 DataRowVersion 丢失了。但这并不容易识别。

相关问答

Selenium Web驱动程序和Java。元素在(x,y)点处不可单击。其...
Python-如何使用点“。” 访问字典成员?
Java 字符串是不可变的。到底是什么意思?
Java中的“ final”关键字如何工作?(我仍然可以修改对象。...
“loop:”在Java代码中。这是什么,为什么要编译?
java.lang.ClassNotFoundException:sun.jdbc.odbc.JdbcOdbc...