Hi all and thanks in advance. I am trying to fix a method that inserts information to a database table. Currently its experiencing timeouts because its running in a while loop that is taking too long to process all the contents. While I know I could just increase the command timeout I don't think that solves the problem because I think its the code. But I'm not certain what the correct fix is. I have access to Dapper and I wonder if it would be more efficient to make a method that passes the necessary variables and executes just a quick simple statement for that group then goes to get the next one? Or is that just perpetuating what's below just in a different way? Should I move this out of the code and onto the server for better performance?
UPDATE Full error message:
Exception of type 'System.Web.HttpUnhandledException' was thrown.
File: c:\WINDOWS\Microsoft.NET\Framework\v4.0.30319\Temporary ASP.NET Files\6caa4c91\19b853c6\App_Web_o3102kpb.9.cs
Method: ProcessRequest Line Number : 0
Inner Exception: {Timeout expired. The timeout period elapsed prior to completion of the operation or the server is not responding.
File: z:\inetpub\wwwroot\SessionTransfer.aspx.cs
Method: AddSessionToDatabase Line Number : 94
Timeout expired. The timeout period elapsed prior to completion of the operation or the server is not responding.
File: z:\inetpub\wwwroot\SessionTransfer.aspx.cs Method: Page_Load Line Number : 33 }
Here is the original code:
SqlConnection con = new SqlConnection(connectionString);
SqlCommand cmd = new SqlCommand();
con.Open();
cmd.Connection = con;
int i = 0;
string strSql, guid = GetGuid();
string temp = "";
while (i < Session.Contents.Count)
{
if (Session.Contents[i] == null)
temp = "";
else {
if ((Session.Contents[i].ToString().Trim().Length) > 0)
temp = Session.Contents[i].ToString().Replace("'", "''");
else
temp = "";
}
strSql = "INSERT INTO SessionTable (GUID, SessionKey, SessionValue) " +
"VALUES ('" + guid + "', '" + Session.Contents.Keys[i].ToString() + "', '" + temp + "')";
cmd.CommandText = strSql;
cmd.ExecuteNonQuery();
i++;
}
con.Close();
cmd.Dispose();
con.Dispose();
return guid;
UPDATE - FINAL SOLUTION:
var SessionList = new List<Session>();
while (i < Session.Contents.Count)
{
string temp = "";
if (Session.Contents[i] == null)
temp = "";
else
{
temp = (Session.Contents[i].ToString().Trim().Length) > 0 ? Session.Contents[i].ToString().Replace("'", "''") : "";
}
var s = new Session
{
TempGuid = guidTemp,
Contents = Session.Contents[i] != null ? Session.Contents[i].ToString() : null,
Temp = temp
};
SessionList.Add(s);
i++;
}
mySession = SerializationUtilities.SerializeObjectToXML(SessionList);
using (var con = new SqlConnection())
{
con.ExecuteHGW("Transfer", new { mySession }, commandType: CommandType.StoredProcedure);
}
Then on the SQL side I just put the XML in a table and did one single insert statement against the table, time is significantly improved.
I would like to suggest you 2 improvements:
in the loop you are executing insert statements one by one against db. It takes much time to open connection to db then send the query, execute it and return result. It is much better to batch them. So gather like 10,000 of such insert statements, build the whole instuction with StringBuilder and execute it against db in one go. This will really increase the speed of your app. Amount of Insert instructions in one batch you should choose yourself basing on system tests.
If after applying 1) hint the problem with timeout still occurs I would suggest 2 possible solutions:
a). do not send all elements to be processed against db to web service at once but instead, as previoulsy, batch them (apply second batching). So for instance send to web service 50,000 elements to be insterted, then wait for confirmation from web service and then proceed with next batch. The big advantage is that you can show to user easily progress bar showing him current operation state.
b). send all items to be processed against db at once but do not wait for result. In your app just show that items are processed and each 10 s send to web service request to ask if the job is finished. When it is finished signal it to user.
Related
I'm attempting to add the finishing touch to a project I've been working on and am currently trying to modify a feature that I've created. The feature being that if a student has completed an examination, they are able to view the results. However, what I want to do is create an if else statement that is essentially: if the exam has been taken and completed, then they are redirected to the page that shows them the specific exam's results. Else, it returns a message at the top of the page stating "This examination has not been completed yet."
The current code I have (which is operated through a button on the page) is:
protected void btnViewPrevExam_Click(object sender, EventArgs e)
{
Session["intExaminationID"] = ddlExamination.SelectedValue;
Int32 int32StudentID = Convert.ToInt32(Session["StudentID"]);
Session["int32StudentID"] = Convert.ToInt32(int32StudentID);
// Define the ADO.NET connection object.
SqlConnection objSqlConnection = new SqlConnection(WebConfigurationManager.ConnectionStrings["OPT"].ConnectionString);
// Develop the SQL call.
// Develop the SQL call.
String strSQL = "";
strSQL = "SELECT AnswerID, Question, OptionA, OptionB, OptionC, OptionD, CorrectAnswer, Answer ";
strSQL += " FROM Question, Answer, Examination, Student ";
strSQL += " WHERE Examination.ExaminationID = " + ddlExamination.SelectedValue;
strSQL += " AND Student.StudentID = " + int32StudentID;
strSQL += " AND Answer.QuestionID = Question.QuestionID ";
strSQL += " AND Answer.StudentID = Student.StudentID ";
strSQL += " AND Examination.ExaminationID = Question.ExaminationID ";
// Create the SQL command object.
SqlCommand objSqlCommand = new SqlCommand(strSQL, objSqlConnection);
// Retrieve the row from the table.
objSqlConnection.Open();
SqlDataReader objSqlDataReader = objSqlCommand.ExecuteReader();
objSqlDataReader.Read();
if (strSQL != null)
{
objSqlDataReader.Close();
objSqlConnection.Close();
Response.Redirect("StudentExamResults.aspx");
}
else
{
this.Master.MessageForeColor = System.Drawing.Color.Red;
this.Master.Message = "The selected examination has not been completed.";
}
}
What this button does currently is that it will send the student to the examination results page regardless if the examination has been completed or not. This is due to the line "if (strSQL != null)" and it never being null because the SQL call has been made and filled. I've attempted other ideas, as well as performing a objSqlDataReader for the AnswerID but it didn't work properly. This is a small extra feature I'd like to add to this project that I thought of and would be very pleased if I could find some help on sorting out what I'm doing wrong. Thank you in advance!
Testing if strSQL is not null will always succeed because you are setting it to a non-null value earlier in the method.
To see if a record already exists for a previously-completed examination, you need to check the return value of the call to objSqlDataReader.Read(); it will return true as long as there are additional rows (or, in this case, a first row) to consume from your SELECT query. Thus, change this...
objSqlDataReader.Read();
if (strSQL != null)
{
...to this...
if (objSqlDataReader.Read())
{
As an additional note, consider wrapping objSqlConnection, objSqlCommand, and objSqlDataReader in using blocks to ensure they are properly closed/disposed. As it is now, you are not closing objSqlDataReader and objSqlConnection when the exam needs to be completed, and objSqlCommand is not disposed at all. objSqlDataReader would then be closed as follows, regardless of which branch of the if is taken...
using (SqlDataReader objSqlDataReader = objSqlCommand.ExecuteReader())
{
if (objSqlDataReader.Read())
{
//objSqlDataReader.Close();// No longer necessary - handled by using
objSqlConnection.Close();
Response.Redirect("StudentExamResults.aspx");
}
else
{
this.Master.MessageForeColor = System.Drawing.Color.Red;
this.Master.Message = "The selected examination has not been completed.";
}
}
Assuming you don't care about the contents, rather you just want to check if the row exists, you can do something like this:
string sql = "SELECT COUNT(AnswerID) FROM Question ........ WHERE ......";
using (var connection = CreateConnection()) {
using (var cmd = new SqlCommand(sql, connection)) {
bool exists = (int) cmd.ExecuteScalar() > 0;
if (exists) {
Response.Redirect("StudentExamResults.aspx");
} else {
// Do the other thing
}
}
}
The Situation: I am creating an automated task which queries MySQL (through ODBC) and inserts the result set to a MS Access Database (.mdb) using OLEDB.
The Code:
OleDbConnection accCon = new OleDbConnection();
OdbcCommand mySQLCon = new OdbcCommand();
try
{
//connect to mysql
Connect();
mySQLCon.Connection = connection;
//connect to access
accCon.ConnectionString = #"Provider=Microsoft.Jet.OLEDB.4.0;" +
#"Data source= " + pathToAccess;
accCon.Open();
var cnt = 0;
while (cnt < 5)
{
if (accCon.State == ConnectionState.Open)
break;
cnt++;
System.Threading.Thread.Sleep(50);
}
if (cnt == 5)
{
ToolBox.logThis("Connection to Access DB did not open. Exit Process");
return;
}
} catch (Exception e)
{
ToolBox.logThis("Faild to Open connections. msg -> " + e.Message + "\\n" + e.StackTrace);
}
OleDbCommand accCmn = new OleDbCommand();
accCmn.Connection = accCon;
//access insert query structure
var insertAccessQuery = "INSERT INTO {0} values({1});";
// key = > tbl name in access, value = > mysql query to b executed
foreach (var table in tblNQuery)
{
try
{
mySQLCon.CommandText = table.Value;
//executed mysql query
using (var dataReader = mySQLCon.ExecuteReader())
{
//variable to hold row data
var rowData = new object[dataReader.FieldCount];
var parameters = "";
//read the result set from mysql query
while (dataReader.Read())
{
//fill rowData with the row values
dataReader.GetValues(rowData);
//build the parameters for insert query
for (var i = 0; i < dataReader.FieldCount; i++)
parameters += "'" + rowData[i] + "',";
parameters = parameters.TrimEnd(',');
//insert to access
accCmn.CommandText = string.Format(insertAccessQuery, table.Key, parameters);
try
{
accCmn.ExecuteNonQuery();
}
catch (Exception exc)
{
ToolBox.logThis("Faild to insert to access db. msg -> " + exc.Message + "\\n\\tInsert query -> " + accCmn.CommandText );
}
parameters = "";
}
}
}
catch (Exception e)
{
ToolBox.logThis("Faild to populate access db. msg -> " + e.Message + "\\n" + e.StackTrace);
}
}
Disconnect();
accCmn.Dispose();
accCon.Close();
The Issues:
The memory usage goes very high (300MB++) while the MS Access file size does not change constantly! Seems like the insert caches the data rather that saving it to disk.
It is very slow! I know my query executes within a few second but rather insertion process takes long.
I have tried using prepared statement in MS Access and insert the values as parameters instead of string concat to create insert query. However I get this exception message:
Data type mismatch in criteria expression.
Anyone know how to fix this or have a better approach?
You could create a VBA macro that uses the DoCmd.TransferDatabase method to pull data through ODBC into your Access database. It would probably be much faster and simpler as well.
To run the VBA code from an external program or scheduled task, simply initiate Access to open your file with the /x command line switch and it will run the import macro on startup. A GB of data though is still going to take a while. I found an article by David Catriel that implemented this approach.
An even better option is to use a different database engine back-end like the free version of SQL Server Express. Then you have a lot more options and it is much more robust. If you need MS Access forms and reports, you can create an ADP project file if you use SQL Server, or you can use linked tables to get at your data. You could even use Access as a front-end to your MySQL database instead of copying all the data if that would satisfy your requirements.
Instead of writing code, you could turn to SQL Server Integration Services (SSIS), and be done before lunch. It is available as an extension to Visual Studio, in case you do not have it on your computer already with SQL Server.
With SSIS you are able to create a reusable SSIS package that can be triggered from the command line or scheduled task. This guide shows how to pull data from MySQL into SQL Server, but the SQL Server part should be easy to replace with Access.
some changes with comment to add transaction for command execution. if transactions is not controlled manually, it will be created and committed every time automatically and it's a time consuming action
OleDbConnection accCon = new OleDbConnection();
OdbcCommand mySQLCon = new OdbcCommand();
try
{
//connect to mysql
Connect();
mySQLCon.Connection = connection;
//connect to access
accCon.ConnectionString = #"Provider=Microsoft.Jet.OLEDB.4.0;" +
#"Data source= " + pathToAccess;
accCon.Open();
var cnt = 0;
while (cnt < 5)
{
if (accCon.State == ConnectionState.Open)
break;
cnt++;
System.Threading.Thread.Sleep(50);
}
if (cnt == 5)
{
ToolBox.logThis("Connection to Access DB did not open. Exit Process");
return;
}
}
catch (Exception e)
{
ToolBox.logThis("Faild to Open connections. msg -> " + e.Message + "\\n" + e.StackTrace);
}
//AMK: transaction starts here
var transaction = accCon.BeginTransaction();
OleDbCommand accCmn = new OleDbCommand();
accCmn.Connection = accCon;
accCmn.Transaction = transaction;
//access insert query structure
var insertAccessQuery = "INSERT INTO {0} values({1});";
// key = > tbl name in access, value = > mysql query to b executed
foreach (var table in tblNQuery)
{
try
{
mySQLCon.CommandText = table.Value;
//executed mysql query
using (var dataReader = mySQLCon.ExecuteReader())
{
//variable to hold row data
var rowData = new object[dataReader.FieldCount];
var parameters = "";
//read the result set from mysql query
while (dataReader.Read())
{
//fill rowData with the row values
dataReader.GetValues(rowData);
//build the parameters for insert query
for (var i = 0; i < dataReader.FieldCount; i++)
parameters += "'" + rowData[i] + "',";
parameters = parameters.TrimEnd(',');
//insert to access
accCmn.CommandText = string.Format(insertAccessQuery, table.Key, parameters);
try
{
accCmn.ExecuteNonQuery();
}
catch (Exception exc)
{
ToolBox.logThis("Faild to insert to access db. msg -> " + exc.Message +
"\\n\\tInsert query -> " + accCmn.CommandText);
}
parameters = "";
}
}
//AMK: transaction commits here if every thing is going well
transaction.Commit();
}
catch (Exception e)
{
ToolBox.logThis("Faild to populate access db. msg -> " + e.Message + "\\n" + e.StackTrace);
//AMK: transaction rollback here if there is a problem
transaction.Rollback();
}
}
Disconnect();
accCmn.Dispose();
accCon.Close();
Create a DSN (data source name) for the SQL server database. Then select that DSN by opening the Microsoft Access database and choosing to import from that DSN. You should have the ability to import that exact 1GB table (schema, data, everything).
More information on using a DSN:
https://support.office.com/en-us/article/Link-to-SQL-Server-data-0474c16d-a473-4458-9cf7-f369b78d3db8
Alternatively you can just link to the SQL server database (not import to an Access table) using that DSN and skip the import altogether.
Should the INSERT be part of a TRANSACTION. Being within a TRANSACTION usually speeds BULK INSERTS
Thanks everyone for the answers. I just found the main problem in my code. The reason for heavy memory usage (issue #1) was ODBC was caching the data from MySQL regardless of C# approach (DataReader). That issue is resolved by checking the Don't cache results of forward-only cursors checkbox in DSN settings. This also made the process slightly faster (30%). However, more concrete approach is still what Brian Pressler and Egil Hansen suggested.But since they require software installation and/or migration plan, easiest way would be to stick to this piece of code.
public TransImport()
{
ConnString = ConfigurationManager.ConnectionStrings["Connection"].ConnectionString;
SqlConnection conn_new;
SqlCommand command_serial_new;
SqlConnection conn;
SqlCommand command_serial;
SqlTransaction InsertUpdateSerialNumbers;
conn = new SqlConnection(ConnString);
command_serial = conn.CreateCommand();
conn_new = new SqlConnection(ConnString);
command_serial_new = conn_new.CreateCommand();
command_serial_new.CommandText = "SELECT 1 FROM YSL00 WHERE SERLNMBR = #slnr";
var p = new SqlParameter("#slnr", SqlDbType.NVarChar, 50);
command_serial_new.Parameters.Add(p);
//Here you will start reading flat file to get serialnumber.
InsertUpdateSerialNumbers = conn.BeginTransaction();
while (!headerFileReader.EndOfStream)
{
headerRow = headerFileReader.ReadLine();
if (CheckSerialNumber(headerFields[0].Trim()))
DisplayMessage("Good serialnumber"); //this function is not copied here.
}
InsertUpdateSerialNumbers.Commit();
}
private Boolean CheckSerialNumber(string SerialNumber)
{
command_serial_new.Parameters["#slnr"].Value = SerialNumber;
try
{
var itExists = Convert.ToInt32(command_serial_new.ExecuteScalar()) > 0;
if (!itExists)
{
command_serial.Transaction = InsertUpdateSerialNumbers;
command_serial.CommandText = "INSERT INTO YSL00([Manifest_Number],[PONUMBER],[ITEMNMBR],[SERLNMBR]"
+ "VALUES ('" + Manifest + "','" + PONr + "','" + itemNumber + "','" + serialNr + "')";
var insertStatus = command_serial.ExecuteNonQuery();
return true;
}
}
catch (Exception ex)
{
LogException(ex, "Error in CheckSerialNumber =>"+ command_serial_new.CommandText.ToString());
}
return false;
}
I get error "Timeout expired. The timeout period elapsed prior to completion of the operation or server is not responding".
The CheckSerialNumber function also does an insert to YSL00 (the same table where I had executescalar. See code above).
As I mentioned earlier there are 1000s of line in a flat file that I read and update YSL000 table.
Note that I have two separate sqlcommands and also two separate connections to handle this. Reason is with sqltransaction it doesn't let me to query on the same table. I think timeout may be happening because of this?
Thanks for reading. Please suggest
Update 1: Since I have not pasted entire code, I want to mention that dispose is done using below code in the program.
if (conn != null)
{
conn.Close();
conn.Dispose();
}
if (conn_new != null)
{
conn_new.Close();
conn_new.Dispose();
}
you can increase the time out of your SqlConnection object.
you can do this with your ConnString:
string connStr = "Data Source=(local);Initial Catalog=AdventureWorks;Integrated
Security=SSPI;Connection Timeout=300";
I think default isolation level - read commited - is preventing your 'CheckSerialNumber' method from being effective. Command_serial_new will not take into consideration rows inserted in your loop - this might lead to some troubles. To be honest I would also look for some deadlock. Perhaps command_serial_new is actually completely blocked by the other transaction.
To start off:
Set command_serial_new query as:
SELECT 1 FROM YSL00 WITH (NOLOCK) WHERE SERLNMBR = #slnr
Think about using lower isolation level to query inserted rows as well (set it to read uncommited).
Close your connections and transactions.
Use just one SqlConnection - you don't need two of them.
Many of the objects you are using implement IDisposable, and you should be wrapping them with using statements. Without these using statements, .NET won't necessarily get rid of your objects until an undetermined time when the garbage collector runs, and could block subsequent queries if it's still holding a transaction open somewhere.
So for example, you'll need to wrap your connections with using statements:
using (conn_new = new SqlConnection(ConnString)) {
...
If I am not mistaken you need to merge the file content with the table content.
For this purpose I would recommend you
Copy the file content in to a temporary table (see temporary tables and BulkInsert)
Use command MERGE (http://msdn.microsoft.com/en-us/library/bb510625.aspx) to merge the temporary table content with the original table
I have written following code.
I have opened the database connection for once for one query
I want to execute another query.
I have written the code below.
But i think there is a mistake
Can anyone help me please?
public void check()
{
try
{
OdbcConnection myOdbcConnection = new OdbcConnection(con1);
OdbcCommand myOdbcCommand = myOdbcConnection.CreateCommand();
String sSQL = "SELECT * FROM(select tdate from tbl_IThelpdesk order by call_no desc)where ROWNUM = 1"; //last record of the call_no column
myOdbcCommand.CommandText = sSQL;
myOdbcConnection.Open();
OdbcDataReader myOdbcDataReader = myOdbcCommand.ExecuteReader();
if (!myOdbcDataReader.Read())
{
txtDate.Text = DateTime.Now.ToShortDateString();
string strcallno = DateTime.Now.Year.ToString("d2") + DateTime.Now.Month.ToString("d2") + DateTime.Now.Day.ToString("d2");
txtcall.Text = "ITHD" + strcallno + "001";
myOdbcConnection.Close();
myOdbcDataReader.Close();
}
else
{
DateTime today = DateTime.Parse(DateTime.Now.ToShortDateString());
if (myOdbcDataReader[0].ToString() == today.ToString())
{
myOdbcConnection.Close();
myOdbcDataReader.Close();
myOdbcConnection.Open();
OdbcCommand myOdbcCommand1 = myOdbcConnection.CreateCommand();
String SQLmax = "SELECT max(call_no) FROM TBL_IThelpdesk";
myOdbcCommand1.CommandText = SQLmax;
OdbcDataReader myOdbcDataReader1 = myOdbcCommand1.ExecuteReader();
while (myOdbcDataReader1.Read() != false)
{
txtcall.Text = myOdbcDataReader1[0].ToString().Trim();
}
myOdbcDataReader1.Close();
myOdbcDataReader.Close();
myOdbcConnection.Close();
}
}
}
catch (Exception e)
{
lblEmpty.Text = e.Message;
lblEmpty.Visible = true;
}
}
Since database connections use a pool, you don't have to maintain the same connection for multiple queries; instead, open a connection when you need it, and close it as soon as possible to free up the resources.
See: http://msdn.microsoft.com/en-us/library/8xx3tyca(v=vs.80).aspx
See also: C# SQLConnection pooling
Note that you've not used using() { } pattern. Given that OdbcConnection and similar types implement IDisposable, you should embed them into a using in order for them to be disposed without waiting the garbage collector.
See: http://msdn.microsoft.com/en-us/library/yh598w02.aspx
You're hitting the database twice when you only need to hit it once. You're getting the latest date then going to the database again to get the corresponding call_no. This is unsafe as the max(call_no) could change even in the small amount of time between the 2 queries.
//get the latest [call_no] and [tdate]. No need for a 2cd trip with max(call_no)
SELECT * FROM(select call_no, tdate from tbl_IThelpdesk order by call_no desc)where ROWNUM = 1
Also the data access code is mixed with UI code. You should create data access methods that do 1 thing; return the data you want. This will make it much easier to follow the main flow of your algorithm.
This question already has answers here:
Capture Stored Procedure print output in .NET
(3 answers)
Closed 6 years ago.
When executing scripts in SQL Server Management Studio, messages are often generated that display in the message window. For example when running a backup of a database:
10 percent processed.
20 percent processed.
Etc...
Processed 1722608 pages for database 'Sample', file 'Sampe' on file 1.
100 percent processed.
Processed 1 pages for database 'Sample', file 'Sample_Log' on file 1.
BACKUP DATABASE successfully processed 1722609 pages in 202.985
seconds (66.299 MB/sec).
I would like to be able to display these message in a C# application that is running SQL scripts against a database. However, I cannot figure out how to get a handle on the message output from SQL as it is generated. Does anybody know how to do this? It doesn't matter to me which connection framework I have to use. I'm relatively comfortable with LINQ, NHibernate, Entity Framework, ADO.Net, Enterprise Library, and am happy to learn new ones.
Here is the example code I tried and it works for me.
http://www.dotnetcurry.com/ShowArticle.aspx?ID=344
Note the code you need is actually this part :
cn.Open();
cn.InfoMessage += delegate(object sender, SqlInfoMessageEventArgs e)
{
txtMessages.Text += "\n" + e.Message;
};
It's the e.Message keeps returning the message back to txtMessages (You can replace as TextBox or Label).
You may also refer to this article:
Backup SQL Server Database with progress
An example of my code is in the following:
//The idea of the following code is to display the progress on a progressbar using the value returning from the SQL Server message.
//When done, it will show the final message on the textbox.
String connectionString = "Data Source=server;Integrated Security=SSPI;";
SqlConnection sqlConnection = new SqlConnection(connectionString);
public void DatabaseWork(SqlConnection con)
{
con.FireInfoMessageEventOnUserErrors = true;
//con.InfoMessage += OnInfoMessage;
con.Open();
con.InfoMessage += delegate(object sender, SqlInfoMessageEventArgs e)
{
//Use textBox due to textBox has Invoke function. You can also utilize other way.
this.textBox.Invoke(
(MethodInvoker)delegate()
{
int num1;
//Get the message from e.Message index 0 to the length of first ' '
bool res = int.TryParse(e.Message.Substring(0, e.Message.IndexOf(' ')), out num1);
//If the substring can convert to integer
if (res)
{
//keep updating progressbar
this.progressBar.Value = int.Parse(e.Message.Substring(0, e.Message.IndexOf(' ')));
}
else
{
//Check status from message
int succ;
succ = textBox.Text.IndexOf("successfully");
//or succ = e.Message.IndexOf("successfully"); //get result from e.Message directly
if (succ != -1) //If IndexOf find nothing, it will return -1
{
progressBar.Value = 100;
MessageBox.Show("Done!");
}
else
{
progressBar.Value = 0;
MessageBox.Show("Error, backup failed!");
}
}
}
);
};
using (var cmd = new SqlCommand(string.Format(
"Your SQL Script"//,
//QuoteIdentifier(databaseName),
//QuoteString(Filename)//,
//QuoteString(backupDescription),
//QuoteString(backupName)
), con))
{
//Set timeout = 1200 seconds (equal 20 minutes, you can set smaller value for shoter time out.
cmd.CommandTimeout = 1200;
cmd.ExecuteNonQuery();
}
con.Close();
//con.InfoMessage -= OnInfoMessage;
con.FireInfoMessageEventOnUserErrors = false;
}
In order to get the progressbar working, you need to implement this with a backgroundworker, which your application won't freeze and get 100% done suddenly.
The SqlConnection.InfoMessage event occurs when SQL Servers returns a warning or informational message. This website shows a possible implementation.