DB connection adapter "Data type mismatch" - c#

I have succesufuly setup a connection to my acces DB (.mdb) using OleDb.I am encountering a
"Data type mismatch in criteria expression."
error if I use a "where" statement in the SQL command.If I remove it I succesufuly get all the Comments.
Any ideas?
My database looks something like this:
ID (short text) Comment (long text)
431 They_study_math
321 They_study_biology
and my code looks like this:
public void auth_group(string group)
{
connDB.Open();
DataSet ds = new DataSet();
OleDbDataAdapter adapter = new OleDbDataAdapter("SELECT Comment FROM groups WHERE ID=431", connDB);
adapter.Fill(ds);
connDB.Close();
DataTable dt = ds.Tables[0];
foreach (DataRow dr in dt.Rows)
{
listBox1.Items.Add(dr["Comment"].ToString());
}
}

I feel like your ID column is a character type, that's why you should use it with single quotes like;
WHERE ID = '431'
I have to say this, looks like the right type for your ID column is integer not character.
Also use using statement to dispose your database connections and OleDbDataAdapter.

your id field is string . you should write like this:
public void auth_group(string group)
{
connDB.Open();
DataSet ds = new DataSet();
OleDbDataAdapter adapter = new OleDbDataAdapter("SELECT Comment FROM groups WHERE ID='431'", connDB);
adapter.Fill(ds);
connDB.Close();
DataTable dt = ds.Tables[0];
foreach (DataRow dr in dt.Rows)
{
listBox1.Items.Add(dr["Comment"].ToString());
}
}

Related

Why does my System.Data.DataSet not work in a ForEach? (No GetEnumerator)

I have a puzzling error: I'm using a DataSet to return the result from a Stored Procedure, but I'm unable to use a ForEach to loop through the data... because apparently DataSet has no Enumerator
Error 111 foreach statement cannot operate on variables of type 'System.Data.DataSet' because 'System.Data.DataSet' does not contain a public definition for 'GetEnumerator'
As far as I was aware, every DataSet had a publicly accessible Enumerator, and in fact there are multiple examples on the internet of a DataSet being used exactly this way! So I'm a little confused... do I have a configuration issue? Am I missing something obvious?
I'm using WebApi in .NET 4.6
Code (genericised) follows
DataSet ds = new DataSet("DataSet");
string connectionString = ConfigurationManager.ConnectionStrings["SQLConnection"].ConnectionString;
using (SqlConnection conn = new SqlConnection(connectionString))
{
SqlCommand sqlComm = new SqlCommand("StoredProcedure", conn);
sqlComm.Parameters.AddWithValue("#Param1", 0);
sqlComm.Parameters.AddWithValue("#Param2", 1);
sqlComm.CommandType = CommandType.StoredProcedure;
SqlDataAdapter da = new SqlDataAdapter();
da.SelectCommand = sqlComm;
da.Fill(ds);
}
foreach (DataRow d in ds)
{
// Do things
}
use it like this
foreach(DataRow dr in ds.Tables[0].Rows)
{
// do your work here
}
A Dataset does not inherit from System.Collections and is not enumerable.
https://msdn.microsoft.com/en-us/library/system.data.dataset(v=vs.110).aspx
However a Datatable does if you call AsEnumerable().
https://msdn.microsoft.com/en-us/library/system.data.datatable(v=vs.110).aspx

Query giving only one result

My query is giving one result only i.e. one word for one URL when it should run for every entry in dt. Here dt is DataTable and contains many rows, url_given is a String. temp is table containing the words to be matched. Can anybody please tell me what is wrong with my query?
wordcount is the name of the table. url_String, word and count are columns.
The purpose of the query is to get the URLs matched with given URL and
their words which are in the list which is temp.
foreach (DataRow row in dt.Rows)
{
// read item
url_given = row["url_String"].ToString();
String qrystring = "select url_String,word,count from wordcount where url_String='" + url_given + "' and word in (select * from temp) ";
dt1 = db.searchandorder(qrystring);
// searchandorder is a call to a function that establishes the db connections and passes the query to the data adapter.
}
Here is my searchandorder function:
public DataTable searchandorder (String sql)
{
conn.Open();
SqlDataAdapter da = new SqlDataAdapter(sql, conn);
DataSet ds = new DataSet();
DataTable dt = new DataTable();
da.Fill( dt);
conn.Close();
Console.Write("table coloumns" + dt.Columns.ToString());
return dt;
}
Your problem comes from the fact you loop overwriting dt1 every time. You need to merge the results not replace them, but I can't say how you would do that without seeing db.searchandorder.
Also you have a very dangerous sql injection attack. If url_given was '; drop table wordcount; -- what would be the query the program will execute on the server? You need to use parameters with your data adapter.
EDIT: So, now that you shown your code, here is how you fix it. Instead of making a new DataTable every single time you pass you make one outside of the loop and pass in the same table every time. TableAdapter does not clear out the table before it fills by default.
private YourFunction(DataTable dt)
{
DataTable dt1 = new DataTable();
foreach (DataRow row in dt.Rows)
{
// read item
url_given = row["url_String"].ToString();
String qrystring = "select url_String,word,count from wordcount where url_String='" + url_given + "' and word in (select * from temp) ";
db.searchandorder(qrystring, dt1);
// searchandorder is a call to a function that establishes the db connections and passes the query to the data adapter.
}
DoSomthingWithResults(dt1);
}
public void searchandorder (String sql, DataTable dt)
{
conn.Open();
SqlDataAdapter da = new SqlDataAdapter(sql, conn);
da.Fill( dt);
conn.Close();
Console.Write("table coloumns" + dt.Columns.ToString());
return dt;
}
Now, that is the bare minimum to make your program work. There are a LOT of other bad practices you are doing.
Don't reuse a connection: Your conn object should be created inside searchandorder and be inside a using statement. Don't worry about making "too many connection", .NET will use connection pooling and reuse old connections.
Use using statments: Anything that implements IDisposable should be in a using statement (unless the item is being returned)
Follow naming standards: There is a set of standards C# code follows, your class searcandhorder should be named SerchAndOrder.
Use Parameters: You are vulnerable to a SQL injection attack use parameters for your data adapters. Not only does it improve safety, it makes your program faster by allowing SQL server to cache the query execution plan.
Here is a version of your program with those fixes applied.
private YourFunction(DataTable dt)
{
DataTable dt1 = new DataTable();
foreach (DataRow row in dt.Rows)
{
// read item
url_given = row["url_String"].ToString();
var parameter = new SqlParameter("#urlGiven", SqlDbType.VarChar, url_given.Length);
parameter.Value = url_given;
String qrystring = "select url_String,word,count from wordcount where url_String=#urlGiven and word in (select * from temp) ";
db.searchandorder(qrystring, dt1, parameter);
// searchandorder is a call to a function that establishes the db connections and passes the query to the data adapter.
}
DoSomthingWithResults(dt1);
}
public void SearchAndOrder (String sql, DataTable dt, params SqlParameter[] parameters)
{
using(var conn = new SqlConnection(_connectionString))
using(var da = new SqlDataAdapter(sql, conn))
{
da.SelectCommand.Parameters.AddRange(parameters);
conn.Open();
da.Fill(dt);
}
Console.Write("table coloumns" + dt.Columns.ToString());
return dt;
}

Column <column name> does not belong to table <table name>

I have a method working with dataset,
var EmpNameList = new List<string>();
var EmpDS = GetEmployeeList();
foreach (DataRow EmpDR in EmpDS.Tables[0].Rows)
{
EmpNameList.Add(EmpDR["EmpName"].ToString()); // Error on this line
}
exception Details:
Column 'EmpName' does not belong to table 'EmpDetailTbl'
at System.Data.DataRow.GetDataColumn(String columnName)
at System.Data.DataRow.get_Item(String columnName)
at System.Data.DataRowExtensions.Field[T](DataRow row, String columnName)
at times we also get the following exception for the same method
Cannot find table 0 at System.Data.DataTableCollection.get_Item(Int32 index)
All the above exception are not reproduced consistently and it is intermittent.
The GetEmployeeList definition looks as below
public DataSet GetEmployeeList()
{
var Connectionstring = "MyConnectionString";
var query = "Select EmpName, EmpId, HireDate from EmpDetail";
DataSet ds = new DataSet();
using (OleDbConnection connection = new OleDbConnection(Connectionstring))
using (OleDbCommand command = new OleDbCommand(query, connection))
using (OleDbDataAdapter adapter = new OleDbDataAdapter(command))
{
adapter.Fill(ds,"EmpDetailTbl");
return ds;
}
}
I have tried with SQL Server using the SqlConnection class also.
This seems to be wierd huh???
If you are filling other DataTables in the DataSet then "EmpDetailTbl" may not be the first one every time (0). Refer to the DataTable by name:
foreach (DataRow EmpDR in EmpDS.Tables["EmpDetailTbl"].Rows) {
http://msdn.microsoft.com/en-us/library/y4b211hz(v=vs.110).aspx
Check out the remarks - if the actual query string you're using returns no rows, no tables are added to the dataset. Also note that the strings used are case sensitive.

Modified Data Table

For example I have this table
EmployeeName EmpoyeeID
John Mark 60001
Bent Ting 60002
Don Park 60003
How I can show the EmployeeID to have a leading asterisk in data table?
Sample: *60001 *60002 *60003
public DataTable ListOfEmployee()
{
DataSet ds = null;
SqlDataAdapter adapter;
try
{
using (SqlConnection myDatabaseConnection = new SqlConnection(myConnectionString.ConnectionString))
{
myDatabaseConnection.Open();
using (SqlCommand mySqlCommand = new SqlCommand("Select * Employee", myDatabaseConnection))
{
ds = new DataSet();
adapter = new SqlDataAdapter(mySqlCommand);
adapter.Fill(ds, "Users");
}
}
}
catch (Exception ex)
{
throw new Exception(ex.Message);
}
return ds.Tables[0];
}
I need to show the dataTable in the crystal report with a leading asterisk in the employee ID
public void Employees()
{
ReportDocument rptDoc = new ReportDocument();
Employees ds = new Employees(); // .xsd file name
DataTable dt = new DataTable();
// Just set the name of data table
dt.TableName = "Employees";
dt = ListOfEmployee(); //This function is located below this function
ds.Tables[0].Merge(dt);
string strReportName = "Employees.rpt";
string strPath = Application.StartupPath + "\\Reports\\" + strReportName;
// Your .rpt file path will be below
rptDoc.Load(strPath);
//set dataset to the report viewer.
rptDoc.SetDataSource(ds);
ReportViewer newReportViewer = new ReportViewer();
newReportViewer.setReport(rptDoc);
newReportViewer.Show();
}
the easiest not the best way to do is to get the data in that format, if and only if it is not meant to be used anywhere else. You can do this in your query
Select '*'+id,col1,col2,col3 from employee
Though the best way is to modify the column value when you consume it. But obviously that is more headache than adding simply in the query.
Add it into the Crystal report itself.
Something like -
"*" & {tblTable.FieldName}
(Although I can't remember the syntax for Crystal reports, sorry!)
Not tested, but replacing the return statement at the end of your function with the following code should work:
DataTable table = ds.Tables[0];
DataTable clonedTable = table.Clone();
clonedTable.Columns["EmployeeID"].DataType = typeof(String);
foreach (DataRow row in table.Rows)
{
clonedTable.ImportRow(row);
}
foreach (DataRow row in clonedTable.Rows)
{
row["EmployeeID"] = "*" + row["EmployeeID"].ToString();
}
return clonedTable;
However, as others have said, I would recommend adding the asterick somewhere down the line when the data is read rather than to the table itself.

store select result

i want to extract my table names and save it into variables this is my cod that return 3 answer:student, teacher and score. how can i change it to save these tree table name to 3 variable. thank you.
try
{
SqlDataReader myreader = null;
SqlCommand mycommand = new SqlCommand("select * FROM information_schema.tables WHERE table_type = 'BASE TABLE'", myconnect);
myreader = mycommand.ExecuteReader();
while (myreader.Read())
{
Console.WriteLine(myreader[2].ToString());
}
}
A simple builtin way is using Connection.GetSchema:
using (var con = new System.Data.SqlClient.SqlConnection(conStr))
{
con.Open();
DataTable schemaTable = con.GetSchema("Tables");
IList<string> allTableNames = schemaTable.AsEnumerable()
.Where(r => r.Field<string>("TABLE_TYPE") == "BASE TABLE")
.Select(r => r.Field<string>("TABLE_NAME"))
.ToList();
}
Now you have a List<string> with all table names which you can access via indexer or in a loop or create a comma separated list with string.Join:
string tNames = string.Join(",", allTableNames);
Console.Write("all tables in the given database: " + tNames);
You can use this :
string tableName ="" ; // Variable to stroe the table names
string connectionString = ""; //Your connectionstring
// get records from the table
string commandString =""; //Your query
// create the data set command object
// and the DataSet
SqlDataAdapter DataAdapter =new SqlDataAdapter(commandString, connectionString);
DataSet DataSet = new DataSet( );
// fill the DataSet object
DataAdapter.Fill(DataSet, "Customers");
// Get the one table from the DataSet
DataTable dataTable = DataSet.Tables[0];
// for each row in the table, display the info
foreach (DataRow dataRow in dataTable.Rows)
{
tableName = dataRow[0].tostring();
//...
}
if you want to save the result for future user or a different session then you can use any of the following to methods
first one
use the "insert" query to save the result one by one in the a different table that you would create specially for saving the data
you can put the insert command/statement directly into the for loop
second method
use the xml to store the value very simple and memory friendly
I Have modified #Doctor code to use ArrayList to store number of table name in single variables.
ArrayList alTableName = new ArrayList(); // Variable to stroe the table names
string connectionString = ""; //Your connectionstring
// get records from the table
string commandString =""; //Your query
// create the data set command object
// and the DataSet
SqlDataAdapter DataAdapter =new SqlDataAdapter(commandString, connectionString);
DataSet DataSet = new DataSet( );
// fill the DataSet object
DataAdapter.Fill(DataSet, "Customers");
// Get the one table from the DataSet
DataTable dataTable = DataSet.Tables[0];
// for each row in the table, display the info
foreach (DataRow dataRow in dataTable.Rows)
{
alTableName.Add(dataRow[0].tostring());
//...
}

Categories