Must declare the scalar variable in C# - c#

I am developing an app in C# in which when I am interacting with my database SQL Server
it is giving me the exception of 'Must declare the Scalar Variable'. The code is following
public DataTable Search(string clas)
{
try
{
DataTable table = new DataTable();
string query = "";
using (SqlConnection connection = new SqlConnection(connectionString))
{
if (clas != "")
{
query = "Select * from StudentManagement Where classEnrolled=#cls";
//dataAdapter
dataAdapter = new SqlDataAdapter(query, connectionString);
dataAdapter.SelectCommand.Parameters.Add(new SqlParameter("cls", clas));
}
dataAdapter = new SqlDataAdapter(query, connectionString);
// Create a command builder to generate SQL update, insert, and
// delete commands based on selectCommand. These are used to
// update the database.
SqlCommandBuilder commandBuilder = new SqlCommandBuilder(dataAdapter);
// Populate a new data table and bind it to the BindingSource.
table.Locale = System.Globalization.CultureInfo.InvariantCulture;
dataAdapter.Fill(table);
}
return table;
}
catch (Exception e)
{
return null;
}
}
Please help me

I have a strong suspicion that clas is a null reference. Note that this will still trigger your != "" branch, since a null-reference is not the same as an empty string.
Maybe use:
if(!string.IsNullOrEmpty(clas)) {...}
Instead?
A peculiarity of db-parameters is that they are not included if the .Value is null. Check the value you are sending in.
It doesn't apply in your case (since in normal SQL nothing ever equals NULL) but: if you intend to send NULL as a parameter, you must set the value to DBNull.Value instead.

Related

The DataSet result is always empty in C#

I am retrieving particular column value using DataSet.
This is my code:
public DataSet GetRedirectURL(string emailId)
{
DataSet ds = new DataSet();
using (SqlConnection con = new SqlConnection(#"Connection_String_Here"))
{
con.Open();
SqlCommand sqlComm = new SqlCommand("usp_Login", con)
{
CommandType = CommandType.StoredProcedure
};
sqlComm.Parameters.AddWithValue("#EmailId", emailId);
SqlDataAdapter da = new SqlDataAdapter
{
SelectCommand = sqlComm
};
da.Fill(ds);
}
return ds;
}
I have also used DataTable instead of it but the same result.
I have checked my Stored Procedure and when I pass Parameter it shows Data. So, nothing wrong with the SP. But the Table doesn't show any data and is always empty as shown below:
What am I missing? Any help would be appreciated.
I'd suggest you to first evaluate the content of your DataSet. For instance, type in your Immediate Window (or add a quick watch) to check ds.Tables[0].Rows.Count. Basically, to assert your DataSet has been properly filled with the contents fetched from the database, and focus on the data assignment from the DataSet to the grid object you're using to display it.
Also, the .Fill() method has a returning object which is an int representing the amount of rows that have been successfully filled into the target object. For instance:
int result = da.Fill(ds);
Check the value of result after the .Fill() method has been executed.
Finally, I guess you're using a DataGridView object to visualize the results. If so, how are you binding data? Should be something like:
dataGridView1.DataSource = ds.Tables[0];
PS: As I've read in other comments, no, you don't need to execute the .Open() method on the connection. That's not necesarry, it's done implicitely when using the (using SqlConnection conn = SqlConnection..)

OleDbCommandBuilder Update - at least one parameter values are missing

What I did:
I am using OleDbAdapter to read from the database, getting a fresh DataTable filled. This went good. Then I want to add a column into that DataTable, which also went good.
I added a OleDbCommandBuilder, to update the database with the DataTable having one more column. And I tried it with the 'automatical way' of the OleDbCommandBuilder, as I thought what I want is simple. But so far this did not work.
What I expect
is that the OleDbCommandBuilder is writing a fresh SQL command for me, having 'UPDATE' or 'INSERT' contained. I further expect, that I can't read all Commands within the OleDbAdapter, except the SELECT command, because OleDbAdapter takes the commands from the builder right before using them.
I have read in the internet, that adapter.Fill(...) is not necessary if I let call adapter.Update(...). But without adapter.Fill(...) I don't get content from the database.
Finally a problem has got a name:
Now, after searching for the problem, I got the following message: System.Data.OleDbException: For at least one parameter no value has been given.
My questions:
1) Do I expect something wrong?
2) Which parameter hasn't got a value? Solved This helped me to understand:
https://learn.microsoft.com/en-us/dotnet/api/system.data.sqlclient.sqlcommand.parameters?redirectedfrom=MSDN&view=netframework-4.7.2#System_Data_SqlClient_SqlCommand_Parameters
3) Are the adapter, builder ... placed in the right order?
4) Have I got something additional to do, like calling a function to update the SQL command withing the adapter?
5) How can I improve the way I solve that problem? E.g.: Is there any event which will help me to understand more what is going on? How to catch such an event?
Many thanks in advance!
This is the my code - originally it is divided into two functions. But I put it all in one for you:
public virtual bool AddColumnOfString_ToDataTable(string tableName, string newColumnName, string defaultCellValue)
{
/// Approach: Accessing database at minimum time.
/// returns true if column name could not be found and column could be added
DataTable table = new DataTable();
string strSQL = "SELECT " + tableName;
OleDbDataAdapter adapter = new OleDbDataAdapter(strSQL, strConnection);
adapter.Fill(table);
OleDbCommandBuilder builder = new OleDbCommandBuilder(adapter);
bool result = false;
if (false == HasColumn(newColumnName))
{
DataColumn newColumn = new DataColumn(newColumnName, typeof(System.String));
newColumn.DefaultValue = defaultCellValue;
table.Columns.Add(newColumn);
result = true;
}
adapter.Update(table);
return result;
}
You modified the structure of the DataTable by adding newcolumn to the datatable and this is not reflected in the generated update/insert/delete sql commands.
Have a look to this example: OleDbCommandBuilder Class
so simply:
adapter.Update(table);
Only update the data in the base table in the server (if changed)
1) Do I expect something wrong?
No, it's working but no change in the structure of base table in MS access
2) Which parameter hasn't got a value?
you don't pass parameters in the SQL command
3) Are the adapter, builder ... placed in the right order?
yes, but remove the part that modify the datatable. It has no effect
4) Have I got something additional to do, like calling a function to update the SQL command withing the adapter?
rview my code with the comments.
5) How can I improve the way I solve that problem? E.g.: Is there any event which will help me to understand more what is going on? How to catch such an event?
You can't modify the structure of the datatable by adding new columns
Update
I test your code , modified it with comments:
public bool AddColumnOfString_ToDataTable(string tableName, string newColumnName, string defaultCellValue)
{
// Approach: Accessing database at minimum time.
// returns true if column name could not be found and column could be added
DataTable table = new DataTable();
//string strSQL = "SELECT " + tableName; // not valid syntax
string strSQL = "SELECT * from " + tableName;
OleDbDataAdapter adapter = new OleDbDataAdapter(strSQL, myConnectionString);
adapter.Fill(table);
OleDbCommandBuilder builder = new OleDbCommandBuilder(adapter);
bool result = false;
// remove this code, it has no effect on the underlying base table in MS Access databas
//any change in the structure of datatable has no effect on the database
/*
if (false == table.HasColumn(newColumnName))
{
DataColumn newColumn = new DataColumn(newColumnName, typeof(System.String));
newColumn.DefaultValue = defaultCellValue;
table.Columns.Add(newColumn);
result = true;
}
*/
// code to modify data in DataTable here
//Without the OleDbCommandBuilder this line would fail
adapter.Update(table);
//just to review the generated code
Console.WriteLine(builder.GetUpdateCommand().CommandText);
Console.WriteLine(builder.GetInsertCommand().CommandText);
return result;
}
Update2:
If you are interested for adding new column to MS Access Database, you can run the following code:
public bool AddColumn(OleDbConnection con,
string tableName,string colName,string colType, object defaultValue)
{
string query = $"ALTER TABLE {tableName} ADD COLUMN {colName} {colType} DEFAULT {defaultValue} ";
var cmd = new OleDbCommand(query, con);
try
{
con.Open();
cmd.ExecuteNonQuery();
Console.WriteLine("Sql Executed Successfully");
return true;
}
catch (OleDbException e)
{
Console.WriteLine("Error Details: " + e);
}
finally
{
Console.WriteLine("closing conn");
con.Close();
}
return false;
}
public void AddColumnTest()
{
OleDbConnection con = new OleDbConnection(myConnectionString);
string tableName="table1";
string colName="country";
string colType="text (30)";
object defaultValue = "USA";
AddColumn(con, tableName, colName, colType, defaultValue);
}
I test the code with MS Access and it's working fine.

SQLiteDataAdapter converts empty value to 0 - how to prevent that?

Below is a snippet of the code. As you can see, that method returns a table from SQLite database, and adds that table to a DataSet if it doesn't exist yet.
SQLiteConnection connection;
DataSet Set = new DataSet();
DataTable GetTable(string tableName, string command)
{
if (!Set.Tables.Contains(tableName))
{
var adapter = new SQLiteDataAdapter(command, connection);
SQLiteCommandBuilder builder = new SQLiteCommandBuilder(adapter);
adapter.FillSchema(Set, SchemaType.Source, tableName);
adapter.Fill(Set, tableName);
adapter.Dispose();
}
return Set.Tables[tableName];
}
To call it, for example
DataTable myTable = GetTable("MyTable", "select * from MyTable);
To access a field:
object emptyValue = myTable.Rows[0]["Some_Column"];
There are some cells in the SQLite file that are of type INT, and their values are empty (not null). However when I'm trying to populate myTable, they are conveniently converted to 0's which I DO NOT WANT. How do I go about fixing that? I would like to keep empty values (and null values) as null's when importing to C#.
You can retrieve the row I was talking about above by executing the following SQL statement:
select * from MyTable where some_column = ''
The SQLite file that I use is SQLite3. Just in case it helps.
Thanks in advance!

Visual Studio 2013 fill DataGrid

I'm trying to read data from a SQLite database. Then I'd like to fill it into my DataGrid, but the following code doesn't work (dataUrl is the DataGrid-Object):
string sql = "SELECT rowid, url FROM urls WHERE url LIKE '%#search%'";
SQLiteConnection myConnection = new SQLiteConnection(#"Data Source=C:\URL Store\URL Store\bin\Release\urlStore.sqlite;Version=3;Password=*censored*;");
SQLiteCommand command = new SQLiteCommand(sql, myConnection);
command.Parameters.AddWithValue("#search", txtSearch.Text);
myConnection.Open();
command.ExecuteNonQuery();
SQLiteDataAdapter adapter = new SQLiteDataAdapter(command);
DataSet set = new DataSet();
try
{
//
//ESPECIALLY THIS PART IS IMPORTANT TO ME
//
adapter.Fill(set);
DataTable table = set.Tables[0];
dataUrl.DataContext = table;
}
catch (Exception ex)
{
MessageBox.Show("Error loading data!");
}
It does't even throw an exception.
You should set ItemsSource instead of DataContext and for that you need to get DataView as it only accepts IEnumerable:
dataUrl.ItemsSource = table.DefaultView;
or
dataUrl.ItemsSource = new DataView(table);
also remove command.ExecuteNonQuery();
You can use the ExecuteNonQuery to perform catalog operations (for example, querying the structure of a database or creating database objects such as tables), or to change the data in a database without using a DataSet by executing UPDATE, INSERT, or DELETE statements.
also, because you use parameters and AddWithValue(..), your query should look like this:
string sql = "SELECT rowid, url FROM urls WHERE url LIKE #search";
and you add parameter like this instead:
command.Parameters.AddWithValue("#search", "%" + txtSearch.Text + "%");
which is the whole point of using parameters

Combobox add rows dynamically and dropdown from SQL Server stored procedure

This is basically a search tool. When I type some thing in a combobox, the combobox drops down and will show me suggestions (something like Google search bar)
I created a procedure which does some complex calculations, which take one parameter and returns some rows. Then I created a combobox event (On Update Text).
And in the event handler I wrote this code:
private void combobox_TextUpdate(object sender, EventArgs e)
{
this.combobox.Items.Clear();
DataTable List = new DataTable();
if (this.combobox.Text.Length > 0)
{
List = searchIt(combobox.text);
foreach (DataRow Row in List.Rows)
{
this.combobox.Items.Add(Row.ItemArray.GetValue(0).ToString());
}
this.combobox.DroppedDown = true;
}
}
static public DataTable searchIt(string STR)
{
string connectionString = McFarlaneIndustriesPOSnamespace.Properties.Settings.Default.McFarlane_IndustriesConnectionString;
SqlConnection con = new SqlConnection(connectionString);
DataTable DT = new DataTable();
con.Open();
SqlDataAdapter DA = new SqlDataAdapter("USE [McFarlane Industries] " +
"EXEC search " +
STR, connectionString);
DA.Fill(DT);
con.Close();
return DT;
}
The function searchIt executes the stored procedure and it returns a DataTable. The stored procedure is working fine in SQL Server Management Studio.
But in the application it is not working correctly in some cases.
When I type [space], then it throws an exception and it says stored procedure needs parameter which is not provided.
There are many other characters when I type them it throws exception that invalid character at end of string "my string".
Any suggestion how could I achieve my goal.
Call your stored procedure with sqlcommand to fill your datatable
using (SqlConnection scn = new SqlConnection(connect)
{
SqlCommand spcmd = new SqlCommand("search", scn);
spcmd.Parameters.Add("#blah", SqlDbType.VarChar, -1); //or SqlDbType.NVarChar
spcmd.CommandType = System.Data.CommandType.StoredProcedure;
using (SqlDataAdapter da = new SqlDataAdapter(spcmd))
{
da.Fill(dt);
}
}
static public DataTable searchIt(string STR)
{
string connectionString = McFarlaneIndustriesPOSnamespace.Properties.Settings.Default.McFarlane_IndustriesConnectionString;
SqlConnection con = new SqlConnection(connectionString);
DataTable DT = new DataTable();
con.Open();
SqlCommand command = new SqlCommand("Name_of_Your_Stored_Procedure",con);
command.CommandType=CommandType.StoredProcedure;
command.Parameters.Add(new SqlParameter("#parameter_name",SqlDbType.NVarChar));
command.Parameters[0].Value="Your Value in this case STR";
SqlDataAdapter DA = new SqlDataAdapter(command);
DA.Fill(DT);
con.Close();
return DT;
}
Important :
'parameter_Name' and 'Name_of_Your_Stored_Procedure' should be replaced by yours which you have in database. And value of parameter could be like "abc" (combox.Text)
Command and its type, its text are necessary.
Adding parameters depends upon your stored procedure. They can be 0,1 or more but once they are added their values must be given. conn(connection) can be passed to new SqlCmmand() or new SqlDataAdapter()
No need of things like 'use' and 'exec'
Following me and this link might be helpful in future for stored procedures
http://www.codeproject.com/Articles/15403/Calling-Stored-procedures-in-ADO-NET
Two optional Suggestions for you
use variable name 'list' instead of 'List' (you used) however you will not get problem with this name until you add a namespace using System.Collections.Generic; but you may need to use this namespace in future.
Use only list.Rows[0].ToString(); no need to get itemarray then get value when you are working with data in strings;

Categories