I got two tables in my access file. and I would like to create relationship between them. The following diagram is the relationship I created manually in Access.
However, I want to create the relationships in VB.net and here is my code:
conn.Open()
daBooks = New OleDb.OleDbDataAdapter("SELECT * FROM Books", conn)
daAuthor = New OleDb.OleDbDataAdapter("SELECT * FROM authors", conn)
daBooks.Fill(ds, "Books")
daAuthor.Fill(ds, "authors")
conn.Close()
'Set the relation
Dim parentColumn As DataColumn
parentColumn = ds.Tables("authors").Columns("AuthorID")
Dim childColumn As DataColumn = New DataColumn
Try
childColumn = ds.Tables("Books").Columns("AuthorID")
Catch ex As Exception
MsgBox(ex.Message)
Exit Sub
End Try
Dim a As String
a = ds.Tables("authors").Rows(0).Item("AuthorID")
Dim b As String
b = ds.Tables("Books").Rows(0).Item("AuthorID")
Dim relation As DataRelation = New _
System.Data.DataRelation("Books_Authors", parentColumn, childColumn)
ds.Relations.Add(relation)
RelationName.Text = relation.RelationName
'End of setting relation
Dim cb1 As New OleDb.OleDbCommandBuilder(daBooks)
Dim cb2 As New OleDb.OleDbCommandBuilder(daAuthor)
Try
daBooks.Update(ds, "books")
Catch ex As Exception
MsgBox(ex.Message)
End Try
daAuthor.Update(ds, "authors")
However after I ran the code, it couldn't change the database. Can anyone help me with this so that I can create a new relationship for two tables in VB.NET.
Generally I think the problem is that the System.Data.DataRelation and ds.Relations.Add(relation) just create the relationship for the dataset but it hasn't been updated to the database through dataadapter or something else. Am I correct by saying so or it's because of other reasons. If I'm correct, then how to update the dataset to database?
You can create that relationship by executing an ALTER TABLE statement from your OleDb connection.
ALTER TABLE Books
ADD CONSTRAINT BooksRelationship
FOREIGN KEY (AuthorID) REFERENCES Authors (AuthorID);
You can create a macro in Access that creates a relationship between your tables and run it via VB.NET.
Here is a function to create a relation in MS Access:
Public Function MacroCreateRelation()
Dim db As DAO.Database
CreateRelation("Author", "IdAuthor", _
"Book", "IdAuthor")
Set db = Nothing
End Function
Private Function CreateRelation(primaryTblName As String, _
primaryFieldName As String, _
foreignTblName As String, _
foreignFieldName As String) As Boolean
On Error GoTo ErrHandler
Dim myDB As DAO.Database
Dim newRelation As DAO.Relation
Dim relatingField As DAO.Field
Dim relationName As String
relationName = primaryTblName + "_" + primaryFieldName + _
"__" + foreignTblName + "_" + foreignFieldName
Set myDB = CurrentmyDB()
' First create the relation
Set newRelation = myDB.CreateRelation(relationName, _
primaryTblName, foreignTblName)
'field of the primary table
Set relatingField = newRelation.CreateField(primaryFieldName)
'Then the field of the the second table
relatingField.ForeignName = foreignFieldName
'now just add the field to the relation
newRelation.Fields.Append relatingField
'Last but not least add the relation to the db
myDB.Relations.Append newRelation
Set myDB = Nothing
return True
Exit Function
ErrHandler:
Debug.Print Err.Description + " [ " + relationName + "]"
return False
End Function
Then you have just to call the macro from VB.NET.
Related
I'm quite new to VB .Net and Databases in general so I'm not sure which SQL Version I am using. I did most of my coding until now with VBA.
I added a "Service Based Database" to my "WinFormsApp" Project and created a Table with 3 Columns:
CREATE TABLE [dbo].[employees] (
[id] INT IDENTITY (1, 1) NOT NULL,
[nr] VARCHAR (MAX) NULL,
[name] TEXT NULL,
PRIMARY KEY CLUSTERED ([id] ASC)
);
Afterwards I added a Dataset for the created Table.
Following this, I added a new Form to my Project and added a few controls to it including two TextBoxes for Dataentry and a DataGridView to show the saved data. On Form_Load I fill the DataGridView using the following code:
Private Sub UpdateGridView()
'Loading the data into the GridView
'---------------------------------------
Dim Conn As SqlConnection = New SqlConnection
Dim ADP As SqlDataAdapter
Dim DS As DataSet = New DataSet
Conn.ConnectionString = My.Settings.DBConnEmployees
ADP = New SqlDataAdapter("SELECT * FROM employees", Conn)
ADP.Fill(DS)
Me.DataGridView_Employees.DataSource = DS.Tables(0)
'---------------------------------------
'Hidding the ID Col
Me.DataGridView_Employees.Columns(0).Visible = False
End Sub
Also in the Form_Load I set a few unrelated variables and TextBoxes (as I'm not able to find the errors after several hour of trial and error, I include this. Maybe I'm overlooking something):
Private Sub NewEmployee()
'Reseting the Variables
DataGridIndex = -1
EmployeeId = 0
EmployeeNr = String.Empty
EmployeeName = String.Empty
'Writing to TBs
Me.tbNr.Text = EmployeeNr
Me.tbName.Text = EmployeeName
'Select Nothing
Me.DataGridView_Employees.CurrentCell = Nothing
'Changing Btn Desc
Me.btnSaveEmployee.Text = "Neuen Mitarbeiter speichern"
End Sub
The testing data I entered into the table by hand fills in without a problem. Inserting, updating an deleting into/from the table by code works perfect.
On DataGrivView_CellDoubleClick I read some data of the the GridView into the TextBoxes to edit them:
Private Sub DataGridView_Employees_CellDoubleClick(sender As Object, e As DataGridViewCellEventArgs) Handles DataGridView_Employees.CellDoubleClick
If e.RowIndex <> -1 Then
'Loading selected Data
DataGridIndex = e.RowIndex
EmployeeId = Me.DataGridView_Employees.Rows(DataGridIndex).Cells(0).Value
EmployeeNr = Me.DataGridView_Employees.Rows(DataGridIndex).Cells(1).Value
EmployeeName = Me.DataGridView_Employees.Rows(DataGridIndex).Cells(2).Value
'Write to TBs
Me.tbNr.Text = EmployeeNr
Me.tbName.Text = EmployeeName
'Changing btn
Me.btnSaveEmployee.Text = "Ă„nderungen speichern"
End If
End Sub
To prevent the User from using the nr twice I wanted to check if the nr is already saved in the Table. However this is where the problems begin. The SQLCommand only finds the row which i double clicked in the GridView. Which is strange as there should be no connection between them. Hereafter my try at checking for the nr:
Private Function EmployeeNrInUse(id As Integer, nr As String) As Boolean
Dim Query As String = String.Empty
Dim Result
Dim Response As Boolean = True
'Checking for nr
'---------------------------------------
Query = "SELECT * FROM employees WHERE nr=#nr"
Using Conn = New SqlConnection(My.Settings.DBConnEmployees)
Using Comm = New SqlCommand()
With Comm
.Connection = Conn
.CommandType = CommandType.Text
.CommandText = Query
.Parameters.AddWithValue("#nr", nr)
End With
Try
Conn.Open()
Result = Comm.ExecuteScalar
Response = Not IsNothing(Result)
Catch ex As SqlException
MsgBox(ex.Message.ToString, vbOKOnly + vbCritical)
End Try
End Using
End Using
'---------------------------------------
'Return
Return Response
End Function
The Result is always returning nothing, unless I double clicked a dataentry before, then it finds it's own row (if the nr matches) but only that, no other matching nr is found.
If I forgot to mention crucial data, please inform me as this is my first question ever in a forum :) (Also please excuse any spelling mistakes etc. as English isn't my native language) Thanks in Advance for your help!
Edit:
This is how the Function EmployeeNrInUse is called (Called on Button_Clicked):
Private Sub SaveEmployeeToDB(id As Integer, nr As String, name As String)
Dim Query As String = String.Empty
'Adding new Employee / Editing existing
'---------------------------------------
If EmployeeNrInUse(id, nr) Then
MsgBox("Nr. bereits in verwendung.", vbOKOnly + vbExclamation)
Exit Sub
End If
If EmployeeId = 0 Then
Query = "INSERT INTO employees (nr, name) VALUES (#nr, #name)"
Else
Query = "UPDATE employees SET nr=#nr, name=#name WHERE id=#id"
End If
Using Conn As New SqlConnection(My.Settings.DBConnEmployees)
Using Comm As New SqlCommand()
With Comm
.Connection = Conn
.CommandType = CommandType.Text
.CommandText = Query
.Parameters.AddWithValue("#id", id) 'Wird nur bei änderung verwendet
.Parameters.AddWithValue("#nr", nr)
.Parameters.AddWithValue("#name", name)
End With
Try
Conn.Open()
Comm.ExecuteNonQuery()
UpdateGridView()
If EmployeeId = 0 Then
MsgBox("Neuen Mitarbeiter gespeichert.", vbOKOnly + vbInformation)
Else
MsgBox("Bestehenden Mitarbeiter aktualisiert.", vbOKOnly + vbInformation)
End If
NewEmployee()
Catch ex As SqlException
MsgBox(ex.Message.ToString, vbOKOnly + vbCritical)
End Try
End Using
End Using
'---------------------------------------
End Sub
The problem was caused by entering the values into the Database by hand. While copying the nr, a linebreak sneaked itself into the values so a check just for the nr instead the nr and the linebreak resulted in nothing. Properly entering the data has fixed the problem.
I'm trying to create columns in an existing access database. The database has already been created, it contains the empty table named "table1", but it does not contain any columns, now I want to add a column into it. But it produces some error.
Arguments are of the wrong type, are out of acceptable range, or are
in conflict with one another.
Imports ADOX
Imports ADOX.DataTypeEnum
Imports ADOX.KeyTypeEnum
Imports System.Data.OleDb
Imports System.Data.SqlClient
Dim database_location As String = Application.UserAppDataPath
Private Sub Button12_Click(sender As Object, e As EventArgs) Handles Button12.Click
insert_columns("DB3", "table1", "Key", adInteger, True, True)
End Sub
Function insert_columns(ByRef Database_file_name As String, ByRef table_name As String, ByRef column_name As String, ByRef data_type As ADOX.DataTypeEnum, Optional ByRef primary_key As Boolean = False, Optional ByRef auto_increment As Boolean = False)
Dim DB_file_name As String = "\" & Database_file_name & ".mdb"
Dim catDB As ADOX.Catalog
Dim tblNew As ADOX.Table
' Dim catstring As String
'Try
catDB = New ADOX.Catalog
' Open the catalog.
catDB.ActiveConnection = "Provider=Microsoft.Jet.OLEDB.4.0;Data Source=" & database_location & DB_file_name
tblNew = New ADOX.Table
' Create a new Table object.
With tblNew
.Name = table_name
.ParentCatalog = catDB
' Create fields and append them to the
' Columns collection of the new Table object.
With .Columns
.Append(column_name, data_type)
If auto_increment = True Then
.Item(column_name).Properties("AutoIncrement").Value = True
End If
If primary_key = True Then
tblNew.Keys.Append("PrimaryKey", KeyTypeEnum.adKeyPrimary, column_name)
End If
End With
End With
' Add the new Table to the Tables collection of the database.
catDB.Tables.Append(tblNew)
'clean up
catDB = Nothing
tblNew = Nothing
Return True
'Catch ex As Exception
' error_entry("Column creation error. Database name: " & DB_file_name & " Column Name: " & column_name & vbNewLine & ex.Message)
' Return False
'End Try
End Function
Argh, didn't read properly that you are using adox. I'll leave the answer just in case.
I used ACE but it should be the same:
Using cmd As New OleDb.OleDbCommand() 'Creates table and columns in it
cmd.Connection = <your connection>
cmd.CommandText = "CREATE TABLE [" & <table_name> & "]([<column_name>] <COLUMN TYPE>, ...repeat)" ' so it looks like "CREATE TABLE [NewTable]([Column1] TEXT, [Columnnnnz2] INTEGER)
cmd.ExecuteNonQuery()
End Using
If you want to add columns independently then Add columns to an Access (Jet) table from .NET
I am writing a program in Access 2013. If it is the first time they will install the program, it will create an external database (that will be linked later) and will create the tables needed. In the attached code, I am running through an array that has a list of all the tables needed and using an internal (local) table that has all the fields associated with the particular table. It runs through the code and creates all the fields just fine, but once it gets to the line db1.TableDefs.Append newTable it throws the Invalid Argument error. I have searched as much as I can and it appears that my setup is the same as all others and cannot figure out what the issue is.
Function CreateDataTables()
Dim db As Database
Dim db1 As Database
Dim rst As Recordset
Dim tblCount As Integer
Dim rst1 As Recordset
Dim newTable As TableDef
Dim newField As Field
Dim newIdx As Index
Dim newType As Variant
Dim newLength As Variant
Dim newPK As String
Dim sysTable As String
Dim SQLstr As String
Dim x As Integer
Dim tblNames() As Variant
Stop
SQLstr = "SELECT DISTINCT tableName "
SQLstr = SQLstr + "FROM sysdata;"
Set db = DBEngine(0)(0)
Set rst = db.OpenRecordset(SQLstr, dbOpenSnapshot, dbSeeChanges)
tblCount = rst.RecordCount
'Creating array to house table names
ReDim tblNames(tblCount)
tblNames() = rst.GetRows(tblCount)
Set db = Nothing
Set rst = Nothing
Set db = DBEngine(0)(0)
Set rst = db.OpenRecordset("sysdata", dbOpenSnapshot, dbSeeChanges)
'Create database reference to newly created database in prior function
Set db1 = OpenDatabase(dbFileLoc)
For x = 1 To tblCount
'Create new tabledef
Set newTable = db1.CreateTableDef(tblNames(0, (x - 1)))
'Loop through each record of particular table (named in rst) to create each field
Do While rst.Fields("tableName") = tblNames(0, (x - 1))
newType = rst.Fields("typeData")
newLength = rst.Fields("lengthField")
newPK = Nz(rst.Fields("PKey"), "No")
Set newField = newTable.CreateField(rst.Fields("fieldName"))
With newField
.Type = newType
If Not IsNull(newLength) Then .Size = newLength
'If field is indicated as a PK, this will create the PK
If newPK = "Yes" Then
With newTable
newField.Attributes = dbAutoIncrField
Set newIdx = .CreateIndex("PrimaryKey")
newIdx.Fields.Append newIdx.CreateField(tblNames(0, (x - 1)))
newIdx.Primary = True
.Indexes.Append newIdx
End With
End If
End With
'Append field
newTable.Fields.Append newField
rst.MoveNext
If rst.EOF Then Exit Do
Loop
MsgBox "Table " + newTable.NAME + " create", vbOKOnly 'Placed to verify loop was completed and showing table name
'''The line below gives the Invalid Argument error
'''Do not know what is causing this
db1.TableDefs.Append newTable
db1.TableDefs.Refresh
Next
I finally ended up figuring out that the numbers in my sysdata table that was designating the Field Type were wrong. I even got the from a MSDN site. I ran through a loop to determine the actual number of the data types and then placed them in the table and it worked! I also located another bug in the code having to do with the Primary Key. Where I'm appending the Index, in the CreateField I have the Table name and not the Field name. Once I changed that, the PK populated as it should too.
I use simple SQL to modyf ACC database conected to DataGridView via dataSet.xsc. Inserting works perfect, but updateing is fail (why?)
Table have 3 columns (2 strings and one boolean represented by Checkbox).
UPDATE Tabele
SET We = True 'or False in another SQL
WHERE (Name = ?) AND (Address = ?)
"We" is checkbox in table column, I try change by mouse in DataGridView.
In code i used this line to modyf table:
Private Sub Tabela_adresowDataGridView_CellContentClick(sender As Object, _
e As Windows.Forms.DataGridViewCellEventArgs) Handles _
Tabela_adresowDataGridView.CellContentClick
If e.ColumnIndex = 2 Then
Try
With Tabela_adresowDataGridView
Me.Tabela_adresowBindingSource.EndEdit()
If .Item(e.ColumnIndex, e.RowIndex).Selected = True Then
Me.Tabela_adresowTableAdapter.UpdateQuery_Checked(.Item(0, e.RowIndex).Value.ToString, _
.Item(1, e.RowIndex).Value.ToString)
Else
Me.Tabela_adresowTableAdapter.UpdateQuery_Uncheck(.Item(0, e.RowIndex).Value.ToString, _
.Item(1, e.RowIndex).Value.ToString)
End If
Tabela_adresowDataGridView.Update()
'Me.Validate()
'Me.TableAdapterManager.UpdateAll(Me.Baza_adresowDataSet)
'Baza_adresowDataSet.AcceptChanges()
End With
Catch ex As Exception
MsgBox(ex.Message)
End Try
End If
Regardless of whether the inserted Primarykey or use one simple SQL with 3th parameter for a check state. Table is not modyfied. (?)
Try to select your quert by you want and after put in your table:
Dim SelectQuery As String = "Your Query"
Dim WhereQuery As String = " WHERE (1=1)"
ElseIf BOX_toDate.Text <> Nothing Then
Name= WhereQuery & " AND TargetDate <= '" & Your value & "'"
End If
Dim con As New SqlConnection
Dim cmd As New SqlCommand
con = FunctionConnection()
cmd.Connection = con
cmd.CommandText = SelectQuery & WhereQuery
cmd.CommandType = CommandType.Text
Or like that: How to search data in all tables in database using select query in vb.net?
I am trying to convert VBA code to vb.net, im having trouble trying to search the database for a specific value around an if statement. any suggestions would be greatly appriciated.
thedatabase is called confirmation, type is the column and email is the value im looking for. could datasets work?
Function SendEmails() As Boolean
Dim objOutlook As Outlook.Application
Dim objOutlookMsg As Outlook.MailItem
Dim objOutlookRecip As Outlook.Recipient
Dim objOutlookAttach As Outlook.Attachment
Dim intResponse As Integer
Dim confirmation As New ADODB.Recordset
Dim details As New ADODB.Recordset
On Error GoTo Err_Execute
Dim MyConnObj As New ADODB.Connection
Dim cn As New ADODB.Connection()
MyConnObj.Open( _
"Provider = sqloledb;" & _
"Server=myserver;" & _
"Database=Email_Text;" & _
"User Id=bla;" & _
"Password=bla;")
confirmation.Open("Confirmation_list", MyConnObj)
details.Open("MessagesToSend", MyConnObj)
If details.EOF = False Then
confirmation.MoveFirst()
Do While Not confirmation.EOF
If confirmation![Type] = "Email" Then
' Create the Outlook session.
objOutlook = CreateObject("Outlook.Application")
' Create the message.
End IF
If you want really convert your code to NET then I think you should remove the ADODB objects and use the System.Data.SqlClient classes. Of course some things are more difficult now because the ADO.NET really use a detached model to work with databases.
The semi-equivalent of your code using the ADO.NET classes
....
' Use Try/Catch not the On Error Goto....'
Try
Dim conStr = "Server=myserver;Database=Email_Text;User Id=XXXX;Password=XXXXX;"
Using MyConnObj = new SqlConnection(conStr)
' Getting all the details rows and columns, '
' but you should select only the columns needed here....'
Using cmdDetails = new SqlCommand("SELECT * FROM MessagesToSend", MyConnObj)
' You need only the rows with Type=Email, so no need to retrieve all the rows'
Using cmdConfirm = new SqlCommand("SELECT * FROM Confirmation_list " & _
"WHERE [Type] = 'EMail' ", MyConnObj)
MyConnObj.Open
Using da = new SqlDataAdapter(cmdConfirm)
Dim dt = new DataTable()
da.Fill(dt)
Using reader = cmdDetails.ExecuteReader()
While reader.Read()
For Each row in dt.Rows
... ' The Outlook app should be instanced outside the loop'
Next
Loop
End Using
End Using
End Using
End Using
End Using
Catch x As Exception
MessageBox.Show("Error:" & x.Message)
End Try
Possibly the usage of the Type column is causing an issue. You might be able to get this working by doing the following:
confirmation.Fields("Type").Value
instead of
confirmation![Type]
but I would recommend you look into ADO.NET isntead of using ADODB as this is quite old now.