Adapter.Update(DataTable dt) не обновляет все записи

205
04 апреля 2019, 03:40

Данные из таблицы базы данных отображаются в treeList1(DevExpress) и дублируются в dataGridView.
Пользователь изменяет данные в treeList1 (изменения происходят в DataTable dt и dataGridView1).

Для обновления данных в таблице базы данных используем выражение: adapter.Update(dt);

Вопрос.
Почему не обновляются все записи в таблице базы данных(см. Картинку)?

   //
using DevExpress.XtraTreeList;
using DevExpress.XtraTreeList.Nodes;
namespace rsh
{
    public partial class Form1 : Form
    {
        DataTable dt;        
        OleDbDataAdapter adapter;
        OleDbCommandBuilder AccessCommandBuilder;

        public Form1()
        {
            InitializeComponent();
        }
        private void Form1_Load(object sender, EventArgs e)
        {
            connect();
            // 
            treeList1.ForceInitialize();
            UpdateNodesPositions(treeList1.Nodes);
            treeList1.ExpandAll();
        }
        #region *** DB *** 
        public void connect()
        {
            string catBD = @"c:\test\visualStudio\csharp\01\01.accdb";
            string conBD = string.Format("Provider=Microsoft.ACE.OLEDB.12.0;Data Source={0}", catBD);
            OleDbConnection connection = new OleDbConnection(conBD);
            connection.Open();
            string query1 = "SELECT * FROM TableTreeView_12";
            OleDbCommand cmd1 = new OleDbCommand(query1, connection);
            dt = new DataTable();
            adapter = new OleDbDataAdapter(cmd1);
            AccessCommandBuilder = new OleDbCommandBuilder(adapter);
            adapter.Fill(dt);

            treeList1.KeyFieldName = "ID";
            treeList1.ParentFieldName = "PrID";
            treeList1.DataSource = dt;
        }
        public void Save()
        {
            adapter.Update(dt);           
        }
        #endregion *** DB *** 
        private void treeList1_AfterDragNode(object sender, DevExpress.XtraTreeList.AfterDragNodeEventArgs e)
        {
            SaveNewRecordPosition(e);
        }
        private void SaveNewRecordPosition(NodeEventArgs e)
        {
            var nodes = e.Node.ParentNode == null
                        ? e.Node.TreeList.Nodes
                        : e.Node.ParentNode.Nodes;
            richTextBox1.Clear();
            for (var i = 0; i < nodes.Count; i++)
            {
                nodes[i].SetValue(0, i);

                string id = nodes[i].GetValue(0).ToString();
                string s = nodes[i].GetValue(1).ToString();
                richTextBox1.Text += id + " -//- " + s + "\r\n";
            }
            dataGridView1.DataSource = dt;
            Save();
        }
        private void UpdateNodesPositions(TreeListNodes nodes)
        {
            var ns = new List<TreeListNode>();
            foreach (TreeListNode n in nodes)
            {
                ns.Add(n);
            }
            foreach (TreeListNode n in ns)
            {
                UpdateNodesPositions(n.Nodes);
                n.TreeList.SetNodeIndex(n, Convert.ToInt32(n.GetValue("sorting")));
            }

        }

Скрин с ошибкой - см. комментарий (сюда ссылку не получилось вставить)

Обновление_1
Изменил метод

   public void Save()
    {
                string s = adapter.UpdateCommand.CommandText;
                adapter.Update(dt);           
    }

Получаю ошибку: System.NullReferenceException: "Ссылка на объект не указывает на экземпляр объекта." - System.Data.OleDb.OleDbDataAdapter.UpdateCommand.get вернул null.

Обновление_2
Изменил метод Save()

public void Save()
        {
            //adapter.Update(dt);
            adapter.UpdateCommand = cb.GetUpdateCommand();
            string s = adapter.UpdateCommand.CommandText;
        }

В string s получаю:

UPDATE TableTreeView_12   
SET PrID = ?, sorting = ?, NodeName = ?   
WHERE ((ID = ?) AND ((? = 1 AND PrID IS NULL) OR (PrID = ?)) AND ((? = 1 AND sorting IS NULL) OR (sorting = ?)) AND ((? = 1 AND NodeName IS NULL) OR (NodeName = ?)))
Answer 1

В ходе обсуждения в комментариях/чате, ответ был найден.

При создании адаптера его свойства UpdateCommand, InsertCommand, DeleteCommand равны null.

Нужно задать их либо вручную:

adapter.UpdateCommand = new OleDbCommand("UPDATE ...");

либо сгенерировать автоматически при помощи OleDbCommandBuilder. Это делается вызовом метода GetUpdateCommand:

adapter.UpdateCommand = cb.GetUpdateCommand();

Более того, достаточно просто вызвать

cb.GetUpdateCommand();

Команда будет присвоена тому адаптеру, который был передан в конструктор билдера.

Важно! В документации базового класса DbCommandBuilder.GetUpdateCommand сказано:

The SQL statements are first generated either when the application calls Update or GetUpdateCommand.

То есть необязательно вызывать GetUpdateCommand - он будет вызван автоматически при первом вызове Update.

Однако, в классе потомке OleDbCommandBuilder.GetUpdateCommand текст немного изменен:

The SQL statements are first generated when the application calls either UpdateCommand or GetUpdateCommand.

Судя по всему, вызова Update недостаточно.

Полезная ссылка: Обновление источников данных с объектами DataAdapter.

READ ALSO
Выбор значений С По из запроса SQLITE

Выбор значений С По из запроса SQLITE

К примеру у меня есть запрос:

126
Запись в масив масивов

Запись в масив масивов

Есть массив массивов, создан таким образом

113
Удаление записи из бд

Удаление записи из бд

У меня есть Windows форма

152
Visual Studio. Не работает консруктор

Visual Studio. Не работает консруктор

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

150