I am working on some project ( VB.Net & SQL Server ) where I have
Patient & Appointment scenario.
These are the public declarations:
Dim DS As New DataSet
Dim SqlAdap, SqlAdapAppointment As SqlDataAdapter
Dim BindSrc, BindSrcAppointment As New BindingSource
and I set the binding in the Load event:
SqlAdap = New SqlDataAdapter(String.Format("select * from {0}",Patient),SqlConMain)
SqlAdap.Fill(DS,"Patient")
Dim SqlCmd As New SqlCommandBuilder(SqlAdap)
SqlAdap.InsertCommand = SqlCmd.GetInsertCommand
SqlAdap.DeleteCommand = SqlCmd.GetDeleteCommand
SqlAdap.UpdateCommand = SqlCmd.GetUpdateCommand
BindSrc.DataSource = DS
BindSrc.DataMember = "Patient"
BindNavMain.BindingSource = BindSrc
SqlAdapAppointment = New SqlDataAdapter("select * from Appointment", SqlConMain)
SqlAdapAppointment.Fill(DS, "Appointment")
Dim SqlCmdAppointment As New SqlCommandBuilder(SqlAdapAppointment)
SqlAdapAppointment.InsertCommand = SqlCmdAppointment.GetInsertCommand
SqlAdapAppointment.DeleteCommand = SqlCmdAppointment.GetDeleteCommand
SqlAdapAppointment.UpdateCommand = SqlCmdAppointment.GetUpdateCommand
Dim Rel As New DataRelation("FK_Patient_Appointment",
DS.Tables("Patient").Columns("PatientId"),
DS.Tables("Appointment").Columns("PatientId"), False)
Rel.Nested = False
DS.Relations.Add(Rel)
BindSrcAppointment.DataSource = BindSrc
BindSrcAppointment.DataMember = "FK_Patient_Appointment"
BindNavAppointment.BindingSource = BindSrcAppointment
everything works well ..
but if I added new patient using its BindingNavigator, then added an appointment for him using the appointment's BindingNavigator
then I tried to save all of it, it will save the patient data successfully but will throw an error after, because it couldn't save the appointment data that its related to the new patient ID
this is my save code:
BindSrcAppointment.EndEdit()
BindSrc.EndEdit()
Dim TblPatient As DataTable = DS.Tables("Patient").GetChanges()
If TblPatient IsNot Nothing Then
SqlAdap.Update(TblPatient)
DS.Tables("Patient").AcceptChanges()
End If
Dim TblAppointment As DataTable = DS.Tables("Appointment").GetChanges()
If TblAppointment IsNot Nothing Then
SqlAdapAppointment.Update(TblAppointment)
DS.Tables("Appointment").AcceptChanges()
End If
It saves successfully of course if I tried to add appointment to some patient who has data already been saved to the DB
but I want to know if there a way to save data of 2 Adapters at once sequentially?
I use SqlDataAdapter.RowUpdated event to 'catch' the identity of the most recently added record, but it seems that there are a lot of different possibilities:
http://www.mikesdotnetting.com/article/54/getting-the-identity-of-the-most-recently-added-record
So you have to update Patient table, retrieve the most recently added record's autoincrement identity value and then update Appointment table.
Related
I have written a stored procedure which gives me result from 3 tables separately. Please have a look on the screenshot.
DataTable dataTable = ds.Tables[0]; gives me top result from screenshot, DataTable dataTable = ds.Tables[1]; gives me middle one from screenshot and ds.Tables[2]; gives me last one.
Now, I want to get all the table information. Please have a look on my code. I am not getting the result.
System.ArgumentException: 'Column 'race_header' does not belong to
table Table2.'
Please provide the solutions for this.
public List<ClsStakesRaces> RaceNameDetails(int? Id)
{
List<ClsStakesRaces> clsStakes = new List<ClsStakesRaces>();
SqlParameter[] prms = new SqlParameter[1];
string sSQL;
sSQL = "exec StakesRacesGetRaceDetails #Id";
prms[0] = new SqlParameter("#Id", SqlDbType.Int);
prms[0].Value = Id;
ds = clsUtilities.CreateCommandwithParams(sSQL, prms);
DataTable dataTable = new DataTable();
dataTable = ds.Tables[0];
dataTable= ds.Tables[1];
dataTable = ds.Tables[2];
foreach (DataRow dr in dataTable.Rows)
{
clsStakes.Add(
new ClsStakesRaces
{
RaceName = Convert.ToString(dr["race_header"]),
HorseId = Convert.ToInt32(dr["HorseID"]),
Horse = Convert.ToString(dr["Horse"]),
Details = Convert.ToString(dr["Details"]),
Breeding = Convert.ToString(dr["Breeding"]),
Earning = Convert.ToDecimal(dr["Earning"]),
PreviousWinner = Convert.ToString(dr["PreviousWinners"])
});
}
return clsStakes;
}
Looking at your code:
DataTable dataTable = new DataTable();
dataTable = ds.Tables[0]; // actually, forget the new DataTable() bit, changed my mind, point to ds.Tables[0] instead
dataTable= ds.Tables[1]; // actually, forget ds.Tables[0], point to ds.Tables[1] instead
dataTable = ds.Tables[2]; // actually, forget ds.Tables[1], point to ds.Tables[2] instead
So then
foreach (DataRow dr in dataTable.Rows)
is actually
foreach (DataRow dr in ds.Tables[2].Rows)
Your third table (ds.Tables[2]) doesn't have a column called race_header, hence your error.
You probably want to return a single statement based upon a JOIN condition in the SQL stored procedure. If you can't do that for some reason, you will need to iterate each of ds.Tables separately, stitching the objects together in memory.
I am new to LINQ query and writing a SSIS script task to read data from two data tables.
I have created the following query, where I want to output to be sent by an email as a table. The body of the email will be the output.
I am able to see the result. But dont know how to use this data (New to linq).
Here is my code:-
Dim Filename As String
Dim Filepath As String
Dim i As Integer
Filename = "TM_xxx_DAILY_*" + Dts.Variables("User::VLoaddt").Value.ToString + "_*.txt"
Filepath = Dts.Variables("User::vSrcFolder").Value.ToString
Dim di As DirectoryInfo = New DirectoryInfo(Filepath)
Dim fi As FileInfo() = di.GetFiles(Filename)
Dim DestTab As DataTable
DestTab = New DataTable("DestinationTable")
Dim column As DataColumn = New DataColumn("Dest")
column.DataType = System.Type.GetType("System.String")
DestTab.Columns.Add(column)
DestTab.Rows.Add("TM_xxx_ONLINE")
DestTab.Rows.Add("TM_xxx_RETAIL")
DestTab.Rows.Add("TM_xxx_TELESALES")
DestTab.Rows.Add("TM_xxx_DAILY_DEVICE")
Dim SrcTab As DataTable
SrcTab = New DataTable("SourceTable")
Dim column1 As DataColumn = New DataColumn("Source")
column1.DataType = System.Type.GetType("System.String")
Dim column2 As DataColumn = New DataColumn("FileExists")
column2.DataType = System.Type.GetType("System.String")
SrcTab.Columns.Add(column1)
SrcTab.Columns.Add(column2)
For i = 0 To fi.Length - 1
SrcTab.Rows.Add(Left(fi.GetValue(i).ToString, Len(fi.GetValue(i).ToString) - 20), "Exists")
Next
Dim query =
From a In DestTab
Group Join b In SrcTab
On a.Field(Of String)("dest") Equals b.Field(Of String)("Source")
Into Group
Let b = Group.FirstOrDefault
Select dest = a.Field(Of String)("dest"), FileExists = If(b Is Nothing, "Missing", b.Field(Of String)("FileExists"))
The biggest challenge and I am not able to understand how to use the variable "query" in "Dim query". While examples in the net and able to use it as a datarow, copytodatatable and other. I can only see tostring,equals and things like that.
My objective is to read files in a folder join it with "Destinationtable" and find the missing ones.
The codes written below are the one right after the select statement
Error Screenshots
I think you should use
For each line in query.ToList()
Dim drRow as DataRow
drRow = MT.NewRow
drRow("Filename") = line.Item(0)
MT.Rows.Add(drRow)
Next
Instead of
For each line in query
MT.Rows.Add(query)
Next
I have a datagrid view which loads data from a data table
This data table is filled with data from a SQL Server database
When the user loads an invoice, I fill a data grid view from this datatable
I then allow the user to modify the invoice, this will include adding/editing/deleting rows from the data table
This data table is then updated to the database when the user presses a save button
I need a way of detecting the row status so that it updates the database correctly
I am able to add a row no problem
However is the user tries to delete a row which was fetched from the database it removes it from the data table, but does not remove it from the database
Furthermore, I need to allow for users to add a row and then delete it without the row ever existing in a database
Here is the code I currently use
Dim boolAdded As Boolean = False
Dim boolDeleted As Boolean = False
Dim boolChanged As Boolean = False
Dim cB As SqlCommandBuilder = New SqlCommandBuilder(SQLAdaptor)
Con.ConnectionString = CropTrackMod.strConn
SQLAdaptor.SelectCommand = New SqlClient.SqlCommand("Select * FROM TicketDetailv2 where ticketref ='" & strEditTicketRef & "'", Con)
For Each row As DataRow In myTable.Rows
If row.RowState = DataRowState.Added Then
boolAdded = True
End If
If row.RowState = DataRowState.Deleted Then
boolDeleted = True
End If
If row.RowState = DataRowState.Modified Then
boolChanged = True
End If
Next
If boolAdded = True Then
Dim tmpAddedMyTable As DataTable = myTable.GetChanges(DataRowState.Added)
If tmpAddedMyTable.Rows.Count >= 0 Then
For Each row As DataRow In tmpAddedMyTable.Rows
row.Item("TicketRef") = strEditTicketRef
Next
SQLAdaptor.InsertCommand = cB.GetInsertCommand
SQLAdaptor.Update(tmpAddedMyTable)
End If
End If
If boolChanged = True Then
Dim tmpChangedMyTable As DataTable = myTable.GetChanges(DataRowState.Modified)
SQLAdaptor.InsertCommand = cB.GetUpdateCommand
SQLAdaptor.Update(tmpChangedMyTable)
End If
If boolDeleted = True Then
Dim tmpDeletedMyTable As DataTable = myTable.GetChanges(DataRowState.Deleted)
SQLAdaptor.InsertCommand = cB.GetDeleteCommand
SQLAdaptor.Update(tmpDeletedMyTable)
End If
Any help would be appreciated
Thanks in advance guys
I have now fixed the error of my ways
The issue was being caused because i was removing the row from the dataTable like this
myTable.Rows.RemoveAt(dgvTicketDetail.CurrentCell.RowIndex)
however if i delete the row like this it works
myTable.Rows(dgvTicketDetail.CurrentCell.RowIndex).Delete()
This works because it marks the row for deletion until an update occurs.
I did have to improve the logic when iterating through the rows in the table in an effort not to include the deleted rows. This was achieved by:
for each row as datarow in myTable.rows
if not row.rowstate = datarowstate.deleted then
end if
next
(I should say that im fairly new to vb.net)
I'm having a problem overwriting the entries in my database. I think the problem is that SqlDataAdapter.Update isn't overwriting the database properly with the new datatable info that i've created.
As I understand it, it should totally replace the the info in the database with the datatable when i tell it to update... no?
Here's the problem in a nutshell:
Basically, I have a database (.mdf file) with a table in it called 'test'. I've used SqlDataAdapter to make a dataset using 'test'. I have another datatable that I've made from parsing in a csv - it's called 'ToLoad'. I now want to clear the 'test' datatable, copy in all entries from the csv datatable, then save this to the database.
I've debugged all this and it all seems to work ok, except when I use SqlDataAdapter.Update I get an error telling me I cant duplicate the primary key. This is because the old entries aren't being cleared from the database entirely, before the new ones are being entered from the datatable.
I've checked that the test datatable is being actually cleared early on in the code... and it is.
I've checked that the new csv entries are being copied to the 'test' datatable... and they are.
Any help you can give on this would be really appreciated
Thanks
Craig
'MAKE A NEW SQL CONNECTION
Dim DBConnection As New SqlConnection
'SET THE CONNECTION STRING.
DBConnection.ConnectionString = "Data Source=(LocalDB)\MSSQLLocalDB;AttachDbFilename=C:\Project\Members.mdf;Integrated Security=True"
'OPEN THE CONNECTION TO THE DATABASE
DBConnection.Open()
'OPEN AN ADAPTER AND SELECT EVERYTHING FROM THE 'TEST' TABLE
Dim mySqlDataAdapter As New SqlDataAdapter("SELECT * FROM Test", DBConnection)
Dim mySqlCommandBuilder As New SqlCommandBuilder(mySqlDataAdapter)
Dim DBDataset As DataSet = New DataSet
'FILL THE DATASET WITH THE TEST TABLE
mySqlDataAdapter.Fill(DBDataset, "Test")
'CLEAR ALL ENTRIES IN THE DATATABLE (SO I CAN FILL IT FROM SCRATCH)
DBDataset.Tables("test").Clear()
''SET UP A LOOP TO ADD EACH RECORD FROM THE CSV DATATABLE TO THE DATABASE DATATABLE
Dim CSV_row_number As Int16
CSV_row_number = ds.Tables("toload").Rows.Count
Dim i As Int16
i = 0
Do Until i = CSV_row_number - 1
'MAKES TWO NEW DATAROW OBJECTS
Dim DB_row As DataRow
Dim CSV_row As DataRow
'SET THE CSV_ROW OBJECT EQUAL TO ROW(i) OF THE CSV DATATABLE
CSV_row = ds.Tables("toload").Rows(i)
DB_row = DBDataset.Tables("test").NewRow()
'THIS SETS ALL OF THE COLUMNS IN THIS NEW ROW AS EQUAL TO ROW1 IN THE CSV DATATABLE
DB_row("Name") = CSV_row("Name")
DB_row("Quality") = CSV_row("Address")
DBDataset.Tables("test").Rows.Add(DB_row)
i = i + 1
Loop
mySqlDataAdapter.Update(DBDataset.Tables("Test"))
I managed to fix this myself after a fair bit of googling and some trial and error. Posting my code in case it's useful for anyone else
Craig
'MAKE A NEW SQL CONNECTION
Dim DBConnection As New SqlConnection
'SET THE CONNECTION STRING. YOU GET THIS BY GOING TO SERVER EXPLORER, THEN CLICKING ON THE DATABASE
'THE CONNECTION STRING IS IN PROPERTIES
DBConnection.ConnectionString = "Data Source=(LocalDB)\MSSQLLocalDB;AttachDbFilename=C:\Users\ME\Project\Members.mdf;Integrated Security=True"
'OPEN THE CONNECTION TO THE DATABASE
DBConnection.Open()
'THIS OPENS AN ADAPTER TO THE DATABASE, AND SELECTS EVERYTHING FROM THE 'TEST' TABLE IN THAT DATABASE
Dim mySqlDataAdapter As New SqlDataAdapter("SELECT * FROM MemberList", DBConnection)
'THIS LETS US USE SQL ON THE DATATABLE (IT GETS PASSED THE ABOVE SQL STATEMENT)
Dim mySqlCommandBuilder As New SqlCommandBuilder(mySqlDataAdapter)
'THIS MAKES ANOTHER NEW DATASET
Dim DBDataset As DataSet = New DataSet
''THIS FILLS THAT DATASET WITH THE TEST TABLE (WHICH THE DATA ADAPTOR GRABBED ABOVE)
mySqlDataAdapter.FillSchema(DBDataset, SchemaType.Source, "MemberList")
mySqlDataAdapter.Fill(DBDataset, "MemberList")
'THIS MAKES A NEW DATATABLE
'I THEN MAKE ALL CHANGES NEEDED
Dim EDITmembers As DataTable
EDITmembers = DBDataset.Tables("MemberList")
''FIRST, IM GOING TO CLEAR ALL ENTRIES IN THE DATATABLE (SO I CAN FILL IT FROM SCRATCH)
'COUNT THE NUMBER OF ENTRIES TO CLEAR
Dim RowsInDB As Integer
RowsInDB = EDITmembers.Rows.Count()
'SET UP A LOOP TO CLEAR THEM
Dim Data_row As DataRow
Dim k As Integer = 0
Do Until k = RowsInDB
Data_row = EDITmembers.Rows(k)
Data_row.Delete()
k = k + 1
Loop
'ONCE ALL THE ROWS ARE CLEARED, SAVE THE CHANGES BY UPDATING THE ACTUAL DATABASE
mySqlDataAdapter.Update(DBDataset, "MemberList")
''THEN I SET UP A LOOP TO ADD EACH RECORD FROM THE CSV DATATABLE TO THE DATABASE DATATABLE
''I FIRST NEED TO KNOW HOW MANY ITERATIONS OF THE LOOP TO DO
Dim CSV_row_number As Int16
'COUNT THE NUMBER OF ROWS AND SET THE ABOVE INT EQUAL TO THIS
CSV_row_number = ToLoad.Rows.Count
Dim j As Int16
j = 0
Do Until j = CSV_row_number - 1
'THIS MAKES TWO NEW DATAROW OBJECTS
Dim DB_row As DataRow
Dim CSV_row As DataRow
'THIS SETS THE CSV_ROW OBJECT EQUAL TO THE FIRST ROW OF THE CSV DATATABLE
CSV_row = ToLoad.Rows(j)
'THIS SETS DB_ROW EQUAL TO A NEW ROW IN THE DATATABLE MADE FROM THE DATABASE
DB_row = EDITmembers.NewRow()
'THIS SETS ALL OF THE COLUMNS IN THIS NEW ROW AS EQUAL TO THE CORRESPONDING ROW IN THE CSV DATATABLE
DB_row("Contact Name") = CSV_row("Contact Name")
DB_row("Do not mail") = CSV_row("Do not mail")
DB_row("Membership Type") = CSV_row("Membership Type")
DB_row("Street Address") = CSV_row("Street Address")
DB_row("Supplemental Address 1") = CSV_row("Supplemental Address 1")
DB_row("Supplemental Address 2") = CSV_row("Supplemental Address 2")
DB_row("City") = CSV_row("City")
DB_row("Postal Code") = CSV_row("Postal Code")
DB_row("Email") = CSV_row("Email")
DB_row("Phone (primary)") = CSV_row("Phone (primary)")
EDITmembers.Rows.Add(DB_row)
j = j + 1
Loop
'UPDATE THE DATABASE WITH ALL THE CHANGES
mySqlDataAdapter.Update(DBDataset, "MemberList")
MessageBox.Show("done!")
I am making a vb .net winform project that uses a sql server database. A user inputs the details of a person (firstName, lastName, company, contactNumber, etc.) visiting a factory into textboxes, hits the save details button, and this saves the data in the datatable. This works fine, the problem is the next part. The user is then redirected to another form where the input details are shown from the database. This works for the first record but not for any record input after that, I get an error that says "There is no row at position 'n'" and the following line of code is highlighted in the form_Load:
txtFirstName.Text = CStr(dtVisitorDetails.Rows(CInt(CDbl(txtIdNumber.Text) - 1)).Item(1))
It is telling me that any rows after row 0 are not there but I know they are because I have input them and they are showing up in the datatable in the sql server database manager.
I cannot sort this problem, any help with this would be greatly appreciated. I am attaching the rest of the code that's involved with this problem.
Thanks in advanced.
Private Sub previousVisitor_Load(sender As Object, e As EventArgs) Handles MyBase.Load
connectionString = "Data Source=.\SQLExpress;InitialCatalog=Visitors;" & _
"IntegratedSecurity=True;MultipleActiveResultSets=True"
sqlVisitorDetails = "SELECT * FROM visitorDetails WHERE idNumber=#idNumber"
sqlCon.Open()
sqlCmd = New SqlCommand(sqlVisitorDetails, sqlCon)
sqlCmd.Parameters.AddWithValue("#idNumber", txtIdNumber.Text)
dtVisitorDetails = loadDtVisitorDetails()
txtFirstName.Text = CStr(dtVisitorDetails.Rows(CInt(CDbl(txtIdNumber.Text) - 1)).Item(1))
txtLastName.Text = CStr(dtVisitorDetails.Rows(CInt(CDbl(txtIdNumber.Text) - 1)).Item(2))
txtCompany.Text = CStr(dtVisitorDetails.Rows(CInt(CDbl(txtIdNumber.Text) - 1)).Item(3))
txtContactNumber.Text = CStr(dtVisitorDetails.Rows(CInt(CDbl(txtIdNumber.Text) - 1)).Item(4))
txtCountryCode.Text = CStr(dtVisitorDetails.Rows(CInt(CDbl(txtIdNumber.Text) - 1)).Item(5))
txtEmail.Text = CStr(dtVisitorDetails.Rows(CInt(CDbl(txtIdNumber.Text) - 1)).Item(7))
sqlCmd.Dispose()
sqlCon.Close()
End Sub
Private Function loadDtVisitorDetails() As DataTable
Dim dtVisitorDetails As DataTable = Nothing
sqlVisitorDetails = "SELECT * FROM visitorDetails WHERE idNumber=" & txtIdNumber.Text
dtVisitorDetails = fillDtVisitorDetails(sqlVisitorDetails)
Return dtVisitorDetails
End Function
Public Function fillDtVisitorDetails(ByVal sqlVisitorDetails As String) As DataTable
Dim dtVisitorDetails As New DataTable
Dim da As New SqlDataAdapter
Dim conCmd As New SqlCommand
conCmd.CommandText = sqlVisitorDetails
da.SelectCommand = conCmd
da.SelectCommand.Connection = sqlCon
dtVisitorDetails.Columns.GetEnumerator()
da.Fill(dtVisitorDetails)
Return dtVisitorDetails
End Function
Since you can only have 1 row for each unique ID number, when you search and filter as WHERE idNumber = ID Number in form, you should get at most 1 record. That means the DataTable can have at most 1 row.
When you access the Rows of a DataTable like dt.Rows(ID), you are trying to access the row at position number ID in the collection of rows. Therefore, when you do dtVisitorDetails.Rows(CInt(CDbl(txtIdNumber.Text) - 1) for any value of ID number greater than 1, it will fail because that index simply does not exist in the table.
Instead, you should directly use dtVisitorDetails.Rows(0) to access the row. Since you have filtered by the ID Numberm you will only get the details for that person by doing so. Finally, remember to add a check for the row count in the table, so that if you search for an ID which has no records, there will not be an error in trying to retrieve from the table.
Pseudo-code:
If dtVisitorDetails.Rows.Count > 0
txtFirstName.Text = CStr(dtVisitorDetails.Rows(0).Item(1))
...
End If