首页 > 解决方案 > 无法将参数值从 Binary 转换为 Byte[]。-- 带有 SQL 时间戳参数的 SqlDataSource

问题描述

首先,不幸的是我无法更改数据库并寻找“时间紧迫”的解决方案。我意识到我要求的不是最佳实践,而是足够的免责声明......

  1. 微软 SQL 服务器
  2. C#/.NET 4.xx
  3. 网络表单
  4. dbo.MyTable -- 不允许应用直接访问表
  5. 系列 dbo.MyTable_[OP] CRUD 存储过程(_GET、_INSERT、_UPDATE 等)
  6. MyTable 有一个名为“ts”的时间戳列

在适当的情况下,CRUD 过程都包含@ts 的输入/输出参数以避免并发问题。

我正在使用 DevExpress WebForms GridView - 完美运行,不是问题。

GridView 正在使用 MS SqlDataSource。它的选择命令正在调用 MyTable_List 过程。它的插入命令调用 MyTable_Insert proc。这两项工作都完美无缺。

更新不是。一直在上网,试图弄清楚这是否可能。所以更新基本上是这样的:

SQL:

CREATE PROC MyTable_Update
  @key int
  @name varchar(100)
  @ts timestamp output
AS
  IF (SELECT TOP 1 1 FROM MyTable WHERE key = @key and ts = @ts) IS NULL 
BEGIN
   RAISEERROR('someone else changed this, reload, try again, 00, 00);
   RETURN;
END
--[simple update the table logic]
SELECT @ts = ts FROM MyTable WHERE key = @key

数据源:

<asp:SqlDataSource id="ds" runat="server" ... OnUpdating="ds_Updating" UpdateCommand="MyTable_UPDATE" UpdateCommandType="StoredProcedure">
  <UpdateParameters>
    <asp:Parameter Name="key" Type="Int32" />
    <asp:Parameter Name="name" Type="String" />
    <asp:Parameter Direction="InputOutput" Name="ts" Type="String" DefaultValue="0" />  <!-- i know, bear with me -->
   </UpdateParameters>
 </asp:SqlDataSource>

C#:

protected void myGrid_StartRowEditing(object sender, [DevEx].ASPxStartRowEditingEventArgs e)
{  
  //get the timestamp value from the db for this row being edited
  int key = (Int32)myGrid.GetRowValuesByKeyValue(e.EditingKeyValue, "key");
  var ts = db.MyTable_Get(key).First().ts; //actually getting the ts from the database
  Session["MyTable_ts"] = ts;
}

protected void ds_Updating(object sender, SqlDataSourceCommandEventArgs e)
{ 
  //override what was set in the aspx
  var p = e.Command.Parameters["@ts"];
  p.DbType = Binary;
  p.Direction = ParameterDirection.InputOutput;
  p.Size = 8;
  var ts = (System.Data.Linq.Binary)Session["MyTable_ts"];
  p.Value = ts;
}

最后,当我开始对网格中的一行进行编辑时,StartRowEditing 会触发,将数据库中的时间戳值按预期保存到会话变量中(显然 .NET 中的格式与 SQL 不同)。当我尝试提交更改时(单击 DevEx 网格编辑器上的“更新”),ts_Updating 触发,所有代码都完成,没有异常。然后当 SqlDataSource 触发实际更新时,它抛出“无法从一个二进制到一个字节[]。”到 DevEx 网格并通过网格的 UI 报告。

我怎样才能(甚至可能吗?)将 db 时间戳值洗牌到会话中,然后通过 SqlDataSource 更新参数发送它?

再一次,我意识到我可以通过写出所有 CSLA 甚至只使用 ObjectDataSource 并写出所有更新逻辑来克服这个问题,但是我需要时间来完成一些我只需要完成并继续前进的网格——项目中的大鱼要炸。

谢谢你!

标签: c#arrayssql-serversqldatasourcesql-timestamp

解决方案


Figured it out -- was stupid simple and I overlooked it. System.Data.Linq.Binary's ToArray() will cast to a Byte[]. Adding .ToArray() to ts on the last line of the function will convert to the appropriate type that the SqlDataSource can communicate back to the DB, allowing the Timestamp value to match, informing the db there isn't a concurrency issue.

protected void ds_Updating(object sender, SqlDataSourceCommandEventArgs e)
{ 
  //override what was set in the aspx
  var p = e.Command.Parameters["@ts"];
  p.DbType = Binary;
  p.Direction = ParameterDirection.InputOutput;
  p.Size = 8;
  var ts = (System.Data.Linq.Binary)Session["MyTable_ts"];
  p.Value = ts.ToArray();  //Binary must be cast to an Array (of Byte)
}

推荐阅读