Форум Херсона. Форум Херсонской молодежи.

Форум Херсона. Форум Херсонской молодежи. (http://forum.norma4.net.ua/)
-   Программирование (http://forum.norma4.net.ua/programmirovanie/)
-   -   Visual Studio Express C# + MySQL (http://forum.norma4.net.ua/programmirovanie/48768-visual-studio-express-c-mysql.html)

wouldnt_even 12.05.2012 00:02

Visual Studio Express C# + MySQL
 

Можно ли заставить работать?

У меня все никак не получается... даже MSSQL нормально подключить в GridDataView не получается. Дает только выбор файла. Но это я обошел - заменил connectionString в пропертиз на локалхост и заработало.

А MySQL вообще никак, какие только connectionStrings не пробовал. При том, что коннекторы скачал и установил. :(

Робот Вертер 12.05.2012 13:13

так а че грид?

ты провайдера какого используешь?

какойто типа TQuery?

попродуй через ADO - не знаю есть ли такое в вижуал С

PhoeniXX 12.05.2012 13:47

А для чего нужен 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

wouldnt_even 13.05.2012 01:42

Цитата:

Сообщение от PhoeniXX (Сообщение 850647)
С этой точки зрения разница только в использовании SqlConnection\SqlCommand\SqlDataAdapter либо MySqlConnection\MySqlCommand\MySqlDataAdapter. Что тот, что тот умеет загружать данные в DataTable\DataSet, с которыми уже умеет работать DataGridView. MySqlConnection должен идти вместе с коннектором

спасибо большое! все работает. просто форм дизайнером пользоваться нельзя, ну и Аллах с ним.

wouldnt_even 18.05.2012 01:08

Остался один вопрос по 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;
}
}

wouldnt_even 18.05.2012 02:14

[MethodImplAttribute(MethodImplOptions.Synchronized )]

это почти решило проблему. то есть все нормально сохраняется, но если совсем уж быстро заполнять селлы, то все равно можно наткнуться на "ошибку параллелизации".

"почти" решила потому что , когда заполняешь в секунду более пяти ячеек, то таки получаешь ексепшн "нарушение параллелизма".

Что удивляет в этой ситуации - во всех книгах по С# говорится, что "было слизано все лучшее с джавы", но как забыли про Synchronized мне не понятно. :(

PhoeniXX 18.05.2012 09:01

Сохранять данные при каждом изменении ячейки немного жестоко :)

Цитата:

Сообщение от wouldnt_even (Сообщение 852481)
Остался один вопрос по DataGridView:
данный метод прекрасно работает, если в таблице были изменения, если изменений не было, то вылетает эксепшн.

А когда вызывается updateOpsTable в первом варианте? И какой exception вылетает?

wouldnt_even 18.05.2012 09:32

Цитата:

Сообщение от PhoeniXX (Сообщение 852526)
А когда вызывается updateOpsTable в первом варианте? И какой exception вылетает?

"Ссылка на объект не указывает на экземпляр объекта."

ночью голова плохо варила. добавил:

if (changesOps == null) return;

теперь все работает шикарно.

PhoeniXX 18.05.2012 09:37

"Ссылка на объект не указывает на экземпляр объекта."

Да, это обычный NullReferenceException. Он происходит когда идет обращение к обьекту, которого не существует :)

wouldnt_even 18.05.2012 20:27

Цитата:

Сообщение от PhoeniXX (Сообщение 852541)
"Ссылка на объект не указывает на экземпляр объекта."

Да, это обычный NullReferenceException. Он происходит когда идет обращение к обьекту, которого не существует :)

:) это понятно, потому и спросил: "как проверить, что изменений не было?". оказалось, что проверка объекта на нулл и есть подтверждение, что изменений не было.

wouldnt_even 19.05.2012 01:09

теперь главная проблема, что невозможно программно выделить строку или ячейку в DataGridView. :(

CurrentRow - readonly, а opsDgv.CurrentCell = opsDgv[1,X]; выдает ошибку: "Текущую ячейку нельзя сделать невидимой.". Google говорит, что это баг.

Проблема в том, что мне нужно выводить некоторые данные из таблицы в RichTextBox, для этого мне нужно определить индекс текущей строки.

Если я вешаю эту операцию на SelectionChanged ивэнт, то попытка узнать текущую строку вызывает эксепшн. Проблема решается только ожиданием ивэнта CellClick, но мне не нравится, что данные не обновляются, если юзер меняет позицию курсора без мыши (клавиатурой)

PhoeniXX 19.05.2012 12:18

Цитата:

Сообщение от wouldnt_even (Сообщение 852755)
теперь главная проблема, что невозможно программно выделить строку или ячейку в DataGridView. :(

CurrentRow - readonly, а opsDgv.CurrentCell = opsDgv[1,X]; выдает ошибку: "Текущую ячейку нельзя сделать невидимой.". Google говорит, что это баг.

Проблема в том, что мне нужно выводить некоторые данные из таблицы в RichTextBox, для этого мне нужно определить индекс текущей строки.

Если я вешаю эту операцию на SelectionChanged ивэнт, то попытка узнать текущую строку вызывает эксепшн. Проблема решается только ожиданием ивэнта CellClick, но мне не нравится, что данные не обновляются, если юзер меняет позицию курсора без мыши (клавиатурой)

Сделал для теста пустое приложение с dataGridView. Выделить нужную ячейку по индексу можно так:
Код:

int x = 1;
int y = 1;
dataGridView.CurrentCell = dataGridView.Rows[x].Cells[y];

Получить индекс текущей ячейки можно так:

Код:

var y = dataGridView.CurrentCell.ColumnIndex;
var x = dataGridView.CurrentCell.RowIndex;

Получить индекс текущей строки можно так:
Код:

var rowIndex = dataGridView.CurrentRow.Index;
Все способы рабочие, проверил сам. Проверил в .Net 3.5\4.0

wouldnt_even 19.05.2012 13:07

Цитата:

Сообщение от PhoeniXX (Сообщение 852826)
Сделал для теста пустое приложение с dataGridView. Выделить нужную ячейку по индексу можно так:
Код:

int x = 1;
int y = 1;
dataGridView.CurrentCell = dataGridView.Rows[x].Cells[y];

Получить индекс текущей ячейки можно так:

Код:

var y = dataGridView.CurrentCell.ColumnIndex;
var x = dataGridView.CurrentCell.RowIndex;

Получить индекс текущей строки можно так:
Код:

var rowIndex = dataGridView.CurrentRow.Index;
Все способы рабочие, проверил сам. Проверил в .Net 3.5\4.0

а теперь сделай хотя бы один столбец Visible=false.

в таблице >100 столбцов, я не собираюсь их все показывать юзеру :) к тому же клиент хочет по некоторым столбцам данные вводились комбобоксами, а при загрузке из MySQL комбобокс нормальным способом получить никак. Поэтому я столбец скрываю и создаю новый с таким же названием, но из комбоксов. проверил, все работает, данные в скрытом столбце дублируются из комбобоксов и таблица апдейтится.

я ведь точно так, как ты написал и делал. в общем try {} catch () {return;} сделал дело. эксепшн игнорируется и программа прекрасно работает.

по ходу уже с редактором таблиц закончил. в понедельник установлю заказчику и операторы смогут вводить и сохранять данные .

PhoeniXX 19.05.2012 13:14

Цитата:

Сообщение от wouldnt_even (Сообщение 852840)
а теперь сделай хотя бы один столбец Visible=false.

в таблице >100 столбцов, я не собираюсь их все показывать юзеру :) к тому же клиент хочет по некоторым столбцам данные вводились комбобоксами, а при загрузке из MySQL комбобокс нормальным способом получить никак. Поэтому я столбец скрываю и создаю новый с таким же названием, но из комбоксов. проверил, все работает, данные в скрытом столбце дублируются из комбобоксов и таблица апдейтится.

Ну да, это ж логично. Как можно выделить CurrentCell для скрытой колонки? Он не может её выделить, и поэтому и валиться с InvalidOperationException - Current cell cannot be set to an invisible cell.

Выделение ж должно быть визуальным, а она колонка.....
Но можно ж выделить боковую колонку. У ячейки можно проверить Visible ли она, и если да, то активировать, либо активировать всю строку целиком.


Цитата:

Сообщение от wouldnt_even (Сообщение 852840)
я ведь точно так, как ты написал и делал. в общем try {} catch () {return;} сделал дело. эксепшн игнорируется и программа прекрасно работает.
.

Не сочтите за критику, но это не всегда хороший подход. Механизм exception-ов довольно медленный в .Net-е, и если их происходит много, это очень негативно скажется на быстродействии этой функциональности.

wouldnt_even 19.05.2012 14:52

Цитата:

Сообщение от PhoeniXX (Сообщение 852841)
Ну да, это ж логично. Как можно выделить CurrentCell для скрытой колонки?

я же не идиот, я пытался выбрать ячейку в видимом столбце и по имени и по индексу. :) да и не важно уже,

if (opsDgv.CurrentRow == null) return;
if (opsDgv.CurrentRow.IsNewRow) return;

и нет больше эксепшенов. ночью просто голова плохо соображала, :)

PhoeniXX 23.05.2012 11:34

Пост уже удалён, наверно потому что решён, но я бы прокомментировал его часть -

Цитата:

string query = "INSERT INTO voyages (" +
"voy_id,vessels_id,voy_number,charterers,"+
"cargo_type,loadport1,loadport2,loadport3,"+
"dport1,dport2,dport3,strait1,"+
"strait2,strait3,est_lport1da,est_lport2da,"+
.......
"VALUES ( "+


"NULL,"+ //cv.voy_id.ToString() + "," +
vsl.vsl_id.ToString() + "," +
cv.voy_number.ToString() + "," +
cv.charterers.ToString() + "," +
cv.cargo_type.ToString() + "," +
Такие запросы редкость. Обычно нужно пытаться более\менее структурировать в разные таблицы, тогда не будет такого полотна из имен колонок.

И второй момент - генерация запроса с использованием ToString плоха, так как вообще и этот пример в частности подвержен Sql Injection.

Достаточно найти на форме текстовое поле из которого берется cv.charterers, и вписать в него типа
1;DROP SomeTable; SELECT 1

Всё зависит от фильтрации в текстовом поле, энкодирования спец символов при построении запроса, типа переменной charterers, и других вещей. Может данный код ему напрямую и не подвержен, так как не видно остальных частей, но нужно не забывать о том, что такое может быть.

ustas 23.05.2012 13:42

для начала хотя бы параметризированные запросы на CRUD операции
если уж не менять структуры бд совсем

PhoeniXX 23.05.2012 13:46

Цитата:

Сообщение от ustas (Сообщение 854180)
для начала хотя бы параметризированные запросы на CRUD операции
если уж не менять структуры бд совсем

Параметризированные запросы это хорошо, но если их сильно много, то может быть проблемно заменить их везде. Самый простой способ это экондировать стринговые значения на наличие кавычек. Хотя разница по трудозатратам не сильно большая

wouldnt_even 23.05.2012 14:36

Цитата:

Сообщение от PhoeniXX (Сообщение 854132)
Пост уже удалён, наверно потому что решён, но я бы прокомментировал его часть -

та, там была проблема в разных форматах DateTime.

Но я все равно, сегодня утром, добавление нового рейса сделал по-другому.

банально:

voyagesDataTable.Rows.Add(cvDataRow);
voyagesDataAdapter.Update(voyagesDataTable);

предварительно сделав метод private DataRow voyageToDataRow() в классе Voyage.

и наоборот, при выборе уже существующего рейса для редактирование, или формирования отчетов, добавил конструктор public Voyage (DataRow dr);

так вроде бы правильнее?

PhoeniXX 23.05.2012 14:37

Цитата:

Сообщение от wouldnt_even (Сообщение 854203)
та, там была проблема в разных форматах DateTime.

Но я все равно, сегодня утром, добавление нового рейса сделал по-другому.

банально:

voyagesDataTable.Rows.Add(cvDataRow);
voyagesDataAdapter.Update(voyagesDataTable);

предварительно сделав метод private DataRow voyageToDataRow() в классе Voyage.

так вроде бы правильнее?

Да, так более правильнее :)
Хотя Typed DataSet-ы уже немного устарели, и есть всякие другие вещи типа LinqToSql\EntityFramework\nHibernate и подобные.
Хотя все они делают в принципе тоже самое :)

wouldnt_even 23.05.2012 15:53

Цитата:

Сообщение от PhoeniXX (Сообщение 854205)
Да, так более правильнее :)
Хотя Typed DataSet-ы уже немного устарели, и есть всякие другие вещи типа LinqToSql\EntityFramework\nHibernate и подобные.
Хотя все они делают в принципе тоже самое :)

я тоже так хотел, что в пособии по LinqToSQL в самом начале сказали, что работает только с MSSQL , MySql пока не поддерживается.

тем более, что я класс 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 кладется текст квери, который создает таблицу.

wouldnt_even 24.05.2012 10:30

Полезно все-таки читать гуру (Феникса и Юстаса) на форуме. Позавчера мысли об изменениях в структуре таблиц меня вгоняли в уныние. сейчас, когда сделал генератор классов из квери, переделывание таблиц обошлось в 15 минут. :)

PhoeniXX 24.05.2012 10:56

Да, автоматизация рутинных задах даже в разработке это очень хорошая практика :)

К слову, еще есть такая штука как 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
Не уверен, что оно актуально в данном случае, но просто к слову, чтоб вы знали, что есть еще такие вещи :)

wouldnt_even 25.05.2012 00:32

сегодня чуть руки не опустились. вчера ведь сделал все, красиво работало - раз 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.

не уверен, что это - правильный выход, но бурю пережить может и поможет.

ustas 25.05.2012 08:03

засвети эксепшн который тебе выкидывают

wouldnt_even 25.05.2012 09:44

System.Data.DBConcurrencyException: Нарушение параллелизма: UpdateCommand затронула 0 из ожидаемых 1 записей.

Почесав затылок, юзер дописал через 6 минут
Цитата:

Сообщение от wouldnt_even (Сообщение 854884)
System.Data.DBConcurrencyException: Нарушение параллелизма: UpdateCommand затронула 0 из ожидаемых 1 записей.

на я уже близко, заметил, что при замене всех переменных на decimal эксепшн больше никогда не происходит на первом апдейте. если после создания рейса форму принудительно закрывать и заходить в менеджер рейсов снова из основной формы, то один апдэйт гарантирован :) можно и так конечно сдать, но я думаю, что сегодня выясню, что при инициализации окна происходит такого, чего не происходит при попытке повторного апдейта. в крайнем случае сделаю полную реинициализацию всех объектов.

Почесав затылок, юзер дописал через 16 минут
хммм, почему-то если после апдэйта вместо voyageDataTable.AcceptChanges,

сделать

voyageDataTable = new DataTable();
voyageDataAdapter.Fill(voyageDataTable);

то параллелизма нет - отакэ.

PhoeniXX 25.05.2012 11:26

Насчет ConcurrencyException-ов. Типичный случай для воспроизведения -
Есть база, и есть клиентская программа, которая её изменяет. Эту программу запускают на двух компах, и на каждом из них открывают какие-то общие данные. На первом компе пользователь сохраняет данные, и они сохраняются. При попытке сохранить на втором компе - он свалится с таким exception-ом, так как данные уже другие, чем он загрузил, и поэтому он не смог их обновить, и он валится с ConcurrencyException.

DataAdapter и DataSet-ы определяют были ли изменения на уровне UPDATE запросов. К примеру есть таблица ID,ColumnA,ColumnB, и у нас есть строка где ID=5,ColumnA=DataA, ColumnB=DataB
Если мы изменим данные, то DataApapter сгенерит такой запрос -

Код:

UPDATE SomeTable
SET ColumnA=NewDataA, ColumnB=NewDataB
WHERE ID=5 AND ColumnA=DataA AND ColumnB=DataB

Тобишь он в запросе использует для фильтра предыдущие значения. Как вариант, можно просто на уровне дизайнера убрать все другие ограничения кроме ID, тогда он просто будет перезаписывать данные либо использовать ConflictOption.OverwriteChanges

Почесав затылок, юзер дописал через 1 минуту
Цитата:

Сообщение от wouldnt_even (Сообщение 854884)
voyageDataTable = new DataTable();
voyageDataAdapter.Fill(voyageDataTable);

то параллелизма нет - отакэ.

В этом случае просто все данные перезагрузатся из базы заново. Как вариант это хорошо конечно, но если таблица большая, там >1 000 000 записей, то при этом подходе, после изменений нескольких строк, все данные из этой таблицы будут загружатся заново, что будет медленно

wouldnt_even 25.05.2012 12:09

[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-ти знаков после запятой.

wouldnt_even 25.05.2012 13:51

только что в другом модуле, там у меня датагрид, ввожу 12345,7777 значение ячейки устанавливается 12345,778 и все последующие попытки сделать апдейт приводят к ошибке параллелизма!

блин. я могу конечно сделать все десималы чарами, но это сильно снизит возможности программы по выборкам. :( я в печали

ustas 25.05.2012 14:19

запили еще раз пож-ста полностью код который добавляет/редактирует данные в какой либо таблице, где эти эксепшены вылазят
+ структуру таблицы
+ какой у тебя движок таблиц мускула isam или innodb?


Время на сервере: 05:18.

vBulletin 3, Copyright © 2000-2024, Jelsoft Enterprises Ltd.
Русский перевод: zCarot, Vovan & Co