Should I use ExecuteNonQuery for this db backup command - c#

I have a method that allows me to kick off a back up of a data base. What I am wondering is if I should be using ExecuteNonQuery() in this context or if there is something better to use. Here is my code currently:
public static void RunBackup(string dbName, string filePath, string backupName, string connString)
{
using(SqlConnection objConnection = new SqlConnection(connString))
{
string commmandText = "BACKUP DATABASE #DBName TO DISK = #FilePath WITH NOFORMAT, NOINIT, NAME = #BackUpName, SKIP, NOREWIND, NOUNLOAD, STATS = 10";
SqlCommand objCommand = new SqlCommand(commmandText,objConnection);
objCommand.Parameters.AddWithValue("#dbName", dbName);
objCommand.Parameters.AddWithValue("#FilePath", filePath);
objCommand.Parameters.AddWithValue("#BackUpName", backupName);
objConnection.Open();
objCommand.ExecuteNonQuery();
objConnection.Close();
}
}
The one thing I am concerned about is being able to verify that the backup is complete and successful while handling time out issues for backups that take and extended time to complete.

ExecuteNonQuery means that the command doesn't return any data. It doesn't mean that it executes asynchronously or that you won't receive error information. It will block until the command finishes and return any errors that may occur

To handle the issue of the long running query I ended up going with this:
public static void RunBackup(string dbName, string filePath, string backupName, string connString)
{
string commmandText = "BACKUP DATABASE #DBName TO DISK = #FilePath WITH NOFORMAT, NOINIT, NAME = #BackUpName, SKIP, NOREWIND, NOUNLOAD, STATS = 10";
SqlConnection objConnection = new SqlConnection(connString);
try
{
SqlCommand objCommand = new SqlCommand(commmandText, objConnection);
objCommand.Parameters.AddWithValue("#dbName", dbName);
objCommand.Parameters.AddWithValue("#FilePath", filePath);
objCommand.Parameters.AddWithValue("#BackUpName", backupName);
objConnection.Open();
IAsyncResult result = objCommand.BeginExecuteNonQuery();
while (!result.IsCompleted)
{
System.Threading.Thread.Sleep(100);
}
int count = objCommand.EndExecuteNonQuery(result);
}
catch (SqlException e)
{
throw e;
}
finally
{
objConnection.Close();
}
}
This will allow me to execute the command without asyncronously without timeout issues. I will be adding some additional error handling etc in my final code set. I may do some additional work to see if I can get a better status returned at the end of the script that I can get via EndExecuteNonQuery or through an AsyncCallBack.

ExecuteNonQuery()
should be fine to use here. What I would do is run a try catch around the using to catch any errors that might happen and deal with them appropiately.

You should use ExecuteNonQuery when you do not what to receive any information from the database as a result of your call. If any error with happen during execute of the command you will get a corresponding exception.

This does look like the type of thing you should put in a stored procedure to do some error handling.
Also, have a look here to see it done in code.

I think ExecuteNonQuery is fine, but You should consider to user a timeout with Your query.
objCommand.CommandTimeout = 60*60; // for an hour or more
If You're using a desktop application, then for sure You should execute this query within asynchronous call.

ExecuteNonQuery is the correct command to use.
If you wish to receive more info about the restore process you should subscribe to the InfoMessage event of the SqlConnection object. That was you can capture all the "non-error" messages as well.

Try it. it resolved timeout expired problem while large size db.
Private Sub Command1_Click()
On Error Resume Next
Dim con As New Connection
Dim tm As String
con.CommandTimeout = 500'''Command timeout should be 500
With con
.ConnectionString = "Provider=SQLOLEDB.1;Persist Security Info=False;User ID=sa;Initial Catalog=dbiBMS;Data Source=192.168.103.4"
.Open
End With
tm = CStr(Time)
con.Execute " backup database dbiBMS to disk='E:\Database_Backup\Test1.bak' with format "
con.Close
MsgBox tm
Exit Sub
x:
MsgBox Err.Description
End Sub

Related

PostgreSQL: command is already in progress

My asynchronous function tries to select a single record from a table. This function accepts a few arguments passed from another function.
So, some processes (6 at least) can use it simultaneously. Often I get an error with the message "command is already in progress".
I know that the problem hides in the reader, because the reader is busy when another process tries to access it.
Let me publish the full code below:
async private void InsertToLog(List<Printer> APrinter, List<PrinterToGridBinds> AGridBind, int index)
{
if (!String.IsNullOrEmpty(APrinter[index].Type.Trim()) && !String.IsNullOrEmpty(AGridBind[index].extBatchNumber.Trim()) && !String.IsNullOrEmpty(AGridBind[index].extBatchCounter.Trim()) && !String.IsNullOrEmpty(AGridBind[index].extDIOCounter.Trim()))
{
string dio_count = "0";
string GetDIOCounter = string.Format(#"SELECT dio_counter FROM {0} WHERE device_type = '{1}' AND batch_number = '{2}' ORDER BY id DESC
LIMIT 1;", log_table_name, lst_PrinterStruct[index].Type, AGridBind[index].extBatchNumber);
try
{
NpgsqlCommand db_getCounter = new NpgsqlCommand(GetDIOCounter, conn);
if (conn.State != ConnectionState.Open)
conn.Open();
using (DbDataReader reader = await db_getCounter.ExecuteReaderAsync())
{
while (await reader.ReadAsync())
dio_count = reader[0].ToString().Trim();
}
AGridBind[index].extDIOCounter = (Int32.Parse(dio_count) + Int32.Parse(AGridBind[index].extDIOCounter.Trim())).ToString();
string Insert_SQL = String.Format(#"INSERT INTO {0} (device_type, batch_number, start_date, batch_counter, dio_counter) VALUES ('{1}', '{2}', '{3}', '{4}', '{5}') ON CONFLICT ON CONSTRAINT unique_log_key DO UPDATE SET batch_counter='{4}', dio_counter='{5}';", log_table_name, APrinter[index].Type.Trim(),
AGridBind[index].extBatchNumber.Trim(), DateTime.Now.ToString(), AGridBind[index].extBatchCounter.Trim(), AGridBind[index].extDIOCounter.Trim());
var db_cmd = new NpgsqlCommand(Insert_SQL, conn);
int res = await db_cmd.ExecuteNonQueryAsync();
}
catch (Exception e)
{
string FMessage = String.Format("Printer {0} \r\n Can not write to table\r\n Error: {1}",
lst_PrinterStruct[index].Name, e.Message);
MessageBox.Show(FMessage);
}
finally
{
conn.Close();
}
}
}
As you can see, the reader is wrapped by using here.
Anyway, I have what I have (an error). So, my question is how to avoid this error message (I'm about "command is already in progress")?
I have a few ideas about possible decisions. Maybe:
Set the DbDataReader as parameter. And the name of the reader can be generated by the Random function. But I don't know how to do that.
Wait until the current process has finished and closes the reader, then run the second etc. But I don't know how to tell the new process to wait until the previous has finished.
So, I need your help, guys.
If several threads share one database connection, you have to synchronize them so that only one of them uses the connection at the same time. You can only run one statement at a time in a PostgreSQL database session.
Since synchronization is cumbersome and may hurt your concurrency, you'd be better off using a connection pool, and each thread requests a connection from the pool if it needs one.
I have encountered same problem in VB.Net when migrating OleDB program to PNGSQL.
My program executed simply a loop to read some records returned by a simple SQL SELECT.
'*******************************************************************
'* SelectMouvements()
'*******************************************************************
Private Function SelectMouvements() As Integer
SQL = _
<sql-select>
SELECT *
FROM mouvements
INNER JOIN comptes
ON comptes.no_compte = mouvements.personnal_account
LEFT OUTER JOIN cartes
ON cartes.no_carte = mouvements.no_carte
</sql-select>
Dim cmd As New NpgsqlCommand(SQL, cn)
Dim dr As NpgsqlDataReader
dr = cmd.ExecuteReader()
While dr.Read()
grid.Rows.Add()
With grid.Rows(iRow)
.Cells(0).Value = dr("communication")
...
End With
call NormalizeSomeFields(dr("name"))
End While
End Sub
The problem with my code that doesn't exist when using OleDb is that NormalizeSomeFields() function was opening a second DataReader.
Private Sub NormalizeSomeFields(ByRef sNom as String)
SQL =
<sql-select>
SELECT NewNom
FROM aliasnom
WHERE Nom = <%= AddQuote(sNom) %>
<sql-select>
Dim cmdNom As New NpgSqlCOmmand(SQL, cn)
Dim drNom As NpgsqlDataReader
drNom = cmdNom.ExecuteReader()
If drNom.Read() Then
sNom = drNom(0)
End If
drNom.Close()
End Sub
This program is returning NpgsqlOperationInProgresException on cmdNom.ExecuteReader() line.
SOLUTION
To solve this problem I have defined another NpgsqlConnection named cn2 just after code that is defining cn connection as in following lines
cn = New NpgsqlConnection(cs)
Try
cn.Open()
Catch ex As Exception
MsgBox(ex.Message)
End Try
cn2 = New NpgsqlConnection(cs)
Try
cn2.Open()
Catch ex As Exception
MsgBox(ex.Message)
End Try
and I use it now when second DataReader is defined
Dim cmdNom As New NpgSqlCOmmand(SQL, cn2)
NPGSQL seems to refuse multiple sets ... but accepts multiple connections !

Error during insert of record from asp.net into SQL Server database

I got this error during insert of data into a SQL Server database
Here is my code in button click event
try
{
string ConnString = "Data Source=(LocalDB)\v11.0;AttachDbFilename=\\MOD03-PC\\Share Folder mod03\\amts\\amtsfuelconsuption\\AmtsFuelConsumption\\AmtsFuelConsumption\\App_Data\\AmtsDatabse.mdf;Integrated Security=True;Connect Timeout=900,providerName=System.Data.SqlClient";
SqlConnection con = new SqlConnection(#ConnString);
SqlCommand cmd = new SqlCommand("InsertBodyTypeMaster", con);
cmd.CommandTimeout = 0;
cmd.CommandType = CommandType.StoredProcedure;
cmd.Parameters.AddWithValue("bodytypename", txtBTname.Text.ToString());
con.Open();
int k = cmd.ExecuteNonQuery();
if (k != 0)
{
lblmessage.Text = "Record Inserted Succesfully into the Database";
lblmessage.ForeColor = System.Drawing.Color.CornflowerBlue;
}
con.Close();
con.Dispose();
}
catch (Exception ex)
{
lblmessage.Text = ex.ToString();
}
I see a few things wrong;
As mentioned, you need to change your Connect Timeout=900, to Connect Timeout=900;
You need to delete providerName=System.Data.SqlClient part since you already using the .NET provider for SQL Server. Provider names for .NET are implicit based on the implementing class and not needed to specified in the connection string. When you delete this, you will not need ; at the end of Connect Timeout=900; anymore
Use using statement to dispose your connection and command automatically instead of calling Close or Dispose methods manually.
Don't use AddWithValue as much as you can. It may generate unexpected and surprising results sometimes. Use Add method overload to specify your parameter type and it's size.
Final connection string should be as;
string ConnString = "Data Source=(LocalDB)\v11.0,AttachDbFilename=\\MOD03-PC\\Share Folder mod03\\amts\\amtsfuelconsuption\\AmtsFuelConsumption\\AmtsFuelConsumption\\App_Data\\AmtsDatabse.mdf;Integrated Security=True;Connect Timeout=900";
You have a comma and not a semi-colon after the 900 in the connect timeout property in the connection string.
Cause your connection string is total weird. remove those ; and replace them with ,. Also, make sure you spell them properly. It should be like
string ConnString = "Data Source=(LocalDB)\v11.0,AttachDbFilename=\\MOD03-PC\\Share Folder mod03\\amts\\amtsfuelconsuption\\AmtsFuelConsumption\\AmtsFuelConsumption\\App_Data\\AmtsDatabse.mdf,Integrated Security=True,Connect Timeout=900;providerName=System.Data.SqlClient";
Also the below line
SqlConnection con = new SqlConnection(#ConnString);
It should be
SqlConnection con = new SqlConnection(ConnString);
You are calling Dispose() inside try block which is big blunder as shown below. Either use Using(...) block (or) finally block
try
{
....
con.Close();
con.Dispose();
}
Should be
finally
{
con.Close();
con.Dispose();
}
Looks like it's time you should start reading through documentation.

data not being written to local SQL Server database file

I have written that gets data from a sensor, I am trying to write this data to a local SQL Server database file.
Code doesn't produce any errors but the data is not being written to the data table.
I have used the following code: (any suggestions?)
static void Insert(string date, double value, string deviceName)
{
string path = Directory.GetCurrentDirectory();
string filename = path + "\\Database1.mdf";
Console.WriteLine(filename);
string connectionString = "Data Source=(LocalDB)\\v11.0;AttachDbFilename=" + filename + ";Database=Database1";
using (SqlConnection conn = new SqlConnection(connectionString))
try
{
{
conn.Open();
SqlDataAdapter adapter = new SqlDataAdapter();
using (SqlCommand cmd = new SqlCommand("INSERT INTO DataTable VALUES(#Id, #Date, #Value, #Device Name)", conn))
{
num11 += 1;
cmd.Parameters.AddWithValue("#Id", num11);
cmd.Parameters.AddWithValue("#Date", date);
cmd.Parameters.AddWithValue("#Value", value);
cmd.Parameters.AddWithValue("#Device Name", deviceName);
cmd.ExecuteNonQueryAsync();
//rows number of record got inserted
}
conn.Close();
}
}
catch (SqlException es)
{
Console.WriteLine(es);
//Display Error message
}
}
You're calling ExecuteNonQueryAsync to asynchronously insert the record - but you're then closing the connection immediately, while the insert has almost certainly not yet completed.
You should either use the synchronous call instead, or use asynchrony properly - probably making the method asynchronous, and awaiting the result of ExecuteNonQueryAsync. You need to wait for the operation to complete before you close the connection, basically.
You don't need to call Close explicitly at all, by the way - you've already got a using statement, so the connection will be disposed as execution exits the block. (It's not clear why you've got an extra block inside the using statement either, by the way.)

How can commit data update in Microsoft SQL sever?

In a web app, I am using SQL server. However, when I try to store some bulk amount of data, it misses some of the records and does not insert them into the database. I want to know whether there is any commit statement or synchronization for the database? Data is being sent object by object using an ajax call.
Here is my code:
try
{
int surah = Convert.ToInt32(Request["surah"]);
string verse = Request["data"];
string connectionString = #"Data Source=(LocalDB)\v11.0;AttachDbFilename=C:\PROGRAM FILES (X86)\MICROSOFT SQL SERVER\MSSQL.1\MSSQL\DATA\PEACE_QURAN.MDF;Integrated Security=True";
System.Data.SqlClient.SqlConnection connection = new SqlConnection(connectionString);
string query = "insert into Ayyat_Translation_Language_old_20131209 values(null,null,"+surah+",'"+verse+"')";
SqlCommand cmd = new SqlCommand(query, connection);
connection.Open();
cmd.ExecuteNonQuery();
connection.Close();
}
catch(Exception e){
System.IO.StreamWriter file = new System.IO.StreamWriter(#"E:\Office_Work\Peace_Quran\Peace_Quran\Files\ExceptionFile.txt", true);
file.WriteLine("exception details : "+e.ToString());
file.Close();
}
As you understand, the records cannot get lost in the way. Either the INSERT statement would execute, or you would get an exception. Since neither is happening, I believe that you loose something in the request generating mechanism.
I would strongly suggest to put some logging message on each request. You will probably find out that your requests are less than you thought. This could be for a number of reasons, but since I don't know the exact mechanism calling the server side code, I cannot have an opinion.
Hope I helped!

SQL Reading from a DB problem using a DataReader

I have a table of Users (tblUsers) which contains details of University staff. I am trying to populate a text box with the names of lecturers associated with a selected module.
I am getting all UserIDs associated with a particular module, testing if the User is a lecturer, if so then I add the ID to an ArrayList.
I then iterate through this array and call the method below during each iteration passing through the current ID.
However, if you look at the method below I am using a SqlDataReader and am getting an error while reading from it on this line:
txtLecturerName.Text += myReader["First_Name"].ToString();
The error message is:
'myReader["First_Name"]' threw an exception of type 'System.IndexOutOfRangeException'
The table layout I am using is below the method code. Any help with this would be greatly appreciated, I am one cup of coffee away from putting my head through the screen.
public void outputLecturerNames(string lecturerID)
{
// Create a new Connection object using the connection string
SqlConnection myConnection = new SqlConnection(conStr);
// If the connection is already open - close it
if (myConnection.State == ConnectionState.Open)
{
myConnection.Close();
}
// 'using' block allows the database connection to be closed
// first and then the exception handling code is triggered.
// This is a better approach than using a 'finally' block which
// would close the connection after the exception has been handled.
using (myConnection)
{
try
{
// Open connection to DB
myConnection.Open();
SqlCommand selectCommand = new SqlCommand(selectQuery, myConnection);
// Declare a new DataReader
SqlDataReader myReader;
selectQuery = "SELECT * FROM tblUsers WHERE User_ID='";
selectQuery += lecturerID + "'";
myReader = selectCommand.ExecuteReader();
while (myReader.Read())
{
txtLecturerName.Text += myReader["First_Name"].ToString();
txtLecturerName.Text += " ";
txtLecturerName.Text += myReader["Last_Name"].ToString();
txtLecturerName.Text += " , ";
}
myReader.Close();
}
catch (Exception err)
{
Console.WriteLine("Error: " + err);
}
}
}
tblUsers:
[User_ID][First_Name][Last_Name][Email_Address]
In your method, the variable selectQuery is not declared, and it is used as parameter to SqlCommand before it is assigned the query string on tblUsers.
You've probably misspelled a column name.
In general, you should never write SELECT * FROM ....
Instead, you should select only the columns you need.
This will make your program run faster by only querying the information that you need, and can produce better error messages.
This error is created when the column name given is not found. If you are anything like me, you've probably checked it several times, but is the table name correct (correct database, correct schema) and is the column name correct?
http://msdn.microsoft.com/en-us/library/f01t4cfy.aspx
You might try fully qualifying the name of the table (database.dbo.tblUsers). This would ensure that you are hitting the table you think you are. Also, try and put the names of the columns into the SQL statement. If they are not correct, your SQL statement will not execute properly.

Categories