As shown in the screenshot, I was trying to insert data into a table. The 1st iteration works fine, but the 2nd iteration throws an error/exception.
What is wrong with my code?
Below is the code.
SqlConnection sqlconn = new SqlConnection(sqlconnectionstring);
// sqlconn.Open();
string InsertData = "INSERT INTO AUStagAPITestData ([TestSuite], [TestCase],[Status], [Info], [Time], [IsArchived], [DateTime]) VALUES (#TestSuite, #TestCase, #Status, #Info, #Time, #IsArchived, #DateTime)";
SqlCommand Insertcmd = new SqlCommand(InsertData, sqlconn);
for (int j = 1; j < TDData.Length; j +=5)
{
sqlconn.Open();
string TestSuite = TDData[j];
string TestCase = TDData[j+1];
string Status = TDData[j + 2];
string Info = TDData[j + 3];
string Time = TDData[j + 4];
Insertcmd.Parameters.AddWithValue("#TestSuite", TestSuite);
Insertcmd.Parameters.AddWithValue("#TestCase", TestCase);
Insertcmd.Parameters.AddWithValue("#Status", Status);
Insertcmd.Parameters.AddWithValue("#Info", Info);
Insertcmd.Parameters.AddWithValue("#Time", Time);
Insertcmd.Parameters.AddWithValue("#IsArchived", "1");
Insertcmd.Parameters.AddWithValue("#DateTime", DateTime.Now);
Insertcmd.ExecuteNonQuery();
sqlconn.Close();
}
What you really should do is:
create the list of parameter objects once, before the loop
during the loop, only set their values
Something like this:
string InsertData = "INSERT INTO AUStagAPITestData ([TestSuite], [TestCase],[Status], [Info], [Time], [IsArchived], [DateTime]) VALUES (#TestSuite, #TestCase, #Status, #Info, #Time, #IsArchived, #DateTime)";
// put your connection and command into *USING* blocks to properly dispose of them
using (SqlConnection sqlconn = new SqlConnection(sqlconnectionstring))
using (SqlCommand Insertcmd = new SqlCommand(InsertData, sqlconn))
{
// create the parameters **ONCE** and define their datatypes
// I have only *guessed* what the datatypes could be - adapt as needed
Insertcmd.Parameters.Add("#TestSuite", SqlDbType.VarChar, 50);
Insertcmd.Parameters.Add("#TestCase", SqlDbType.VarChar, 50);
Insertcmd.Parameters.Add("#Status", SqlDbType.VarChar, 50);
Insertcmd.Parameters.Add("#Info", SqlDbType.VarChar, 50);
Insertcmd.Parameters.Add("#Time", SqlDbType.Time);
Insertcmd.Parameters.Add("#IsArchived", SqlDbType.Boolean);
Insertcmd.Parameters.Add("#DateTime", SqlDbType.DateTime);
sqlconn.Open();
// now loop over the data and set the parameter values
for (int j = 1; j < TDData.Length; j +=5)
{
string TestSuite = TDData[j];
string TestCase = TDData[j+1];
string Status = TDData[j + 2];
string Info = TDData[j + 3];
string Time = TDData[j + 4];
Insertcmd.Parameters["#TestSuite"].Value = TestSuite;
Insertcmd.Parameters["#TestCase"].Value = TestCase;
Insertcmd.Parameters["#Status"].Value = Status;
Insertcmd.Parameters["#Info"].Value = Info;
Insertcmd.Parameters["#Time"].Value = Time;
Insertcmd.Parameters["#IsArchived"].Value = true;
Insertcmd.Parameters["#DateTime"].Value = DateTime.Now;
// execute the query in the loop
Insertcmd.ExecuteNonQuery();
}
sqlconn.Close();
}
It's complaining you have already added:
Insertcmd.Parameters.AddWithValue("#TestSuite
The fix is to instantiate a new SqlCommand each iteration:
for (int j = 1; j < TDData.Length; j +=5)
{
sqlconn.Open();
SqlCommand Insertcmd = new SqlCommand(InsertData, sqlconn);
string TestSuite= TDData[j];
try to move sqlconn.Open() & sqlconn.Close() out of the for loop and renew sqlcommand object.
sqlconn.Open();
for (int j = 1; j < TDData.Length; j += 5)
{
SqlCommand Insertcmd = new SqlCommand(InsertData, sqlconn);
string TestSuite = TDData[j];
...
}
sqlconn.Close();
Check this example based on your code:
string connectionString, queryInsert;
string[] arrayData = new string[10];
connectionString = ConfigurationManager.ConnectionStrings["DbConn"].ConnectionString;
queryInsert = #"
INSERT INTO AUStagAPITestData
(
[TestSuite], [TestCase], [Status], [Info], [Time], [IsArchived], [DateTime]
)
VALUES (
#TestSuite, #TestCase, #Status, #Info, #Time, #IsArchived, #DateTime
)
";
using (SqlConnection connection = new SqlConnection(connectionString))
using (SqlCommand command = new SqlCommand(queryInsert, connection))
{
string testSuite, testCase, status, info, time;
connection.Open();
for (int j = 1; j < arrayData.Length; j += 5)
{
testSuite = arrayData[j];
testCase = arrayData[j + 1];
status = arrayData[j + 2];
info = arrayData[j + 3];
time = arrayData[j + 4];
command.Parameters.AddWithValue("#TestSuite", testSuite);
command.Parameters.AddWithValue("#TestCase", testCase);
command.Parameters.AddWithValue("#Status", status);
command.Parameters.AddWithValue("#Info", info);
command.Parameters.AddWithValue("#Time", time);
command.Parameters.AddWithValue("#IsArchived", "1");
command.Parameters.AddWithValue("#DateTime", DateTime.Now);
command.ExecuteNonQuery();
// To Clear parameters
command.Parameters.Clear();
}
// no need to close a disposed object since dispose will call close
}
You can use Insertcmd.Parameters.Clear() inside your for loop.
As I wrote in the comments, I would use a stored procedure with a table valued parameter instead of inserting the records one by one. This has the advantage of only making one round trip from your application code to your database.
However, it also has a disadvantage - if one row fails for any reason (say, violating a constraint), the entire insert will fail.
Having said that, in order to use a table valued parameter you should first create a user defined table type. Note that I'm guessing your columns data types here, you might need to change them:
CREATE TYPE dbo.tt_TestData (
[TestSuite] int, -- I'm guessing foreign keys
[TestCase] int,
[Status] int,
[Info] nvarchar(255),
[Time] time,
[IsArchived] bit,
[DateTime] datetime
);
GO
After you've done that, you can create your stored procedure:
CREATE PROCEDURE stp_AUStagAPITestData_Insert
(
#Data dbo.tt_TestData READONLY -- Note: Readonly is a must!
)
AS
INSERT INTO AUStagAPITestData (
[TestSuite],
[TestCase],
[Status],
[Info],
[Time],
[IsArchived],
[DateTime]
)
SELECT
[TestSuite],
[TestCase],
[Status],
[Info],
[Time],
[IsArchived],
[DateTime]
FROM #Data;
GO
Now, to execute this stored procedure using ADO.Net, you will need to create a data table for your data, and send it as a paramameter of type SqlDbType.Structured to the stored procedure:
using (var sqlconn = new SqlConnection(sqlconnectionstring))
{
using (var Insertcmd = new SqlCommand("stp_AUStagAPITestData_Insert", sqlconn))
{
// Create the data table
using (var dt = new DataTable())
{
dt.Columns.Add("TestSuite", typeof(int));
dt.Columns.Add("TestCase", typeof(int));
dt.Columns.Add("Status", typeof(int));
dt.Columns.Add("Info", typeof(string));
dt.Columns.Add("Time", typeof(DateTime));
dt.Columns.Add("IsArchived", typeof(bool));
dt.Columns.Add("DateTime", typeof(DateTime));
// Populate the data table from the TDData string array
for (int j = 1; j < TDData.Length; j += 5)
{
dt.Rows.Add
(
TDData[j], // TestSuite
TDData[j + 1], // TestCase
TDData[j + 2], // Status
TDData[j + 3], // Info
TDData[j + 4], // Time
true, // IsArchived
DateTime.Now // DateTime
);
}
Insertcmd.CommandType = CommandType.StoredProcedure;
Insertcmd.Parameters.Add("#Data", SqlDbType.Structured).Value = dt;
try
{
sqlconn.Open();
Insertcmd.ExecuteNonQuery();
}
catch (Exception e)
{
// Exception handling code goes here...
}
}
}
}
I have the following code . I can extract all data from all data existing in sheets in a workbook and the name of the sheet
foreach (var sheetName in GetExcelSheetNames(connectionString))
{
using (OleDbConnection con = new OleDbConnection(connectionString))
{
var dataTable = new DataTable();
string query = string.Format("SELECT {0} as sheetName, * FROM [{0}]", sheetName);
con.Open();
OleDbDataAdapter adapter = new OleDbDataAdapter(query, con);
adapter.Fill(dataTable);
ds.Tables.Add(dataTable);
}
}
Then I write the following code to store data in a table in sql server
if (ds.Tables.Count > 0)
{
foreach (DataTable dt in ds.Tables)
{
using (SqlConnection con = new SqlConnection(consString))
{
con.Open();
for (int i = 2; i < dt.Rows.Count; i++)
{
for (int j = 1; j < dt.Columns.Count; j += 3)
{
//Here the problem
SqlCommand command = new SqlCommand( what should I write? ) ;
command.ExecuteNonQuery();
}
}
con.Close();
}
}
My problem is how to store sheetname in a table [Obj CA]?
I think your
"...VALUES('sheetname" + dt.Rows[0][j].ToString() + "' )
should be
"...VALUES('sheetname', '" + dt.Rows[0][j].ToString() + "' )
since you try to insert two values but you didn't seperate them with a comma.
But as a better way, use parameterized queries. This kind of string concatenations are open for SQL Injection attacks.
var command = new SqlCommand(#"INSERT INTO [Obj CA] (sheetname, [Rayon])
VALUES('sheetname', #rayon"), con);
for (int i = 2; i < dt.Rows.Count; i++)
{
for (int j = 1; j < dt.Columns.Count; j += 3)
{
command.Parameters.Clear();
command.Parameters.AddWithValue("#rayon", dt.Rows[0][j].ToString());
command.ExecuteNonQuery();
}
}
By the way, since I didn't know your column types, I used AddWithValue as an example but you don't. This method may generate unexpected results sometimes. Use Add overload to specify your parameter type and it's size.
Also I strongly suspect you should change your column definition order as well like (sheetname, [Rayon]) in your INSERT statement.
I am writing my first SQL transaction code and have scoured stackoverflow to make sure I've done it right. The basic idea of the project is to get an email, parse it into a RawDatum object, then write the contents of the object to the SQL database. I was hoping to commit the new rows in batches of 100.
I have the code running without errors, but nothing is being actually written to the database.
I have a local DB (MS SQL Server Express). I have a few things commented out for testing purposes. What am I doing wrong?
using (SqlConnection connection = new SqlConnection(Properties.Settings.Default.MissionMetricsConnectionString))
{
connection.Open();
SqlCommand command = connection.CreateCommand();
command.CommandType = CommandType.Text;
command.CommandText = #"INSERT INTO RawData (MessageUID, DateTime, Attribute, DigitalValue, AnalogValue) VALUES (#MessageUID, #DateTime, #Attribute, #DigitalValue, #AnalogValue)";
command.Parameters.Add("#MessageUID", SqlDbType.Int);
command.Parameters.Add("#DateTime", SqlDbType.DateTime);
command.Parameters.Add("#Attribute", SqlDbType.Text);
command.Parameters.Add("#DigitalValue", SqlDbType.Bit);
command.Parameters.Add("#AnalogValue", SqlDbType.Float);
command.Connection = connection;
RawDatum currentDatum = null;
int uid;
List<int> uidsToDelete = new List<int>();
int numLoops = 1;//(int)(ids.Length / loopSize) + 1;
for (var loopIndex = 0; loopIndex < numLoops; loopIndex++)
{
int startIndex = loopIndex * loopSize;
int endIndex = 10;// Math.Min((loopIndex + 1) * loopSize, ids.Length);
using (SqlTransaction transaction = connection.BeginTransaction())
{
try
{
command.Transaction = transaction;
for (int i = startIndex; i < endIndex; i++)
{
msg = inbox.Fetch.MessageObject(ids[i]);
uid = inbox.Fetch.Uid(ids[i]);
if (msg.Subject == "[METRICS]")
{
currentDatum = new RawDatum(uid, msg.Date, msg.BodyText.TextStripped);
command.Parameters["#MessageUID"].Value = currentDatum.MessageUid;
command.Parameters["#DateTime"].Value = currentDatum.DateTime;
command.Parameters["#Attribute"].Value = currentDatum.Attribute;
command.Parameters["#DigitalValue"].Value = currentDatum.DigitalValue;
command.Parameters["#AnalogValue"].Value = currentDatum.AnalogValue;
int queryResult = command.ExecuteNonQuery();
if (queryResult != 1)
{
throw new InvalidProgramException();
}
}
uidsToDelete.Add(uid);
}
transaction.Commit();
//Delete(uidsToDelete);
output[1] += uidsToDelete.Count;
uidsToDelete.Clear();
}
catch
{
transaction.Rollback();
output[0] += 1;
output[2] += endIndex - startIndex;
}
}
}
connection.Close();
}
My code looks like this:
var settings = ConfigurationManager.ConnectionStrings["InsurableRiskDB"];
string server = ConfigurationManager.AppSettings["Server"];
string cs = String.Format(ConfigurationManager.AppSettings[settings.ProviderName], ConfigurationManager.AppSettings[server]);
SqlConnection connection = new SqlConnection(cs);
string PolicyKeys = "";
for (int i = 0; i < keys.Count(); i++)
{
if (i == keys.Count() - 1)
PolicyKeys += keys[i] ;
else
PolicyKeys += keys[i] + ", ";
}
//have to change the code to pull the user's NBK.
string user = "'DATALOAD'";
const string updateQuery = #"UPDATE [InsurableRisk].[dbo].[Policy]
SET [InsuranceCarrierKey] = #ToKey
,[AuditUser] = #User
,[AuditDate] = SYSDATETIME()
WHERE PolicyKey in (#PolicyKeys) and InsuranceCarrierKey = #FromKey";
using (connection)
{
using (SqlCommand dataCommand = new SqlCommand(updateQuery, connection))
{
dataCommand.Parameters.AddWithValue("#ToKey", toKey);
dataCommand.Parameters.AddWithValue("#User", user);
dataCommand.Parameters.AddWithValue("#PolicyKeys", PolicyKeys);
dataCommand.Parameters.AddWithValue("#FromKey", fromKey);
connection.Open();
dataCommand.ExecuteNonQuery();
connection.Close();
}
}
res = true;
}
catch (Exception ex)
{
MessageBox.Show("There is an error while try in save the changes " + ex.Message, "Error Message", MessageBoxButtons.OKCancel);
res = false;
}
return res;
Now, when i run this code, it says query is unable to execute. It throws and exception stating, it is unable to convert NVarchar to int for variable #PolicyKeys
Any suggestions as to what i am missing in this code?
Typically, in SQL you'd write an IN statement like this:
WHERE SomeColumn IN ('A', 'B', 'C')
What you're doing is the equivalent of this in SQL (which won't work):
WHERE SomeColumn IN ('A, B, C')
Change your SQL statement accordingly: (modified from this answer)
WHERE PolicyKey in ({0})
And then add your parameters in a loop, like this:
var parameters = new string[keys.Count()];
for (int i = 0; i < keys.Count(); i++)
{
parameters[i] = string.Format("#Key{0}", i);
cmd.Parameters.AddWithValue(parameters[i], keys[i]);
}
cmd.CommandText = string.Format(updateQuery, string.Join(", ", parameters));
I need select the maximum ID of PolygonId column. I save my data like this
string sql = "create table Polygons (PolygonId int, PointId int, X double, Y double)";
// Выполнение нашей команды
using (SQLiteCommand command = new SQLiteCommand(sql, m_dbConnection))
{
command.ExecuteNonQuery();
}
int pointId = 1;
for (int i = 0; i < listOfCustomPolygons.Count; i++)
for (int j = 0; j < listOfCustomPolygons[i].listOfVertexes.Count; j++)
{
string strSQL =
string.Format("INSERT INTO Polygons (PolygonId,PointId,X,Y) Values ('{0}','{1}','{2}','{3}')",
i+1,pointId,listOfCustomPolygons[i].listOfVertexes[j].X,
listOfCustomPolygons[i].listOfVertexes[j].Y );
pointId++;
using (SQLiteCommand insertCommand = new SQLiteCommand(strSQL, m_dbConnection))
{
insertCommand.ExecuteNonQuery();
}
}
After this I want select the max value from table Polygons and column PolygonId, but I got an IndexOutOfRangeException. How a can solve this problem?
using (SQLiteConnection connection = new SQLiteConnection("Data Source=" + openFileDialog.FileName + ";Version=3;"))
{
connection.Open();
string selectMaxId = "Select Max(PolygonId) From Polygons";
string selectQuery = "Select * From Polygons";
SQLiteCommand selectMaxCmd = new SQLiteCommand(selectMaxId,connection);
SQLiteDataReader dataReader = selectMaxCmd.ExecuteReader();
int maxId = Convert.ToInt32(dataReader["Select Max(PolygonId) From Polygons"]); // This is don't work! Why?
I found out the solution! It should look like
string selectMaxId = "Select Max(PolygonId) From Polygons";
SQLiteCommand selectMaxCmd = new SQLiteCommand(selectMaxId,connection);
object val = selectMaxCmd.ExecuteScalar();
int maxId = int.Parse(val.ToString());
I hope it can help somebody who face with similar problem)
First of all don't create table every time you run your code :) But you probably know that
You type like this:
int maxId = Convert.ToInt32(dataReader["Select Max(PolygonId) From Polygons"]);
Try this:
string selectMaxId = "Select Max(PolygonId) From Polygons";
SQLiteCommand selectMaxCmd = new SQLiteCommand(selectMaxId,connection);
SQLiteDataReader dataReader = selectMaxCmd.ExecuteReader();
int maxID = -1;
while(dataReader.read())
{
maxID = (int)dataReader.GetValue(0);
}
//This Works for me in WPF C#:
int MaxNum=0;
sqliteCon.Open();
string Query = "SELECT MAX(Promo_No)FROM Promo_File";
SQLiteCommand createCommand = new SQLiteCommand(Query, sqliteCon);
SQLiteDataReader DR = createCommand.ExecuteReader();
while (DR.Read())
{
MaxNum = DR.GetInt16(0);
}
sqliteCon.Close();
I had the same problem!
You have to learn the difference method of SQLiteCommand.
1.SQLiteCommand.ExecuteReader(). Get a SqlDataReader.
2.SQLiteCommand.ExecuteScalar(). Get a single value from the database.
Microsoft Doc:
cmd.CommandText = "SELECT COUNT(*) FROM dbo.region";
Int32 count = (Int32) cmd.ExecuteScalar();