Visual Studio Express C# + MySQL Можно ли заставить работать?
У меня все никак не получается... даже MSSQL нормально подключить в GridDataView не получается. Дает только выбор файла. Но это я обошел - заменил connectionString в пропертиз на локалхост и заработало. А MySQL вообще никак, какие только connectionStrings не пробовал. При том, что коннекторы скачал и установил. :( |
так а че грид?
ты провайдера какого используешь? какойто типа TQuery? попродуй через ADO - не знаю есть ли такое в вижуал С |
А для чего нужен DataGridView? Только для отображения или редактирования тоже?
Для отображения должно хватать загрузки данных в DataTable\DataSet, и подстановки его в DataSource. С этой точки зрения разница только в использовании SqlConnection\SqlCommand\SqlDataAdapter либо MySqlConnection\MySqlCommand\MySqlDataAdapter. Что тот, что тот умеет загружать данные в DataTable\DataSet, с которыми уже умеет работать DataGridView. MySqlConnection должен идти вместе с коннектором Вот пару сэмплов: http://forums.mysql.com/read.php?38,115063,115063 http://ycouriel.blogspot.com/2009/10...and-mysql.html |
Цитата:
|
Остался один вопрос по DataGridView:
данный метод прекрасно работает, если в таблице были изменения, если изменений не было, то вылетает эксепшн. private void updateOpsTable() { DataTable changesOps = dataOps.GetChanges(); foreach (DataRow dr in changesOps.Rows) { dr[1] = selectedVoyageIndex; dr[2] = selectedVesselIndex; } daOps.Update(changesOps); dataOps.AcceptChanges(); } как проверить, что изменений не было? я могу, конечно, устанавливать кнопку сэйва в Ивенте CellValueChanged, а до того случая просто держать ее дизэйблд... но как-то это кривовато на мой взгляд... Вариант без ручного апдэйта неплохо работает, но в случае быстрого заполнения выдает периодически "Ошибка параллелизма". В джаве это решалось модификатором Synchronized, в дотнете аналога пока не нашел. пока прикрутил временное решение - сохраняет по CellValueChanged каждое второе изменение private void updateOpsTable() { if (cellChangesCount % 2 == 0) { DataTable changesOps = dataOps.GetChanges(); foreach (DataRow dr in changesOps.Rows) { dr[1] = selectedVoyageIndex; dr[2] = selectedVesselIndex; } daOps.Update(changesOps); dataOps.AcceptChanges(); opsUpdBtn.Enabled = false; } } |
[MethodImplAttribute(MethodImplOptions.Synchronized )]
это почти решило проблему. то есть все нормально сохраняется, но если совсем уж быстро заполнять селлы, то все равно можно наткнуться на "ошибку параллелизации". "почти" решила потому что , когда заполняешь в секунду более пяти ячеек, то таки получаешь ексепшн "нарушение параллелизма". Что удивляет в этой ситуации - во всех книгах по С# говорится, что "было слизано все лучшее с джавы", но как забыли про Synchronized мне не понятно. :( |
Сохранять данные при каждом изменении ячейки немного жестоко :)
Цитата:
|
Цитата:
ночью голова плохо варила. добавил: if (changesOps == null) return; теперь все работает шикарно. |
"Ссылка на объект не указывает на экземпляр объекта."
Да, это обычный NullReferenceException. Он происходит когда идет обращение к обьекту, которого не существует :) |
Цитата:
|
теперь главная проблема, что невозможно программно выделить строку или ячейку в DataGridView. :(
CurrentRow - readonly, а opsDgv.CurrentCell = opsDgv[1,X]; выдает ошибку: "Текущую ячейку нельзя сделать невидимой.". Google говорит, что это баг. Проблема в том, что мне нужно выводить некоторые данные из таблицы в RichTextBox, для этого мне нужно определить индекс текущей строки. Если я вешаю эту операцию на SelectionChanged ивэнт, то попытка узнать текущую строку вызывает эксепшн. Проблема решается только ожиданием ивэнта CellClick, но мне не нравится, что данные не обновляются, если юзер меняет позицию курсора без мыши (клавиатурой) |
Цитата:
Код:
int x = 1; Код:
var y = dataGridView.CurrentCell.ColumnIndex; Код:
var rowIndex = dataGridView.CurrentRow.Index; |
Цитата:
в таблице >100 столбцов, я не собираюсь их все показывать юзеру :) к тому же клиент хочет по некоторым столбцам данные вводились комбобоксами, а при загрузке из MySQL комбобокс нормальным способом получить никак. Поэтому я столбец скрываю и создаю новый с таким же названием, но из комбоксов. проверил, все работает, данные в скрытом столбце дублируются из комбобоксов и таблица апдейтится. я ведь точно так, как ты написал и делал. в общем try {} catch () {return;} сделал дело. эксепшн игнорируется и программа прекрасно работает. по ходу уже с редактором таблиц закончил. в понедельник установлю заказчику и операторы смогут вводить и сохранять данные . |
Цитата:
Выделение ж должно быть визуальным, а она колонка..... Но можно ж выделить боковую колонку. У ячейки можно проверить Visible ли она, и если да, то активировать, либо активировать всю строку целиком. Цитата:
|
Цитата:
if (opsDgv.CurrentRow == null) return; if (opsDgv.CurrentRow.IsNewRow) return; и нет больше эксепшенов. ночью просто голова плохо соображала, :) |
Пост уже удалён, наверно потому что решён, но я бы прокомментировал его часть -
Цитата:
И второй момент - генерация запроса с использованием ToString плоха, так как вообще и этот пример в частности подвержен Sql Injection. Достаточно найти на форме текстовое поле из которого берется cv.charterers, и вписать в него типа 1;DROP SomeTable; SELECT 1 Всё зависит от фильтрации в текстовом поле, энкодирования спец символов при построении запроса, типа переменной charterers, и других вещей. Может данный код ему напрямую и не подвержен, так как не видно остальных частей, но нужно не забывать о том, что такое может быть. |
для начала хотя бы параметризированные запросы на CRUD операции
если уж не менять структуры бд совсем |
Цитата:
|
Цитата:
Но я все равно, сегодня утром, добавление нового рейса сделал по-другому. банально: voyagesDataTable.Rows.Add(cvDataRow); voyagesDataAdapter.Update(voyagesDataTable); предварительно сделав метод private DataRow voyageToDataRow() в классе Voyage. и наоборот, при выборе уже существующего рейса для редактирование, или формирования отчетов, добавил конструктор public Voyage (DataRow dr); так вроде бы правильнее? |
Цитата:
Хотя Typed DataSet-ы уже немного устарели, и есть всякие другие вещи типа LinqToSql\EntityFramework\nHibernate и подобные. Хотя все они делают в принципе тоже самое :) |
Цитата:
тем более, что я класс Voyage все равно не делаю руками, :) а генерирую другой программой. типа: string line; System.IO.StreamReader file; try { file = new System.IO.StreamReader("c:\\voyage_templ.txt"); StreamWriter swd = new StreamWriter("C:\\constrdr.txt"); StreamWriter swv = new StreamWriter("c:\\constrvoid.txt"); StreamWriter swc = new StreamWriter("c:\\todatarow.txt"); while ((line = file.ReadLine()) != null) { counter++; string[] buff = line.Split('\"','+',' ',','); if (buff[2].Equals("int")) { swd.WriteLine("if (row[\"{0}\"].Value == DBNull.Value)", buff[1]); swd.WriteLine("{"); swd.WriteLine(" this.{0} = 0;", buff[1]); swd.WriteLine("}"); swd.WriteLine("else"); swd.WriteLine("{"); swd.WriteLine(" this.{0} = Convert.ToInt32(row[\"{1}\"].Value;", buff[1], buff[1]); swd.WriteLine("}"); swd.WriteLine(); swv.WriteLine("this.{0}=0;", buff[1]); swc.WriteLine ("dr[\"{0}\"]=Convert.ToInt32(this.{1});", buff[1], buff[1]); } и так же для float, string, DateTime и bool. в файл voyage_templ.txt кладется текст квери, который создает таблицу. |
Полезно все-таки читать гуру (Феникса и Юстаса) на форуме. Позавчера мысли об изменениях в структуре таблиц меня вгоняли в уныние. сейчас, когда сделал генератор классов из квери, переделывание таблиц обошлось в 15 минут. :)
|
Да, автоматизация рутинных задах даже в разработке это очень хорошая практика :)
К слову, еще есть такая штука как T4 Templates. Она нативно поддерживается в студии, и в ней же можно их делать. Идея схожая, в них можно писать код, который будет генерировать что-то (другой код\xml\etc) - http://msdn.microsoft.com/en-us/library/bb126445.aspx http://habrahabr.ru/post/64895/ http://andir-notes.blogspot.com/2009...al-studio.html Не уверен, что оно актуально в данном случае, но просто к слову, чтоб вы знали, что есть еще такие вещи :) |
сегодня чуть руки не опустились. вчера ведь сделал все, красиво работало - раз 20 проверил. потом начал писать логику. сегодня вечером закончил, при этом, пока тестировал, сохранял все просто в файл (serialize). когда убедился, что расчеты правильные - добавил сохранение рейса в базу... и шо вы думаете? ОШИБКИ ПАРАЛЛЕЛИЗМА! при этом, что характерно, хоть кол на голове теши этой программе, хоть комп перегружай, делает апдейты исправно несколько раз, после первой такой ошибки, с таблицей делать ничего невозможно, даже другой программой специально быстро склепаной - типа загрузка таблица в датагрид и попытка изменений. Ошибка параллелизма мертво. помогает только удаление таблицы, но потом все равно некоторое время апдейтит, а потом все по-старому.
после долгих и мучительных экспериментов наткнулся на такой спасительный пост: Some general input to the wretched ConcurrencyViolation problem: I was struggling with the same problem, and the changing Double to Decimal didn't work. But to my huge relief I found that in .NET Framework v.2 the CommandBuilder has a new property "ConflictOption". If you set this to "ConflictOption.OverwriteChanges" then the database will be updated no matter if the DataSet "thinks" the database has been updated in the meantime. не уверен, что это - правильный выход, но бурю пережить может и поможет. |
засвети эксепшн который тебе выкидывают
|
System.Data.DBConcurrencyException: Нарушение параллелизма: UpdateCommand затронула 0 из ожидаемых 1 записей.
Почесав затылок, юзер дописал через 6 минут Цитата:
Почесав затылок, юзер дописал через 16 минут хммм, почему-то если после апдэйта вместо voyageDataTable.AcceptChanges, сделать voyageDataTable = new DataTable(); voyageDataAdapter.Fill(voyageDataTable); то параллелизма нет - отакэ. |
Насчет ConcurrencyException-ов. Типичный случай для воспроизведения -
Есть база, и есть клиентская программа, которая её изменяет. Эту программу запускают на двух компах, и на каждом из них открывают какие-то общие данные. На первом компе пользователь сохраняет данные, и они сохраняются. При попытке сохранить на втором компе - он свалится с таким exception-ом, так как данные уже другие, чем он загрузил, и поэтому он не смог их обновить, и он валится с ConcurrencyException. DataAdapter и DataSet-ы определяют были ли изменения на уровне UPDATE запросов. К примеру есть таблица ID,ColumnA,ColumnB, и у нас есть строка где ID=5,ColumnA=DataA, ColumnB=DataB Если мы изменим данные, то DataApapter сгенерит такой запрос - Код:
UPDATE SomeTable Почесав затылок, юзер дописал через 1 минуту Цитата:
|
[quote=PhoeniXX;854921]Насчет ConcurrencyException-ов. Типичный случай для воспроизведения -
Есть база, и есть клиентская программа, которая её изменяет. Эту программу запускают на двух компах, и на каждом из них открывают какие-то общие данные. это я понимаю, это нормально, базы редактируются довольно редко, база судов - вообще трогаться почти не будет. рейсы создаются максимум 3 в месяц. и только оперативная информация - несколько строк в день. но я-то запускаю программу в одном потоке на одном компе. :) я подозреваю, что у меня вот этот случай: If the database record contains a floating point value (even if that floating point value is not being changed) then this exception can be generated due to a rounding error. For example the value 5.6 cannot be stored without rounding the database (or in memory either, but will be represented by the approximation 5.599999...) To complicate matters slight hardware differences between the implementation of floating point calculations on CPUs can mean that for identical data this error may be thrown on one system but not on another - which means that this error can arise in production and yet even with identical data cannot be reproduced in test - it has happened to me. для клиентской программы 5.9999999999 == 6, а для sql server'а нет. я пишу в таблицу 0,0157 дней, а назад с сервера считываю 0,015699999. я уже понемногу подумываю, чтобы хранить все числа с плавающей точкой в текстовом виде. последняя надежда - попробую округлить все переменные до 5-ти знаков после запятой. |
только что в другом модуле, там у меня датагрид, ввожу 12345,7777 значение ячейки устанавливается 12345,778 и все последующие попытки сделать апдейт приводят к ошибке параллелизма!
блин. я могу конечно сделать все десималы чарами, но это сильно снизит возможности программы по выборкам. :( я в печали |
запили еще раз пож-ста полностью код который добавляет/редактирует данные в какой либо таблице, где эти эксепшены вылазят
+ структуру таблицы + какой у тебя движок таблиц мускула isam или innodb? |
Время на сервере: 05:18. |
vBulletin 3, Copyright © 2000-2024, Jelsoft Enterprises Ltd.
Русский перевод: zCarot, Vovan & Co