Kirjautuminen

Haku

Tehtävät

Keskustelu: Yleinen keskustelu: MVVM SQLite VB.Net Viimeksi lisätyn tietueen ID?

ari kood [07.09.2022 12:33:20]

#

Hei,

Tässä harjoittelen otsikon mukaista yhdistelmää ja usean tunnin googlaaminen ei tuottanut tulosta.

Public Class PGViewModel
    Private PGL as ObservableCollection(Of PGModel) 'PGModel sisältää vain Id ja Name muuttujat
    Public ReadOnly Property AddNewCommand As ICommand

   Public Sub New()
        PGL = New ObservableCollection(Of PGModel)(PGService.GetAll)
        AddHandler PGL.CollectionChanged, AddressOf CollectionChanged
        AddNewCommand = New AddNewPGCommand(PGL)
    End Sub

    Private Sub CollectionChanged(sender As Object, e As System.Collections.Specialized.NotifyCollectionChangedEventArgs)
        If e.Action = Specialized.NotifyCollectionChangedAction.Add Then
            Try
                PGService.Insert(PGL(e.NewStartingIndex))
            Catch ex As Exception
                MsgBox(ex.Message)
            End Try
        End If
    End Sub
End Class
Public Class PGService

    Public Sub Insert(ByRef PG As PGModel)
        Using conn As New SQLiteConnection(My.Settings.ConnString)
            Using cmd As New SQLiteCommand
                With cmd
                    .CommandType = CommandType.Text
                    .CommandText = "INSERT INTO tblProcessGroup (Name) VALUES ('" & PG.Name & "');"
                    '.CommandText = "INSERT INTO tblProcessGroup (Name) VALUES ('" & PG.Name & "'); SELECT last_insert_rowid();"
                    .Connection = conn
                End With
                conn.Open()
                cmd.ExecuteNonQuery()
                'PG.Id = cmd.ExecuteScalar()
            End Using
        End Using
    End Sub
End Class
Public Class AddNewPGCommand
    Inherits CommandBase

    Private _PGL As ObservableCollection(Of PGModel)

    Public Sub New(ByRef PGL As ObservableCollection(Of PGModel))
        _PGL = PGL
    End Sub

    Public Overrides Sub Execute(parameter As Object)
        Try
            _PGL.Add(New PGModel With {.Name = "TestPG11"})
        Catch ex As Exception
            MsgBox(ex.Message)
        End Try
    End Sub
End Class

Viewissä on DataGrid (bindattu PGViewModel.PGL ) ja Button(bindattu PGViewModel.AddNewCommand).
Eli button siis laukaisee AddNewCommand-komennon, joka lisää PGL kokoelmaan yhden rivin, joka taas laukaisee CollectionCanged eventin PGViewModelissa, joka kirjoittaa kyseisen tietueen tietokantaan.

Homma toimii ihan kivasti näin, mutta tarvisin tuon uuden rivin Id:n joka generoidaan automaattisesti tietokannassa(Nyt se on aina 0). Kokeilin asettaa sitä tuossa PGService.Insert metodissa (comment out rivit) mutta CollectionChanged Eventissä saan virheen (try catch message) -> "Cannot change ObservableCollection during a CollectionChanged event.". Id Muutos menee kuitenkin läpi pelkällä em. ilmoituksella. Ilman try-catch blokkeja prosessi ei mene läpi.

Miten tämä oikeaoppisesti toteutetaan?

Metabolix [08.09.2022 15:25:11]

#

Yleensä sen saa automaattisesti jostain. Netissä vihjataan, että SQLiteConnection-luokassa olisi LastInsertRowId. Näköjään System.Data.SQLite-kirjaston dokumentaatio on vain CHM-formaatissa ja lähdekoodiakaan ei saa netissä selattua, joten voit varmaan selailla näitä omalla koneellesi asian tarkistamiseksi.

ari kood [09.09.2022 12:49:05]

#

Siis juuri tuotahan olen käyttänytkin, mutta saan tämän herjan:
"Cannot change ObservableCollection during a CollectionChanged event.".

Ihmettelen että se kuitenkin menee läpi kunhan poikkeus "käsitellään" (=MsgBox) Catch blokissa, enkä millään saata uskoa että tämä olisi se oikea tapa.

Public Class PGService

    Public Sub Insert(ByRef PG As PGModel)
        Using conn As New SQLiteConnection(My.Settings.ConnString)
            Using cmd As New SQLiteCommand
                With cmd
                    .CommandType = CommandType.Text
                    .CommandText = "INSERT INTO tblProcessGroup (Name) VALUES ('" & PG.Name & "');"
--------->          '.CommandText = "INSERT INTO tblProcessGroup (Name) VALUES ('" & PG.Name & "'); SELECT last_insert_rowid();"
                    .Connection = conn
                End With
                conn.Open()
                cmd.ExecuteNonQuery()
--------->      'PG.Id = cmd.ExecuteScalar()
            End Using
        End Using
    End Sub
End Class

Metabolix [09.09.2022 14:14:23]

#

Kyllähän SQL-kyselyn muuttaminen on ihan eri asia kuin valmis LastInsertRowId-ominaisuus. Kiva jos toimii kuitenkin.

Debuggausvinkkejä: Kun saamasi virheilmoitus valittaa muokkaamisesta, niin olisiko vika siinä, että PG.Id:tä ei saa muuttaa tuossa kohti? Eli jos laitat vaikka ihan PG.Id = 123, niin tuleeko virhe tästäkin? Sittenhän sinun pitää ratkaista tätä ihan ohjelman rakenteesta lähtien, että onko tuo oikea paikka laittaa tietoja kantaan tai mitä muuta reittiä id:n voisi välittää.

Mystinen PG aiheuttaa PääGipua, mutta MVVM jää tuosta lyhyestä koodista vielä aika epäselväksi. Nähdäkseni CollectionChanged olisi tarkoitettu enemmänkin siihen, että tietoa (ja ilmoitus muuttumisesta) välittyisi tietokannasta käyttöliittymän suuntaan. Sen sijaan napista tieto pitäisi lisätä ensin kantaan ja sitten vasta tuohon ObservableCollection-olioon.

ari kood [18.09.2022 10:21:52]

#

Metabolix kirjoitti:

Sen sijaan napista tieto pitäisi lisätä ensin kantaan ja sitten vasta tuohon ObservableCollection-olioon.

Tuohan se ratkaisi ongelman, kiitos avusta.

Vastaus

Aihe on jo aika vanha, joten et voi enää vastata siihen.

Tietoa sivustosta