Версия для печати темы
Нажмите сюда для просмотра этой темы в оригинальном формате
Форум программистов > Базы данных под .NET > Обновление БД средствами DataAdapter


Автор: kaa 5.1.2006, 23:39
Тут в процессе изучения C# столкнулся с одной проблемой - нигде немогу найти вразумительного описания обновления информации в базе данных средствами DataAdapter. Знаю что в ADO.NET логику обновления надо писать самому. А как писать, что писать, какие св-ва и методы приметь толком нигде (из того что я видел) не говориться. Я бы попросил знающих людей объяснитьsmile или направить в нужную сторонуsmile, а то уже почти неделю на месте топчусь из-за этого обновления smile

Автор: -ser- 6.1.2006, 05:26
ну что ты все заладил со своей логикой обновления. видать не работал с простым АДО и уж тем более без него.
поскольку ты ничего из 700 станиц по АДО.НЕТ не понял, что не удивительно, давай начнем с конкретики, с самых азов. что ты хочешь сделать?
вообщем-то всю необходимую информацию по работе с АДО.НЕТ для себя я нашел на этом форуме.
вот, например, начни отсюда http://forum.vingrad.ru/index.php?showtopic=29461&st=0&#entry213780
но здесь нехватает одной существенной детали.
да, все знают что обновления осуществляются с помощью
Код

dataAdapter.Update( dataSet, tbl );

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

        public void UpdateDataSet( SqlDataAdapter da, DataSet ds, string tbl )
        {
            if ( !ds.HasChanges( DataRowState.Added | DataRowState.Modified ) )
            {
                MessageBox.Show("Hasn't been changed:" + DataRowState.Added + "  " + DataRowState.Modified);
                return;
            }

            DataSet xDataSet;            
            xDataSet = ds.GetChanges( DataRowState.Added | DataRowState.Modified );    // Changes for modified rows only.            
            if( xDataSet.HasErrors )             // Check the DataSet for errors.
                MessageBox.Show( "Has Errors" ); // Resolve errors.
            
            da.Update( xDataSet, tbl );             // After fixing errors, update the data source with da            
        }

з.ы. а вообще, чиловек, я бы даже рекомендовал попробовать использовать Enterprize Library. они там поднялись еще выше всей этой земной суеты. smile у тебя есть шанс быть в первых рядах и стать почетным консультантом по EntLib.

Автор: kaa 6.1.2006, 13:44
Да, с ADO я поработать неуспел, тока с ODBC... За код конечно спасиба smile

А что такое Enterprize Library?

Автор: kaa 6.1.2006, 14:12
Ладна, удачи всем пойду ломать се голову... smile smile

Автор: Exception 6.1.2006, 20:28
Цитата(kaa @ 6.1.2006, 14:44 Найти цитируемый пост)

А что такое Enterprize Library?

http://forum.vingrad.ru/index.php?showtopic=76374
Цитата(-ser- @ 6.1.2006, 06:26 Найти цитируемый пост)

поднялись еще выше всей этой земной суеты

Ну, ИМХО не сложно самому создать свои объекты доступа к данным. Как я всегда и делаю. А они, в свою очередь, работают на типизированном датасете.

Автор: kaa 7.1.2006, 13:32
В общем на меня сегодня в три часа ночи снизошло прозрение и я родил следующий код:

Код

private void Create_Click(object sender, System.EventArgs e)
        {
            ds.Tables["trunk"].Columns["KEY"].AutoIncrement=true;
            ds.Tables["trunk"].Columns["KEY"].AutoIncrementStep=-1;
            ds.Tables["trunk"].Columns["KEY"].AutoIncrementSeed =-1;
            ds.Tables["trunk"].Columns["KEY"].Unique=true;

            DataRow row = ds.Tables["trunk"].NewRow();

            row["NUMMASCH"]="10000";
            row["NUMTRUNK"]="10000";
            row["MARK"]="10000";
            row["SER_NUM"]="10000";
            
            ds.Tables["trunk"].Rows.Add(row);
            //Ищем изменения в таблице
            DataTable dt = new DataTable("Updating");
            DataRow dr;
            dt = ds.Tables["trunk"].GetChanges();
            dr = dt.Rows[0];
            string sNUMMASCH = (string)dr[1];
            MessageBox.Show(sNUMMASCH);
            string sNUMTRUNK = (string)dr[2];
            MessageBox.Show(sNUMTRUNK);
            string sMARK = (string)dr[3];
            MessageBox.Show(sMARK);
            string sSER_NUM = (string)dr[4];
            MessageBox.Show(sSER_NUM);
string strSQL="INSERT INTO trunk(NUMMASCH,NUMTRUNK,MARK,SER_NUM) VALUES('34',"+sNUMTRUNK+","+sNUMTRUNK+","+sNUMTRUNK+");";
            OleDbCommand cs = new OleDbCommand(strSQL,cn);
            
            cs.ExecuteNonQuery();
        }


Вышеприведённый код нужен только для того, чтобы тупо вставить строку и обновить данные в БД - так сказать пробный вариант...

Но тут начинаются траблы - когда я в строковой переменной (в любой) пишу вместо цифр буквы (например
Код

row["NUMTRUNK"]="hhhhh";
) при попытке обновить БД выскакивает трабл в виде исключения неизвестного типа.


Подскажите пожалуйста, почему он так странно реагирует на буквы? Ведь переменные один хрен - строки!

Прошу не обращать внимание на корявость подставляемых значений - прога так сказать пробная...

Автор: -ser- 8.1.2006, 06:27
в 3 часа ночи лучше спать
Код

string strSQL="INSERT INTO trunk(NUMMASCH,NUMTRUNK,MARK,SER_NUM) VALUES('34','"+sNUMTRUNK+"','"+sNUMTRUNK+"','"+sNUMTRUNK+"')";

Автор: kaa 8.1.2006, 13:21
-ser-
Мдя-я-я-я... Вот это я лажанулся smile smile
Усё работат smile

Автор: kaa 15.1.2006, 00:29
Гм, а у меня тут возник чисто академический вопрос - зачем вообще нужно средство обновления баз данных с помощью хранимых процедур, если они и запросами неплохо обновляются?

ЗЫ: Честно говоря незнаю, в тему или нет...

Автор: lovermann 15.1.2006, 00:56
Это уже другой вопрос (см. правила), и хотя мне бы не следовало тебе отвечать в этой теме, всё же:


Выгод много.. вот некоторые из них:
  • Писать SQL прямо в коде - это плохая манера, неудобно это. Лучше хранить запросы в процедурах. Удобно, потому что в код лезть не надо, к примеру, а только переписать процедуру в базе данных. Структура данных в DB ведь может поменяться.
  • В MS SQL Server, например, уложенные процедуры пре-компилируются и запросы оптимализируются.
  • Время работы программы уменьшается, потому что процедура исполняется на сервере и данные не нужно лишний раз гонять туда-сюда (программа - > база данных -> программа).
  • Процедура представляет собой более высокую степень абстракции. Напишешь GetListOfVIPClients("proc_CORE_GetVIPClientsNumberByIncome"); и сразу всё понятно и ясно, нежели писать запрос, который может состоять из 500 строк кода.

Автор: kaa 15.1.2006, 01:11
Спасибо за ответ smile

Автор: Hidrag 29.1.2006, 23:28
-ser- Спасибо за приемер в начале топика!
Немного модифицировав применил к своему случаю:

Код

        private void remBut_Click(object sender, EventArgs e)
        {
            int curr = dataGrid.CurrentRowIndex;
            string message = "Удалить текщую запись? Восстановление будет невозможным!";
            MessageBoxButtons buttons = MessageBoxButtons.YesNo;
            DialogResult result;
            result = MessageBox.Show(this, message, "", buttons, MessageBoxIcon.Question, MessageBoxDefaultButton.Button1, MessageBoxOptions.RightAlign);
            if (result == DialogResult.Yes)
            {

                ds.Tables[0].Rows[curr].Delete();
                ds.AcceptChanges();
            }

        }

        private void okBut_Click(object sender, EventArgs e)
        {
            if (!ds.HasChanges(DataRowState.Added | DataRowState.Modified | DataRowState.Deleted))
            {
                MessageBox.Show("Hasn't been changed:" + DataRowState.Added + "  " + DataRowState.Modified);
                return;
            }

            DataSet xDataSet = new DataSet();
            xDataSet = ds.GetChanges(DataRowState.Added | DataRowState.Modified | DataRowState.Deleted);
            adapter.Update(xDataSet, "client");
        }


...то есть удаляю из таблицы строчку и хочу обновить данные, а они не хотят обнавляться, что не так?

Автор: -ser- 30.1.2006, 09:02
Hidrag
Существует масса более простейших способов удалить строку из таблицы. Например, тот же ExecuteNonQuery()
Код

SqlCommand dataCommand = new SqlCommand();
dataCommand.CommandType = CommandType.Text;
dataCommand.CommandText = "DELETE FROM tbl WHERE CustomerId = '122'";
dataCommand.Connection = conn1;

conn1.Open();
Int32 rowsAffected = dataCommand.ExecuteNonQuery();
conn1.Close(); 


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

Поскольку ты уже предупредил -Восстановление будет невозможным-, так тогда сразу и удаляй, т.е. вместо вызова ds.AcceptChanges(), вызывай метод с содержимым okBut_Click. зачем ты его вынес в отдельную кнопку? а если она не будет нажата?. А у тебя еще получается что вызов ds.AcceptChanges() сбрасывает все флаги изменений, т.е. делает DataRowState проперти равным Unchanged и соответственно ds.HasChanges всегда возвратит false.

Другой немаловажный момент я бы хотел чтобы ты обратил внимание
Код

int curr = dataGrid.CurrentRowIndex;

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

Используй CurrencyManager, для связи содержимого контрола (в нашем случае датагрид) с таблицей в датасете, в противном случае мы рискуем удалить совсем не ту строку.

Код

CurrencyManager cmngr =  CurrencyManager)this.dg1.BindingContext[dg1.DataSource, dg1.DataMember];
DataRow row = ((DataRowView) cmngr.Current).Row;


Вот теперь выбранный row совпадает с соответствующей строкой таблицы в нашем датасете.

Код

int customerID = (int)row[ "CustomerID" ];


Разумеется, после удаления строки необходимо освежить датасет и датагрид соответственно.


Автор: Hidrag 6.2.2006, 20:59
Исправил....

Код

        private void remBut_Click(object sender, EventArgs e)
        {
            string message = "Удалить текщую запись? Восстановление будет невозможным!";
            MessageBoxButtons buttons = MessageBoxButtons.YesNo;
            DialogResult result;
            result = MessageBox.Show(this, message, "Удаление", buttons, MessageBoxIcon.Question, MessageBoxDefaultButton.Button1, MessageBoxOptions.RightAlign);
            if (result == DialogResult.Yes)
            {
                CurrencyManager cmngr = (CurrencyManager)this.dataGrid.BindingContext[dataGrid.DataSource, dataGrid.DataMember];
                DataRow row = ((DataRowView) cmngr.Current).Row;
                int ID = (int)row["ID"];
                cn.Open();
                string s = "DELETE FROM client WHERE ID = '" + ID.ToString() + "'";
                this.Text = s;
                OleDbCommand dC = new OleDbCommand(s,cn);
                int reader = dC.ExecuteNonQuery();
                cn.Close();
            }
        }



но где то все равно ошибка, не удаляет строку....

Ошибка: "Несоответствие типов данных в выражении условия отбора".
А это не может зависить от типа поля (ID) по которому удаляю строку в аксессе (текстовый, счетчик, числовой)?

Автор: -ser- 7.2.2006, 05:48
похоже на то, и вроде все правильно если ID имеет тип int (было бы странным если ID был текстовый).
может в аксессе свои нюансы. попробуй удалить строку с помощью этого же sql-запроса в самом аксессе, что он говорит?

Powered by Invision Power Board (http://www.invisionboard.com)
© Invision Power Services (http://www.invisionpower.com)