I'm trying to fill a data grid view in my windows form application but nothing is being returned from the database when I execute the select query. I've looked at other questions about this topic on this site but cannot find anything that addresses my problem.
The name of the data view table is qbcMemDataView and the data source is a sqlite dataset called sqlite_dbDataSet1
Here is the code I have in place:
public Form1()
{
InitializeComponent();
dbConnection = new SQLiteConnection("Data Source=sqlite_db.sqlite;Version=3");
dbConnection.Open();
string[] restrictions = new string[4];
restrictions[2] = "test_table_mom";
using (DataTable dTbl = dbConnection.GetSchema("Tables", restrictions))
{
for (int i = 0; i < dTbl.Rows.Count; i++)
{
tblChooser.Items.Add(dTbl.Rows[i].ItemArray[dTbl.Columns.IndexOf("TABLE_NAME")].ToString());
}
if (tblChooser.Items.Count > 0)
{
tblChooser.SelectedIndex = 0;
}
}
}
private void btnSelect_tbl_Click(object sender, EventArgs e)
{
string sql = "SELECT id, name FROM test_table_mom";
using (SQLiteDataAdapter dbAdapter = new SQLiteDataAdapter(sql, dbConnection))
{
DataTable dataTbl = new DataTable();
dbAdapter.Fill(dataTbl);
qbcMemDataView.DataSource = dataTbl;
}
}
Also, here is a screenshot of the program running that might help better explain the issue I am having: http://imgur.com/j9ffeVi
I know there is data inside the table, I just don't know why it is not appearing in the data grid when the btnSelect_tbl_Click method is executed.
Any help would be appreciated.
Thanks!
Per the tutorial How to: Bind Data to the Windows Forms DataGridView Control, you are missing a BindingSource component that binds the data from the datasource to your table to the DataGrid.
Initialize the BindingSource at the top of your class like so:
private BindingSource bindingSource1 = new BindingSource();
Then near the top of your button click method before the sql add the line:
qbcMemDataView.DataSource = bindingSource1;
and finally change the last line of code
qbcMemDataView.DataSource = dataTbl;
to
bindingSource1.DataSource = dataTbl;
try that and see if it works for you.
Note: I'm not sure if this applies to c# but maybe it's universal fix.
Android builtin adapters and such use _id as the name of the id field. The other problem is _id and id well it's not well documented in android.
About "_id" field in Android SQLite
You can use this technique renaming in the select but it gets messy and you may not catch all occurrences.
string sql = "SELECT id _id, name FROM test_table_mom";
My Opinion: Go back and refactor your db id to _id.
Related
Iam currently working on a book management project and I'm using SQL Server from Visual Studio. I have a Book Category table in the database and I'm trying to place it in a combobox.
This the code - I don't see anything wrong with it but the categories are taking so long to be visible in the combobox.
Also the list is repetitive, is it maybe because of the while Loop? If so is there any way to fix it?
private void comboBox1_SelectedIndexChanged(object sender, EventArgs e)
{
try
{
con.ConnectionString = (#"Data Source=(LocalDB)\MSSQLLocalDB;AttachDbFilename=C:\Users\malek\source\repos\BookStore\BookStore\BOOKDB.mdf;Integrated Security=True");
scmd.Connection = con;
con.Open();
scmd.CommandText = "SELECT CATEGORY FROM BOOKCAT";
var rd = scmd.ExecuteReader();
while (rd.Read())
{
List.Add(Convert.ToString(rd[0]));
}
int i = 0;
while (i < List.LongCount())
{
comboBox1.Items.Add(List[i]);
i = i + 1;
}
}
catch (Exception EX)
{
MessageBox.Show(EX.Message);
}
finally
{
con.Close();
}
}
What did I miss?
NOTE: I am not getting any errors!!
How do you mean with data binding?
Like this
var da = new SqlDataAdapter(
"SELECT DISTINCT CATEGORY FROM BOOKCAT ORDER BY CATEGORY"
#"Data Source=(LocalDB)\MSSQLLocalDB;AttachDbFilename=C:\Users\malek\source\repos\BookStore\BookStore\BOOKDB.mdf;Integrated Security=True"
);
var dt = new DataTable();
da.Fill(dt);
categoryComboBox.DisplayMember = "CATEGORY";
categoryComboBox.ValueMember = "CATEGORY";
categoryComboBox.DataSource = dt;
And when you want the thing the user selected:
var cat = categoryComboBox.SelectedValue as string;
Simple eh?
It gets even easier if you use a strongly typed dataset; for that you just add a new DataSet type file to your project (must use net framework not net core/5+), drag your db into your dataset, add a query to the category TableAdapter that gets the distinct categories (like above) then open the data sources window, change Category to a combo and tag it onto the form. No code to write; vs will write it all
Based on the code you've posted, it looks like you're loading the categories from the database in the SelectedIndexChanged event of comboBox1.
So, every time you choose a new item from comboBox1 you're executing this code; you're going to the database and loading everything from the BOOKCAT table and you're putting those items into List and comboBox1. That is why you're seeing duplicated categories. It's probably also why it takes so long for a category to be visible in the ComboBox.
You probably don't want to load the ComboBox items from the database every time the selected index changes, so you should do that somewhere else. For example, you could do it in the Form's constructor, or in the 'Load' event.
I have bounded data to datagridview from DataSetand I am trying to filter
these bounded data within datagridview on event of textchange
I got two issues when
I start typing it work fine except it delete the custom datagridview headers and set the name of columns query ex. Header is 'First Name' it replaced by 'NAM' which is the column name at database...
Second issue when I came into else part it wont re-bounded and throw an Exception what I have missed ?
public DataSet GetPatientList()
{
string connStr = ConfigurationManager.ConnectionStrings["SRJDconnstr"].ToString();
string cmdStr = #"SELECT ROW_NUMBER()OVER(ORDER BY ID) AS SEQ,
ID,
DocNUM,
NAM,
FNAME,
LFNAME,
PHONE,
MOBILE,
SEX,
BIRTHDAY,
ADDRESS,
ENDATETIME
FROM SICK
ORDER BY ENDATETIME ASC;";
SqlConnection conn = new SqlConnection(connStr);
using (SqlCommand cmd = new SqlCommand(cmdStr, conn))
{
conn.Open();
cmd.CommandText = cmdStr;
cmd.CommandType = CommandType.Text;
ds = new DataSet();
da = new SqlDataAdapter(cmd);
da.Fill(ds, "PatientList");
DGV_PatientList.Columns["DGV_PatientList_RowNum"].DataPropertyName = ds.Tables["PatientList"].Columns["SEQ"].ColumnName;
DGV_PatientList.Columns["DGV_PatientList_PatientID"].DataPropertyName = ds.Tables["PatientList"].Columns["ID"].ColumnName;
DGV_PatientList.Columns["DGV_PatientList_DocNUM"].DataPropertyName = ds.Tables["PatientList"].Columns["DocNUM"].ColumnName;
DGV_PatientList.Columns["DGV_PatientList_FirstName"].DataPropertyName = ds.Tables["PatientList"].Columns["NAM"].ColumnName;
DGV_PatientList.Columns["DGV_PatientList_FatherName"].DataPropertyName = ds.Tables["PatientList"].Columns["FNAME"].ColumnName;
DGV_PatientList.Columns["DGV_PatientList_LastName"].DataPropertyName = ds.Tables["PatientList"].Columns["LFNAME"].ColumnName;
DGV_PatientList.Columns["DGV_PatientList_Phone"].DataPropertyName = ds.Tables["PatientList"].Columns["PHONE"].ColumnName;
DGV_PatientList.Columns["DGV_PatientList_Mobile"].DataPropertyName = ds.Tables["PatientList"].Columns["MOBILE"].ColumnName;
DGV_PatientList.Columns["DGV_PatientList_Gender"].DataPropertyName = ds.Tables["PatientList"].Columns["SEX"].ColumnName;
DGV_PatientList.Columns["DGV_PatientList_Birthday"].DataPropertyName = ds.Tables["PatientList"].Columns["BIRTHDAY"].ColumnName;
DGV_PatientList.Columns["DGV_PatientList_Address"].DataPropertyName = ds.Tables["PatientList"].Columns["ADDRESS"].ColumnName;
DGV_PatientList.Columns["DGV_PatientList_EntryDate"].DataPropertyName = ds.Tables["PatientList"].Columns["ENDATETIME"].ColumnName;
return ds;
}
}
Text Change event
private void TB_FirstName_TextChanged(object sender, EventArgs e)
{
if (!string.IsNullOrWhiteSpace(TB_FirstName.Text))
{
// first try below
(ds.Tables["PatientList"] as DataTable).DefaultView.RowFilter = string.Format("NAM LIKE '%{0}%'", TB_FirstName.Text);
// second try below
//ds.Tables["PatientList"].DefaultView.RowFilter = string.Format("NAM LIKE '%{0}%'", TB_FirstName.Text);
}
else
{
DGV_PatientList.DataSource = GetPatientList();
DGV_PatientList.DataSource = ds.Tables["PatientList"].DefaultView;
}
}
Set AutoGenerateColumns to false.
That is what is causing the names to change, and also why you are getting the exception. The columns don't exist anymore and you are referencing them by name.
Working with DataGridView bound to a dataset isn't supposed to be this hard - you must have been following a really old, or poorly written tutorial
The way this is all supposed to hang together is much more neat and compact:
//in your code that handles loading the grid with data, e.g. in a Load button handler
patientListTableAdapter.Fill(ds.PatientList); //strongly typed dataset, table is already bound to grid in design time.
//Visual Studio binds it fully for you when you add it to the form, in the designer
//you never again mess with the bindings, just fill and empty the table: MVC
private void TB_FirstName_TextChanged(object sender, EventArgs e){
if(string.IsNullOrWhiteSpace(TB_FirstName.Text)
patientListBindingSource.Filter = null;
else
patientListBindingSource.Filter = string.Format("NAM LIKE '%{0}%'", TB_FirstName.Text);
}
Yes... just 5 lines of code should be doing everything you're trying to achieve here. Right now, you're using these technologies in an incorrect way, and achieving a difficult and poor performing result.
For guidance on how you should be using datatables, refer to MSDN:
https://msdn.microsoft.com/en-us/library/fxsa23t6.aspx
Start with the "Creating a Simple Data Application" walk through, make a new project, follow th steps and create a new sample app. After you've done that, i recommend coming back to the existing app and making NO attempts to salvage what has already been done - delete the lot, remove the datagridview from the form, create a new typed dataset, link it to your DB, drop a new correctly bound datagridview on your form and th designer will set everything up. Then all you need to do is pick a suitable place to load it with data, and apply a textchanged handler (the 5 lines of code I put above)
I know it's going to be hard, throwing away all that code you poured blood weat and tears into.. but it will always be a headache, and never work right, because it's plain up the wrong way to go about working with data and bound controls
id pojam opis id pojam opis(duplicate columns)
I am just testing connection from db to c#, and instead of columns id pojam opis I am actually getting id pojam opis id pojam opis in datagridview in c#. Here is part of code which I use to connect database to c#:
public partial class Form1 : Form
{
BindingSource bindingSource1 = new BindingSource();
MySqlConnection conn = new MySqlConnection("Data Source=localhost;database=test;user=root;password=;");
public Form1()
{
this.Load += new System.EventHandler(Form1_Load);
InitializeComponent();
}
public void Form1_Load(object sender, EventArgs e)
{
dataGridView1.DataSource = bindingSource1;
ubaciPodatke();
}
public void ubaciPodatke()
{
try
{
MySqlDataAdapter da = new MySqlDataAdapter("SELECT * FROM csharp", conn);
DataTable table = new DataTable();
da.Fill(table);
bindingSource1.DataSource = table; dataGridView1.AutoResizeColumns(DataGridViewAutoSizeColumnsMode.AllCellsExceptHeader);
}
catch (Exception ex)
{
MessageBox.Show(ex.Message);
}
}
Is it my mistake, or It has to do something with phpmyadmin: Version information: 4.7.0-rc1. I was thinking it can happen because this version isnt stable yet?
edit: what do You think if I delete this form.resx file
user added rows, would this solve the problem?
Few things:
There is no need to do the data binding in the Load event. You can just do it in the constructor after the InitializeComponent() call. This is irrelevant to your issue.
I don't know what ubaciPodatke means since I don't speak that language, but hopefully it is equivalent of InitializeGrid(). In that case you should put
dataGridView.DataSource = null;
dataGridView.Rows.Clear();
dataGridView.Columns.Clear();
as the first line after try. I do such "clean initialize" since I sometimes design the Grid in designer, for "documentation & visualization" purposes, but do the actual grid from the code. Also, it keeps the InitializeGrid() reusable, to be called from other places.
Also, related to the question in the comments,
Am I reading data from dgv wrong?
You should read the data from the bound DataTable and not directly from the DataGridView when binding.
Solution: I had to comment some lines link1 in form.designer.cs and problem disappeared as shown in this photo link2. I am still curious why this happened as I remember only dragging dgv from toolbox and not adding manually column names.
I am attempting to build a simple application that allows me to interact with a MySQL database I have set up. I can add records just fine; however, I cannot get them to display. I am simply presented with a blank datagrid control.
It could be something simple, but I have tried different approaches, searched online, and messed with it longer than I should have - to no avail. I have a feeling the issue might lie in my lack of understanding the DataGrid control. Any help is sincerely appreciated.
The Select method from the Database Connection class:
public DataTable Select(string tableName)
{
string query = "SELECT * FROM " + tableName;
this.Open();
MySqlCommand cmd = new MySqlCommand(query, connection);
MySqlDataAdapter adapter = new MySqlDataAdapter(cmd);
DataSet dataSet = new DataSet();
adapter.Fill(dataSet);
this.Close();
return dataSet.Tables[0];
}
The following is a portion of the code for the window (called View) containing the datagrid. The table name is passed to it from the main window upon the click of a button.
public View()
{
InitializeComponent();
}
public View(string table)
{
this.table = table;
InitializeComponent();
}
private void windowLoad(object sender, RoutedEventArgs e)
{
DatabaseConnection myConnection = new DatabaseConnection();
dataGrid.DataContext = myConnection.Select(table).DefaultView;
}
Okay guys,
After many readings and finding solutions down here I just need to ask this.
I already searched for it but it didn't help me as good as it should to sort this out.
Also, excuse me for my grammatical mistakes if any...
What's the problem?
I load up a WPF form with a combobox in. This combobox gets all the names from all the tables in my database. I choose a table name and press a button to fill up a DataGrid (WPF) with the chosen table. This all works perfectly. But, then when I changed a cell or added/deleted a row or column I have to update this to the database.
This is where I'm stuck. I got it working trough a not so optimal way. So that's why I ask if there is a better solution.
//fill the datagrid with data from chosen table in combobox!
selectedTable = cboxTables.SelectedItem.ToString();
dataset = db.getDataFromTable(selectedTable);
datatable = dataset.Tables[selectedTable];
datagridAdmin.ItemsSource = datatable.DefaultView;
And when the selection in the DataGrid has changed, I set the 'Submit' button as active wich calls this code:
db.updateTable(selectedTable, datatable);
Note that 'db' is a instance off my databaseclass. The method is as following:
public bool updateTable(String tableName, DataTable datatable)
{
using (SqlBulkCopy bulkcopy = new SqlBulkCopy(thisConnection.ConnectionString, SqlBulkCopyOptions.CheckConstraints))
{
//Set destination table name
//to table previously created.
bulkcopy.DestinationTableName = tableName;
try
{
thisCommand = new SqlCommand("DELETE FROM " + tableName, thisConnection);
thisCommand.ExecuteNonQuery();
bulkcopy.WriteToServer(datatable);
}
catch (Exception ex)
{
logger.WriteLine(applicationName, ex.Message);
}
}
}
But the problem is, the first column is a auto increment ID wich keeps raising every time I submit the changed DataGrid.
Isn't there a better way to do this?
Thanks!
PS: I'm coding in Visual Studio 2010 with C# in WPF.
In short for the method you have given you would be better off using the Truncate table method before calling your bulk copy, this will reset the Identity column back to 0:
thisCommand = new SqlCommand("TRUNCATE TABLE " + tableName, thisConnection);
However either method is going to cause problems with foreign keys in your database. I am not sure how you are retrieving your data in your database class, but I would look at using the SqlCommandBuilder to update your database rather than deleting and re-inserting all the data with each update.
EDIT
To further explain my suggestion of the SqlCommandBuilder.
A ViewModel such as the following should allow use of the SqlCommandBuilder (Note: this is hugely cut down and in real terms this requires better validation, exception and event handling, but the rough idea is there):
public class YourViewModel
{
private SqlDataAdapter adapter;
private DataTable table;
private SqlCommandBuilder commandBuilder;
public DataTable Table { get { return table; } set { table = value; } }
public void LoadTable(string connectionString, string tableName, int[] primaryKeyColumns)
{
adapter = new SqlDataAdapter(string.Format("SELECT * FROM {0}", tableName), connectionString);
table = new DataTable();
adapter.Fill(table);
List<DataColumn> primaryKeys = new List<DataColumn>();
for (int i = 0; i < primaryKeyColumns.Length; i++)
{
primaryKeys.Add(table.Columns[primaryKeyColumns[i]]);
}
table.PrimaryKey = primaryKeys.ToArray();
commandBuilder = new SqlCommandBuilder(adapter);
commandBuilder.GetUpdateCommand();
}
public int Update()
{
if (table == null || table.Rows.Count == 0 || adapter == null)
{
return 0;
}
if (table.PrimaryKey.Length == 0)
{
throw new Exception("Primary Keys must be defined before an update of this nature can be performed");
}
else
{
return adapter.Update(table);
}
}
}
Bind the Table property to the grid view, then call the Update method when required. You can even bind the update to the table's rowchanged events etc to automatically update the db. The Code Project has a fairly good article on WPF, Data grids and database integration.