I am trying to insert rows into cassandra table using C# datareader loop, after insert one records it give me the below error
Error:{"Object cannot be cast from DBNull to other types."}
What am i doing wrong
--Code
ConnectionString._SQLServerName = txtsql.Text;
ConnectionString._DBName = "casmonitor";
SqlConnection MyConn = ConnectionString.GetOpenedConnection();
SqlCommand MyCommand = ConnectionString.GetOpenedConnection().CreateCommand();
SqlDataReader SqlReader;
string sqltext = ("select * from DBAdmin..[stockhist1] (nolock)");
MyCommand.CommandText = sqltext;
SqlReader = MyCommand.ExecuteReader();
while (SqlReader.Read())
{
ISession CluSession = cluster2.Connect("dbs");
var ps = CluSession.Prepare("insert into stocks (id,name,price1,price2,price3,price4) values (?,?,?,?,?,?)");
// var dbstring= "insert into stocks (id,name,price1,price2,price3,price4) values (" + SqlReader["id"].ToString() + ",'" + SqlReader["name"].ToString() + "'," + Convert.ToUInt64(SqlReader["price1"].ToString()) + "," + Convert.ToUInt64(SqlReader["price2"]) + "," + Convert.ToUInt64(SqlReader["price3"]) + "," + Convert.ToUInt64(SqlReader["price4"]) + ");";
// CluSession.Execute(dbstring);
// CluSession.Execute("insert into stocks (id,name,price1,price2,price3,price4) values (" + SqlReader["id"].ToString() + ",'" + SqlReader["name"].ToString() + "'," + Convert.ToUInt64(SqlReader["price1"].ToString()) + "," + Convert.ToUInt64(SqlReader["price2"]) + "," +Convert.ToUInt64(SqlReader["price3"]) + "," +Convert.ToUInt64(SqlReader["price4"]) + ")");
// var ps = CluSession.Prepare("insert into Product(id,name,p_image) values (?,?,?)");
var statement = ps.Bind(Convert.ToInt32(SqlReader["id"]),SqlReader["name"].ToString() ,Convert.ToDecimal(SqlReader["price1"]) ,Convert.ToDecimal(SqlReader["price2"]) ,Convert.ToDecimal(SqlReader["price3"]),Convert.ToDecimal(SqlReader["price4"]));
CluSession.Execute(statement);
cluster2.Shutdown();
CluSession.Dispose();
}
SqlReader.Close();
MyConn.Close();
One of these values (the Convert.To....()) is returning null from the database
var statement = ps.Bind(Convert.ToInt32(SqlReader["id"]),SqlReader["name"].ToString() ,Convert.ToDecimal(SqlReader["price1"]) ,Convert.ToDecimal(SqlReader["price2"]) ,Convert.ToDecimal(SqlReader["price3"]),Convert.ToDecimal(SqlReader["price4"]));
You cannot, for example, convert a DBNull to a decimal or int.
I would suggest you create a function that you can pass each of these into, and then return either a 0 (where DBNull) or the value
Something like this (not tested, just quick and dirty):
public static decimal GetDecimalValue(SqlDataReader reader, string fieldName)
{
if (!reader.IsDBNull(reader[fieldName])))
return reader.GetDecimal(reader[fieldName]);
else
return 0;
}
then adjust your statement to:
var statement = ps.Bind(Convert.ToInt32(SqlReader["id"]),
SqlReader["name"].ToString() ,
GetDecimalValue(SqlReader, "price1"),
GetDecimalValue(SqlReader, "price2"),
GetDecimalValue(SqlReader, "price3"),
GetDecimalValue(SqlReader, "price4"));`
Create one for int's too (haven't done that for you in the above)
Related
I've a problem with SqlConnection in C#. I do a large number of INSERT NonQuery, but in any case SqlConnection save in the database always the first 573 rows. This is the method I use for queries. In this method there is a lock because I use different thread to save the data.
public void InsertElement(string link, string titolo, string text)
{
string conString = "*****************";
using (SqlConnection connection = new SqlConnection(conString))
{
connection.Open();
text = text.Replace("\"", "");
DateTime localDate = DateTime.Now;
lock (thisLock)
{
string query = "IF (NOT EXISTS(SELECT * FROM Result " +
" WHERE Link = '" + link + "')) " +
" BEGIN " +
" INSERT INTO Result ([Titolo],[Link],[Descrizione],[DataRicerca],[FKDatiRicercheID]) " +
" VALUES('" + titolo + "', '" + link + "', '" + text + "', '" + localDate + "', 1) " +
" END";
if (connection != null)
{
SqlCommand cmd = new SqlCommand(query, connection);
cmd.ExecuteNonQuery();
}
}
}
}
This is the code of the loop that call the method InsertElement()
public void Save()
{
string[] DatiLetti;
string url = "";
while (result.Count > 0)
{
try
{
url = result.Last();
result.RemoveAt(result.Count - 1);
DatiLetti = ex.DirectExtractText(url);
if (DatiLetti[0].Length > 2)
{
ssc.InsertGare(url, DatiLetti[0], DatiLetti[1]);
}
}
catch (Exception exc)
{
logger.Error("Exception SpiderSave> " + exc);
}
}
}
Result is a volatile array that is progressively filled from other thread. I'm sure that the array contains more than 573 items.
I try to search one solution, but all the answers say that the number of database connections for SQLServer is over 32K at a time and I've already checked this number in my database. Is there anyone who can help me understand the problem?
Don't open a connection for every insert. Use one connection, then pass that connection through to your insert, like this :
public void InsertElement(string link, string titolo, string text, SqlConnection conn)
{
text = text.Replace("\"", "");
DateTime localDate = DateTime.Now;
lock (thisLock)
{
string query = "IF (NOT EXISTS(SELECT * FROM Result " +
" WHERE Link = '" + link + "')) " +
" BEGIN " +
" INSERT INTO Result ([Titolo],[Link],[Descrizione],[DataRicerca],[FKDatiRicercheID]) " +
" VALUES('" + titolo + "', '" + link + "', '" + text + "', '" + localDate + "', 1) " +
" END";
if (connection != null)
{
SqlCommand cmd = new SqlCommand(query, connection);
cmd.ExecuteNonQuery();
}
}
}
I recommend also looking at paramatizing your query, as well as using bulk inserts, and not individual inserts
If you are executing InsertElement() once for each rows of data to insert, then the execution will be too slow for large no. of rows. (Also, you are creating SqlConnection for each query execution.) Try adding many rows at once using a single INSERT query:
INSERT INTO tablename
(c1,c2,c3)
VALUES
(v1,v2,v3),
(v4,v5,v6)
...
try
{
int i = 0;
using (SqlConnection sqlCon = new SqlConnection(Form1.connectionString))
{
string commandString = "INSERT INTO Logindetail (Account,ID,Logint,Logoutt) values ('" + acc + "'," + textbxID.Text + "," + null + ", SYSDATETIME()" + ");";
// MessageBox.Show(commandString);
SqlCommand sqlCmd = new SqlCommand(commandString, sqlCon);
sqlCon.Open();
SqlDataReader dr = sqlCmd.ExecuteReader();
i = 1;
if (i == 0)
{
MessageBox.Show("Error in Logging In!", "Error");
}
MessageBox.Show("Successfully Logged In");
}
}
catch (Exception ex)
{
MessageBox.Show(ex.ToString());
}
I'm making a LoginForm for a Project.I have created a table which shows the LoginDetails(Account,ID,LoginTime,LogoutTime).But when I run the Program,it doesn't runs successfully.I face an error which is in Pic-2.When I remove sql 'data reader',the program runs without displaying the error.
When you concatenate a null it basically adds nothing to the string, so this code:
string commandString = "INSERT INTO Logindetail (Account,ID,Logint,Logoutt) values ('" + acc + "'," + textbxID.Text + "," + null + ", SYSDATETIME()" + ");";
results of this string, and as you can see it has an extra comma, that causes the exception:
"INSERT INTO Logindetail (Account,ID,Logint,Logoutt) values ('acc',textbxID,, SYSDATETIME());"
If you want to add NULL to the query it has to be a string, so do this instead:
string commandString = "INSERT INTO Logindetail (Account,ID,Logint,Logoutt) values ('" + acc + "'," + textbxID + ", NULL , SYSDATETIME()" + ");";
And you are using ExecuteReader instead of ExecuteNonQuery. You cannot use ExecuteReader for inserting rows to the DB.
Also, as someone mentioned in the other answer, you better do it with parametes to avoid SQL Injections.
I have a field that is 50 caracters long so I need to do a sub-string but in insert command, but first I have to check if the value is to long and then sub-string this is the part of the code, I know it's not good, so how can this be done?
myQuery = "INSERT INTO ERP_HEADER(IDOC_NUM,SEG_NUM,DOCTYP,HDRNUM,WHNUM,DOCNUM,DOCNOT)" +
"VALUES(" + Lidoc_num + ",'" +
SEG_NUM + "','" +
drDOK["DOCTYP"] + "'," +
drDOK["HDRNUM"] + "," +
drDOK["WHNUM"] + "," +
drDOK["DOCNUM"] + ",'" +
drDOK["DOCNOT"].ToString().Replace("'", string.Empty).Length > 50 ? Substring(0,50) + "')";
Of course, you should read carefully and adapt your code based on Jon Skeet's comment.
Beside that, you could write a small extension method
public static string ToShortenString(this string str, int maxLength) {
if (str == null) return null;//or string.Empty if you want to "hide" null values
return str.Substring(0, Math.Min(str.Length, maxLength));
}
then you could change your code to
drDOK["DOCNOT"].ToString().Replace("'", string.Empty).ToShortenString(50) + "')";
SqlCommand command = new SqlCommand("INSERT INTO ERP_HEADER(#IDOC_NUM,#SEG_NUM,#DOCTYP,#HDRNUM,#WHNUM,#DOCNUM,#DOCNOT)", connection);
string DOCNOT = drDOK["DOCNOT"].ToString()
if(DOCNOT.Length > 50)
DOCNOT = DOCNOT.Substring(0,50);
command.Parameters.AddWithValue("#IDOC_NUM", Lidoc_num);
command.Parameters.AddWithValue("#SEG_NUM", SEG_NUM);
command.Parameters.AddWithValue("#DOCTYP", drDOK["DOCTYP"]);
command.Parameters.AddWithValue("#HDRNUM", drDOK["HDRNUM"]);
command.Parameters.AddWithValue("#WHNUM", drDOK["WHNUM"]);
command.Parameters.AddWithValue("#DOCNUM", drDOK["DOCNUM"]);
command.Parameters.AddWithValue("#DOCNOT", DOCNOT);
command.ExecuteNonQuery();
Never ever concatenate sql-strings, it's just like asking for trouble.
Use parameters to avoid SQL injection like Jon skeet already pointed out and avoid syntactic abomniations:
//assuming myQuery is of type SqlCommand
myQuery = "INSERT INTO ERP_HEADER(IDOC_NUM,SEG_NUM,DOCTYP,HDRNUM,WHNUM,DOCNUM,DOCNOT)" +
"VALUES( #Lidoc_num, #SEG_NUM, #DOCTYPHDRNUM, #WHNUM, #DOCNUM, #DOCNOT)";
myquery.CommandType = CommandType.Text;
myQuery.Parameters.AddWithValue("Lidoc_num", Lidoc_num);
//...other values
myQuery.Parameters.AddWithValue("DOCNUM", drDOK["DOCNUM"]);
string DOCNOT = drDOK["DOCNOT"].ToString();
//check for your string
if(DOCNOT.Length > 50)
DOCNOT = DOCNOT.Substring(0,50);
myQuery.Parameters.AddWithValue("DOCNOT", DOCNOT);
myQuery = "INSERT INTO ERP_HEADER(IDOC_NUM,SEG_NUM,DOCTYP,HDRNUM,WHNUM,DOCNUM,DOCNOT)" +
"VALUES(" + Lidoc_num + ",'" +
SEG_NUM + "','" +
drDOK["DOCTYP"] + "'," +
drDOK["HDRNUM"] + "," +
drDOK["WHNUM"] + "," +
drDOK["DOCNUM"] + ",'" +
drDOK["DOCNOT"].ToString().Replace("'", string.Empty).Length > 50 ? drDOK["DOCNOT"].ToString().Substring(0,50) : drDOK["DOCNOT"].ToString() + "')";
So i am trying to delete data in database based on two things.
First is a combox box which selects the column name and second is the value whose row is to be deleted.
(#"SELECT * FROM Contacts WHERE " + var + " LIKE " + textBox1.Text + ";");
Now the problem here is that as long as the value in the textBox is numerical this query will work fine. However if it is a string value the query will fail because i haven't inserted the single quote.
Is there anyway i can make just a single unified query for handling both numerical and text data.
Okay, let's not do this. We need to just use parameters.
(#"SELECT * FROM Contacts WHERE " + var + " LIKE #" + var + ";");
...
cmd.Parameters.AddWithValue("#" + var, textBox1.Text);
So the overall code might look something like this:
string varName = string.Format("#{0}", var);
string sql = string.Format("SELECT * FROM Contacts WHERE {0} LIKE #{0}", var);
using (SqlConnection c = new SqlConnection(cString))
using (SqlCommand cmd = new SqlCommand(sql, c))
{
cmd.Parameters.AddWithValue(varName, textBox1.Text);
DataTable dt = new DataTable();
dt.Load(cmd.ExecuteReader());
}
Also, have a look at this post on my blog. It talks about what I just went through, as well as how to safely do a LIKE.
Try using parameterized query
SqlCommand command = new SqlCommand(
#"SELECT * FROM Contacts WHERE " + var + " LIKE #param", connection));
command.Parameters.AddWithValue("#param", textBox1.Tex);
You need to add quotes arounf the value so that it will accept string as well numerical values
(#"SELECT * FROM Contacts WHERE " + var + " LIKE '" + textBox1.Text + "';");
How about this:
(#"SELECT * FROM Contacts WHERE " + var + " LIKE " _
+ iif(isnumeric(textBox1.Text),textbox1.text, "'" +textbox1.text +"'" + ";");
That's a vb-centric IIF statement, but there's an equivolent in C#.
(#"SELECT * FROM Contacts WHERE " + var + " LIKE '" + textBox1.Text + "';");
U can check the value whether its integer or string and format different query accordingly.U can use like operator also.
String str = Console.ReadLine();
int myval;
String query="";
if(int.TryParse(str,out myval))
query=#"SELECT * FROM Contacts WHERE " + var + " LIKE " + myval + ";";
else
query=#"SELECT * FROM Contacts WHERE " + var + " LIKE '" + str + "';";
Copy table content to another table in the same database with C#.
I got one database (Baza) with some data in two tables NEW and OLD. I need to periodically move NEW data to OLD data table (after I do some measuring). I need to compare these data in next step.
I'm using SQL Server CE wit Baza.sdf file. In any sophisticated way to copy table to table do it (some loop doing it automatically)?
Thanks
I solved it in this way:
Program reads in loop table NEW row by row and each value changes to parameter. I got 8 columns so 8 parameters(7 integers and one string)
Next each of parameter is inserted to OLD table.
Resuld is also displayed in textBox1:
SqlCeConnection conn = new SqlCeConnection("Data Source = \\Program Files\\My Program\\Program.sdf; Password ='mypassword'");
conn.Open();
try
{
SqlCeCommand cmd = new SqlCeCommand("SELECT * FROM [NEW]", conn);
SqlCeDataReader rdr = cmd.ExecuteReader();
cmd.Connection = conn;
cmd.ExecuteNonQuery();
while (rdr.Read())
{
int param1 = rdr.GetInt32(0);
int param2 = rdr.GetInt32(1);
int param3 = rdr.GetInt32(2);
int param4 = rdr.GetInt32(3);
int param5 = rdr.GetInt32(4);
int param6 = rdr.GetInt32(5);
int param7 = rdr.GetInt32(6);
string param8 = rdr.GetString(7);
textBox1.AppendText(" " + param1 + " " + param2 + " " + param3 + " " + param4 + " " + param5 + " " + param6 + " " + param7 + " " + param8);
textBox1.AppendText(System.Environment.NewLine);
SqlCeCommand ins = new SqlCeCommand("insert into [OLD] values ('" + param1 + "','" + param2 + "','" + param3 + "','" + param4 + "','" + param5 + "','" + param6 + "','" + param7 + "','" + param8 + "');");
ins.Connection = conn;
ins.ExecuteNonQuery();
}
}
catch (Exception msg)
{
MessageBox.Show(msg.ToString());
}
conn.Close();
What's wrong with:
insert into [table] (field1, field2)
select field1, field2 from [table2] where (your conditions are met)
? :-)
Since that's not supported in CE, thanks #marc_s, you could get the records from the NEW table using a select, then insert them into the OLD table, and then loop through the initial recordset to delete the rows from the NEW by ID for example.
Adding to what CodeCaster stated,
Put his code in a storedprocedure and create a job to run on a set interval of your choosing.
You can add logic to the storedprocedure to check the validity of the data as well and set it to notify you if the data was incorrect. Examples could be given if you included a more specific information in your question.