VB.NET dataset displaying database rows incorrectly - database

I would say I'm new to VB but I have been using it for over a year although for mainly small tasks (mostly school related). Anyway my current project is for my A-Level task and I need to be able to add, update, delete and read from a database. My current code allows this to happen but after a new record is added to my database the dataset in VB displays the rows differently. I have 3 tables: "PlayerInfo", "PlayerSkill" and "PlayerAbilities". when a new record is added; the new "PlayerInfo" information becomes the first row in my dataset while the "PlayerSkill" and "PlayerAbilities" become the last row. This causes all of the information to be improperly matched up. I was wondering if anyone else has had this problem and if they know how to solve it.
This shows the working code to add to my database.
If inc <> -1 Then
Dim cb1 As New OleDb.OleDbCommandBuilder(da1)
Dim cb2 As New OleDb.OleDbCommandBuilder(da2)
Dim cb3 As New OleDb.OleDbCommandBuilder(da3)
Dim dsNewRow1 As DataRow
Dim dsNewRow2 As DataRow
Dim dsNewRow3 As DataRow
Try
dsNewRow1 = ds1.Tables("Players").NewRow()
dsNewRow1.Item("Forename") = Forename.Text()
dsNewRow1.Item("Surname") = Surname.Text()
ds1.Tables("Players").Rows.Add(dsNewRow1)
da1.Update(ds1, "Players")
dsNewRow3 = ds3.Tables("Players").NewRow()
dsNewRow3.Item("Reactions") = Reactions.Text()
dsNewRow3.Item("Strength") = Strength.Text()
dsNewRow3.Item("Speed") = Speed.Text()
dsNewRow3.Item("Stamina") = Stamina.Text()
dsNewRow3.Item("Accuracy") = Accuracy.Text()
dsNewRow3.Item("Coordination") = Coordination.Text()
ds3.Tables("Players").Rows.Add(dsNewRow3)
da3.Update(ds3, "Players")
dsNewRow2 = ds2.Tables("Players").NewRow()
dsNewRow2.Item("RegularShot") = RegularShot.Text()
dsNewRow2.Item("ShortServe") = ShortServe.Text()
dsNewRow2.Item("FlickServe") = FlickServe.Text()
dsNewRow2.Item("Clear") = Clear.Text()
dsNewRow2.Item("Smash") = Smash.Text()
dsNewRow2.Item("DropShot") = DropShot.Text()
ds2.Tables("Players").Rows.Add(dsNewRow2)
da2.Update(ds2, "Players")
MsgBox("New Record added to the Database")
Commit.Enabled = False
AddNew.Enabled = True
Update.Enabled = True
Delete.Enabled = True
Catch
MsgBox("Error")
Me.Close()
End Try
End If
This shows the code that displays each of the dataset records inside different text boxes.
Try
Forename.Text = ds1.Tables("Players").Rows(inc).Item(1)
Surname.Text = ds1.Tables("Players").Rows(inc).Item(2)
Speed.Text = ds3.Tables("Players").Rows(inc).Item(3)
Strength.Text = ds3.Tables("Players").Rows(inc).Item(2)
Reactions.Text = ds3.Tables("Players").Rows(inc).Item(1)
Stamina.Text = ds3.Tables("Players").Rows(inc).Item(4)
Coordination.Text = ds3.Tables("Players").Rows(inc).Item(6)
Accuracy.Text = ds3.Tables("Players").Rows(inc).Item(5)
ShortServe.Text = ds2.Tables("Players").Rows(inc).Item(2)
FlickServe.Text = ds2.Tables("Players").Rows(inc).Item(3)
Clear.Text = ds2.Tables("Players").Rows(inc).Item(4)
Smash.Text = ds2.Tables("Players").Rows(inc).Item(5)
DropShot.Text = ds2.Tables("Players").Rows(inc).Item(6)
RegularShot.Text = ds2.Tables("Players").Rows(inc).Item(1)
Catch
MsgBox("Error")
Me.Close()
End Try
Sadly I do not currently have enough "Rep" to upload a picture of the dataset.
Also sorry if this is not enough information, I'm not really used to using forums and such.

I'm not entirely sure if this counts as an answer as I still don't know what caused the problem in the first case. Anyway I've got my code doing what I wanted by editing the SQL statements to display the rows in order of the primary key. ORDER BY [Player#]. I did have to change the name to just "Player" because the "CommandBuilder" doesn't like special characters.

Related

DataView.RowFilter not reflected back to DataGridView

I created an Access Database with 3 tables (Recs, Artist, Album)
I want to filter the DataSet (Recs) on an Album Title but the DataView.RowFilter is not reflected back to the DataGridView.
TaggerDataSet is the container for Recs, Artist, Album tables dgvRecs is my DataGridView for the Recs Table dgvArtist is my DataGridView for the Artist Table dgvAlbum is my DataGridView for the Album Table
to reference the Recs Table I use TaggerDataSet.Recs to reference the Artist Table I use TaggerDataSet.ArtistTable to reference the Album Table I use TaggerDataSet.AlbumTable
Private Sub SetRecFilter(SQLFilter As String, LookFor As String)
'The SQL filter contains "AlbumTitle = Taken By Force"
'LookFor is for testing and contains "Taken By force"
Dim DView As DataView 'To get the Data View from the table 'Recs'
Dim DTable As DataTable 'To get the Recs table from the Dataset
Dim DVal(0) As Object 'For Testing of the Data View
Dim Index As Integer 'Index into the Table Records
DTable = TaggerDataSet.Recs 'This gets the Recs table from the Dataset
DView = New DataView(DTable) 'This associates the Data View to the DataTable
DView.Sort = "AlbumTitle" 'Needed for the Find request
DVal(0) = LookFor 'Sets the object to the passed in LookFor value
Index = DView.Find(DVal) 'Index returns a value of 4 (which is correct)
'This call is confirmed to work (the DView.count is changed from 7 to 1)
'but has no effect on TaggerDataSet.Recs (TaggerDataSet.Recs.Rows.Count still at 7)
DView.RowFilter = SQLFilter 'This changes the record count to 1 (which is correct)
DTable = DView.ToTable 'This saves the Table back to the Data Table
'This call also has no effect
TaggerDataSet.Tables(2).DefaultView.RowFilter = SQLFilter 'This has no effect
'This call also has no effect even though the table is specifically referenced
TaggerDataSet.Recs.DefaultView.RowFilter = SQLFilter
Validate()
TaggerDataSetBindingSource.EndEdit()
TaggerDataSetBindingSource.Filter = SQLFilter
RecsTableAdapter.Fill(TaggerDataSet.Recs)
RecsTableAdapter.Update(TaggerDataSet.Recs)
TableAdapterManager.UpdateAll(TaggerDataSet)
dgvRecs.Refresh()
dgvRecs.FirstDisplayedScrollingRowIndex = 0
End Sub
Solved this problem (at least for a short test) with:
dgvRecs.DataMember = ""
dgvRecs.DataSource = DTable.DefaultView
just after the DTable = DView.ToTable line
Everything after that may not be needed any more.
I now have a new problem. Resetting the RowFilter to "" or to Nothing leaves the first column after the ID blank (All Song Titles are blank)
I have tried the following:
DTable = TaggerDataSet.ArtistTable
DView = New DataView(DTable)
DView.RowFilter = Nothing
DTable = DView.ToTable
dgvArtist.DataSource = ""
dgvArtist.Refresh()
dgvArtist.DataSource = ArtistDataGridViewSource
dgvArtist.DataMember = ArtistDataGridViewMember
Validate()
TaggerDataSetBindingSource.EndEdit()
ArtistTableTableAdapter.Update(TaggerDataSet.ArtistTable)
Me.ArtistTableTableAdapter.Fill(Me.TaggerDataSet.ArtistTable)
TableAdapterManager.UpdateAll(TaggerDataSet)
dgvArtist.Refresh()
where ArtistDataGridViewSource was set when the form was loaded with the original DataSource and the same with the DataMember.

What is the most efficient way to extract information from a text file formatted like this

Consider a text file stored in an online location that looks like this:
;aiu;
[MyEditor45]
Name = MyEditor 4.5
URL = http://www.myeditor.com/download/myeditor.msi
Size = 3023788
Description = This is the latest version of MyEditor
Feature = Support for other file types
Feature1 = Support for different encodings
BugFix = Fix bug with file open
BugFix1 = Fix crash when opening large files
BugFix2 = Fix bug with search in file feature
FilePath = %ProgramFiles%\MyEditor\MyEditor.exe
Version = 4.5
Which details information about a possible update to an application which a user could download. I want to load this into a stream reader, parse it and then build up a list of Features, BugFixes etc to display to the end user in a wpf list box.
I have the following piece of code that essentially gets my text file (first extracting its location from a local ini file and loads it into a streamReader. This at least works although I know that there is no error checking at present, I just want to establish the most efficient way to parse this first. One of these files is unlikely to ever exceed more than about 250 - 400 lines of text.
Dim UpdateUrl As String = GetUrl()
Dim client As New WebClient()
Using myStreamReader As New StreamReader(client.OpenRead($"{UpdateUrl}"))
While Not myStreamReader.EndOfStream
Dim line As String = myStreamReader.ReadLine
If line.Contains("=") Then
Dim p As String() = line.Split(New Char() {"="c})
If p(0).Contains("BugFix") Then
MessageBox.Show($" {p(1)}")
End If
End If
End While
End Using
Specifically I'm looking To collate the information about Features, BugFixes and Enhancements. Whilst I could construct what would in effect be a rather messy if statement I feel sure that there must be a more efficient way to do this , possibly involving linq. I'd welcome any suggestions.
I have added the wpf tag on the off chance that someone reading this with more experience of displaying information in wpf listboxes than I have might just spot a way to effectively define the info I'm after in such a way that it could then be easily displayed in a wpf list box in three sections (Features, Enhancements and BugFixes).
Dom, Here is an answer in C#. I will try to convert it to VB.Net momentarily. First, since the file is small, read all of it into a list of strings. Then select the strings that contain an "=" and parse them into data items that can be used. This code will return a set of data items that you can then display as you like. If you have LinqPad, you can test thecode below, or I have the code here: dotnetfiddle
Here is the VB.Net version: VB.Net dotnetfiddle
Imports System
Imports System.Collections.Generic
Imports System.Linq
Public Class Program
Public Sub Main()
Dim fileContent As List(Of String) = GetFileContent()
Dim dataItems = fileContent.Where(Function(c) c.Contains("=")).[Select](Function(c) GetDataItem(c))
dataItems.Dump()
End Sub
Public Function GetFileContent() As List(Of String)
Dim contentList As New List(Of String)()
contentList.Add("sb.app; aiu;")
contentList.Add("")
contentList.Add("[MyEditor45]")
contentList.Add("Name = MyEditor 4.5")
contentList.Add("URL = http://www.myeditor.com/download/myeditor.msi")
contentList.Add("Size = 3023788")
contentList.Add("Description = This is the latest version of MyEditor")
contentList.Add("Feature = Support for other file types")
contentList.Add("Feature1 = Support for different encodings")
contentList.Add("BugFix = Fix bug with file open")
contentList.Add("BugFix1 = Fix crash when opening large files")
contentList.Add("BugFix2 = Fix bug with search in file feature")
contentList.Add("FilePath = % ProgramFiles %\MyEditor\MyEditor.exe")
contentList.Add("Version = 4.5")
Return contentList
End Function
Public Function GetDataItem(value As String) As DataItem
Dim parts = value.Split("=", 2, StringSplitOptions.None)
Dim dataItem = New DataItem()
dataItem.DataType = parts(0).Trim()
dataItem.Data = parts(1).Trim()
Return dataItem
End Function
End Class
Public Class DataItem
Public DataType As String
Public Data As String
End Class
Or, in C#:
void Main()
{
List<string> fileContent = GetFileContent();
var dataItems = fileContent.Where(c => c.Contains("="))
.Select(c => GetDataItem(c));
dataItems.Dump();
}
public List<string> GetFileContent()
{
List<string> contentList = new List<string>();
contentList.Add("sb.app; aiu;");
contentList.Add("");
contentList.Add("[MyEditor45]");
contentList.Add("Name = MyEditor 4.5");
contentList.Add("URL = http://www.myeditor.com/download/myeditor.msi");
contentList.Add("Size = 3023788");
contentList.Add("Description = This is the latest version of MyEditor");
contentList.Add("Feature = Support for other file types");
contentList.Add("Feature1 = Support for different encodings");
contentList.Add("BugFix = Fix bug with file open");
contentList.Add("BugFix1 = Fix crash when opening large files");
contentList.Add("BugFix2 = Fix bug with search in file feature");
contentList.Add("FilePath = % ProgramFiles %\\MyEditor\\MyEditor.exe");
contentList.Add("Version = 4.5");
return contentList;
}
public DataItem GetDataItem(string value)
{
var parts = value.Split('=');
var dataItem = new DataItem()
{
DataType = parts[0],
Data = parts[1]
};
return dataItem;
}
public class DataItem
{
public string DataType;
public string Data;
}
The given answer only focuses on the first part, converting the data to a structure that can be shaped for display. But I think you main question is how to do the actual shaping.
I used a somewhat different way to collect the file data, using Microsoft.VisualBasic.FileIO.TextFieldParser because I think that makes coding just al little bit easier:
Iterator Function GetTwoItemLines(fileName As String, delimiter As String) _
As IEnumerable(Of Tuple(Of String, String))
Using tfp = New TextFieldParser(fileName)
tfp.TextFieldType = FieldType.Delimited
tfp.Delimiters = {delimiter}
tfp.HasFieldsEnclosedInQuotes = False
tfp.TrimWhiteSpace = False
While Not tfp.EndOfData
Dim arr = tfp.ReadFields()
If arr.Length >= 2 Then
Yield Tuple.Create(arr(0).Trim(), String.Join(delimiter, arr.Skip(1)).Trim())
End If
End While
End Using
End Function
Effectively the same thing happens as in your code, but taking into account Andrew's keen caution about data loss: a line is split by = characters, but the second field of a line consists of all parts after the first part with the delimiter re-inserted: String.Join(delimiter, arr.Skip(1)).Trim().
You can use this function as follows:
Dim fileContent = GetTwoItemLines(file, "=")
For display, I think the best approach (most efficient in terms of lines of code) is to group the lines by their first items, removing the numeric part at the end:
Dim grouping = fileContent.GroupBy(Function(c) c.Item1.TrimEnd("0123456789".ToCharArray())) _
.Where(Function(k) k.Key = "Feature" OrElse k.Key = "BugFix" OrElse k.Key = "Enhancement")
Here's a Linqpad dump (in which I took the liberty to change one item a bit to demonstrate the correct dealing with multiple = characters:
You could do it with Regular Expressions:
Imports System.Text.RegularExpressions
Private Function InfoReader(ByVal sourceText As String) As List(Of Dictionary(Of String, String()))
'1) make array of fragments for each product info
Dim products = Regex.Split(sourceText, "(?=\[\s*\w+\s*])")
'2) declare variables needed ahead
Dim productProperties As Dictionary(Of String, String)
Dim propertyNames As String()
Dim productGroupedProperties As Dictionary(Of String, String())
Dim result As New List(Of Dictionary(Of String, String()))
'2) iterate along fragments
For Each product In products
'3) work only in significant fragments ([Product]...)
If Regex.IsMatch(product, "\A\[\s*\w+\s*]") Then
'4) make array of property lines and extract dictionary of property/description
productProperties = Regex.Split(product, "(?=^\w+\s*=)", RegexOptions.Multiline).Where(
Function(s) s.Contains("="c)
).ToDictionary(
Function(s) Regex.Match(s, "^\w+(?=\s*=)").Value,
Function(s) Regex.Match(s, "(?<==\s+).*(?=\s+)").Value)
'5) extract distinct property names, ignoring numbered repetitions
propertyNames = productProperties.Keys.Select(Function(s) s.TrimEnd("0123456789".ToCharArray)).Distinct.ToArray
'6) make dictionary of distinctProperty/Array(Of String){description, description1, ...}
productGroupedProperties = propertyNames.ToDictionary(
Function(s) s,
Function(s) productProperties.Where(
Function(kvp) kvp.Key.StartsWith(s)
).Select(
Function(kvp) kvp.Value).ToArray)
'7) enlist dictionary to result
result.Add(productGroupedProperties)
End If
Next
Return result
End Function

"PDM" is "not declared" as a class of SqlClient.SqlDataReader

My code below won't compile, the error message saying that PDM is not declared. I'm trying to call a SQL Server stored procedure from vb.net, and the code I have seems to match similar examples that I've found. Why doesn't the PDM part work for me?
Public Function ReturnPointSource(ByVal PlantName)
Dim TempList = New ArrayList
Dim sqlDR As SqlClient.SqlDataReader = PDM.Data.SqlHelper.ExecuteReader(GLOBALS.ConnectionString, "sp_readLocation")
If sqlDR.HasRows Then
While sqlDR.Read()
Dim Loc As New Location
Loc.strFID = sqlDR(0)
Loc.strFeature = sqlDR(1).ToString
Loc.intPlantNo = sqlDR(2).ToString
Loc.strPlantName = sqlDR(3).ToString
Loc.strMunicipality = sqlDR(4).ToString
Loc.strRegion = sqlDR(5).ToString
Loc.strOperator = sqlDR(6).ToString
Loc.strDistrict = sqlDR(7).ToString
Loc.strWatercourse = sqlDR(8).ToString
Loc.dblCapacity = sqlDR(9).ToString
Loc.dblPopulation = sqlDR(10).ToString
Loc.strOwnership = sqlDR(11).ToString
Loc.strOwnerClass = sqlDR(12).ToString
Loc.strCofNum = sqlDR(13).ToString
Loc.strComments = sqlDR(14).ToString
Loc.dblLatitude = sqlDR(15).ToString
Loc.dblLongitude = sqlDR(16).ToString
Loc.strSource_Point = sqlDR(17).ToString
Loc.intSeverity = sqlDR(18).ToString
Loc.dblSafe_buffer_distance_m = sqlDR(19).ToString
TempList.Add(Loc)
End While
End If
Return TempList
End Function
If you've taken that directly from an example then PDM would be something that they have defined themselves. It's not something that is part of the .NET Framework. I'm guessing that PDM is the author and SqlHelper is a class in their PDM.Data namespace.
If you want to get a data reader then you create a SqlCommand and then call ExecuteReader on it. That is what that PDM.Data.SqlHelper will be doing internally.

update dataset command

I have a dataset and I'm adding new rows, and then I'm updating the database behind the dataset using the following command:
DataSetReasons ds = new DataSetReasons();
DataSetReasonsTableAdapters.Data_Tracker_RcodeTableAdapter dta = new DataSetReasonsTableAdapters.Data_Tracker_RcodeTableAdapter();
DataSetReasons.Data_Tracker_RcodeDataTable GRX =
new DataSetReasons.Data_Tracker_RcodeDataTable();
DataRow rowx = GRX.NewRow();
rowx[0] = 111;
rowx[1] = 28;
rowx[2] = "C";
rowx[3] = 12;
rowx[4] = "C";
rowx[5] = 16;
rowx[6] = TextBox2.Text;
GRX.Rows.Add(rowx); //<--- adding the row
dta.Update(GRX); //<-- updating the DB
now everything works fine, except that I want to put the update command in a separate button. when I do so, the DB update are not happening.
any idea?
Solved, I was missing the "static" word before defining the data table.
Many thanks to whoever passed on this question.

problem with update strong typed dataset turn to database in C# .net framework 3.5

I want to remove some special characters in a table of database. I've used strong typed table to do it. When i got all data into dataset from database and modified it then i called method update() of data adapter to turn dataset to database but it doesn't work.
Below is my code
DsTel tel = new DsTel();
DsTelTableAdapters.telephone_bkTableAdapter adapter = new DsTelTableAdapters.telephone_bkTableAdapter();
adapter.Connection = new SqlConnection(ConfigurationManager.AppSettings["SiteSqlServer"].ToString());
adapter.Fill(tel.telephone_bk);
foreach (DsTel.telephone_bkRow row in tel.telephone_bk.Rows)
{
row.telephoneNo = RemoveWhiteSpace(row.telephoneNo.ToString());
row.AcceptChanges();
}
tel.AcceptChanges();
adapter.Update(tel.telephone_bk);
Please give me some ideas?
Thanks in advance.
I've found the solution for this problem by using the TableAdapterManager.
Below is my code:
DsTel tel = new DsTel();
DsTelTableAdapters.telephone_bkTableAdapter adapter = new DsTelTableAdapters.telephone_bkTableAdapter();
adapter.Connection = new SqlConnection(ConfigurationManager.AppSettings["SiteSqlServer"].ToString());
adapter.Fill(tel.telephone_bk);
foreach (DsTel.telephone_bkRow row in tel.telephone_bk.Rows)
{
if (!row.IstelephoneNoNull())
{
row.telephoneNo = RemoveWhiteSpace(row.telephoneNo.ToString());
}
}
DsTelTableAdapters.TableAdapterManager mrg = new DsTelTableAdapters.TableAdapterManager();
mrg.telephone_bkTableAdapter = adapter;
mrg.BackupDataSetBeforeUpdate = true;
mrg.UpdateAll((DsTel)tel.GetChanges());
You've called AcceptChanges before the update. This means the dataset has no changes any more so there is nothing to send to the database.
Remove all of the calls to AcceptChanges and add one AFTER the update. ie:
DsTel tel = new DsTel();
DsTelTableAdapters.telephone_bkTableAdapter adapter = new DsTelTableAdapters.telephone_bkTableAdapter();
adapter.Connection = new SqlConnection(ConfigurationManager.AppSettings["SiteSqlServer"].ToString());
adapter.Fill(tel.telephone_bk);
foreach (DsTel.telephone_bkRow row in tel.telephone_bk.Rows)
{
row.telephoneNo = RemoveWhiteSpace(row.telephoneNo.ToString());
}
adapter.Update(tel.telephone_bk);
tel.telephone_bk.AcceptChanges();

Resources