[VB.NET 2008] Creare una gestione Master Detail

  • Creatore Discussione Creatore Discussione mythar
  • Data di inizio Data di inizio

mythar

Utente Attivo
16 Gen 2006
148
0
0
46
Naples
Ho un form con 2 griglie, DGView_Impianto e DGView_Verifica.
I dati da visualizzare sono prelevati da 2 tabelle di un database access, Impianto(Chiave, Descrizione) e Verifica(Chiave, FK_Impianto, Descrizione)

Ho creato una relazione 1-n tra le due tabelle: Impianto_Verifica, Chiave, FK_Impianto

Spulciando il web ho visto che da codice posso impostare una relazione e aggiungerla al dataset, per poi impostare il bindingsource per la griglia di dettaglio(nel mio caso Verifica) ma io tale relazione ce l'ho già.

Se però provo a impostare il bindingsource.datamember della griglia di dettaglio, ottengo l'errore: "Impianto_Verifica" non è membro di datamember(o qualcosa di simile)

Come posso risolvere il problema?

Ringraziamenti anticipati per l'interessamento
 
Problema risolto, non associavo correttamente il bindingsource master a quello di dettaglio.

Nuovo problema, non mi si aggiorna automaticamente la griglia di dettaglio quando mi sposto tra le righe della griglia master.

Avete suggerimenti?
 
Ciao,

devi impostare correttamente le proprietà DataSource e DataMember del bindingSource di dettaglio.

Nella proprietà DataSource del bindingSource di dettaglio devi impostare il bindingSource di testata,

nella proprietà DataMember invece devi impostare la relazione che hai creato nel dataset.

In questo modo quando ti sposterai nella griglia di testata automaticamente si aggiornerà il dettaglio.
 
Grazie Vins,
ho risolto stamattina.
Impostavo male i datasource delle griglie, però ora ho un nuovo problema.

In pratica ho dei controlli sul form che vanno collegati ai campi della griglia di dettaglio.
Per quella di testata ho usato istruzioni tipo questa:
cmbModello.DataBindings.Add("SelectedValue", objBinding, "FK_Modello")
dove "objBinding" è il binding della griglia di testata

Per il dettaglio ho effettuato la stessa operazione, ma il databinding del dettaglio ha come datamember la relazione tra le mie due tabelle interessate, e manca quindi dei campi a me necessari.
Come imposto il databindings dei controlli di dettaglio?

Io continuo a studiare per trovare una soluzione, ma ogni suggerimento è gradito :)
grazie.
 
Risolto anche questo.
Ora mi "complico" la vita aumentando il numero di tabelle di dettaglio.
 
Cambiando il database ho un nuovo problema.
Sono passato da Access a SQL Server Express 2008.

Ho fatto le opportune modifiche agli oggetti, cioè passando dalle classi OleDb a quelle per Sql.
Onde evitare grossi problemi sono partito con la tabella di testata, e successivamente vorrei passare ad aggiungere i dettagli.

Il problema è il seguente:
sulla griglia di testata, quando apro e chiudo il form più volte, senza uscire dall'applicazione, i record del database vengono aggiunti in coda ... mmm ... in pratica se nella tabella del database ho 2 record, alla prima apertura del form sulla griglia mi ritrovo 2 record, ma chiudendolo e riaprendolo ce ne sono 4, poi 6 e così via.

Avevo risolto in principio usando questo codice:

objDataAdapter = New SqlDataAdapter("SELECT * FROM dbo.Impianto", StringaDiConnessione)
Dim cmdBuilderDAutocertificazione As New SqlCommandBuilder(objDataAdapter)
Dim table As New DataTable()
objDataAdapter.Fill(table)
objBinding.DataSource = table

ma da qui poi non riesco a collegarmi alla tabella di dettaglio.

Avete suggerimenti?
Mentre attendo la vostra risposta faccio un paio di prove con un dataset creato a runtime, in quanto normalmente io utilizzo quello che ho generato nel progetto(ho la vaga impressione che sia proprio quello il mio problema).
 
Ma il Fill della tabella del dataset quando lo fai? Ogni volta che apri il form? In tal caso è normale

che le righe vengano inserite ogni volta perchè non svuoti mai la tabella. Puoi agganciarti all'evento

Deactivate del form e in esso svuoti la tabella (nome_tabella.Clear).

Tuttavia mi pare strano che ogni volta che visualizzi il form tu debba fare il fill della tabella.
 
OT
Prima di pocedere è meglio che io chiarisca alcune cose:
1) Fino a poco tempo fa sviluppavo esclusivamente in VB6, senza mai usare classi.
2) Ho usato per un pò VB.NET 2003 appena uscito, poi l'ho abbandonato.
3) Ho ripreso a studiare la piattaforma .NET pochi mesi fa.

Visti i miei precedenti(quasi penali :D) ho un pò di difficoltà ad entrare nella logica di .NET
In particolare, quando usavo i form in VB6 per me era scontato che aprendo un form, alla sua chiusura "tutti" gli oggetti fossero "automaticamente" distrutti.
Inoltre trovo difficoltà ad inquadrare l'oggetto DataSet, e di conseguenza il suo utilizzo(ad esempio spesso mi capita di considerarlo come se corrispondesse all'oggetto RecordSet).

Tornando al problema ... in parte è risolto.
Ho aggiunto le 2 relazioni al dataset disconnesso che ho creato(in realtà ho 1 testata e 3 dettagli, ma il 3° lo faccio con comodo ora che ho capito questo passaggio), e settato correttamente i bindingsource, e le griglie mi vengono caricate correttamente.
Ho adesso il problema di fare il refresh delle DataGridView presenti sul form.
 
Prima di rischiare il linciaggio specifico che il refresh che mi serve è quello delle griglie di dettaglio.
In pratica ho il problema che quando uso la funzione refresh non mi si aggirna la griglia, anche se i dati nel database sono stati inseriti.
 
Per il refresh delle griglie devi rifare il fill delle tabelle corrispondenti tramite i rispettivi tableadapter
 
Vediamo se ho capito:

Salvo i dati
Svuoto il dataset dai record precedenti
Rieffettuo la fill tramite i DataAdapter

Se la procedura è corretta continua a leggere, altrimenti vediamo cosa sbaglio e poi procediamo.

Problema: avendo due relazioni che legano la testata con i due dettagli, effettuo la clear delle relazioni,
ma sulla riga successiva, dove effettuo la clear delle tabelle, ottengo l'errore:
"... esiste un vincolo ForeignKey in FK_tabdettaglio_tabtestata ... "
Volendo rimuovere anche questo vincolo, come procedo?
Sto cercando sulla rete e nelle risirse di vb.net, ma non riesco a venirne a capo.
 
Tu hai chiesto come effettuare il refresh (che io intendo come ricaricamento dei dati dal DB) e io ti ho consigliato di utilizzare il metodo Fill del tableadapter ma secondo me tutta la procedura che utilizzi andrebbe rivista.

I passi da seguire sarebbero:

- creare un dataset con le tabelle che ti servono del progetto (ognuna dotata del rispettivo tableadapter)

- riempire le tabelle quando ti serve con il metodo Fill dei rispettivi tableadapter

- legare (o "bindare" in gergo) le griglie ed i controlli della tua applicazione ai dati presenti sul dataset tramite i bindingsource

- effettuare tutte le operazioni sui bindingsource senza necessità di caricare/ricaricare i dati o fare refresh delle griglie

- interagire con il database solo al momento del salvataggio delle modifiche (tramite il metodo update dei table adapter)

Tutti questi concetti sono alla base del "Data Binding", una tecnica di lavorare sui dati che ti consiglio di studiare attentamente (sono disponibili tante risosre in rete, ebook e libri). E' solo un consiglio, ma per progettare applicazioni efficienti dovresti studiare bene questi aspetti.

Ciao
 
Premessa:
'DS_Impianti = Dataset creato a run time
'La gestione è ovviamente una master detail
objBinding.DataSource = DS_Impianti
objDataAdapter.DataSource = objBinding

Questo di seguito è il codice della funzione di salvataggio.

'Imposto i valori dei parametri
If Operazione = "A" Then
objDataAdapter.InsertCommand.Parameters.Item("@FK_Modello").Value = cmbModello.SelectedValue
objDataAdapter.InsertCommand.Parameters.Item("@FK_Categoria").Value = cmbCategoria.SelectedValue
objDataAdapter.InsertCommand.Parameters.Item("@FK_Marca").Value = cmbMarca.SelectedValue
objDataAdapter.InsertCommand.Parameters.Item("@FK_Convenzione").Value = cmbConvenzione.SelectedValue
objDataAdapter.InsertCommand.Parameters.Item("@FK_Comune").Value = cmbComune.SelectedValue
objDataAdapter.InsertCommand.Parameters.Item("@Visibile").Value = True
ElseIf Operazione = "M" Then
objDataAdapter.UpdateCommand.Parameters.Item("@FK_Modello").Value = cmbModello.SelectedValue
objDataAdapter.UpdateCommand.Parameters.Item("@FK_Categoria").Value = cmbCategoria.SelectedValue
objDataAdapter.UpdateCommand.Parameters.Item("@FK_Marca").Value = cmbMarca.SelectedValue
objDataAdapter.UpdateCommand.Parameters.Item("@FK_Convenzione").Value = cmbConvenzione.SelectedValue
objDataAdapter.UpdateCommand.Parameters.Item("@FK_Comune").Value = cmbComune.SelectedValue
objDataAdapter.UpdateCommand.Parameters.Item("@Visibile").Value = chkVisibile.Checked
objDataAdapter.UpdateCommand.Parameters.Item("@Chiave").Value = txtPratica.Text
End If


Try
'Eseguo l'istruzione SQL
Dim x As Int32
If Operazione = "A" Then
x = objDataAdapter.InsertCommand.ExecuteNonQuery()
ElseIf Operazione = "M" Then
x = objDataAdapter.UpdateCommand.ExecuteNonQuery()
End If

Salva = "S"
Catch sqlExceptionErr As SqlException
MsgBox("Errore in fase di salvataggio." & vbCrLf & sqlExceptionErr.Message, MsgBoxStyle.OkOnly)
Salva = "N"
End Try

Arrivato a questo punto i dati non vengono aggiornati sulla griglia(nel database ci sono), quindi mi sembra ovvio che manca qualcosa...ma cosa???
 
Hai saltato il passaggio

" effettuare tutte le operazioni sui bindingsource senza necessità di caricare/ricaricare i dati o fare refresh delle griglie"

in pratica le operazioni di inserimento, modifica e cancellazione li devi effettuare sui binding source e in questo modo i dati delle griglie saranno sempre aggiornati. Per salvare le modifiche sul DB poi devi soltanto chiamare il metodo Update dei vari table adapter
 
C'è un punto che non mi è chiaro dopo aver letto vari articoli on line.
Negli esempi che ho trovato, si fa sempre riferimento a bindingsource collegati a griglie.
Nel mio caso questo è vero solo fino ad un certo punto: le griglie sono collegate al bindingsource solo
in lettura, ma i dati da modificare e/o inserire si trovano su controlli textbox e combobox,
regolarmente bindati.
Da quello che ho letto in rete, per salvare i dati tramite bindingsource devo utilizzare il metodo
EndEdit(),
ma se sulla griglia tali inserimenti/modifiche non sono visibili, mi viene spontaneo pensare che il
refresh dei dati sulla griglia non avviene proprio perchè non lavoro su di essa, ma su altri controlli.
A questo punto mi viene spontaneo pensare che prima di richiamare l'EndEdit() devo modiicare i dati
sulla griglia, e solo dopo effettuare la chiamata al metodo EndEdit().

Spero che il mio ragionamento sia chiaro(e corretto), quindi chiedo conferma.
Va da se che farò comunque qualche prova in tal senso, ma se sto sbagliando mi farebbe piacere
essere fermato :P .
 
Ho capito dove sbagliavo con il BindingSource.
Sul form ho il pulsante "Aggiungi".
Nel codice del pulsante ho inserito il codice:
objBinding.AddNew()

e nella funzione di salvataggio ho inserito
If pulsante="SALVA" Then
objBnding.EndEdit()
ElseIf pulsante="ANNULLA" Then
objBinding.CancelEdit()
End If

Mi resta il problema del refresh della griglia, perchè quando vado ad inserire un nuovo record, e lo salvo, sulla griglia la nuova riga è vuota.

Help Me Please ...
 
Risolto anche il refresh, non avevo richiamato la funzione in cui richiamo le varie fill.
Devo solo implementare un'ottimizzazione del codice e rivedere, alla luce delle conoscenze acquisite, le gestioni precedentemente realizzate.

Grazie per l'aiuto, ora sembra funzionare tutto alla perfezione!!!
 
Ultima modifica:

Discussioni simili