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
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+"),";
After an hour of debugging I am trying to find why my Query returns only 1 ID where there are at least 3:
public static string[] selectAGIdOfKC(string id)
{
int nbAg = 0;
DataTable results = new DataTable();
using (OleDbConnection conn = new OleDbConnection(#"Provider=Microsoft.ACE.OLEDB.12.0;Data Source=bdd.mdb;
Persist Security Info=False;"))
{
OleDbCommand cmd = new OleDbCommand("SELECT Id FROM ActionG WHERE Num_Kc = #Id", conn);
conn.Open();
cmd.Parameters.AddWithValue("#Id", id);
OleDbDataAdapter adapter = new OleDbDataAdapter(cmd);
conn.Close();
adapter.Fill(results);
nbAg=results.Rows[0].ItemArray.Count();
}
string[] myTab = new string[nbAg];
for (int i = 0; i < nbAg; i++)
{
myTab[i] = results.Rows[0].ItemArray[i].ToString();
}
return myTab;
}
I tried to use some workarounds but nothing solves the problem of the missing returned IDs...
Can anyone help me ? Thanks for your time!
It all depends on how you want the results, but assuming that you want nbAg to contain the number of rows returned, and assuming that you want myTab to contain the id-values returned, your code is not written to do what you want.
Please note the ellipsis ... - I have only modified the code that was causing your current symptoms.
public static string[] selectAGIdOfKC(string id)
{
int nbAg = 0;
...
nbAg = results.Rows.Count();
string[] myTab = new string[nbAg];
for (int i = 0; i < nbAg; i++)
{
myTab[i] = results.Rows[i][0].ToString();
// This is the first column of row i
}
return myTab;
}
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
im working on a project in mvc4 visual studio and have add an Uploadhandler.ashx.cs to upload the files.
the code is working to upload the files and insert into the information into my database.
Now what i try/need:
i have add a column where i want insert a number of each row like 1, 2 ,3, 4 etc...
in my code i have a for loop to do what i want for each file.
How can i generate a variable which add automatically +1 to insert it into my database.
i have try a lot of things like:
var a=1;
for(.......)
{
/*******My code****************/
a=a+1;
}
Hope that someone can give a hand with this:
here is my code:
private void UploadWholeFile(HttpContext context, List<FilesStatus> statuses)
{
using (SqlConnection cn = new SqlConnection(System.Configuration.ConfigurationManager.ConnectionStrings["DefaultConnection"].ConnectionString))
{
var a= 1;
for (int i = 0; i < context.Request.Files.Count; i++)
{
var file = context.Request.Files[i];
var fullpath = "/Files/" + Path.GetFileName(file.FileName);
var myfilename=Path.GetFileName(file.FileName);
file.SaveAs(fullpath);
statuses.Add(new FilesStatus(fullName, file.ContentLength, fullpath
string sql1 = "insert into Image(FileName, Number) values (#FileName, #Number)";
using (SqlCommand cmd = new SqlCommand(sql1, cn))
{
cmd.Parameters.AddWithValue("#FileName", myfilename);
cmd.Parameters.AddWithValue("#Number", a);
cn.Open();
cmd.ExecuteNonQuery();
cn.Close();
}
a = a + 1;
}
}
}
Why don't you just use your iteration variable, i?
Your pasted code has some errors, here is fixed code. (corrections are marked with ).
private void UploadWholeFile(HttpContext context, List<FilesStatus> statuses)
{
using (SqlConnection cn = new SqlConnection(System.Configuration.ConfigurationManager.ConnectionStrings["DefaultConnection"].ConnectionString))
{
var a= 1;
**cn.Open();**
for (int i = 0; i < context.Request.Files.Count; i++)
{
var file = context.Request.Files[i];
var fullpath = "/Files/" + Path.GetFileName(file.FileName)
file.SaveAs(fullpath);
**statuses.Add(new FilesStatus(fullName, file.ContentLength, fullpath));**
**string sql1 = "insert into Imagem(FileName, Number, Id_Magazine, Tem_Conteudo) values (#FileName, #Number, #Id_Magazine, #Tem_Conteudo)";**
using (SqlCommand cmd = new SqlCommand(sql1, cn))
{
cmd.Parameters.AddWithValue("#NomeFicheiro", myfilename);
cmd.Parameters.AddWithValue("#Id_Magazine", context.Request.Form["MagazineId"]);
cmd.Parameters.AddWithValue("#Tem_Conteudo", false);
cmd.Parameters.AddWithValue("#Number", a++);
**cmd.ExecuteNonQuery();**
}
}
**cn.Close();**
}
}
Hope it helps!
Regards,
Uroš
Try declaring the variable as an int, and you can use a++ to increment a by 1:
int a=1;
for(.......)
{
/*******My code****************/
a++;
}
Also, you have declared an integer i in your for loop that increments by 1 each time the loop is run, so you could use this instead of declaring a:
for (int i = 0; i < context.Request.Files.Count; i++)
{
...
cmd.Parameters.AddWithValue("#Number", i);
...
}
Finally, I'm not sure why you need this column in your database at all. If you are using it as a unique identifier the make it the Primary Key. You can then set this to auto-increment without needing to add the value each time.
I've data in DataTable with 2 rows and 3 columns. I want to insert that data into Oracle table.
How can I insert? please give me with some example.
And also
How can I pass datatable to storedprocedure in ORACLE...
I pass datatable in below mensioned manner, but datatable type problem is comming. how can I solve this?
cmd.Parameters.Add("#Details",dtSupplier);
(OR)
cmd.Parameters.Add("Details", DbType.Single).Value = dtSupplier.ToString();
want to insert dataset or a datatable into ORACLE,
create an ORACLE data adapter.
create a command object for insertion,
set the CommandType to StoredProcedure.
Update command of the data adapter,
pass the dataset or datatable as parameter.
like this:
OracleDataAdapter da = new OracleDataAdapter();
OracleCommand cmdOra = new OracleCommand(StoredProcedureName, Connection);
cmdOra.CommandType = CommandType.StoredProcedure;
da.InsertCommand = cmdOra;
da.Update(dsDataSet);
OR
if above dont work than pass datatable as xml prameter than than process it
For details check : ADO.NET DataTable as XML parameter to an Oracle/SQL Server Database Stored Procedure
OR
Check this thread on Oracle site : Thread: Pass data table to Oracle stored procedure
Check existing answer : How to Pass datatable as input to procedure in C#?
I'm very late for this answer, but I elaborated a bit to have some more readable (I hope) code, and to avoid all those .ToString() for the values so nulls and other less common values can be handled; here it is:
public void Copy(String tableName, DataTable dataTable)
{
var insert = $"insert into {tableName} ({GetColumnNames(dataTable)}) values ({GetParamPlaceholders(dataTable)})";
using (var connection = /*a method to get a new open connection*/)
{
for (var row = 0; row < dataTable.Rows.Count; row++)
{
InsertRow(dataTable, insert, connection, row);
}
}
}
private static void InsertRow(DataTable dataTable, String insert, OracleConnection connection, Int32 row)
{
using (var command = new OracleCommand(insert, connection))
{
AssembleParameters(dataTable, command, row);
command.ExecuteNonQuery();
}
}
private static void AssembleParameters(DataTable dataTable, OracleCommand command, Int32 row)
{
for (var col = 0; col < dataTable.Columns.Count; col++)
{
command.Parameters.Add(ParameterFor(dataTable, row, col));
}
}
private static OracleParameter ParameterFor(DataTable dataTable, Int32 row, Int32 col)
{
return new OracleParameter(GetParamName(dataTable.Columns[col]), dataTable.Rows[row].ItemArray.GetValue(col));
}
private static String GetColumnNames(DataTable data) => (from DataColumn column in data.Columns select column.ColumnName).StringJoin(", ");
private static String GetParamPlaceholders(DataTable data) => (from DataColumn column in data.Columns select GetParamName(column)).StringJoin(", ");
private static String GetParamName(DataColumn column) => $":{column.ColumnName}_param";
Hope this can be still useful to somebody
The best idea would be follow the step mentioned below
Create a transaction
Begin the transaction
Loop through you data table
call your procedure
If no error occurred commit transaction
else roll back transaction
Regarding this part of your question:
cmd.Parameters.Add("#Details",dtSupplier);
(OR)
cmd.Parameters.Add("Details", DbType.Single).Value = dtSupplier.ToString();
What is the type of the "Details" parameter? Is it a Single? Then you would have to pick one (1) value from your DataTable and pass it to your parameter, something like dtSupplier.Rows[0]["col"].
If you use dtSupplier.ToString() you are just making a string of the entire DataTable (which i guess will always be the type name of DataTable).
First of all, you need to add Oracle.DataAccess.dll as reference in Visual Studio. In most cases, you can find this dll in the directory C:\ProgramData\Oracle11g\product\11.2.0\client_1\ODP.NET\bin\2.x\Oracle.DataAccess.dll
If just you need to insert the records from DataTable to Oracle table, then you can call the below function. Consider that your DataTable name is dt.
string error = "";
int noOfInserts = DataTableToTable(dt,out error);
1. Without using Oracle Parameters(special character non-safe)
The definition of the function is given below. Here, we are just making the query dynamic for passing this as a sql statement to the InsertWithQuery function.
public int DataTableToTable(DataTable dt,out string error)
{
error = "";
for (int i = 0; i < dt.Rows.Count; i++)
{
finalSql = "INSERT INTO TABLENAME SELECT ";
for (int j = 0; j < dt.Columns.Count; j++)
{
colValue += "'" + dt.Rows[i][j].ToString() + "',";
}
colValue = colValue.Remove(colValue.Length - 1, 1);
finalSql += colValue + " FROM DUAL";
InsertWithQuery(finalSql, out error);
if (error != "")
return error;
inserts++;
colValue = "";
}
}
The code for InsertWithQuery function is given below. Here, in the connection string you have to place you database details like Host,Username,Password etc.
public int InsertWithQuery(string query, out string error)
{
error = "";
int rowsInserted = 0;
if (error == "")
{
OracleConnection con = new OracleConnection("Data Source=(DESCRIPTION=(ADDRESS_LIST=(ADDRESS=(PROTOCOL=TCP)(HOST=)(PORT=)))(CONNECT_DATA=(SERVER=DEDICATED)(SID=)));User Id=;Password=");
OracleTransaction trans = con.BeginTransaction();
try
{
error = "";
OracleCommand cmd = new OracleCommand();
cmd.Transaction = trans;
cmd.Connection = con;
cmd.CommandText = query;
rowsInserted = cmd.ExecuteNonQuery();
trans.Commit();
con.Dispose();
return rowsInserted;
}
catch (Exception ex)
{
trans.Rollback();
error = ex.Message;
rowsInserted = 0;
}
finally
{
con.Dispose();
}
}
return rowsInserted;
}
2. With using Oracle Parameters(special character safe)
This can handle special characters like single quotes like scenarios in the column values.
public int DataTableToTable(DataTable dt,out string error)
{
error = "";
string finalSql = "";
List<string> colValue = new List<string>();
List<string> cols = new List<string>() {"COLUMN1","COLUMN2","COLUMN3"};
for (int i = 0; i < dt.Rows.Count; i++)
{
finalSql = "INSERT INTO TABLENAME(COLUMN1,COLUMN2,COLUMN3) VALUES(:COLUMN1,:COLUMN2,:COLUMN3) ";
for (int j = 0; j < dt.Columns.Count; j++)
{
colValue.Add(dt.Rows[i][j].ToString());
}
objDAL.InsertWithParams(finalSql,colValue,cols, out error);
if (error != "")
return error;
inserts++;
colValue.Clear();
}
}
And the InsertWithParams is given below
public string InsertWithParams(string sql, List<string> colValue, List<string> cols, out string error)
{
error = "";
try
{
OracleConnection con = new OracleConnection("Data Source=(DESCRIPTION=(ADDRESS_LIST=(ADDRESS=(PROTOCOL=TCP)(HOST=)(PORT=)))(CONNECT_DATA=(SERVER=DEDICATED)(SID=)));User Id=;Password=");
OracleCommand command = new OracleCommand(sql, con);
for (int i = 0; i < colValue.Count; i++)
{
command.Parameters.Add(new OracleParameter(cols[i], colValue[i]));
}
command.ExecuteNonQuery();
command.Connection.Close();
}
catch (Exception ex)
{
error = ex.Message;
}
return null;
}
try {
//Suppose you have DataTable dt
string connectionString = #"Provider=Microsoft.ACE.OLEDB.12.0;" +
#"Data Source='Give path of your access database file here';Persist Security Info=False";
OleDbConnection dbConn = new OleDbConnection(connectionString);
dbConn.Open();
using (dbConn)
{
int j = 0;
for (int i = 0; i < 2; i++)
{
OleDbCommand cmd = new OleDbCommand(
"INSERT INTO Participant_Profile ([column1], [column2] , [column3] ) VALUES (#c1 , #c2 , #c3 )", dbConn);
cmd.Parameters.AddWithValue("#c1", dt.rows[i][j].ToString());
cmd.Parameters.AddWithValue("#c2", dt.rows[i][j].ToString());
cmd.Parameters.AddWithValue("#c3", dt.rows[i][j].ToString());
cmd.ExecuteNonQuery();
j++;
}
}
}
catch (OleDbException exception)
{
Console.WriteLine("SQL Error occured: " + exception);
}
I know it's been a big WHILE upon the matter, but the same need: "to insert data from a datatable to an Oracle table" has happened to me. I found this thread. I also tried the answers and came to the conclusion that executing a
...
cmd.ExecuteNonQuery();
...
in a loop, is bad. Reeaaally bad. The first thing that is bad is performance, the second is unnecessary complexity, the third is unnecessary Oracle Objects (stored proc). The time it takes to complete, lets say 200 rows, is almost 1 minute and that's me rounding it down. So in the hope that someone else will find this helpful here's my experience.
I got stubborn and searched some more, so I found out this, true it's from 2018. But I'm in 2021 myself...
So the base code is:
using Oracle.ManagedDataAccess.Client; // you don't need other dll, just install this from nuget gallery
using System.Data;
public static void Datatable2Oracle(string tableName, DataTable dataTable)
{
string connString = "connection string";
OracleBulkCopy copy= new(connString, OracleBulkCopyOptions.UseInternalTransaction /*I don't know what this option does*/);
copy.DestinationTableName = tableName;
copy.WriteToServer(dataTable);
copy.Dispose();
}
This should match a raw oracle DDL performance:
create table table_name as select * from other_table_name