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
Related
I'm just learning databases to store a (large amount) of user entry data.
I have the following code, which checks a record and chooses whether to update or create new
using (SqlConnection connection = new SqlConnection(connectionString))
{
connection.Open();
string sc1 = #"select count(*) from job1 where report = #report";
SqlCommand check = new SqlCommand(sc1, connection);
check.Parameters.AddWithValue("#report", jname);
// check if the report number already exists, if not make a new table otherwise insert
int test = (int)check.ExecuteScalar();
if (test > 0)
{
jobCardExistingTable(connection);
digCardExistingTable(connection);
//insert into existing table code
}
If I use either jobCardExistingTable or digCardExisting table, they work fine. If I use both, I get the error
require open and available connection
I assume that the first ExecuteNonQuery (which are contained in the jobCard and digCard methods) is doing something with the connection - can I keep this one open, or do I have to open a new one each time I call a method? Maybe I'm doing this all wrong anyways...each method is calling a new table in the database, should I be calling them all at once?
Edit: part of the issue is jobCardTable (digCardTable is identical, just a different query)
public void jobCardNewTable(SqlConnection connection)
{
using (connection)
{
string sc3 = "";
sc3 = #"INSERT INTO job1 (" + pv.jobstring + ") VALUES (" + pv.jobparam + ")";
SqlCommand cmd = new SqlCommand(sc3, connection);
queryParams(cmd, 0);
cmd.ExecuteNonQuery();
}
}
Edit: solved - realised that using{} disposes the connection. Took all the using{} out of the methods, and used a single using{} to encompass all the method calls and it works
You should not use using (connection) if you are using same connection in other part of code. using dispose connection and make unavailable for further connection.
So, your jobCardNewTable method implementation should be without using statement :
public void jobCardNewTable(SqlConnection connection)
{
string sc3 = "";
sc3 = #"INSERT INTO job1 (" + pv.jobstring + ") VALUES (" + pv.jobparam + ")";
SqlCommand cmd = new SqlCommand(sc3, connection);
queryParams(cmd, 0);
cmd.ExecuteNonQuery();
}
I would recommend to create new connection whenever you need it and dispose it.
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.
Earlier I posted this code but it was much more messy, parts were commented out, and I was using concatenation to INSERT to the database. I was told to clean it up, challenged to use parameters, and ask more concise questions. With that being said, the connection to the database was given to me with mostly pseudo-code with some direct commands.
1) Is my Try-Catch set up correctly?
2) "server = LOCALHOST" is underlined in red, it says it can't convert 'string' to System.Data.SqlClient.SqlConnection'
3) "Database" and "Lab1" are underlined saying it doesn't exist in current context? What does this mean?
4) "Trusted_connection" and "yes" have the same error message as #3.
5) I'm not sure what to put after "cmd.Connection = " which is why it's commented out and has a question mark after it.
6) Is my varname1.Close(); in the right spot? I feel like it makes sense for it to actually go between the last 2 closing brackets?
7) In the Catch "SqlException" is underlined and the error says "The type or namespace SqlException could not be found". I found a try-catch from another user on stackoverflow that asked the question and someone responded with the catch set up like that so I copied it.
8) I'm trying to figure out parameters, Is mine set up correctly? All I have is 1 textbox in which the user inputs data and it enters into an array. "Name" is the name of the attribute of the student in the database, and I just made up #Name as a variable? I found a parameter example from another user also on stackoverflow and kind of made match mine.
public static int counter = 0;
protected void btnDisplay_Click(object sender, EventArgs e)
{
try
{
System.Data.SqlClient.SqlConnection varname1 = new System.Data.SqlClient.SqlConnection();
varname1 = "server = LOCALHOST";
Database = Lab1;
Trusted_connection = yes;
varname1.Open();
System.Data.SqlClient.SqlCommand cmd = new System.Data.SqlClient.SqlCommand();
// cmd.Connection = (?)
cmd.CommandText = "Delete From Student";
cmd.ExecuteNonQuery();
for(int i=0; counter >= i; i++)
{
cmd.CommandText = "INSERT INTO Lines (Name) " + "VALUES (#Name)";
cmd.Parameters.AddWithValue("#Name", studentList[i]);
counter++;
}
varname1.Close();
}
catch (SqlException ex)
{
lbl5.Text = "Connection could not be established";
}
}
You need to find a good resource (or a few) and learn how to make proper database calls. Here's one. Here's another, on creating connection strings.
I haven't tested the following, but something like this should work.
using (var conn = new System.Data.SqlClient.SqlConnection("Server=LOCALHOSTDatabase=Lab1;Trusted_Connection=True;"))
{
conn.Open();
using (var cmd = new SqlCommand("Delete From Student", conn))
{
cmd.ExecuteNonQuery();
}
using (var cmd = new SqlCommand("INSERT INTO Lines (Name) VALUES (#Name)", conn))
{
for (int i = 0; counter >= i; i++)
{
cmd.Parameters.Clear();
cmd.Parameters.AddWithValue("#Name", studentList[i]);
cmd.ExecuteNonQuery();
}
counter++;
}
}
As for some of your other questions...
#1 - Your try/catch is setup okay.
#6 - Don't bother calling Close() - use a using block
#7 - The exception name looks okay. Do you have using System.Data.SqlClient; at the top of your form? You may be getting an error here because of other lines of code with errors... hard to say.
#8 - That looks fine.
You should have a finally block with your try-catch
Your SQLConnection should be created with the connection string as a parameter. You can't set it equal to a String, it's a SQLConnection.
I don't know where Database and Lab1 are declared but it's obviously not within the scope of your function.
See 3. And yes has no meaning.
cmd.Connection = varName1
You should close your connection in a finally block to ensure it is closed even if an exception is thrown
Have you imported System.Data.SQLClient?
Adding parameters with values will replace #Name in your SQL string with the value you supplied
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.
I am using this code to delete a database through C#
Int32 result = 0;
try
{
String Connectionstring = CCMMUtility.CreateConnectionString(false, txt_DbDataSource.Text, "master", "sa", "happytimes", 1000);
SqlConnection con = new SqlConnection();
con.ConnectionString = Connectionstring;
String sqlCommandText = "DROP DATABASE [" + DbName + "]";
if (con.State == ConnectionState.Closed)
{
con.Open();
SqlConnection.ClearPool(con);
con.ChangeDatabase("master");
SqlCommand sqlCommand = new SqlCommand(sqlCommandText, con);
sqlCommand.ExecuteNonQuery();
}
else
{
con.ChangeDatabase("master");
SqlCommand sqlCommand = new SqlCommand(sqlCommandText, con);
sqlCommand.ExecuteNonQuery();
}
con.Close();
con.Dispose();
result = 1;
}
catch (Exception ex)
{
result = 0;
}
return result;
But I get an error
Database currently in use
Can anyone help?
Try this:
String sqlCommandText = #"
ALTER DATABASE " + DbName + #" SET SINGLE_USER WITH ROLLBACK IMMEDIATE;
DROP DATABASE [" + DbName + "]";
Also make sure that your connection string defaults you to the master database, or any other database other than the one you're dropping!
As an aside, you really don't need all of that stuff around your queries. The ConnectionState will always start off Closed, so you don't need to check for that. Likewise, wrapping your connection in a using block eliminates the need to explicitly close or dispose the connection. All you really need to do is:
String Connectionstring = CCMMUtility.CreateConnectionString(false, txt_DbDataSource.Text, "master", "sa", "happytimes", 1000);
using(SqlConnection con = new SqlConnection(Connectionstring)) {
con.Open();
String sqlCommandText = #"
ALTER DATABASE " + DbName + #" SET SINGLE_USER WITH ROLLBACK IMMEDIATE;
DROP DATABASE [" + DbName + "]";
SqlCommand sqlCommand = new SqlCommand(sqlCommandText, con);
sqlCommand.ExecuteNonQuery();
}
result = 1;
Here is how you do it using Entity Framework version 6
System.Data.Entity.Database.Delete(connectionString);
You should take a look at SMO.
These allow you to manage all aspects of SQL Server from code, including deleting of databases.
The database object has a Drop method to delete database.
Create sqlconnection object for different database other than you want to delete.
sqlCommandText = "DROP DATABASE [DBNAME]";
sqlCommand = new SqlCommand(sqlCommandText , sqlconnection);
sqlCommand.ExecuteNonQuery();
In this case i would recommend that you take the database offline first... that will close all connections and etc... heres an article on how to do it: http://blog.sqlauthority.com/2010/04/24/sql-server-t-sql-script-to-take-database-offline-take-database-online/
Microsoft clearly states that A database can be dropped regardless of its state: offline, read-only, suspect, and so on. on this MSDN article (DROP DATABASE (Transact-SQL))
Connection pooling at a guess, use sql server's activity monitor to make sure though.
Pooling keeps connections to the database alive in a cache, then when you create a new one, if there's one in the cache it hands it back instead of instantiating a new one. They hang around for a default time, (2 minutes I think) if they don't get re-used in that time, then they killed off.
So as a first go connect straight to master, instead of using change database, as I suspect change database will simply swap connections in the pool.
Add a check routine for database in use (use a connection to master to do it!). You can force the database to be dropped anyway by first executing
ALTER DATABASE [MyDatabase] SET SINGLE_USER WITH ROLLBACK IMMEDIATE
again from the connection to master!
However everybody else using the db, will no longer like you at all...
Just don't use DB name in connection string.
"Data Source=.\SQLEXPRESS;Integrated Security=True;"
I was having the same troubles as Anshuman...
By my testing of the code in question of Anshuman there have been very simple error:
there have to be SqlConnection.ClearAllPools(); instead of SqlConnection.ClearPool(con);
Like this trouble of
"cannot drop database because is in use..."
disappears.