Не удалось преобразовать значение параметра из двоичного в байт []. - SqlDataSource с параметром отметки времени SQL - PullRequest
0 голосов
/ 11 января 2019

Во-первых, к сожалению, я не могу изменить базу данных и ищу решение «не по времени». Я понимаю, что то, о чем я прошу, - это не лучшая практика, а достаточно оговорок ...

  1. MS SQL Server
  2. C # / .NET 4.xx
  3. WebForms
  4. dbo.MyTable - приложениям не разрешен прямой доступ к таблицам
  5. серия dbo.MyTable_ [OP] CRUD-хранимых процессов (_GET, _INSERT, _UPDATE и т. Д.)
  6. MyTable имеет столбец Timestamp с именем "ts"

Все процессы CRUD, где это уместно, включают параметр ввода / вывода @ts, чтобы избежать проблем параллелизма.

Я использую DevExpress WebForms GridView - работает отлично, не проблема.

GridView использует MS SqlDataSource. Его команда select вызывает процедуру MyTable_List. Его команда вставки вызывает метод MyTable_Insert. Оба из них работают безупречно.

Обновления нет. Работал в интернете, пытаясь понять, возможно ли это. Итак, обновление в основном таково:

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, сохраняя значение метки времени из БД в сеанс var, как и ожидалось (очевидно, что формат в .NET отличается от SQL). Когда я пытаюсь зафиксировать изменение (нажмите «обновить» в редакторе сетки DevEx »), ts_Updating запускается, весь код завершается без исключений. Затем, когда SqlDataSource запускает фактическое обновление, он выдает« Не удалось преобразовать значение параметра из Binary to Byte []. "в сетку DevEx и сообщает об этом через пользовательский интерфейс сетки.

Как я могу (возможно ли даже?) Перетасовать значение метки времени в базе данных в сеанс, а затем отправить его через параметр обновления SqlDataSource?

Опять же, я понимаю, что могу преодолеть это, выписав все CSLA или даже просто используя ObjectDataSource и выполнив всю логику обновления, но мне не хватает времени для нескольких сеток, которые мне просто нужно сделать и переместить на - большую рыбу в проекте жарить.

СПАСИБО!

1 Ответ

0 голосов
/ 11 января 2019

Разобрался - было глупо просто, и я упустил это из виду. ToArray () класса System.Data.Linq.Binary будет приведен к байту []. Добавление .ToArray () к ts в последней строке функции преобразует в соответствующий тип, который SqlDataSource может передавать обратно в БД, позволяя сопоставить значение Timestamp, информируя db, что проблема параллелизма отсутствует.

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)
}
...