Linking two DataGridViews - vb.net

I have two Grid controls in VB.Net Winform application connected to Oracle Database. The first one shows a table 1 with fields (among others) ID and TaskName. The second one shows a linked table with fields (among others) Task. In the logic of the application the two tables are linked (Table 1, Field ID) <----> (Table 2, Field Task).
I would like, when selecting a row in the first DataGridView, have only the linked row in the second GridView but I can't make it work.
Here is my code attempt :
Dim SQLQuery As String = "SELECT * FROM SCHEME.ARCH_TASKS"
Conn = New OracleConnection(ConnectionString)
Command = New OracleCommand(SQLQuery, Conn)
DataAdapter = New OracleDataAdapter(Command)
DataSet = New DataSet()
DataTable1 = New DataTable
DataSet.Tables.Add(DataTable1)
DataAdapter.Fill(DataTable1)
DataGridView.DataSource = DataTable1.DefaultView
GridControl1.DataSource = DataTable1.DefaultView
SQLQuery = "SELECT * FROM SCHEME.ARCH_LINK_ROLE_TASK"
Command = New OracleCommand(SQLQuery, Conn)
DataAdapter = New OracleDataAdapter(Command)
DataTable2 = New DataTable
DataSet.Tables.Add(DataTable2)
DataAdapter.Fill(DataTable2)
GridControl2.DataSource = DataTable2
DataSet.Relations.Add(DataTable1.Columns("ID"), DataTable2.Columns("TASK"))
Here is the result
http://img11.hostingpics.net/pics/4713062013102413h1253.png
As you can see, I added manually a relationship between the two data tables but it doesn't really do what i'm looking for. It simply adds a subline in the first grid control.
http://img11.hostingpics.net/pics/7508382013102413h1309.png
I tried to apply what PeterG suggested but I still can't make it work.
Dim SQLQuery As String = "SELECT * FROM SCHEME.ARCH_TASKS"
Command = New OracleCommand(SQLQuery, Conn)
DataAdapter = New OracleDataAdapter(Command)
DataSet.Tables.Add(DataTable1)
DataAdapter.Fill(DataTable1)
SQLQuery = "SELECT * FROM SCHEME.ARCH_LINK_ROLE_TASK"
Command = New OracleCommand(SQLQuery, Conn)
DataAdapter = New OracleDataAdapter(Command)
DataSet.Tables.Add(DataTable2)
DataAdapter.Fill(DataTable2)
DataSet.Relations.Add(DataTable1.Columns("ID"), DataTable2.Columns("TASK"))
BindingSource1.DataSource = DataSet
GridControl1.DataSource = BindingSource1.DataSource
GridControl1.DataMember = "Table1"
BindingSource2.DataSource = BindingSource1.DataSource
GridControl2.DataSource = BindingSource2.DataSource
GridControl2.DataMember = "Table2"
Am I missing something ?
Thank you.

Related

Combo box isn't filling from DB table that is different than the datagridview data source

I have a datagridview in my application that has its DataSource set to pull from the MemberInfo table in my DB:
m_DataAdapt = New SqlDataAdapter("Select * FROM memberInfo ORDER BY lName ASC", m_DBConn)
m_CommBuild = New SqlCommandBuilder(m_DataAdapt)
m_DataSet = New DataSet()
m_DataAdapt.Fill(m_DataSet)
dgvMemberInfo.AutoGenerateColumns = False
dgvMemberInfo.DataSource = m_DataSet.Tables("Table")
This works as expected and gives me all the correct columns. However I want the Rank and Role columns to be combo boxes that get their options from a different table in the DB:
https://imgur.com/a/ZxOiBsw
However when I run the application and choose the drop downs, they are empty and there are no errors thrown. As far as I've seen so far this should work. Is there a setting/code line somewhere else that I have to do?
For whatever reason, setting it in the Designer did nothing, but setting the same stuff through code worked:
Dim b_rankAdapt As SqlDataAdapter
b_rankAdapt = New SqlDataAdapter("Select * From availRanks", m_DBConn)
Dim dt As DataTable
dt = New DataTable
b_rankAdapt.Fill(dt)
For Each iRow As DataGridViewRow In dgvMemberInfo.Rows
RankDataGridViewTextBoxColumn.DataSource = dt
RankDataGridViewTextBoxColumn.ValueMember = "rankID"
RankDataGridViewTextBoxColumn.DisplayMember = "rankName"
Next
I didn't try this before because I didn't know I could reference the cell directly through RankDataGridViewTextBoxColumn.

How to get DevExpress GridControl to show captions instead of field names?

I have a DevExpress GridControl with a master and and detail. On the detail, I want to show one column. The dataset I'm using has two columns, the one I want to show and the foreign key back to the master. In the designer, I've included only the column I want and in design mode it show one column. However, when I run the application I see both columns with the names from the data set. How do I get the detail grid to just show the one column I want?
Here's an example of my code. I've tried it with and without the level tree add and tried different names for the relation. Nothing I've tried uses the formatting I set in the designer for the detail view.
Dim cmd As SqlCommand
Dim da As SqlDataAdapter
Dim da2 As SqlDataAdapter
cmd = MSSQL_CONN.CreateCommand
cmd.CommandType = CommandType.Text
cmd.CommandText = "select * from vw_backlog with (nolock) where order_id = " & m_order.id
da = New SqlDataAdapter(cmd)
cmd = MSSQL_CONN.CreateCommand
cmd.CommandType = CommandType.Text
cmd.CommandText = "SELECT order_id, backlog_id, special_handling_id, comment_id, message FROM vw_backlog_special_handling_comments with (nolock) WHERE order_id = " & m_order.id
da2 = New SqlDataAdapter(cmd)
Dim ds As New DataSet()
da.Fill(ds, "Backlogs")
da2.Fill(ds, "Messages")
Dim keyColumn As DataColumn = ds.Tables("Backlogs").Columns("backlog_id")
Dim foreignKeyColumn As DataColumn = ds.Tables("Messages").Columns("backlog_id")
ds.Relations.Add("gvSpecialHandlingComments", keyColumn, foreignKeyColumn)
gcBacklog.DataSource = ds.Tables("Backlogs")
gcBacklog.ForceInitialize()
gcBacklog.LevelTree.Nodes.Add("SpecialHandlingComments", gvSpecialHandlingComments)
gvSpecialHandlingComments.PopulateColumns(ds.Tables("Messages"))

Visual Basic - No value given for one or more required parameters

I have a DataGridView which displays the contents of a table (with sql query). But whenever I run the code, it displays this error:
No value given for one or more required parameters.
Where did it went wrong? The program ran without displaying any errors.
Here's the code for displaying in the DataGridView:
Dim connString As String = "Provider=Microsoft.ACE.OLEDB.12.0;Data Source=|DataDirectory|\BSPDatabase.accdb"
MyConn = New OleDbConnection
MyConn.ConnectionString = connString
ds = New DataSet
tables = ds.Tables
da = New OleDbDataAdapter("Select * from [Transactions] where transMonth=" & monthCombobox.Text & "", MyConn)
da.Fill(ds, "BSPDatabase") 'Change items to your database name
Dim view As New DataView(tables(0))
source1.DataSource = view
TransactionsDataGridView.DataSource = view
I think you are forming bad SQL. The value needs to be in quotes.
da = New OleDbDataAdapter(String.Format("Select * from [Transactions] where transMonth ='{0}'", monthCombobox.text), MyConn)

DataSet, DataAdapter, no dataTable Primary key

Ok so I'm having this:
Dim sql As String = "SELECT * FROM Articles"
dAdapter = New OleDbDataAdapter(sql, connection)
dSet = New DataSet("tempDatatable")
With connection
.Open()
dAdapter.Fill(dSet, "Articles_table")
.Close()
End With
With DataGridView1
.DataSource = dSet
.DataMember = "Articles_table"
End With
And I wonder if there is any possible way to define the first column as the primary key. I've looked around but everyone is using a manual datatable to fill up the datagrid. Since I'm using a dataBase I don't know how to set a primary key from there. I need some help.
You have to set the DataAdapter's MissingSchemaAction to AddWithKey:
var table = new DataTable();
using(var con = new SqlConnection(connectionString))
using (var da = new SqlDataAdapter("SELECT * FROM Articles", con))
{
da.MissingSchemaAction = MissingSchemaAction.AddWithKey
da.Fill(table);
}
Edit: VB.NET:
Dim table = New DataTable()
Using con = New SqlConnection(connectionString)
Using da = New SqlDataAdapter("SELECT * FROM Articles", con)
da.MissingSchemaAction = MissingSchemaAction.AddWithKey
da.Fill(table)
End Using
End Using
Now the necessary columns and primary key information to complete the schema are automaticaly added to the DataTable.
Read: Populating a DataSet from a DataAdapter
You can add a primary key to your data table using something like this:
var table = dSet.Tables["Articles_table"];
table.PrimaryKey = new DataColumn[] { table.Columns[0] };
Sorry, just realised the question was tagged with vb.net, not c#. VB.net would be:
Dim table = dSet.Tables("Articles_table")
table.PrimaryKey = New DataColumn() {table.Columns(0)}
Please do it like this.
Dim objTmpTable As New DataTable
objTmpTable.PrimaryKey = New DataColumn() {objTmpTable.Columns(0)}
dgrdMeasure.DataSource = objTmpTable
dgrdMeasure.DataBind()
That is, before assigning to Grid, just set the Primary key.

Remove repeated values from dataGridViewComboBoxColumn

I use DataGridViewComboBoxColumn to make a ComboBox in DataGridView but my ComboBox isn't good enough. I need my ComboBox to not have repeated values on it. This is an example:
Apple
Blackberry
Chrome
Apple
I want to remove the values that appear more than one time. How can I do that?
This is my code:
OleDbConnection conn = new OleDbConnection();
OleDbCommand cmd = new OleDbCommand();
Dataset data = new Dataset();
OleDbDataAdapter adapter = new OleDbDataAdapter();
string path = "Data Source = "+".\\"+"test.accdb";
string conStr = "Provider = Microsoft.ACE.OleDb.12.0;"+#path;
conn.Open();
string sql = "SELECT * FROM Table1;"
cmd = new OleDbCommand(sql,conn);
adapter = new OleDbDataAdapter(cmd);
data = new Dataset();
adapter.Fill(data,"Table1");
DataGridViewComboBoxColumn testcolumn = new DataGridViewComboBoxColumn();
testcolumn.Name = "test na ja";
testcolumn.Datasource = data.table[0];
testcolumn.ValueMember = "Remedy";
testcolumn.DisplayMember = "Remedy";
dataGridview1.Columns.Add(testcolumn);
conn.Close()
change the SELECT statement to return distinct values of remedy:
string sql = "SELECT DISTINCT remedy FROM Table1;"
and if you want it ordered:
string sql = "SELECT DISTINCT remedy FROM Table1 ORDER BY remedy ASC;"
or
string sql = "SELECT DISTINCT remedy FROM Table1 ORDER BY remedy DESC;"
As well as applying the distinct statement to your SQL it is possible to apply a distinct to the original DataTable when creating a second table as shown below (with a unit test and helper classes included that I used to prototype this).
I've added a comment below to highlight the line where the distinct is applied - what you use is the .ToTable() method which takes the Boolean parameter Distinct to specify only return distinct rows.
[TestMethod]
public void CreateDistinctDataTable()
{
DataTable originalTable = CreateDataTable();
AddDataToTable("Fred", "Bloggs", originalTable);
AddDataToTable("Fred", "Bloggs", originalTable);
AddDataToTable("John", "Doe", originalTable);
// This is the key line of code where we use the .ToTable() method
DataTable distinctTable = originalTable.DefaultView.ToTable( /*distinct*/ true);
// The original table has two rows with firstname of Fred
Assert.AreEqual(2, originalTable.Select("firstname = 'Fred'").Length);
// The new table only has one row with firstname of Fred
Assert.AreEqual(1, distinctTable.Select("firstname = 'Fred'").Length);
}
private DataTable CreateDataTable()
{
DataTable myDataTable = new DataTable();
DataColumn myDataColumn;
myDataColumn = new DataColumn();
myDataColumn.DataType = Type.GetType("System.String");
myDataColumn.ColumnName = "firstname";
myDataTable.Columns.Add(myDataColumn);
myDataColumn = new DataColumn();
myDataColumn.DataType = Type.GetType("System.String");
myDataColumn.ColumnName = "lastname";
myDataTable.Columns.Add(myDataColumn);
return myDataTable;
}
private void AddDataToTable(string firstname, string lastname, DataTable myTable)
{
DataRow row = myTable.NewRow();
row["firstname"] = firstname;
row["lastname"] = lastname;
myTable.Rows.Add(row);
}
One additional thought is I would suggest not selecting * from your table in the SQL statement. This can have performance implications down the track if more columns are added (particularly things like blobs) and could also mean you get columns that break the distinct nature of your query.