Версия для печати темы
Нажмите сюда для просмотра этой темы в оригинальном формате
Форум программистов > Общие вопросы по .NET и C# > Глупый вопрос по работе с БД (DataGridView)


Автор: brother79 4.10.2010, 09:29
Здравствуйте. 

На текущем этапе нужен простой вар-нт редактирования таблицы. Я использую DataGridView

Нашёл где-то такой код:

Код

        private void dataGridView1_CellEndEdit(object sender, DataGridViewCellEventArgs e)
        {
            try
            {
                this.Validate();
                this.algorithmBindingSource.EndEdit();
                this.algorithmTableAdapter.Update(this.diagramDataSet.algorithm);
                //MessageBox.Show("Update successful");
            }
            catch (System.Exception ex)
            {
                MessageBox.Show("Update failed");
            }
        }



Принципе работает, с некоторыми неточностями. Когда сохраняется последняя строка таблицы, которая новая - то при первом сохранении - сохраняется нормально, автоматически расчитывается id как автоинкремент, но в самой таблице в компоненте - id никак не обновляется и при повторном сохранении этой строки - срабатывает исключение.

Как правильно сделать это простое сохранение результатов?

Автор: brother79 4.10.2010, 14:02
Что-то порылся порылся очень даже не глупый вопрос получается :( Ghtдлагают делать через хранимую процедуру своё добавление с возвратом параметра. А других вар-ов нету?

Автор: jonie 4.10.2010, 18:43
без хранимки можно, просто используя два sql statement для выполнения. Подробнее: http://msdn.microsoft.com/en-us/library/ks9f57t0.aspx

Автор: brother79 5.10.2010, 06:19
Почитал, можно select добавить после insert только в этом дураском TableAdapter не могу найти куда свой запрос на добавление засунуть. И вообзе компоненту sqlDataAdapter не вижу, которая в доке описана.

Автор: jonie 5.10.2010, 11:17
В общем я тут поразмыслил и сделал следующую штуку.
1) я унаследовался от TableAdapter-а, который использовал назвав класс TblTableAdapter2, чтобы можно было override-днуть методы
Код

public override int Update(global::System.Data.DataRow[] dataRows)
и
public override int Insert(string p1)


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

2) я сделал метод у адаптера в DataSet-е который получает последний вставленный Id-шник по sql запросу select @@IDENTITY (см. примечание2)

3) в перегруженном методе Update у себя я произвожу обновления по одной строке ,статус которой равен Added, после чего руками меняю её Id шник и снова сбрасываю ее состояние на Unchanged вызывая AccepChanges().

4) а да, в коде сгененым дизайнером я подменил название класса Адаптера на мой унаследованный руками (в дальнейшем визуальный редактор не будет это ломать).

Пример в аттачменте...


Примечания:
2) В примере я использовал SQLCe в котором обычно нет конкуренции при вставках данных. Однако, для MSSQLя не уверен что базовый Update у адаптера не производит соединение\отсоединение Connection от источника данных, это надо проверить, если не производит тогда хорошо - у нас есть сессия, в рамках которой можно использовать SCOPE_IDENTITY(). . это надо проверить например тем же профилировщиком для MSSQL....

Да, наверно можно открыть пееред base.Update-тами соединение, и использовать метод Insert() , т.к. он не закрывает-открывает соединение, если оно уже открыто:
Код

        [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
        [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Data.Design.TypedDataSetGenerator", "4.0.0.0")]
        [global::System.ComponentModel.Design.HelpKeywordAttribute("vs.data.TableAdapter")]
        [global::System.ComponentModel.DataObjectMethodAttribute(global::System.ComponentModel.DataObjectMethodType.Insert, true)]
        public virtual int Insert(string p1) {
            if ((p1 == null)) {
                this.Adapter.InsertCommand.Parameters[0].Value = global::System.DBNull.Value;
            }
            else {
                this.Adapter.InsertCommand.Parameters[0].Value = ((string)(p1));
            }
            global::System.Data.ConnectionState previousConnectionState = this.Adapter.InsertCommand.Connection.State;
            if (((this.Adapter.InsertCommand.Connection.State & global::System.Data.ConnectionState.Open) 
                        != global::System.Data.ConnectionState.Open)) {
                this.Adapter.InsertCommand.Connection.Open();
            }
            try {
                int returnValue = this.Adapter.InsertCommand.ExecuteNonQuery();
                return returnValue;
            }
            finally {
                if ((previousConnectionState == global::System.Data.ConnectionState.Closed)) {
                    this.Adapter.InsertCommand.Connection.Close();
                }
            }
        }

Автор: umlprog 7.10.2010, 09:33
Цитата(jonie @ 5.10.2010,  11:17)
В общем я тут поразмыслил и сделал следующую штуку.
1) я унаследовался от TableAdapter-а, который использовал назвав класс TblTableAdapter2, чтобы можно было override-днуть методы
Код

public override int Update(global::System.Data.DataRow[] dataRows)
и
public override int Insert(string p1)


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

2) я сделал метод у адаптера в DataSet-е который получает последний вставленный Id-шник по sql запросу select @@IDENTITY (см. примечание2)

3) в перегруженном методе Update у себя я произвожу обновления по одной строке ,статус которой равен Added, после чего руками меняю её Id шник и снова сбрасываю ее состояние на Unchanged вызывая AccepChanges().

4) а да, в коде сгененым дизайнером я подменил название класса Адаптера на мой унаследованный руками (в дальнейшем визуальный редактор не будет это ломать).


А просто перезаполнить свой грид после апдейта не пробовали?  smile 

Автор: jonie 7.10.2010, 09:51
umlprog, это не нормальный подход, "школьный" ....

Автор: brother79 12.10.2010, 11:46
Что-то я запарился уже с этими таблицами.
С наследованием - что-то не разобрался пока, я делаю на wpf  -  там немного отличается похоже. а так просто - сделал запрос в датасете чтобы последнюю добавленную дёргать как в примере - но он не дёргает никак. Я уже сделал запрос на добавление отдельный, подряд сначала добавление вызываю, потом хочу последний дёрнуть - он пустоту возвращает и всё.

Автор: brother79 12.10.2010, 13:08
Дошёл до такого кода:

Код

   public override int Update(diagramDataSet.section1DataTable dataTable)
        {
            int rv = 0;

            System.Data.DataTable t = dataTable.GetChanges();
            if (t != null)
            {
                foreach (WpfApplication1.diagramDataSet.section1Row addedRow in t.Rows)
                {
                    if (addedRow.id < 0)
                    {
                        rv += base.Update(addedRow);
                        //refresh our Row ...
                        try
                        {
                            t.Columns[2].ReadOnly = false;
                            diagramDataSet.section1DataTable tt = this.GetDataByLast();
                            if (tt.Rows.Count > 0)
                            {
                                WpfApplication1.diagramDataSet.section1Row r = tt.Rows[0] as WpfApplication1.diagramDataSet.section1Row;
                                long lastId = r.id;
                                addedRow.id = lastId;
                                addedRow.AcceptChanges();
                            }
                        }
                        finally
                        {
                            t.Columns[2].ReadOnly = true;
                        }
                    }
                }
                dataTable.Merge(t);
            }
            rv += base.Update(dataTable);
            return rv;
        }


1) не могу получить никак последний id, запрос пустой получается
2) Когда делаю мерге - у меня добавляется строка, вместо того, чтобы поменять id, т.е. не правильный подход

Автор: brother79 12.10.2010, 14:00
Сделал так:

Код


        public override int Update(diagramDataSet.section1DataTable dataTable)
        {
            int rv = 0;

            System.Data.DataTable t = dataTable.GetChanges();
            if (t != null)
            {
                foreach (WpfApplication1.diagramDataSet.section1Row addedRow in t.Rows)
                {
                    if (addedRow.RowState == System.Data.DataRowState.Added)
                    {
                        int colIndex = dataTable.Columns.IndexOf("id");
                        rv += base.Update(addedRow);
                        //refresh our Row ...
                        try
                        {
                            WpfApplication1.diagramDataSet.section1Row r = dataTable.Rows.Find(addedRow.id) as WpfApplication1.diagramDataSet.section1Row;
                            dataTable.Columns[colIndex].ReadOnly = false;
                            r.id = System.Convert.ToInt64(this.MaxId());
                            addedRow.AcceptChanges();
                        }
                        finally
                        {
                            dataTable.Columns[colIndex].ReadOnly = true;
                        }
                    }
                }
                //dataTable.Merge(t);
            }
            rv += base.Update(dataTable);
            return rv;
        }



Теоретически работает, только не нравится костыль с вычислением добавленного id, который просто получается как max(id). Так я это и не смог победить

Автор: brother79 13.10.2010, 10:48
Если я руками добавляю эл-нт, типа: 

Код


                diagramDataSet.section1Row r = this.diagramDataSet.section1.NewRow() as diagramDataSet.section1Row;
                r.name = nameTextBox.Text.ToString();
                r.description = descriptionTextBox.Text.ToString();
                this.diagramDataSet.section1.Rows.Add( r );
// Вот до сюда - всё нормально, дальше надо в гриде перевести строку на новую запись, как это сделать?

                Int64 id = r.id;

                int i = diagramDataSet.section1.Rows.IndexOf( r );

// т.е. надо как-то посчитать i чтобы потом сделать:

                section1ViewSource.View.MoveCurrentToPosition(i);

// Сейчас i встаёт на последнюю строку, т.к. в DataGrid - таблица может быть сортированна, нужно перемещаться не на последнюю, а на добавленную, которая встаёт где-то в середине.



Как вычислить позицию для System.Windows.Data.CollectionViewSource ?

Автор: brother79 13.10.2010, 11:56
Sory, поторопился с выводами

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