-
Проблема ASP.NET и LINQ
Поставлена тривиальная задача: отобразить список вопросов в виде таблицы с возможностью изменения позиции вопроса. Единственное требование использование GridView + Linq. Итак имеем: таблица со структурой ID (Pimary Key), Text, Position; GridView и LinqDataSource. В GridView создаем поля: BoundField к Position, BoundField к Text и два ButtonField с командами MoveUp и MoveDown. В обработчике OnRowCommand имеем такой код:
...
if (e.CommandName == "MoveUp")
{
int index = Convert.ToInt32(e.CommandArgument);
GridViewRow row = gridView.Rows[index];
byte currentPostion = Convert.ToByte(row.Cells[0].Text);
if (currentPostion > 1)
{
DataContext db = new DataContext();
Question qPrev = (from q in db.Questions where q.Position == (currentPostion-1) select q).FirstOrDefault();
Question qNew = (from q in db.Questions where q.Position == currentPostion select q).FirstOrDefault();
qNew.OrdinalPosition = (byte)(currentPostion - 1);
qPrev.OrdinalPosition = currentPostion;
db.SubmitChanges();
gridView.DataBind();
}
}
...
Для команды MoveDown код аналогичный. Таблица заполнена правильно, т.е. у всех записей позиция отличается на 1, и минимальная позиция равна 1. В Опере и ФФ это все работает отлично, но в ИЕ8 (как в принципе и в ИЕ7) все время получаю ошибки
либо на строке
"Question qPrev = (from q in db.Questions where q.Position == (currentPostion-1) select q).FirstOrDefault();" получаю ошибку, что запись не найдена, либо на строке "db.SubmitChanges();" ошибку "Row not found or changed.". Хотя я уверен, что эти записи есть 100%. Вот и возник вопрос почему в Опере и ФФ это работет безотказно, а в ИЕ не хочет? И как это побороть?
-
Вообще-то сам код обрабатывается на сервере
к браузеру отношение не имеет, можете зайти дебагером и глянуть правильно выполнятся ли код на стороне сервера.
Если проблема отображения в браузерах, то Вам надо смотреть сторону клиента тоесть как делается вывод в браузер - непосредственно хтмл код ...
-
Да, я прекрасно понимаю, что серверный код никак не зависит от браузера клиента. Но вот сложилась такая ситуация, что хтмл код одинаков (серверный естественно тоже) для разных браузеров, а вот в одних оно работает, а в других не хочет.
-
[QUOTE=el_Wild;7393720]...а в других не хочет.[/QUOTE]
в другом
-
Попробуйте пройтись отладчиком по функции пошагово.
В первую очередь в строке:
>int index = Convert.ToInt32(e.CommandArgument);
Убедитесь, что в параметре e.CommandArgument передаются правильные данные.
PS: Мой вам совет - привязывайте CommandArgument не к полю Position, а к PK строки.
У вас изменятся, соответственно, запросы, но такое решение более правильное. Несгласное соглашение о том, что номера позиций вопросов должны отличаться не более чем на 1 очень негибко.
-
А для GridView в свойстве DataKeyNames указано ключевое поле? Типовое решение - это добавление невидимой колонки, привязанной к PK таблицы, и указании ее в качестве ключевой для грида.
Кроме того, зачем для каждой записи рендерить кнопки MoveUp и MoveDown? Не проще ли разместить их рядом с гридом и менять положение выделенной записи (записей)?
-
Спасибо всем за помощь. Итак по порядку.
[QUOTE]Попробуйте пройтись отладчиком по функции пошагово.
В первую очередь в строке:
>int index = Convert.ToInt32(e.CommandArgument);
Убедитесь, что в параметре e.CommandArgument передаются правильные данные.[/QUOTE]
В e.CommandArgument передаются правильные данные. К сожалению отладчиком воспользоваться не могу, возникают ошибки доступа к файлам базы данных (ну это уже особенности моей системы), поэтому приходится пользоваться доступными методами вывода через Response и запись в файл.
[QUOTE] PS: Мой вам совет - привязывайте CommandArgument не к полю Position, а к PK строки.
У вас изменятся, соответственно, запросы, но такое решение более правильное. Несгласное соглашение о том, что номера позиций вопросов должны отличаться не более чем на 1 очень негибко. [/QUOTE]
Я бы не сказал, что это негласное соглашение. Просто создать запись с позицией отличающейся не на 1 от соседних через интерфейс не получится. Если же позиции будут отличаться не на 1, то задача перестановки местами строк усложняется. Но про привязку к РК строки полностью согласен.
[QUOTE]А для GridView в свойстве DataKeyNames указано ключевое поле? Типовое решение - это добавление невидимой колонки, привязанной к PK таблицы, и указании ее в качестве ключевой для грида.
Кроме того, зачем для каждой записи рендерить кнопки MoveUp и MoveDown? Не проще ли разместить их рядом с гридом и менять положение выделенной записи (записей)?[/QUOTE]
Да, для GridView указано ключевое поле. Рендерить кнопки для каждой записи все же проще, чем размещать их рядом с гридом и работать с выделенной записью. Насколько это правильней вопрос личных предпочтений. К тому же в моем случае этот вопрос решаю не я, а заказчик с дизайнером. Так что тут вариантов не оставалось.
В любом случае задача решена. Проблема была в том что при использовании ButtonField в GridView событие RowCommand срабатывает дважды (это вроде как баг стандартного GridView). Решение: использовать TemplateField с кнопками внутри вместо ButtonField.
Измененный код теперь выглядит примерно так:
...
int QuestionID = Convert.ToInt32(e.CommandArgument);
DataContext db = new DataContext();
Question qCurrent = (from q in db.Questions where q.ID == QuestionID select q).FirstOrDefault();
if (e.CommandName == "MoveUp")
{
if ((qCurrent != null) && (qCurrent.Position > 1))
{
Question qPrev = (from q in db.Questions
where q.Position == (qCurrent.Position-1)
select q).FirstOrDefault();
if (qPrev != null)
{
qPrev.Position = qCurrent.Position;
qCurrent.Position--;
try
{
db.SubmitChanges();
}
catch (System.Data.Linq.ChangeConflictException ex)
{
db.SubmitChanges();
}
gridViewQuestions.DataBind();
}
}
}
...
-
Столько времени решение заняло всего лишь из-за невозможности воспользоваться нормально отладчиком и обнаружить двойное событие. Ну и из-за особенностей ИЕ при передаче данных.