Обновление изменений в связанных таблицах в VB.Net - PullRequest
1 голос
/ 17 февраля 2020

У меня есть две связанные SQL таблицы, обе из которых я открываю с помощью адаптера данных и заполняю в набор данных. Я установил соотношение следующим образом:

DS.Relations.Add("RBT", DS.Tables("Jobs").Columns("ID"), DS.Tables("BillTech").Columns("JobID"), False)
Dim BSBT As New BindingSource
BSBT.DataSource = BS
BSBT.DataMember = "RBT"

Столбец идентификатора в таблице Jobs SQL - это начальное значение идентификатора, увеличенное на 1.

Столбцы из таблицы Jobs отображаются на Форма с обязательным навигатором для перехода с работы на работу. Связанные столбцы из таблицы BillTech отображаются в виде сетки данных в форме «Задания».

Если пользователь добавляет строку в представление данных (т.е. новую строку в таблице BillTech) для существующего задания, я помещаю Идентификатор из выбранного задания в столбце JobID сетки данных в событии DefaultValuesNeeded сетки данных. Все это прекрасно работает.

Проблема заключается в том, что пользователь добавляет новое задание в таблицу заданий, а затем пытается добавить новую строку в представление данных для этого нового задания. Поскольку идентификатор этого нового задания неизвестен (поскольку он не был обновлен до таблицы SQL), я использую адаптер данных для обновления таблицы заданий, а затем извлекаю назначенный идентификатор из обновленной таблицы SQL, используя Функция "GetNewJobID". Затем я пытаюсь вставить это значение в новую строку таблицы данных. См. Приведенный ниже код:

Private Sub DataGridView2_DefaultValuesNeeded(sender As Object, e As DataGridViewRowEventArgs) Handles DataGridView2.DefaultValuesNeeded
    Dim JobID As Integer = 0
    With e.Row
        Dim DR() As DataRow = DS.Tables("Jobs").Select("Name = '" & Replace(Me.JobName.Text, "'", "''") & "'")
        If DR.Length = 1 Then
            JobID = DR(0).Item("ID")
        Else
            Dim Name As String = Me.JobName.Text
            BS.EndEdit()
            DA.InsertCommand = CB.GetInsertCommand
            DA.Update(DS.Tables("Jobs"))
            'Because we have already added this job to the database, we keep a list so we can see if the user wants this job added to QB.
            If NewJobs.Contains(Name) = False Then
                NewJobs.Add(Name)
            End If
            JobID = GetNewJobID(Name)
        End If
        .Cells("JobID").Value = JobID
    End With
End Sub

Я получаю сообщение об ошибке рядом с последней строкой вышеуказанного подпункта ".Cells (" JobID "). Значение = JobID, говорящее о том, что столбец" JobID "не существует Поскольку это происходит только при добавлении строки BillTech в новую строку задания, я предполагаю, что при обновлении таблицы Jobs SQL это каким-то образом разрывает соединение с представлением данных?

Как я могу обновить это правильно? Я посмотрел TableAdapterManager, но, похоже, он работает только с типизированными наборами данных. Поскольку эти SQL таблицы находятся на сервере Windows Server 2003, я не могу вызвать их с помощью мастера «Добавить новый источник данных».

1 Ответ

0 голосов
/ 21 февраля 2020

Я выберу типичного родителя / ребенка или мастера / детали клиентов: заказы. Если вы использовали сервер доступа или sql БД с отношением, определенным в БД, и вы создали новый набор данных, открыли его в конструкторе, щелкнули правой кнопкой мыши поверхность и выбрали «Добавить TableAdapter», поместили SELECT * FROM customers и повторили процесс ( если щелкнуть правой кнопкой мыши ..) для заказов вы получите DataTable и TableAdapter клиентов, DataTable и TableAdapter заказов и DataRelation между двумя связывающими (скажем) orders.customerid с Customers.id

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

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

Перетащите узел Customers из источников данных на новую форму. Появятся: сетевая информация о клиентах, набор данных, клиентская таблица адаптации, источник связи с клиентами и связующий клиент. Удалить навигатор (для наглядности прямо сейчас). Вы заметите, что представление данных о клиентах привязано к источнику связи клиентов, а источник связи связан с таблицей клиентов набора данных

Перетащите Заказы верхнего уровня из окна источников данных в форму. Вы заметите, что отображаются данные о датах заказов, источник заказов, таблица заказов и навигация. Удалить навигатор. Обратите внимание, что, как и прежде ,riddidgridvew привязывается к источнику ordersbindings, а источник ordersbindigsource связывается с Orders в наборе данных. Я думаю, это то, что вы сделали

Удалите все, что появилось, когда вы перетаскивали ордера (dgv / bs / ta для ордеров). Не удаляйте набор данных - он все еще используется связями с именами клиентов *

Теперь go обратно в окно источников данных, и на этот раз перетащите дочерние заказы, которые находятся ниже узла «Клиенты». Появляются те же компоненты (ordersdgv / bs / ta / nav). Удалить навигацию. На этот раз посмотрите на источник данных ordersbindingsource и свойства datamember. Вы заметите, что в отличие от прошлого раза, этот источник связывания заказов привязан не непосредственно к набору данных, а к источнику связи, в частности, к устройству данных, названному в честь того же имени, что и отношение данных в наборе

В этой настройке, когда текущая родительская строка изменяется в customerbindingsource, ordersbindingsource будет видеть только отфильтрованный набор строк заказов - фильтр пропускает только те строки, у которых orders.customerid равен текущему идентификатору в th Customersbindingsource

Note; важно, чтобы данные Orders были в наборе данных. Ничто здесь не может автоматически загружать данные базы данных. Если вы заполняете клиентов, но не заполняете данные заказов, то никакие данные не будут отображаться в заказах, независимо от того, как они связаны.

В упрощенном c подходе используются запросы по умолчанию в таблицах-адаптерах (* 1024). *) и загружает ВСЕ базы данных в набор данных. Это будет работать в демонстрационных целях, но вы действительно не хотите делать это в производственной программе.

Go вернуться к набору данных и изменить запросы по умолчанию в таблицах адаптеров, чтобы они были SELECT * FROM customers WHERE id = @id и соответствовали заказам. Затем добавьте ДРУГОЙ запрос к ТА клиента (щелкните его правой кнопкой мыши и выберите добавить запрос):

SELECT * FROM customers WHERE lastname = @lastname

Назовите этот запрос FillByLastName (мастер попросит вас назвать его и предложить FillBy. Не принимать значение по умолчанию). ; дайте ему разумное имя)). Это может загрузить 10 клиентов.

Теперь go к табличному адаптеру ORDERS и добавьте к нему еще один запрос:

SELECT * FROM orders WHERE customerid = @customerid

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

'fill the form dataset with customers named smith:

Me.someDataSet.Clear()
customersTableAdapter.FillByLastName(someDataSet, "Smith") 'it will fill the Customers table with Smiths

ordersTableAdapter.ClearBeforeFill = false 'turn this off or every call to fill will remove existing order from the datatable
For Each cro as CustomersRow in someDataSet.Customers 'for all our smiths
  ordersTableAdapter.FillByCUstomerId(someDataSet, cro.Id) 'fill orders for customer with that id
Next cro

Так что теперь у вас есть 10 клиентов, и, возможно, более 50 заказов - у вас нет всего БД в вашем наборе данных, просто интересные данные. Привязка данных через отношение данных, предоставляемое в bindingsource клиентов, будет показывать только связанные строки. Щелкните по различным строкам в сетевом представлении данных клиентов и обратите внимание, что заказы, показанные в сетевом представлении ordersdatagrid, изменяются и отображают только соответствующие строки

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

SELECT orders.*
FROM
  orders INNER JOIN customers on orders.customerid = customers.id
WHERE
  customers.lastname = @lastName

Запрос выбирает только данные из заказов, но присоединяется к клиентам и ищет их по фамилии, поэтому мы должны назвать это FillByCustomerLastName

Наш код может выглядеть следующим образом:

'fill the form dataset with customers named smith:

Me.someDataSet.Clear()
customersTableAdapter.FillByLastName(someDataSet, "Smith") 'it will fill the Customers table with Smiths

ordersTableAdapter.FillByCustomerLastName(someDataSet, "Smith") 'fill orders for all customers with a last name of smith

Лошади для выбранных вами курсов. Я склонен выбирать первый подход и l oop, потому что он более гибкий, но там, где важна прямая производительность, может быть быстрее использовать шаблон, подобный второму

...