I have an Employee table in my sql database which has emp_Id, emp_name, manager_Id.
I'm trying to get all the emp_name as a LIST and put them in a ComboBox
here my sql statement:
string sql = "SELECT emp_name FROM Employee";
And this how i'm putting them in the LIST
public static List<T> GetList<T>(DataTable dt)
where T : IPopulateColumns, new()
{
List<T> TList = new List<T>();
foreach (DataRow dr in dt.Rows)
{
T t1 = new T();
t1.PopulateColumns(dr);
TList.Add(t1);
}
return TList;
Here my PopulateColumns method inside the Employee Class: I have fields and properties name for empId, empName, managerID inside the class.
public void PopulateColumns(DataRow dr)
{
this.empId = (int)dr["EmpId"];
this.empName = dr["EmpName"].ToString();
this.managerId = dr["ManagerID"].ToString();
}
I getting an error that stated " Columnn 'EmpId ' does not belong to table
Since I don't have the completed code you provided, I recommend you use the following code
to get get all the emp_name as a LIST and add them as the datasource of the combobox.
Code:
private void Form1_Load(object sender, EventArgs e)
{
string connstring = #"";
SqlConnection connection = new SqlConnection(connstring);
connection.Open();
string sql = "SELECT emp_name FROM Employee";
SqlCommand command = new SqlCommand(sql, connection);
DataSet set = new DataSet();
SqlDataAdapter adapter = new SqlDataAdapter(command);
adapter.Fill(set);
var result = set.Tables[0].AsEnumerable().Select(i=>i.Field<string>("emp_name")).ToList();
comboBox1.DataSource = result;
}
Related
I am using the below code to search for the inputted textBox ID in an accessdb and returning the row of data to a dataGridView. When I search for a second ID, the first row in the GridView is replaced, How can I make it save multiple rows?
The end goal of this project is to allow the user to search as many ID's as they like and pull the corresponding row of data into the gridview to then save all into a csv.
private void searchButton_Click(object sender, EventArgs e)
{
conn1.Open();
//return ID, IMEI, ICCID, IMSI from dataBase
OleDbCommand cmd1 = new OleDbCommand("Select ID, IMEI,ICCID, IMSI from TBL where ID=#param1", conn1);
cmd1.Parameters.AddWithValue("#param1", txtScannedValue.Text);
OleDbDataReader reader1;
reader1 = cmd1.ExecuteReader();
DataTable dt = new DataTable();
dt.Load(reader1);
//dataGridView1.DataSource= dt;
if (dt.Rows.Count > 0)
{
((DataTable)dataGridView1.DataSource).ImportRow(dt.Rows[0]);
}
else
{
MessageBox.Show("No Data Found");
}
//reset textBox
txtScannedValue.Text = "";
conn1.Close();
}
What you are doing is - each time you press the searchButton_Click button you are running a query that returns 1 row only(ID=#param1) and then you are inserting ALL(which is always 1 in your case due to query) your searched rows to your dataGridView via .DataSource() bind.
To solve this I would recommend you to re-implement your data bindings:
I am assuming that DataTable is from ADO.NET so without changing a query you could bind your data something like this:
// this is pseudocode
private void searchButton_Click(object sender, EventArgs e) {
var row = (DataGridViewRow) dataGridView1.Rows[0].Clone();
var retrievedRow = getRowById(txtScannedValue.Text);
if (retrievedRow is null) return;
row.Cells[0].Value = retrievedRow.value1; // bind here you model fields
row.Cells[1].Value = retrievedRow.value2;
// ...
dataGridView1.Rows.Add(row);
}
private void getRowById(string id) {
conn1.Open();
OleDbCommand cmd1 = new OleDbCommand("Select ID, IMEI, TekNum, BatchNum, ICCID, IMSI from TBLTest1 where ID=#param1", conn1);
cmd1.Parameters.AddWithValue("#param1", id);
OleDbDataReader reader1;
reader1 = cmd1.ExecuteReader();
DataTable dt = new DataTable();
dt.Load(reader1);
DataRow row;
if (dt.Rows.Count > 0) {
row = dt.Rows[0];
}
conn1.Close();
return row;
}
I'd use a ListBox or ComboBox to present data they can recognize with the id available. To append rows, use DataTable.ImportRow.
Here a ComboBox is used to present, in this case employees and the DataGridView is initially populated with an empty DataTable.
Click a button to get a row to append to the underlying DataTable for the DataGridView.
Model and data operations
using System.Collections.Generic;
using System.Data;
using System.Data.OleDb;
namespace AccessApplication.Classes
{
public class EmployeesOperations
{
public static string ConnectionString =>
"Provider=Microsoft.ACE.OLEDB.12.0;Data Source=NorthWind.accdb";
public static List<Employee> EmployeesList()
{
List<Employee> list = new List<Employee>();
using var cn = new OleDbConnection { ConnectionString = ConnectionString };
using var cmd = new OleDbCommand() { Connection = cn };
cmd.CommandText = "SELECT EmployeeID, FirstName, LastName FROM Employees";
cn.Open();
var reader = cmd.ExecuteReader();
while (reader.Read())
{
list.Add(new Employee()
{
Id = reader.GetInt32(0),
FirstName = reader.GetString(1),
LastName = reader.GetString(2)
});
}
return list;
}
public static DataTable EmptyDataTable()
{
using var cn = new OleDbConnection { ConnectionString = ConnectionString };
using var cmd = new OleDbCommand() { Connection = cn };
cmd.CommandText =
"SELECT TOP 1 EmployeeID, FirstName, LastName FROM Employees";
cn.Open();
DataTable table = new DataTable();
table.Load(cmd.ExecuteReader());
table.Rows.Clear();
return table;
}
public static DataTable SingleRow(int identifier)
{
using var cn = new OleDbConnection { ConnectionString = ConnectionString };
using var cmd = new OleDbCommand() { Connection = cn };
cmd.CommandText =
"SELECT TOP 1 EmployeeID, FirstName, LastName " +
"FROM Employees WHERE EmployeeID = #Id";
cmd.Parameters.Add("#Id", OleDbType.Integer).Value = identifier;
cn.Open();
DataTable table = new DataTable();
table.Load(cmd.ExecuteReader());
return table;
}
}
public class Employee
{
public int Id { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
public override string ToString() => $"{FirstName} {LastName}";
}
}
Form code
public partial class EmployeeForm : Form
{
private readonly BindingSource _employeesBindingSource =
new BindingSource();
public EmployeeForm()
{
InitializeComponent();
_employeesBindingSource.DataSource = EmployeesOperations.EmployeesList();
EmployeesComboBox.DataSource = _employeesBindingSource;
dataGridView1.DataSource = EmployeesOperations.EmptyDataTable();
}
private void GetSingleEmployeeButton_Click(object sender, EventArgs e)
{
int id = ((Employee)EmployeesComboBox.SelectedItem).Id;
DataTable table = ((DataTable)dataGridView1.DataSource);
DataRow result = table.AsEnumerable()
.FirstOrDefault(row => row.Field<int>("EmployeeID") == id);
// only add if not already in the data grid view
if (result == null)
{
table.ImportRow(EmployeesOperations.SingleRow(id).Rows[0]);
}
}
}
The below code is now working for using the textbox to search the database and enter multiple rows of code into the dataGridView. The question was answered in the comments on the op by JohnG. Posting here for future reference.
private void searchButton_Click(object sender, EventArgs e)
{
conn1.Open();
//return ID, IMEI, BatchNum, ICCID, IMSI from dataBase
OleDbCommand cmd1 = new OleDbCommand("Select ID, IMEI, BatchNum, ICCID, IMSI from TBLTest1 where ID=#param1", conn1);
cmd1.Parameters.AddWithValue("#param1", txtScannedValue.Text);
OleDbDataReader reader1;
reader1 = cmd1.ExecuteReader();
DataTable dt = new DataTable();
dt.Load(reader1);
if (dt.Rows.Count > 0)
{
if (dataGridView1.DataSource != null) {
((DataTable)dataGridView1.DataSource).ImportRow(dt.Rows[0]);
}
else
{
dataGridView1.DataSource = dt;
}
}
else
{
MessageBox.Show("No Data Found");
}
//reset textBox
txtScannedValue.Text = "";
conn1.Close();
}
This is my code:
public partial class AddMovieForm : System.Web.UI.Page
{
const string connStr = #"Data Source=.\SQLEXPRESS;AttachDbFilename=C:\Users\user\Documents\MovieTimeDB.mdf;Integrated Security=True;Connect Timeout=30;User Instance=True";
SqlDataAdapter adapter;
DataSet ds;
DataSet genreDS;
protected void Page_Load(object sender, EventArgs e)
{
string name = Request.Form["name"];
string producer = Request.Form["producer"];
string summary = Request.Form["summary"];
string genre = Request.Form["genre"];
int year = int.Parse(Request.Form["year"]);
int length = int.Parse(Request.Form["length"]);
string sqlStr = "SELECT * FROM Movies";
ds = GetDataSet(sqlStr);
string genreSqlString = "SELECT * FROM Genres WHERE genre='"+genre1+"'";
genreDS = GetDataSet(genreSqlString);
DataRow GenreDR = genreDS.Tables[0].Rows[0];
int genre2 = (int)GenreDR["id"];
Insert(name, producer, summary, genre2, year,length);
Response.Redirect("Main.aspx");
}
protected void Insert(string name, string producer, string summary, int genre, int year, int length)
{
DataRow dr = ds.Tables[0].NewRow();
dr["name"] = name;
dr["producer"] = producer;
dr["summary"] = summary;
dr["genre"] = genre;
dr["year"] = year;
dr["length"] = length;
ds.Tables[0].Rows.Add(dr);
SqlCommandBuilder builder = new SqlCommandBuilder(adapter);
adapter.InsertCommand = builder.GetInsertCommand();
adapter.Update(ds);
}
public DataSet GetDataSet(string strSql)
{
DataSet ds = new DataSet();
SqlConnection conn = new SqlConnection(connStr);
adapter = new SqlDataAdapter(strSql, conn);
conn.Open();
adapter.Fill(ds);
conn.Close();
return ds;
}
I have three tables in ds: Movies, Members and Category. Movies is in ds, but when I ran the code, the line adapter.Update(ds); causes trouble:
Description: An unhandled exception occurred during the execution of
the current web request. Please review the stack trace for more
information about the error and where it originated in the code.
Exception Details: System.InvalidOperationException: Missing the
DataColumn 'id' in the DataTable 'Table' for the SourceColumn 'id'.
The thing is that I have an id column only in the table Category, and I don't understand why it refers to that table when I filled my ds with the table Movies.
When using a single adapter for multiple tables, between each update you must reset the commandtext and SqlCommandBuilder, otherwise it still refers to the previous one. For example, adapter was used initially on table1. To update table2 code is:
adapter.SelectCommand.CommandText = "Select * From table2"
builder = New SqlCommandBuilder(adapter)
adapter.Update(ds, "table2")
Most other posts specify you must use a separate adapter for each table, but I have not found that to be necessary.
I tried to convert a datatable that just has one field (the field's data is primary key) to int , in order to using in sql commands such as Select and etc.
but it fails!
and when i cast it to an object or convert it to string first , the commands gone wrong!
please help me
i want to select * from a table which has a foreign key where the foreign code equals by an int value that has been selected from a table in another sql command and returned as a datatable row with just one field.
here is my code :
class mydata :
public string strsql;
public DataTable showData()
{
SqlConnection Con1 = new SqlConnection("Data Source=.;database=daneshgah;integrated security=true");
Con1.Open();
SqlDataAdapter da = new SqlDataAdapter(strsql, Con1);
DataTable dt = new DataTable();
da.Fill(dt);
Con1.Close();
return (dt);
}
button event :
myData search = new myData();
int aa = int.Parse(txt_stdcourse.Text);
search.strsql = "select tchNo from University where couNo='" + aa + "'";
DataTable a = search.showData();
string b = a.Rows[0][0].ToString();
int c = int.Parse(b);
myData akhz = new myData();
akhz.strsql = "insert into stc (couNo,tchNo,stuNo)values('" + aa + "','" + c + "','" + id + "')";
akhz.Data();
lbl_stdcourseok.Visible = false;
lbl_stdcourseok.Visible = true;
Sounds like you need to use ExecuteScalar on a SqlCommand instead of using a DataAdapter. ExecuteScalar gives the first column of the first row of the dataset returned.
public object RunSQL(string sql)
{
SqlConnection Con1 = new SqlConnection("Data Source=.;database=daneshgah;integrated security=true");
Con1.Open();
SqlCommand command = new SqlCommand(strsql, Con1);
return command.ExecuteScalar();
}
//In some event handler
int myValue = (int)RunSQL("Select Value from Table where ID = " + ID);
That said, please don't do that - it is very bad practice. You almost certainly want to create a class that models whatever data objects you are dealing with, instead of executing arbitrary SQL from event handlers. It is also probably best to manage connections independently of your data class, in a separate data access layer.
An extremely rudimentary example:
public class Student
{
public int StudentID { get; set; }
public bool CurrentlyEnrolled { get; set; }
public string Name { get; set; }
public static Student LoadByID(int ID)
{
DataTable results = DAL.ExecuteSQL("Select * from Students WHERE StudentID = #StudentID", new SqlParameter("#StudentID", ID));
if (results.Rows.Count == 1)
{
return FillFromRow(results.Rows[0]);
}
else
{
throw new DataException("Could not find exactly one record with the specified ID.");
}
}
private static Student FillFromRow(DataRow row)
{
Student bob = new Student();
bob.CurrentlyEnrolled = (bool)row["CurrentlyEnrolled"];
bob.Name = (string)row["Name"];
bob.StudentID = (int)row["StudentID"];
return bob;
}
}
public static class DAL
{
private const string ConnectionString = "SomeConnectionString"; //Should really be stored in configuration files.
public static DataTable ExecuteSQL(string SQL, params SqlParameter[] parameters)
{
using (SqlConnection connection = new SqlConnection(ConnectionString))
{
using (SqlCommand command = new SqlCommand(SQL))
{
command.Parameters.AddRange(parameters);
using (SqlDataAdapter adapter = new SqlDataAdapter(command))
{
DataTable result = new DataTable();
adapter.Fill(result);
return result;
}
}
}
}
}
I have a DataTable -> "CheckProduct(String id)" where String ID is invoice id which is used fetch product ids of that invoice
Now i want to compare it with a Textbox value.
I have tried a code for it.
My Datalogic :-
public DataTable CheckProduct(String id)
{
DataTable dt = new DataTable();
SqlConnection sqlconnection;
sqlconnection = new SqlConnection(#" Database Connection String");
sqlconnection.Open();
SqlCommand cmd = new SqlCommand("checkproduct", sqlconnection);
cmd.CommandType = CommandType.StoredProcedure;
cmd.Parameters.Add("#inv_id", SqlDbType.VarChar).Value = int.Parse(id);
DataSet dtset = new DataSet();
SqlDataAdapter adpt = new SqlDataAdapter(cmd);
adpt.Fill(dtset);
dt = dtset.Tables[0];
return dt;
}
My Business logic :-
public List<String> CheckProduct(String id)
{
SPDatalogic sp = new SPDatalogic(); //datalogic class
DataTable dt = new DataTable() ;
dt = sp.CheckProduct(id);
List<String> list = new List<String>();
SPBusinesslogic ab = new SPBusinesslogic(); //businesslogic class
String pro;
pro =ab.CheckProduct(id).ToString();
list.Add(pro);
return list;
}
My Presentation Layer:-
string id = invoice_no_textbox.Text;
SPBusinesslogic ab = new SPBusinesslogic(); //businesslogic class
List<String> id_list = new List<String>();
id_list = ab.CheckProduct(id); //passing invoice_no as string id
if (id_list.Any(x => x.Equals(invoice_no_textbox.Text)))
{
MessageBox.Show("the product already exist");
}
Supposing that the field name for your invoice id is called "invoice_id" I would rewrite the code of CheckProduct to be
public List<String> CheckProduct(String id)
{
SPDatalogic sp = new SPDatalogic(); //datalogic class
DataTable dt = sp.CheckProduct(id);
List<String> list = new List<String>();
foreach (DataRow dr in dt.Rows)
{
list.Add(dr["invoice_id"].ToString());
}
return list;
}
In your code, you call recursively the CheckProduct method passing again the ID of the invoice and doesn't seems to be a way out of that loop. Instead the list of products for the invoice are already known from the previous call to the SPDatalogic class. So you just need to add them to your list
Also in the DataLogic class there is a possible error in the declaration of the parameter. If #inv_id is of type integer, then don't declare the parameter as VarChar
cmd.Parameters.Add("#inv_id", SqlDbType.Int).Value = int.Parse(id);
And as a final note, I don't understand why you want to work with a List<string> when your IDs are clearly numbers. This causes continue conversions of type from string to int and viceversa. You shoud retrive a List<int> and convert just the input of your textbox.
In the development, I intent to retrieve the Index Key from SQL Server Database and apply to the local.sdf database. However, I failed to retrieve the Index Key from SQL Server Database. So, how could i retrieve the value stored in DataSet?
E.g: tableName = "ProductTable", indexName = "IX_product".
Or my SqlDataAdapter doesn't return any value?
P/s: I understand that there are numerous of working tutorial in forum and stackoverflow, unfortunately, i couldn't get it worked.
private void btnGetSchema_Click(object sernder, RoutedEventArgs e)
{
SyncDbSchema();
}
private void SyncDbSchema()
{
// setIndexSchema();
DataSet dsIndex = getIndexSchema();
MessageBox.Show("Table Row Count : " + dsIndex.Tables["tbIndex"].Rows.Count);
for (int i = 0; i < dsIndex.Tables[0].Rows.Count; i++)
{
string tableName = dsIndex.Tables[0].Rows[i]["TableName"].ToString();
string indexName = dsIndex.Tables[0].Rows[i]["IndexName"].ToString();
string indexType = dsIndex.Tables[0].Rows[i]["IndexType"].ToString();
}
}
public DataSet getIndexSchema()
{
SqlConnection conn = new SqlConnection(lblServerCon.Content.ToString());
DataSet dataSet = new DataSet();
SqlDataAdapter sqlDataAdapter = new SqlDataAdapter();
conn.Open();
sqlDataAdapter = new SqlDataAdapter(String.Format(#"USE SyncServer SELECT T.[name] AS [TableName], I.[name] AS [IndexName],
COL_NAME(T.[object_id], IC.[column_id]) AS [ColumnName], I.[type] AS [IndexType], I.[is_unique] AS [Unique]
FROM sys.tables T INNER JOIN [sys].[indexes] I ON I.[object_id] = T.[object_id]
AND I.[is_primary_key] = '0'
INNER JOIN [sys].[index_columns] IC ON IC.[object_id] = T.[object_id]
AND IC.[index_id] = I.[index_id]"), conn);
sqlDataAdapter.FillSchema(dataSet, SchemaType.Source,"tbIndex");
conn.Close();
return dataSet;
}
The query is perfect working in T-SQL and get the result that i intent to retrieve.
TableName IndexName ColumnName IndexType Unique
tbReport IX_tbReport_SID SalesID 2 0
tbReport IX_tbReport_RID ReportID 2 0
Are you sure that you want to use FillSchema?
Why not just?
adapter.Fill(dataSet);
Of course you can combine them first FillSchema (but why you need it?), next data (just Fill)