Value cannot be null c#.net - c#

I am creating a simple project on c#.net. I want to put the AutoNo textbox in my program. I have put but it is not working. it shown the error while ran program error said that
Value cannot be null Parameter name: Stringmscorlib
Code what I tried I attached below
public void Load()
{
SqlConnection Con = new SqlConnection("Data Source=.;Initial Catalog=test1;Persist Security Info=True;User ID=sa;Password=admin123");
Con.Open();
cmd = new SqlCommand("select id from records", Con);
Data = cmd.ExecuteReader();
while (Data.Read() != false)
{
auto = int.Parse(Data[0].ToString());
}
try
{
int newid = auto;
int id = newid + 1;
this.textBox1.Text = "S00" + id.ToString();
}
catch (Exception ex)
{
MessageBox.Show(ex.Message + ex.Source);
}
Data.Close();
}
}

There are two problems I can see here; the first would be: what if there are zero rows? what is auto then? is it null? then int.Parse(null) will fail. You don't actually show where auto is declared, which makes this bit a little hard to intuit about.
The other possibility is here:
auto = Data.GetString(0);
in which case: this is simply a null database value. Check for that, and handle it:
if (Data.IsDBNull(0))
{ ... do whatever; perhaps just "continue" }
else
{
auto = Data.IsDBNull(0);
// and process it, etc
}
But frankly, you're making life hard for yourself here; here's the same thing with a tool like Dapper:
using (var conn= new SqlConnection("...whatever..."))
{
// here we're asserting *exactly* zero or one row
string auto = conn.QuerySingleOrDefault<string>("select id from records");
if (auto == null)
{ ... do something else? ... }
else
{
var newid= int.Parse(auto);
}
}
Note: your query could currently return any number of rows; since the code only processes the last value, I suggest that the SQL needs fixing; perhaps MAX, MIN, or TOP 1 with an ORDER BY clause; i.e. something like select MAX(id) as [id] from records. Note, however, that this sounds like a scenario where you should probably have used SCOPE_IDENTITY() in some query that added or inserted the value. And an id should very rarely be a string.

Parse method is not able to handle null value. Assuming auto is variable name.
instead of this
int newid = Int32.Parse(auto);
use something like below
int newid=0;
int.TryParse(auto, out newid);

Related

Auto generation of Order id

I wanted to have a unique transaction id for each order placed on my system and it only increments once. this is the code that i am using. help me out to have the incrementation fixed.
string transactionCode;
con = new SqlConnection(#"Data Source=LAPTOP-KA7UGSG3;Initial Catalog=imsysdb;Integrated Security=True");
cmd = new SqlCommand("SELECT TransactionCode from tblOrders", con);
con.Open();
dr = cmd.ExecuteReader();
if (dr.Read())
{
int code = int.Parse(dr[0].ToString()) + 1;
transactionCode = code.ToString("000");
}
else if (Convert.IsDBNull(dr))
{
transactionCode = ("001");
}
else
{
transactionCode = ("001");
}
lblTransactionCode.Text = transactionCode.ToString();
OUTPUT
|transaction code|
|001|
|002|
|002|
|002|
It looks like your current code wants something that you can pull successive values from without inserting rows anywhere. You don't mention what database you are using, but in SQL Server this concept is a "sequence", see CREATE SEQUENCE
However, when talking about things like "orders", the more common approach is to make the Id column an "identity" (see CREATE TABLE / IDENTITY, so that the server generates the Id when you INSERT. You can read the newly generated value with any of (in preference order, earlier is better):
the OUTPUT clause on the INSERT
SCOPE_IDENTITY() (usually fine, but limited to one row)
##IDENTITY (many problems; don't use unless the others aren't available on your server)
I can see that your id generating is not related to SQL, you are trying to generate it in C# for some reason, so try replacing this :
if (dr.Read())
{
int code = int.Parse(dr[0].ToString()) + 1;
transactionCode = code.ToString("000");
}
else if (Convert.IsDBNull(dr))
{
transactionCode = ("001");
}
else
{
transactionCode = ("001");
}
With this:
Edited - code updated
int code; //OR int code = 0;
if (dr.Read())
{
code = int.Parse(dr[0].ToString()) + 1;
transactionCode = code.ToString("000");
}
else if (Convert.IsDBNull(dr))
{
transactionCode = ("001");
}
else
{
transactionCode = ("001");
}
If it does not work, Edit your post and add some sample data, please.
I second the suggestions that you use a SQL identity column. With that said, assuming you don't control schema...
The logic of your attempt here is flawed in a couple of ways...
First I'm pretty sure you want to be querying MAX(TransactionCode)
Second, you can easily have two clients querying very close to each other, they both read the current maximum TransactionCode and both increment it to get the same new code.
Therefore you want to remove the increment from your C# code and do it in SQL script if at all possible with something like this (NB see #Marc Gravell's comment below)...
INSERT INTO tblOrders (TransactionCode, field1, field2...)
VALUES (CONVERT(VARCHAR(10), SELECT CONVERT(INT, MAX(TransactionCode)) + 1) FROM tblOrders, newfield1data, ...)

ExecuteScalar() always return NULL

I am trying to return an integer from the database using ExecuteScalar(). However, when I run the query on the database itself, I get the correct answer, and c# gives me a 0 (Null) all the time. I know it returns a null because before i added id = Convert.ToInt32(command.ExecuteScalar()); it would give me an error telling me to make sure NULL is handled. I am expecting it to return a 3 btw.
private int getFamilyId()
{
int id = 0;
using (SqlConnection connection = new SqlConnection(Globaldata.ConnectionString))
{
using (SqlCommand command = new SqlCommand())
{
string sqlString = #"SELECT [Id] FROM [dbo].[FamilyDetails];";
command.Connection = connection;
command.CommandText = sqlString;
try
{
connection.Open();
id = Convert.ToInt32(command.ExecuteScalar());
}
catch (Exception e)
{
MessageBox.Show(e.Message, "Error", MessageBoxButtons.OK);
}
finally
{
connection.Close();
}
return id;
}
}
}
When you do this:
string sqlString = #"SELECT [Id] FROM [dbo].[FamilyDetails];";
You don't want to do this:
id = Convert.ToInt32(command.ExecuteScalar());
Three things could go wrong here.
Problem #1:
If there are no rows in the table, command.ExecuteScalar() wil return Null.
Problem #2:
If there are any rows in the table, command.ExecuteScalar() wil return the value of the first rows it happens to encounter because the SELECT statement is not restricted to 1 value.
Problem #3:
If the Id column is not declared as NOT NULL command.ExecuteScalar() could return a DbNull, which which makes no sense when converted to an Integer.
Try and see what happens when there are 0 or 1 or 2 records in the table.
--UPDATE--
It works now, My connection string had one character missing. I think it happened when I took out the connection Timeout part of the connection string.
Thank you for your suggestions!!!

How do i prevent duplicate records in my database while updating records?

in my mysql table I made look like this one
ControlNum|Title |NumOfEpis|Description|
001 |naruto |500 |some text |
002 |conan |700 |some text |
now I made a user control in C# where in the user is allowed to update all columns except the primary"ControlNum". so assuming each column has its own textboxes in that said user control so in order to avoid duplication in the title column like for example if the user edit the row 2 title and put it "naruto" also it would be duplicated..so I create this method called checkData();
void checkData()
{
SuspendLayout();
try
{
MySqlConnection conn = new MySqlConnection(myConnection);
conn.Open();
MySqlCommand command = new MySqlCommand("SELECT * FROM maindatabase.animelist where TitleAnime=?Title;", conn);
//command.Parameters.AddWithValue("?CN", int.Parse(a.ToString()));
command.Parameters.AddWithValue("?Title", textBox3.Text);
MySqlDataReader reader = command.ExecuteReader();
int ctr = 0;
while (reader.Read())
{
ctr++;
}
if (ctr == 1)
{
my = Form.ActiveForm as MyList;
my.msg = new Message_Box();
my.msg.Descrip.Text = "Record is already in the Database";
my.msg.Title.Text = "Duplicate Record";
my.msg.ShowDialog();
}
else
{
updateData();
}
conn.Close();
ResumeLayout();
}
catch (Exception ex)
{
MessageBox.Show("" + ex);
}
}
it was working but my problem is what if the user only update the number of epis and descrip and doesn't really intend to update the title,my method still detect that there's a duplicate since my logic was "if(ctr == 1)"..I think I'm missing some method or I'm in a wrong approach here..so I hope someone will enlighten me..sorry for being noob here Y.Y
If your application supports multiple users you need to ensure changes are not made by another user between your check for duplicates and the database update.
The easiest way to do this is as mbeckish suggested, create a UNIQUE constraint on the title column:
ALTER TABLE maindatabase.animelist
ADD CONSTRAINT U_animelist_TitleAnime UNIQUE (TitleAnime)
The database engine will then enforce unique titles and your client can handle user feedback by catching any constraint violation exception:
void checkData()
{
SuspendLayout();
try
{
updateData();
}
catch (Exception ex)
{
MySqlException sqlEx = ex as MySqlExecption;
// If there is a constraint violation error.
// (I may have the wrong error number, please test.)
if (sqlEx != null && sqlEx.Number == 1062)
{
my = Form.ActiveForm as MyList;
my.msg = new Message_Box();
my.msg.Descrip.Text = "Record is already in the Database";
my.msg.Title.Text = "Duplicate Record";
my.msg.ShowDialog();
}
else
{
MessageBox.Show("" + ex);
}
}
finally
{
ResumeLayout();
}
}
You don't want to have two Title with the same content. This could be achieved automatically with an UNIQUE index on that column. However, if you don't want to add an index for this then you could change your query to
SELECT ControlNum FROM maindatabase.animelist
WHERE TitleAnime=?Title;
Then your logic should check also the ControlNum for differences
int currentNum = int.Parse(a.ToString()));
while (reader.Read())
{
int ctrlNum = reader.GetInt32(0);
if(ctrlNum != currentNum)
ctr++;
}
if (ctr > 0)
......
In this way you increment your counter only if the ControlNum retrieved is different from the one you have selected in your interface
Another approach is the following (see comment below from #mbeckish)
SELECT 1 FROM maindatabase.animelist
WHERE TitleAnime=?Title AND ControlNum <> ?CN
command.Parameters.AddWithValue("?CN", int.Parse(a.ToString()));
command.Parameters.AddWithValue("?Title", textBox3.Text);
object result = command.ExecuteScalar();
if(result != null)
{
// Found a record with different ControlNum but with the same title
// Error here
}
This is probably preferable to the first one because you don't need a loop and could use a simpler and more performant ExecuteScalar that returns only the first column of the first row (the 1 in this case) without building the MySqlDataReader object
Change the duplicate finding SQL :
SELECT MAX(Title) as Count
FROM maindatabase.animelist
GROUP BY Title , NumOfEpis, Description
if Count > 1 , then there is a duplicate.

Using C# to connect and insert to SQL Server 2012

I'm working on some code to try and get my array that's entered by the user to connect and send to SQL Server 2012. I've been told to use all of these commands to connect to the database.
One of my issues is that I've been looking through Stack Overflow and everyone suggests using parameters instead of concatenating to avoid SQL injection, but this is for my class and we are only 2 weeks into C# so I don't think he's going to like it if I use parameters.
I think my try catch is wrong, the top half is filled with red lines and how do you use the INSERT command with a for loop?
protected void btnDisplay_Click(object sender, EventArgs e)
{
//try
//{
// System.Data.SqlClient.SqlConnection varname1 = new System.Data.SqlClient.SqlConnection();
// varname1 = "server = LOCALHOST"; Database = Lab1; Trusted_connection = yes;
// varname1.Open();
// System.Data.SqlClient.SqlCommand cmd = new System.Data.SqlClient.SqlCommand();
// cmd.Connection = conn;
// cmd.CommandText = "Delete From Student";
// cmd.ExecuteNonQuery();
//
string sql = null;
for(int i=0; counter1 >= i; i++)
{
sql += "INSERT into Student VALUES(" + StudentId + Name + Address);
}
varname1.Close();
//}
catch (SqlException ex)
{
MessageBox.Show("Database failed" + ex.Message);
}
}
So, there are quite a few problems with this code. It might be best to spend another hour on it or so, then post any specific questions you can't figure out. Let me give you a few quick pointers though.
You have a catch() block, but the matching try block is commented out. This will result in a compiler error. It looks like you were just debugging some stuff, so no big deal. However, it's usually wise to post the actual code you're trying to run.
You're initializing a string to null, but you're concatenating on to the end. This will result in a runtime error. You should initialize your string to String.Empty instead. Also, look into the StringBuilder class if you're doing large amounts of string concatenation, as it's much faster.
You're (in theory) building a SQL string, but never actually running it anywhere. Nor do you return the value to anything that could run it.
Your INSERT statement isn't even valid. You don't have a matching end ) in the INSERT statement, and you have a rogue ) after your variables, which will result in a compiler error. You also just mash all the variables together, without quotes or commas between them. You probably want something more like:
sql += String.Format("INSERT into Student VALUES('{0}', '{1}', '{2}');", StudentId, Name, Address);
Use parameterized queries. Always. Who cares what your teacher says. If you don't, at the very least, check the strings for apostrophes first, as these will screw up your SQL statement by prematurely ending the string.
Your loop doesn't seem to make much sense. What is counter1? What value does it have? Even if it's set to a positive value, all you're doing is building the same SQL string over and over again since the values within the loop don't change. It's not clear what you're trying to do here.
You're calling varname1.Close(); but you've commented out the declaration of varname1, which will result in a compiler error.
Hope this helps!
Is this what you are after. You may have to adapt some of it. Sorry if it doesent fully work dont have a debugger at the moment.
class Data {
public int StudentId {get;set;}
public string Name {get;set;}
public string Address {get;set;}
}
protected void btnDisplay_Click(object sender, EventArgs e)
{
var datas = new List<Data>();
try
{
StringBuilder sql = new StringBuilder();
foreach(data in datas)
{
sql.Append(String.Format("INSERT into Student VALUES({0},'{1}','{2}') ",data.UserId,data.Name,data.Address));
}
var sqlConnection = new SqlConnection(#"Data Source=LOCALHOST;Initial Catalog=Lab1;Trusted_Connection=True;");
sqlConnection.Open();
var command = new SqlCommand(sql.ToString(),sqlConnection);
command..ExecuteNonQuery();
sqlConnection.Close();
}
catch(SqlException ex){
MessageBox.Show("Database failed" + ex.Message);
}
}

Add Unique Column Name to Access Database via Application - C#

I have a program which records ID,Name,TimeIn,TimeOut. On the first scan of a card it record the id,name and timein, and then on second swipe it adds to the timeout column. I am trying to get it to add another "TimeIn" column on the third swipe, so I tried to get it to insert "TimeIn + Unique Number", but it does not pick up the variable due to the quotes.
Here is my code:
private void SignIn_Time(OleDbCommand updateCmd, OleDbConnection OLEDB_Connection, Object varName, Object varID, String varTime)
{
object varTimeColumn;
varTimeColumn = "TimeIn" + GetUniqueNumber();
updateCmd.CommandText = "ALTER TABLE TestDB ADD COLUMN varTimeColumn TEXT";
updateCmd.CommandText = "INSERT INTO TestDB (varTimeColumn) VALUES (#TIMEIN)";
updateCmd.Parameters.AddWithValue("#TIMEIN", varTime);
OLEDB_Connection.Open();
updateCmd.Connection = OLEDB_Connection;
updateCmd.ExecuteNonQuery();
OLEDB_Connection.Close();
}
static int counter;
public static int GetUniqueNumber()
{
return counter++;
}
There are two errors in the code above:
The Access Jet Engine doesn't support two concatenated commands. You should send each command by itself.
Another problem is the variable name used to represent the column name. You cannot embedd the variable inside the command. You should put its value, and to do that, you could only use a string concatenation.
private void SignIn_Time(OleDbCommand updateCmd, OleDbConnection OLEDB_Connection,
Object varName, Object varID, String varTime)
{
try
{
OLEDB_Connection.Open();
string varTimeColumn = "TimeIn" + GetUniqueNumber().ToString();
updateCmd.Connection = OLEDB_Connection;
updateCmd.CommandText = "ALTER TABLE TestDB ADD COLUMN " + varTimeColumn + " TEXT";
updateCmd.ExecuteNonQuery();
updateCmd.CommandText = "INSERT INTO TestDB (varTimeColumn) VALUES (#TIMEIN)";
updateCmd.Parameters.AddWithValue("#TIMEIN", varTime);
updateCmd.ExecuteNonQuery();
OLEDB_Connection.Close();
}
catch(Exception ex)
{
if(OLEDB_Connection.State == ConnectionState.Open)
OLEDB_Connection.Close();
// Perhaps in debug you could do something here with the exception like a log message
// or rethrow the execption to be handled at an upper level...
throw;
}
}
static int counter;
public static int GetUniqueNumber()
{
return counter++;
}
Also I suggest to use a try/catch block around your code because, in case of exceptions, you don't close the connection. A better approach should be the using statement, but from the code above is not clear how to implement this pattern
I completely agree with the comment from #Corak above. The proposed solution is the only rationale approach to your logical requirements. Also, remember that an Access Table has limitations on the max number of columns that could be added to a table. 255 is this limit and your code doesn't seem to keep this in any consideration.
Microsoft Access 2010 specifications

Categories