I intend to populate an access DB table that has three columns; Entity(text type), Date and Value(double type).
I wrote the following code by going through some online links. Although the code runs fine, the table has no data. I am probably missing some part. Any advice?
for (int i = 0; i < model.CDFResults.Count; i++)
{ // connection details to the DB here...
for (int j = 0; j < model.CDFResults[i].DataPoints.Count; j++)
{
OleDbCommand myAccessCommand = new OleDbCommand();
myAccessCommand.CommandType = CommandType.Text;
myAccessCommand.CommandText = "INSERT INTO TypeCurves([Entity],[Date],[Value])VALUES(?,?,?)";
myAccessCommand.Parameters.AddWithValue("#Entity", model.CDFResults[i].catname_db);
myAccessCommand.Parameters.AddWithValue("#Date", model.CDFResults[i].DataPoints[j].dt);
myAccessCommand.Parameters.AddWithValue("#Value", model.CDFResults[i].DataPoints[j].CDFVal);
} // end of FOR(j) loop
} // end of FOR(i) loop
EDIT: Still not working
for (int i = 0; i < model.CDFResults.Count; i++)
{ // connection details to the DB here...
for (int j = 0; j < model.CDFResults[i].DataPoints.Count; j++)
{
OleDbConnection thisConnection = new OleDbConnection(connectionname);
thisConnection.Open();
OleDbCommand myAccessCommand = new OleDbCommand();
myAccessCommand.CommandType = CommandType.Text;
myAccessCommand.CommandText = "INSERT INTO TypeCurves([Entity],[Date],[Value])VALUES(?,?,?)";
myAccessCommand.Parameters.AddWithValue("#Entity", model.CDFResults[i].catname_db);
myAccessCommand.Parameters.AddWithValue("#Date", model.CDFResults[i].DataPoints[j].dt);
myAccessCommand.Parameters.AddWithValue("#Value", model.CDFResults[i].DataPoints[j].CDFVal);
myAccessCommand.ExecuteNonQuery();
} // end of FOR(j) loop
} // end of FOR(i) loop
You need create the connection to the database and execute the query.
using (OleDbConnection connection = new OleDbConnection(connectionString))
{
string query = "INSERT INTO TypeCurves([Entity],[Date],[Value])VALUES(#Entity,#Date,#Value)";
OleDbCommand myAccessCommand = new OleDbCommand(query, connection);
myAccessCommand.Parameters.AddWithValue("#Entity", model.CDFResults[i].catname_db);
myAccessCommand.Parameters.AddWithValue("#Date", model.CDFResults[i].DataPoints[j].dt);
myAccessCommand.Parameters.AddWithValue("#Value", model.CDFResults[i].DataPoints[j].CDFVal);
connection.Open();
myAccessCommand.ExecuteNonQuery();
}
connectionString is whatever your connection string is to your database.
In this example you don't need to explicitly close the connection after the query is executed as the connection is wrapped in a using block, and so will be disposed of once it has exited the block.
https://msdn.microsoft.com/en-us/library/system.data.oledb.oledbcommand.executenonquery(v=vs.110).aspx
Related
I wonder how can i bulk insert instead of execute this method everytime.
It's getting slow when i try to insert 1000 rows:
queryText = "INSERT INTO `player_items` (`player_id`, `item_id`, `count`) VALUES (#player_id, #item_id, #count)";
for (int i = 0; i < player.invenotrySize; i++)
{
Item item = player.inventory.GetItem[i];
MySqlParameter[] parameters = {
new MySqlParameter("player_id", 1),
new MySqlParameter("item_id", item.data.id),
new MySqlParameter("count", item.amount),
};
ExecuteNonQuery(queryText, parameters);
}
public int ExecuteNonQuery(string queryText, params MySqlParameter[] parameters)
{
int affectedRows = 0;
using (MySqlConnection mySqlConnection = CreateConnection())
{
using (MySqlCommand mySqlCommand = new MySqlCommand(queryText, mySqlConnection))
{
mySqlCommand.CommandType = CommandType.Text;
mySqlCommand.Parameters.AddRange(parameters);
affectedRows = mySqlCommand.ExecuteNonQuery();
}
}
return affectedRows;
}
I think the optimal way is to insert everything as a huge row. E.g
INSERT INTO tbl_name (a,b,c) VALUES(1,2,3),(4,5,6),(7,8,9);
But i have no idea how i can make a method to take care of this setup
You are opening and closing your connection for every single insert.
using (MySqlConnection mySqlConnection = CreateConnection())
This is a very expensive procedure, and therefore not really the way to work with a DB.
You should open your connection just once, and then close it when finished. Depending on what you app does this might be when you start your App (or before you do your first DB query) and then close it when exiting the App (or after you are certain there will be no more DB queries.
Then ideally you should also reuse the SqlCommand instance as well. But you need to make sure that you clear your parameters in between. So then you have something like this
int affectedRows = 0;
using (MySqlConnection mySqlConnection = CreateConnection())
{
string queryText = "INSERT INTO `player_items` (`player_id`, `item_id`, `count`) VALUES (#player_id, #item_id, #count)";
using (MySqlCommand mySqlCommand = new MySqlCommand(queryText, mySqlConnection))
{
mySqlCommand.CommandType = CommandType.Text;
for (int i = 0; i < player.invenotrySize; i++)
{
Item item = player.inventory.GetItem[i];
MySqlParameter[] parameters = {
new MySqlParameter("player_id", 1),
new MySqlParameter("item_id", item.data.id),
new MySqlParameter("count", item.amount)};
mySqlCommand.Parameters.Clear();
mySqlCommand.Parameters.AddRange(parameters);
affectedRows += mySqlCommand.ExecuteNonQuery();
}
}
}
It's not realy clean with your "ExecuteNonQuery" (do a multi row insert solution or just isolate/singleton the connection class like the solution above, will be better) but you can construct your whole query before execute instead of get/add connection, replace, execute foreach player.
queryText = "INSERT INTO `player_items` (`player_id`, `item_id`, `count`) VALUES";
for (int i = 0; i < player.invenotrySize; i++)
{
Item item = player.inventory.GetItem[i];
MySqlParameter[] parameters = {
new MySqlParameter("player_id_"+i, 1),
new MySqlParameter("item_id_"+i, item.data.id),
new MySqlParameter("count_"+i, item.amount),
};
queryText+= " (#player_id_"+i+", #item_id_"+i+", #count_"+i+"),";
}
//remove the last ,
queryText= queryText.Remove(queryText.Length - 1)+";";
ExecuteNonQuery(queryText, parameters);
Altnernate for to skip params if you are sure about your data.
Item item = player.inventory.GetItem[i];
queryText+= " (1, "+item.data.id+", "+item.amount+"),";
I need to change my field QB_STATUS from value R to value C. I am doing this in a loop because i cannot "requery" the table as data may have changed.
I have built a list of entries to update. The code does not error and iterates through 5 times (correct based on my idInvoices list) but the field does not get updated.
for (int i = 0; i < idInvoices.Count; i++)
{
// following command will update one row as ID_Invoice is primary key.
// ID_Invoice taken from list previously built in ReadDataToNAVArray
SqlCommand cmd = new SqlCommand("UPDATE tblINVOICES SET QB_STATUS=#Status WHERE ID_INVOICE = #IDInvoice", myConnection);
cmd.Parameters.Add("#Status", "C");
cmd.Parameters.Add("#IDInvoice", idInvoices[i]);
cmd.Dispose();
}
First, you have to execute your query: ExecuteNonQuery; second - do not create command, parameters etc within the loop, just assign values and execute:
// Make SQL readable
String sql =
#"UPDATE tblINVOICES
SET QB_STATUS = #Status
WHERE ID_INVOICE = #IDInvoice";
// wrap IDisposable into "using"
// do not recreate command in the loop - create it once
using (SqlCommand cmd = new SqlCommand(sql, myConnection)) {
cmd.Parameters.Add("#Status", SqlDbType.VarChar); //TODO: check types, please
cmd.Parameters.Add("#IDInvoice", SqlDbType.Decimal); //TODO: check types, please
// Assign parameters with their values and execute
for (int i = 0; i < idInvoices.Count; i++) {
cmd.Parameters["#Status"].Value = "C";
cmd.Parameters["#IDInvoice"].Value = idInvoices[i];
cmd.ExecuteNonQuery();
}
}
You are missing the ExecuteNonQuery in your command.
for (int i = 0; i < idInvoices.Count; i++)
{
SqlCommand cmd = new SqlCommand("UPDATE tblINVOICES SET QB_STATUS=#Status WHERE ID_INVOICE = #IDInvoice", myConnection);
cmd.Parameters.Add("#Status", "C");
cmd.Parameters.Add("#IDInvoice", idInvoices[i]);
cmd.ExecuteNonQuery();
cmd.Dispose();
}
I think you're missing cmd.ExecuteNonQuery();.
An example for a different way of using sql commands:
SqlConnection addConn = new SqlConnection();
addConn.ConnectionString = Properties.Settings.Default.yourDataBaseConnection;
addConn.Open();
SqlCommand addComm = new SqlCommand();
addComm.Connection = addConn;
addComm.CommandText = "sql command";
addComm.ExecuteNonQuery();
public static int SQLUpdate(string sql, string[] names, object[] values)
{
if (names.Length != values.Length)
{
throw new ArgumentException("name/value mismatch");
}
using (var sqlconn = new SqlConnection(GetConnectionString))
{
sqlconn.Open();
using (var cmd = new SqlCommand(sql, sqlconn))
{
for (int i = 0; i < names.Length; i++)
{
cmd.Parameters.AddWithValue(names[i], values[i]);
}
return cmd.ExecuteNonQuery();
}
}
I wrote method to create Update command.
For example I have a Picture table in my SQL Server database with PictureID, UserID columns.
And user can add 3 pictures at once. You see values is array.
But in my example value[i] also is array. (3 pictures).
How can I write my SQLUpdate method for this ?
I think you are almost there except I would switch your code around a little so:
sqlconn.Open();
for (int i = 0; i < names.Length; i++)
{
using (var cmd = new SqlCommand(sql, sqlconn))
{
cmd.Parameters.AddWithValue(names[i], values[i]);
return cmd.ExecuteNonQuery();
}
}
**AS you are declaring a new SQLCommand everytime you may need to do cmd.Close() and cmd.Dispose() each time.
I think you need to pass data table in SQL procedure
http://www.codeproject.com/Tips/214492/Passing-a-datatable-to-a-stored-procedure-in-Sql-S
For example, the following code prints "System.Int32", not "int":
string connArgs = "..."; // use your settings here
string query = "SELECT 1";
using (SqlConnection conn = new SqlConnection(connArgs)) {
conn.Open();
SqlCommand cmd = new SqlCommand(query, conn);
using (SqlDataReader reader = cmd.ExecuteReader())
for (int col = 0; col < reader.VisibleFieldCount; ++col)
Console.WriteLine(reader.GetFieldType(col));
}
How can I obtain the underlying SQL type, not just its equivalent .NET system type?
You can use a GetDataTypeName method for that:
Gets a string representing the data type of the specified column.
for (int col = 0; col < reader.VisibleFieldCount; ++col) {
Console.WriteLine(reader.GetDataTypeName(col));
}
I use the following code to execute a query in C#:
AdomdConnection con = new AdomdConnection("Datasource=local;...");
con.Open();
AdomdCommand command = con.CreateCommand();
command.CommandText = input;
AdomdDataReader reader = command.ExecuteReader();
while (reader.Read())
{
for(i =0; i<reader.fieldCount; i++){
a[i]=reader.GetString(i);
}
return a;
Howeever, this code returns the full path in the hierarchy for each cell. I.e., each row of data is like [AllGeography, Canada, Vancouver, Allproduct, bikes, accessories, 297483].
I want to retrieve only the leaves and the measure value that is :[vancouver, accessories, 297483]. What should I do? How I can specify the leaves?
Because the result of MDX query is actually multidimentional, i feel myself more comfortable with ExecuteCellSet. You can get the whole CellSet, then you get Measures via coordinates.
For example (if you have one measure in query):
AdomdCommand cmd = conn.CreateCommand();
cmd.CommandText = #"SELECT
[Geography].[Geography].[Country].&[Canada].Children ON 0,
[Product].[Id] ON 1
FROM [Cube]
WHERE [Measures].[Your Measure]";
CellSet cs = cmd.ExecuteCellSet();
TupleCollection CanadaChildren = cs.Axes[0].Set.Tuples;
TupleCollection ProductIds = cs.Axes[1].Set.Tuples;
for (int row = 0; row < CanadaChildren.Count; row++)
{
for (int col = 0; col < ProductIds.Count; col++)
{
a[i++] = cs.Cells[col, row].Value;
}
}
conn.Close();
If you have several measures, than it will be a third dimention in query and a third cooridinate in a cellset.