Benutzer mit den meisten Antworten
Duplikate verhindern.

Frage
-
Hallo Zusammen,
ich habe eine Anwendung in VB 2005 mit einem numerischen Datenfeld, das keine doppelten Nummern enthalten darf. Das Feld im Dataset ist nicht als Unique eingestellt. Kann mir jemand sagen, wie ich bereits bei der Eingabe verhindern kann, dass Duplikate angelegt werden? Irgendwie haut das bei mir nicht hin. Ich habe schon eine Validation im Dataset.vb versucht und auch in der Form Klasse. Beides funktioniert nicht wirklich sauber.
Vielen Dank vorab
Christina
Antworten
-
Hi Christina,
nachfolgend mal ein Beispiel, wie man so etwas im Parse-Ereignis des Binding-Objektes lösen kann:
Public Class Form1 Private dt As DataTable = Testdata.Getdata ' Testdaten laden Private bs As New BindingSource(dt, "") Private sc As New SplitContainer With {.Dock = DockStyle.Fill, _ .SplitterDistance = 100} Private dgv As New DataGridView With {.Dock = DockStyle.Fill, _ .AllowUserToAddRows = False, _ .ReadOnly = True, .DataSource = bs} Private lbl1 As New Label With {.Top = 10, .Text = "Nummer"} Private tb1 As New TextBox With {.top = 20} Private ep As New ErrorProvider Private lbl2 As New Label With {.Top = 55, .Text = "col2"} Private tb2 As New TextBox With {.Top = 75} Private WithEvents btn As New Button With {.Top = 100, .Text = "OK"} Private Sub Form1_Load(ByVal sender As System.Object, _ ByVal e As System.EventArgs) Handles MyBase.Load Me.Width = 600 ' Formulargröße erhöhen, um alles anzuzeigen Me.Controls.AddRange(New Control() {sc}) ' SplitContainer im Formular platzieren sc.Panel1.Controls.Add(dgv) ' im linken teil des Splitcontainers das Grid füllend platzieren sc.Panel2.Controls.AddRange(New Control() {btn, tb2, lbl2, tb1, lbl1}) ' Steuerelement im rechten Teil AddHandler tb1.DataBindings.Add("Text", bs, "Unikat").Parse, AddressOf tb1_Parse ' Parse-Handler binden tb2.DataBindings.Add("Text", bs, "col2") ' 2. TextBox für Text End Sub Private Sub btn_Click(ByVal sender As Object, _ ByVal e As System.EventArgs) Handles btn.Click bs.EndEdit() ' Editiervorgang beenden und Binding-Objekte zum Datenaustausch auffordern End Sub Private Sub tb1_Parse(ByVal sender As Object, ByVal e As ConvertEventArgs) ep.SetError(tb1, "") ' ErrorProvider rücksetzen Dim nr = CType(e.Value, Integer) ' neu eingegebenen Wert holen Dim res1 = Aggregate el In dt.Rows _ Let rnr = CType(CType(el, DataRow).Item("Unikat"), Integer) _ Where rnr = nr And el IsNot CType(bs.Current, DataRowView).Row _ Into Count() ' Auftreten in vorhandenen Datenobjekten zählen If res1 > 0 Then Dim res2 = Aggregate el In dt.Rows _ Let rnr = CType(CType(el, DataRow).Item("Unikat"), Integer) _ Into Max(rnr) ' Maximalwert aus vorhandenen datenobjekten bestimmen e.Value = res2 + 1 ' neuen wert festlegen ep.SetError(tb1, String.Format("Falsche Eingabe: {0}, neuer Wert {1} gesetzt", _ nr, res2 + 1)) ' ErrorProvider aktivieren End If End Sub End Class Friend Class Testdata Public Shared Function Getdata() As DataTable Dim dt As New DataTable("Tab1") With dt With .Columns With .Add("ID", GetType(Integer)) .AutoIncrement = True .AutoIncrementSeed = 1 .AutoIncrementStep = 1 End With .Add("Unikat", GetType(Integer)).Unique = True .Add("col2", GetType(String)) End With For i = 1 To 100 Dim r As DataRow = .NewRow r.Item("Unikat") = i * 2 r.Item("col2") = "Zeile " & i.ToString .Rows.Add(r) Next End With Return dt End Function End Class
--
Peter- Als Antwort vorgeschlagen Peter Fleischer Donnerstag, 17. Dezember 2009 08:41
- Als Antwort markiert Robert BreitenhoferModerator Freitag, 18. Dezember 2009 07:34
Alle Antworten
-
Hi Christina,
warum kannst du die Spalte in der DataTable im DataSet nicht unikat machen?
Wenn du bereits bei der Eingabe (beim Tastenanschlag) verhindern willst, dann musst du schon beim KeyPress eingreifen, Ich würde das aber nicht machen, sondern erst im Validate prüfen, um z.B. auch Einfügeoperationen zu berücksichtugen. Im ungebundenen Modus kann dann ein ErrorProvider gesetzt werden, damit der Anwender weiß, dass er falsche Daten eingegeben hat. Und erst, wenn die Prüfung erfolgreich war, dann werden die Daten in die Datenquelle eingetragen. Wenn gebunden gearbeitet werden soll, dann kann man im Parse-Ereignis des Binding-Objektes den Transfer der Daten in die Datenwuelle verhindern, wenn die Daten nicht passen.
Bevor aber mit einer Lösung begonnen wird, sollte erst einmal genau die Bedientechnologie beschrieben werden: was soll passieren und wie soll der Bediener im Problemfall informiert und weiter geführt werden?
--
Peter -
Hallo Peter,
danke fuer die Infos. Ich bin noch ziemlich neu in VB.NET und habe die Anwendung wie in den "How Do I" Videos von Microsoft Beth Massy erstellt. Ich habe bei einer frueheren Google-Suche ein Beispiel gefunden, das mit .FIND und .EXISTS arbeitet. Ich dachte, das merke ich mir, und jetzt hab ich es vergessen und finde den Link nicht mehr :-(
Wenn ich das Feld unique setze, bekomme ich bereits beim Ausfuehren des Codes mit F5 eine Fehlermeldung vom Debugger, wenn versucht wird, eine bereits existierende Nummer zu speichern. "ConstraintException wurde nicht behandelt"
Ich moechte, dass beim Verlassen des Eingabefeldes geprueft wird, ob die Nummer schon existiert. Trifft dies zu, soll eine Fehlermeldung ausgegeben werden, z. B. "Die Nummer 999 existiert bereits"
Dann soll bei einer Neuanlage die naechsthoehere freie Nummer als Vorschlag im Eingabefeld erscheinen.
Wurde ein bestehender Datensatz geaendert, so soll die Nummer wieder angezeigt werden, bevor sie geaendert wurde.
Viele Gruesse
Christina -
Hi Christina,
nachfolgend mal ein Beispiel, wie man so etwas im Parse-Ereignis des Binding-Objektes lösen kann:
Public Class Form1 Private dt As DataTable = Testdata.Getdata ' Testdaten laden Private bs As New BindingSource(dt, "") Private sc As New SplitContainer With {.Dock = DockStyle.Fill, _ .SplitterDistance = 100} Private dgv As New DataGridView With {.Dock = DockStyle.Fill, _ .AllowUserToAddRows = False, _ .ReadOnly = True, .DataSource = bs} Private lbl1 As New Label With {.Top = 10, .Text = "Nummer"} Private tb1 As New TextBox With {.top = 20} Private ep As New ErrorProvider Private lbl2 As New Label With {.Top = 55, .Text = "col2"} Private tb2 As New TextBox With {.Top = 75} Private WithEvents btn As New Button With {.Top = 100, .Text = "OK"} Private Sub Form1_Load(ByVal sender As System.Object, _ ByVal e As System.EventArgs) Handles MyBase.Load Me.Width = 600 ' Formulargröße erhöhen, um alles anzuzeigen Me.Controls.AddRange(New Control() {sc}) ' SplitContainer im Formular platzieren sc.Panel1.Controls.Add(dgv) ' im linken teil des Splitcontainers das Grid füllend platzieren sc.Panel2.Controls.AddRange(New Control() {btn, tb2, lbl2, tb1, lbl1}) ' Steuerelement im rechten Teil AddHandler tb1.DataBindings.Add("Text", bs, "Unikat").Parse, AddressOf tb1_Parse ' Parse-Handler binden tb2.DataBindings.Add("Text", bs, "col2") ' 2. TextBox für Text End Sub Private Sub btn_Click(ByVal sender As Object, _ ByVal e As System.EventArgs) Handles btn.Click bs.EndEdit() ' Editiervorgang beenden und Binding-Objekte zum Datenaustausch auffordern End Sub Private Sub tb1_Parse(ByVal sender As Object, ByVal e As ConvertEventArgs) ep.SetError(tb1, "") ' ErrorProvider rücksetzen Dim nr = CType(e.Value, Integer) ' neu eingegebenen Wert holen Dim res1 = Aggregate el In dt.Rows _ Let rnr = CType(CType(el, DataRow).Item("Unikat"), Integer) _ Where rnr = nr And el IsNot CType(bs.Current, DataRowView).Row _ Into Count() ' Auftreten in vorhandenen Datenobjekten zählen If res1 > 0 Then Dim res2 = Aggregate el In dt.Rows _ Let rnr = CType(CType(el, DataRow).Item("Unikat"), Integer) _ Into Max(rnr) ' Maximalwert aus vorhandenen datenobjekten bestimmen e.Value = res2 + 1 ' neuen wert festlegen ep.SetError(tb1, String.Format("Falsche Eingabe: {0}, neuer Wert {1} gesetzt", _ nr, res2 + 1)) ' ErrorProvider aktivieren End If End Sub End Class Friend Class Testdata Public Shared Function Getdata() As DataTable Dim dt As New DataTable("Tab1") With dt With .Columns With .Add("ID", GetType(Integer)) .AutoIncrement = True .AutoIncrementSeed = 1 .AutoIncrementStep = 1 End With .Add("Unikat", GetType(Integer)).Unique = True .Add("col2", GetType(String)) End With For i = 1 To 100 Dim r As DataRow = .NewRow r.Item("Unikat") = i * 2 r.Item("col2") = "Zeile " & i.ToString .Rows.Add(r) Next End With Return dt End Function End Class
--
Peter- Als Antwort vorgeschlagen Peter Fleischer Donnerstag, 17. Dezember 2009 08:41
- Als Antwort markiert Robert BreitenhoferModerator Freitag, 18. Dezember 2009 07:34