Home Page
Articoli
Tips & Tricks
News
Forum
Archivio Forum
Blogs
Sondaggi
Rss
Video
Utenti
Chi Siamo
Contattaci
Username:
Password:
Login
Registrati ora!
Recupera Password
Home Page
Stanze Forum
App. WinForms / WPF .NET
Dataset e campi contatore
mercoledì 15 ottobre 2003 - 10.34
Elenco Threads
Stanze Forum
Aggiungi ai Preferiti
Cerca nel forum
tas
Profilo
| Newbie
12
messaggi | Data Invio:
mer 15 ott 2003 - 10:34
Da un programma in VB.NET accedo ad un archivio Access così strutturato:
tabella Documenti:
---ID (contatore)
---Descrizione
---Tipo
---Numero
---Data
---Segno
tabella Magazzino:
---ID (contatore)
---Documento
---Articolo
---Quantità
---Prezzo
Esiste una relazione in integrità referenziale tra Magazzino.Documento e Documenti.ID, definita in Access. Un record in Documenti può avere quindi zero o più record figli in Magazzino.
Ho creato un dataset e ho aggiunto le due tabelle col metodo Fill, ho aggiunto sul campo Documenti.ID una chiave primaria e impostato le proprietà AutoIncrement=True, AutoIncrementSeed=1, ReadOnly=True. Infine ho aggiunto un vincolo tra Magazzino.Documento e Documenti.ID. Ecco una parte di codice:
Dim dad As OleDbDataAdapter
Dim dam As OleDbDataAdapter
Dim dt As DataTable
Dim dcp As DataColumn
Dim dcc As DataColumn
Dim dr As DataRelation
Dim cb As OleDbCommandBuilder
Dim bm As BindingManagerBase
sql = "SELECT * FROM Documenti"
dad = New OleDbDataAdapter(sql, conn)
dad.Fill(ds, "Documenti")
sql = "SELECT * FROM Magazzino"
dam = New OleDbDataAdapter(sql, conn)
dam.Fill(ds, "Magazzino")
Dim pk(1) As DataColumn
pk(0) = ds.Tables("Documenti").Columns("ID")
ds.Tables("Documenti").PrimaryKey = pk
With ds.Tables("Documenti").Columns("ID")
.AutoIncrement = True
.AutoIncrementSeed = 1
.ReadOnly = True
End With
dcp = ds.Tables("Documenti").Columns("ID")
dcc = ds.Tables("Magazzino").Columns("Documento")
Dim fkc As New ForeignKeyConstraint(dcp, dcc)
fkc.AcceptRejectRule = AcceptRejectRule.Cascade
ds.Tables("Magazzino").Constraints.Add(fkc)
'databindings
txbDescription.DataBindings.Add(New Binding("Text", ds, "Documenti.Descrizione"))
bm = Me.BindingContext(ds, "Documenti")
'nuovo record
bm.AddNew()
Quando creo una nuova riga in Documenti, il campo Documenti.ID assume automaticamente il prossimo numero valido, per esempio il valore 5. Creo quindi vari record nella tabella Magazzino, caricando valori opportuni. In particolare, imposto per ogni riga il campo Magazzino.Documento = 5, in modo che tali record non rimangano "orfani". A questo punto effettuo l'update delle tabelle:
dad.Update(ds, "Documenti")
dam.Update(ds, "Magazzino")
Con questa operazione aggiorno i dati all'interno delle rispettive tabelle di Access, ma se un altro utente si è collegato nel frattempo alla tabella Documenti e ha aggiunto un suo record, il mio record di Documenti non avrà più ID=5 ma per esempio ID=6. A questo punto le righe della tabella Magazzino contenute nel dataset puntano ad un record di Documenti sbagliato (Magazzino.Documento=5) con tutte le ovvie conseguenze.
Forse ho sbagliato approccio al problema, ma non trovo una soluzione, qualcuno ha dei suggerimenti?
Brainkiller
Profilo
| Guru
7.999
messaggi | Data Invio:
ven 17 ott 2003 - 11:11
Ciao Tas,
sai che sono 2/3 giorni che penso a questo problema.
Devo dire che sono ignorante su questo particolare. Non saprei proprio coem si comporta, anche perchè a livello di transazionalità e concorrenza non so come sia messo Access. Sicuramente SQL è messo meglio.
Io pensavo, potresti fare così, metti il tutto in un try catch almeno la parte di update. In questo modo se qualcuno ha già fatto l'update prima di te e ha inserito dei record con degli ID che magari sono gli stessi che hai tu nel Dataset ti ritorna un Exception che tu puoi Gestire.
Cosa ne pensi?
Ciao
David De Giacomi
tas
Profilo
| Newbie
12
messaggi | Data Invio:
sab 18 ott 2003 - 12:17
Ciao, grazie innanzitutto per avermi risposto.
La soluzione che ho trovato non è forse il massimo ma per il momento mi accontento. In pratica ho eliminato qualunque vincolo nel dataset su Documenti.ID (chiave primaria, relazioni e proprietà varie) e lo lascio vuoto. faccio l'update della tabella Documenti e subito dopo ripeto il metodo Fill, per avere nel dataset le modifiche apportate da Access, ossia il numero progressivo assegnato a ID. Carico questo valore nel campo Magazzino.Documento di ogni riga della tabella Magazzino, infine faccio l'update anche di questa tabella e chiudo tutto.
Tu che ne dici?
Brainkiller
Profilo
| Guru
7.999
messaggi | Data Invio:
lun 20 ott 2003 - 19:39
Ciao Tas,
in effetti così come hai descritto potrebbe andare bene.
Certo non credo sia il metodo corretto anche perchè sarai d'accordo con me che è un giro lungo, però magari funziona.
Resto comunque molto dubbioso sull'esempio che hai posto e mi piacerebbe capire come funziona la cosa che hai descritto.
Ora non ho ancora avuto tempo ma volevo testarla personalmente e chiedere ad alcuni miei colleghi cosa ne pensano.
Quando e se avrò risposte valide posterò qui.
Ciao
David
tas
Profilo
| Newbie
12
messaggi | Data Invio:
lun 20 ott 2003 - 20:44
Ciao, ecco il codice completo (o quasi). Si tratta di un form contenente essenzialmente una textbox (txbDescription) collegata in databinding al campo Documenti.Descrizione; un combobox scollegato dai dati; una ListView (lsvMaterial) nella quale vado a visualizzare le righe della tabella Magazzino.
Un overload a ShowDialog mi permette di visualizzare il form e di preparare opportunamente i vari controlli. La variabile id passata come argomento a ShowDialog può contenere il valore di Documenti.ID di un record già esistente che voglio mostrare nel form, oppure il valore 0 per indicare che voglio creare un nuovo record.
Public Overloads Function ShowDialog(ByVal id As Long) As DialogResult
Dim ret As DialogResult
Dim sql As String
Dim daa As OleDbDataAdapter
Dim dad As OleDbDataAdapter
Dim dam As OleDbDataAdapter
Dim dt As DataTable
Dim dcp As DataColumn
Dim dcc As DataColumn
Dim dr As DataRelation
Dim cb As OleDbCommandBuilder
Dim bm As BindingManagerBase
conn.Open()
ds = New DataSet
'tabella Articoli
sql = "SELECT * FROM Articoli"
daa = New OleDbDataAdapter(sql, conn)
daa.Fill(ds, "Articoli")
'tabella Documenti
If id = 0 Then
sql = "SELECT * FROM Documenti"
Else
sql = "SELECT * FROM Documenti WHERE ID = " & id.ToString
End If
dad = New OleDbDataAdapter(sql, conn)
dad.Fill(ds, "Documenti")
'tabella Magazzino
sql = "SELECT Magazzino.* FROM Magazzino WHERE Documento = " & id.ToString
dam = New OleDbDataAdapter(sql, conn)
dam.Fill(ds, "Magazzino")
'relazione tra Articoli.ID e Magazzino.Articolo
dcp = ds.Tables("Articoli").Columns("ID")
dcc = ds.Tables("Magazzino").Columns("Articolo")
dr = New DataRelation("ArticlesRelation", dcp, dcc, True)
ds.Relations.Add(dr)
'databindings
txbDescription.DataBindings.Add(New Binding("Text", ds, "Documenti.Descrizione"))
bm = Me.BindingContext(ds, "Documenti")
'nuovo record
If id = 0 Then
bm.AddNew()
End If
conn.Close()
'carica dati
Call LoadMaterial()
Call LoadPromotions()
'visualizza finestra
ret = MyBase.ShowDialog()
conn.Open()
'salva dati
If ret = DialogResult.OK Then
bm.EndCurrentEdit()
cb = New OleDbCommandBuilder(dad)
'se il record è nuovo imposta alcuni campi
If id = 0 Then
dt = ds.Tables("Documenti")
With dt.Rows(dt.Rows.Count - 1)
.Item("Numero") = GetNextNumber()
.Item("Tipo") = 3
.Item("Segno") = -1
.Item("Data") = Now.Date
End With
End If
'aggiorna l'origine dati e ricarica le modifiche
dad.Update(ds, "Documenti")
dad.Fill(ds, "Documenti")
'aggiorna il datatable relativo a Magazzino
Call SaveMaterial()
cb = New OleDbCommandBuilder(dam)
dam.Update(ds, "Magazzino")
Else
bm.CancelCurrentEdit()
End If
conn.Close()
Return ret
End Function
Private Sub SaveMaterial()
Dim id As Long
Dim dr As DataRow
Dim dt As DataTable
dt = ds.Tables("Documenti")
id = dt.Rows(dt.Rows.Count - 1).Item("ID")
'imposta il campo Documento = Documenti.ID
For Each dr In ds.Tables("Magazzino").Rows
dr("Documento") = id
Next
End Sub
Private Sub LoadMaterial()
Dim dr As DataRow
Dim dt As DataTable
Dim lvi As L
tas
Profilo
| Newbie
12
messaggi | Data Invio:
lun 20 ott 2003 - 20:45
Continua dal post precedente:
Private Sub LoadMaterial()
Dim dr As DataRow
Dim dt As DataTable
Dim lvi As ListViewItem
Dim tot As Decimal
Dim dra As DataRow
dt = ds.Tables("Magazzino")
lsvMaterial.Items.Clear()
For Each dr In dt.Rows
dra = dr.GetParentRow("ArticlesRelation")
lvi = lsvMaterial.Items.Add(dra("Codice"))
lvi.Tag = dr
lvi.SubItems.Add(dra("Descrizione"))
lvi.SubItems.Add(dr("Quantità"))
lvi.SubItems.Add(CType(dr("Prezzo"), Decimal).ToString("F2"))
lvi.SubItems.Add(CType(dr("Quantità") * dr("Prezzo"), Decimal).ToString("F2"))
tot += dr("Quantità") * dr("Prezzo")
Next
txbTotal.Text = tot.ToString("F2")
End Sub
Nella programmazione in VB6 ed in particolare con la tecnologia (obsoleta) DAO c'era una comoda proprietà del recordset chiamata LastModified, che utilizzata in congiunzione con la proprietà Bookmark permetteva di posizionarsi sull'ultimo record aggiunto nel recordset:
rs.Bookmark = rs.LastModified
Non c'è nulla del genere in ADO.NET?
Torna su
Stanze Forum
Elenco Threads
Partecipa anche tu! Registrati!
Hai bisogno di aiuto ?
Perchè non ti registri subito?
Dopo esserti registrato potrai chiedere
aiuto sul nostro
Forum
oppure aiutare gli altri
Consulta le
Stanze
disponibili.
Registrati ora !