I am trying to get column information in C# from a SQL table on SQL Server. I am following the example in this link: http://support.microsoft.com/kb/310107 My program strangely gets hung up when it tries to close the connection. If the connection is not closed, the program exits without any Exceptions. Here's my code:
SqlConnection connection = new SqlConnection(#"MyConnectionString");
connection.Open();
SqlCommand command = new SqlCommand("SELECT * FROM MyTable", connection);
SqlDataReader reader = command.ExecuteReader(CommandBehavior.KeyInfo); // If this is changed to CommandBehavior.SchemaOnly, the program runs fast.
DataTable table = reader.GetSchemaTable();
Console.WriteLine(table.Rows.Count);
connection.Close(); // Alternatively If this line is commented out, the program runs fast.
Putting the SqlConnection inside a using block also causes the application to hang unless CommandBehavior.KeyInfo is changed to CommandBehavior.SchemaOnly.
using (SqlConnection connection = new SqlConnection(#"MyConnectionString"))
{
connection.Open();
SqlCommand command = new SqlCommand("SELECT * FROM MyTable", connection);
SqlDataReader reader = command.ExecuteReader(CommandBehavior.KeyInfo); // If this is changed to CommandBehavior.SchemaOnly, the program runs fast even here in the using
DataTable table = reader.GetSchemaTable();
Console.WriteLine(table.Rows.Count);
}
The table in question has over 3 million rows, but since I am only obtaining the Schema information, I would think this wouldn't be an issue. My question is: Why does my application get stuck while trying to close a connection?
SOLUTION: Maybe this isn't optimal, but it does work; I inserted a command.Cancel(); statement right before Close is called on connection:
SqlConnection connection = new SqlConnection(#"MyConnectionString");
connection.Open();
SqlCommand command = new SqlCommand("SELECT * FROM MyTable", connection);
SqlDataReader reader = command.ExecuteReader(CommandBehavior.KeyInfo); // If this is changed to CommandBehavior.SchemaOnly, the program runs fast.
DataTable table = reader.GetSchemaTable();
Console.WriteLine(table.Rows.Count);
command.Cancel(); // <-- This is it.
connection.Close(); // Alternatively If this line is commented out, the program runs fast.
I saw something like this, long ago. For me, it was because I did something like:
SqlCommand command = new SqlCommand("SELECT * FROM MyTable", connection);
SqlDataReader reader = command.ExecuteReader();
// here, I started looping, reading one record at a time
// and after reading, say, 100 records, I'd break out of the loop
connection.Close(); // this would hang
The problem is that the command appears to want to complete. That is, go through the entire result set. And my result set had millions of records. It would finish ... eventually.
I solved the problem by adding a call to command.Cancel() before calling connection.Close().
See http://www.informit.com/guides/content.aspx?g=dotnet&seqNum=610 for more information.
It looks right to me overall and I think you need a little optimization. In addition to the above suggestion regarding avoiding DataReader, I will recommend to use connection pooling. You can get the details from here :
http://www.techrepublic.com/article/take-advantage-of-adonet-connection-pooling/6107854
Could you try this?
DataTable dt = new DataTable();
using(SqlConnection conn = new SqlConnection("yourConnectionString"))
{
SqlCommand cmd = new SqlCommand("SET FMTONLY ON; " + yourQueryString + "; SET FMTONLY OFF;",conn);
conn.Open();
dt.Load(cmd.ExecuteReader());
}
SET FMTONLY ON/OFF from MSDN seems the way to go
There is an specific way to do this, using SMO (SQL Server management objects)
You can get the collection of tables in the database, and then read the properties of the table you're interested in (columns, keys, and all imaginable properties)
This is what SSMS uses to get and set properties of all database objects.
Look at this references:
Database.Tables Property
Table class
This is a full example of how to get table properties:
Retrieving SQL Server 2005 Database Info Using SMO: Database Info, Table Info
This will allow you to get all the possible information from the database in a very easy way. there are plenty of samples in VB.NET and C#.
I would try something like this. This ensures all items are cleaned up - and avoids using DataReader. You don't need this unless you have unusually large amounts of data that would cause memory issues.
public void DoWork(string connectionstring)
{
DataTable dt = new DataTable("MyData");
using (var connection = new SqlConnection(connectionstring))
{
connection.Open();
string commandtext = "SELECT * FROM MyTable";
using(var adapter = new SqlDataAdapter(commandtext, connection))
{
adapter.Fill(dt);
}
connection.Close();
}
Console.WriteLine(dt.Rows.Count);
}
Related
So I'm trying to practice c# and stumbled with the connection error, I already stated that my connection will be closed but it tells me that my connection is still open. I really have no idea what's wrong with this.
public void getdept()
{
con.Open();
string query = "SELECT * FROM positions where PositionName=" + cbxposname.SelectedValue.ToString() + "";
SqlCommand cmd = new SqlCommand(query, con);
DataTable dt = new DataTable();
SqlDataAdapter sda = new SqlDataAdapter(query, con);
sda.Fill(dt);
foreach (DataRow dr in dt.Rows)
{
txtdeptname.Text = dr["Department"].ToString();
}
con.Close();
}
Any tips is welcomed!
You appear to be using a common connection object. Don't. Create your connection object where you use. Do so with a using statement and then the connection will be closed and destroyed at the end of the block. Store your connection string in a common location and then use that each time to create a new connection, e.g.
var table = new DataTable();
using (var connection = new SqlConnection(connectionString)
using (var adapter = new SqlDataAdapter("SQL query here", connection)
{
adapter.Fill(table);
}
// use table here.
There are a number of things to note from this code, other than the using block.
Firstly, it doesn't explicitly open the connection because there's no point. The Fill and Update methods of a data adapter will implicitly open the connection if it's currently closed and it will implicitly close the connection if it opened it. When using a data adapter, the only reason to open the connection explicitly is if you're calling multiple Fill and/or Update methods, so the connection is closed and reopened in between. Even if you do open the connection though, there's still no need to close it explicitly because that happens implicitly at the end of the using block.
Secondly, this code doesn't create a command object because there's no point. In your original code, you create a command object and then you don't use it. If you already have a command object then you can pass that to the data adapter constructor but you don't do that. You pass the SQL query and the connection, so the data adapter will create its own SelectCommand.
In actual fact, there's no point even creating a connection object here. The data adapter has a constructor that accepts a SQL query and a connection string, so you can just create the data adapter and let it do the rest internally:
var table = new DataTable();
using (var adapter = new SqlDataAdapter("SQL query here", connectionString)
{
adapter.Fill(table);
}
// use table here.
You are unnecessary opening and closing connections in your case. It's not needed here.
Your code should look like this.
using (SqlConnection con = new SqlConnection(connetionString))
{
using (DataTable dt = new DataTable())
{
using (SqlDataAdapter sda = new SqlDataAdapter(sql, con))
{
sda.Fill(dt);
foreach (DataRow dr in dt.Rows)
{
txtdeptname.Text = dr["Department"].ToString();
}
}
}
}
A few suggestions also, Please don't use * in the query, instead, use column names, Please use NOLOCK in the Query if it's required in your case and use the parameterized query.
Here's what I got: User selects from a checklistbox of database names one they'd like to archive. Switch case in place to catch the selection.
case "userSelection":
sqlAdapter = CreateMyAdapter("dbName", true, sqlconn, null);
sqlAdapter.SelectCommand.CommandText += "";
sqlAdapter.Fill(myDS.tableName);
sqlAdapter.Dispose();
The adapter:
private SqlDataAdapter CreateMyAdapter(string TableName, bool IncludeUpdates, SqlConnection sqlConn, SqlTransaction sqlTran)
{
SqlDataAdapter sqlAdapter = null;
SqlConnection sqlConnArchive = new SqlConnection();
strSQL = "SELECT " + TableName + ".* FROM " + TableName;
sqlAdapter = new SqlDataAdapter(strSQL, sqlConn);
// Right here, I create another sqlConnection that is pointed to
// another datasource.
sqlConnArchive = getThisOtherConnection();
SqlCommand sqlComm;
if (IncludeUpdates)
{
string strInsertSQL = "<insertQuery>";
sqlComm = new SqlCommand(strInsertSQL, sqlConnArchive);
sqlComm.Parameters.Add("#TableID", SqlDbType.Int, 0, "TableID");
// More params here...
sqlAdapter.InsertCommand = sqlComm;
// Update
// Delete
}
}
return sqlAdapter;
The issue:
As you can see sqlConn is the connection that is tied to the SELECT command. And sqlConnArchive is tied to the INSERT. The thought here is that I could select the data from DB_1 if you will, and insert it into DB_2 using the same SQLDataAdapter. But the issue that I'm running into is trying to insert. The select works fine, and at this line sqlAdapter.Fill(myDS.tableName); once fill executes the data is there. But the INSERT isn't working.
A few things:
I tested to see if perhaps SQLDataAdapter couldn't handle multiple datasources/connections, switched things around so it was pointing the the same DB just different tables, and I'm seeing the same results.
I've confirmed that the issue does not reside within the INSERT query.
There are no errors, just steps right over in debug.
I have tried several permutations of .Update() and none of them worked. This project that I've been assigned, throughout the entire thing it appears that .Fill(); is what is submitting the data back to the DB.
I've tested the database side and connectivity is a go. No issues with login, etc etc..
Any help is greatly appreciated.
Please note - I tried to place an even larger emphasis on the word "greatly" but was limited by my toolset. Apparently SOF doesn't support bold, blink, underline, flames, or embedded music.
I think you want ExecuteNonQuery.
var rowsAffected = sqlAdapter.InsertCommand.ExecuteNonQuery();
This executes the statement and then returns the number of rows affected. The Fill method won't run any InsertCommands.
I'm rewriting part of an old webforms application. I want to make a central function that will do the select queries. I will feed it the SQL query and parameters and it will do the rest.
So far I have this:
MySqlDataReader DoRead(string query, params MySqlParameter[] pms)
{
MySqlCommand myCommand;
if (!myConnection)
myConnection = new MySqlConnection(sCon);
if (myConnection.State != ConnectionState.Open)
{
myConnection.Close();
myConnection.Open();
}
myCommand = myConnection.CreateCommand();
myCommand.CommandText = query;
foreach (MySqlParameter p in pms)
{
myCommand.Parameters.Add(p);
}
return myReader = myCommand.ExecuteReader();
}
My question is, can I save the results of myReader to a variable and return that same variable instead of myReader just so I could close the connection and the reader immediately in the function instead in the main code?
Of course. And that's exactly what you should be doing, for exactly the reason you state:
so I could close the connection and the reader immediately in the function
The problem you're facing is the use of the reader in the first place, which itself is coupled to the open data stream. So if consuming code is expecting a reader, it's going to have to change in order to fix this.
How does the application later use this reader? If you're trying to make a generic function, then the result needs to be pretty generic too. So if consuming code is all doing custom things with the reader then perhaps you can instead return a DataSet and consuming code can do custom things with that instead. Something like this:
var result = new DataSet();
using(var myConnection = new MySqlConnection(sCon))
{
myConnection.Open();
var myCommand = myConnection.CreateCommand();
myCommand.CommandText = query;
foreach (var p in pms)
myCommand.Parameters.Add(p);
var myAdapter = new MySqlDataAdapter(myCommand);
myAdapter.Fill(result);
}
return result;
(Note that I made another change here as well. The connection object should also be local to the scope of the method. Shared connection objects open up a world of potential problems, one of which you've undoubtedly tried to fix with that conditional to close/open the connection state. Just avoid that world of problems entirely and dispose of connections once you're done with them.)
I have an application which is written in asp.net and C#. I am using a class with Connected mode for Insert/Update and delete statements. I have proper try, catch and Finally statements which is opening and closing the OracleConnection. But still sometimes its just getting out without closing the connection and is making locks in the DataBase, which in turn makes the website stop.
Now i thought to change the Queries into a Disconnected mode where the DataAdapter will manage the connection issues. I need to execute custom Queries with parameters.
I wrote an application where i tried calling INSERT/UPDATE/DELETE statements using DataAdapter objects FILL method. Its working fine.(For da.Update() method it needs a row and row state etc which i thought will be tough)
I want to know will there be any issues in performance of database or in the application if i use this method??
int i = 0;
using (OracleConnection con = new OracleConnection(WebConfigurationManager.ConnectionStrings["MYSTRING"].ConnectionString))
{
OracleCommand cmd = new OracleCommand("INSERT INTO MYTABLE(ID) VALUES(:ID)", con);
cmd.Parameters.AddWithValue(":ID", 123);
using (OracleDataAdapter da = new OracleDataAdapter(cmd))
{
i = da.Fill(new DataSet());
}
cmd.Dispose();
}
return i;
The above code runs any query(insert,update,delete) which is sent to the DataAdapter. Should i do it in any other way or will this be ok??
I don't know about OracleCommand Objects, but in SqlDataAdapter you have Insert Command, DeleteCommand, UpdateCommand. DataAdapterProperties or else you can use IdbDataAdapter Interface IDbDataAdapter Interface
yourDataAdapter.InsertCommand = YourInsertCommandObject;//
for Update
yourDataAdapter.UpdateCommand = YourUpdatcommand;
I want to use an Access database for my Windows Forms application. (written with C#)
I have used OleDb namespace for connecting, and I'm able to select the records from the source using the OleDbConnection and ExecuteReader objects.
However, I can't insert, update or delete records yet.
My code is the following:
OleDbConnection con = new OleDbConnection(strCon);
try
{
string con="Provider=Microsoft.Jet.OLEDB.4.0;Data Source=xyz.mdb;Persist Security Info=True";
con.Open();
OleDbCommand com = new OleDbCommand("INSERT INTO DPMaster(DPID, DPName, ClientID, ClientName) VALUES('53', 'we', '41', 'aw')", con);
int a = com.ExecuteNonQuery();
//OleDbCommand com = new OleDbCommand("SELECT * FROM DPMaster", con);
//OleDbDataReader dr = com.ExecuteReader();
//while (dr.Read())
//{
// MessageBox.Show(dr[2].ToString());
//}
MessageBox.Show(a.ToString());
}
catch
{
MessageBox.Show("cannot");
}
If I the commentted block is executed, the application works fine. But the insert block doesn't.
Knowing this, why I am unable to insert, update or delete database records?
the problem that I encountered myself is as:
You've added the mdb file to your solution and every time you run the program it will be copied into debug folder.
So you can select from it but deleting rows doesn't affect the original file you have in your solution.
Check for it.
First, never strangle your exception. It is better to let your exception bubble up so that you may get important information regarding what is not working properly. It is better to write:
con.Open();
OleDbCommand com = new OleDbCommand("INSERT INTO DPMaster(DPID,DPName,ClientID,ClientName) VALUES('53','we','41','aw')", con);
int a = com.ExecuteNonQuery();
than
try {
con.Open();
OleDbCommand com = new OleDbCommand("INSERT INTO DPMaster(DPID,DPName,ClientID,ClientName) VALUES('53','we','41','aw')", con);
int a=com.ExecuteNonQuery();
} catch {
MessageBox.Show("cannot");
}
Second, make use of using blocks as much as possible, since those blocks will dispose the no longer needed objects. So your code should look like this:
using (OleDbConnection con = new OleDbConnection(conStr))
using (OleDbCommand com = new OleDbCommand("INSERT INTO DPMaster(DPID,DPName,ClientID,ClientName) VALUES('53','we','41','aw')", con) {
con.Open();
int a = com.ExecuteNonQuery();
MessageBox.Show(a.ToString());
}
With this code, you will more likely get to know what is going wrong while the exception will bubble up, plus, as soon as you'll quit the scope of the using blocks, resources used will be freed up as your objects will get disposed.