SQL Server timeout in recursive code - c#

I have a base class which implements my database connection. I have a second class that inherits this base database class. The second class has some recursion inside of it, where when evaluating it's value, it may instantiate another instance of the second class. The recursion is only a few levels deep. I am running everything single-threaded.
My code will run correctly for about 1 or 2 minutes, then I begin getting consistent errors: "Timeout Expired. The timeout period elapsed prior to obtaining a connection from the pool".
My base class has a destructor which calls the .Dispose() method on the database objects. My second class has a destructor which closes the connection object in the base class.
My connection string to the database specifies a connection timeout = 0.
Any ideas as to why the code will work correctly for a few minutes and then begin timing out trying to connect to the database? I'm baffled.
namespace BaseLib2
{
public class TSBase
{
protected StreamWriter logFile;
protected OleDbCommand queryCmd;
protected OleDbCommand exeCmd;
protected OleDbConnection connection;
protected OleDbDataReader reader;
public SqlConnection sqlconn;//used for BCP
public TSBase()
{
}
~TSBase()
{
try
{
queryCmd.Dispose();
exeCmd.Dispose();
reader.Dispose();
connection.Dispose();
sqlconn.Dispose();
}
catch (Exception ex)
{
Console.WriteLine("BaseLib2 destrutor:" + ex.Message);
}
}
public void ConnectToDB()
{
string connString = "Provider=SQLNCLI11;Server=myserver;Database=mydb;Uid=myid;pwd=password;connection timeout=0";
queryCmd = new OleDbCommand();
exeCmd = new OleDbCommand();
connection = new OleDbConnection(connString);
queryCmd.CommandTimeout = 60000;
exeCmd.CommandTimeout = 60000;
connection.Open();
queryCmd.Connection = connection;
exeCmd.Connection = connection;
string sqlConnString = "server=dc2k8housql;database=mydb;Uid=myid;pwd=password;connection timeout=0";
sqlconn = new SqlConnection(sqlConnString);
sqlconn.Open();
}
public class Expression : BaseLib2.TSBase
{
private string ExpName;
private string ExpressionTxt;
private string sql;
private DateTime Contract_dt;
private DateTime Quote_dt;
private bool SaveToDB;
private string BaseSymbol;
public Expression(string expNameIn, DateTime contract_dtIn, DateTime quote_dtIn)
{
ExpName = expNameIn;
Contract_dt = contract_dtIn;
Quote_dt = quote_dtIn;
try
{
try
{
ConnectToDB();
}
catch (Exception ex)
{
Console.WriteLine("Error in EXP constructor connecting to database." + ex.Message );
throw new Exception("Error in EXP constructor connecting to database.");
}
//get expression text from database
sql = "select expression, save_to_db, coalesce(base_symbol, '') as base_symbol from expressions where exp_name = " + DBI(ExpName);
reader = ReadData(sql);
if (reader.Read())//should only return 1 row
{
ExpressionTxt = reader[0].ToString();
SaveToDB = bool.Parse(reader[1].ToString());
BaseSymbol = reader[2].ToString();
}
reader.Close();
}
catch (Exception ex)
{
Console.WriteLine("Exception in Expression constructor:" + ex.Message);
}
}
~Expression()
{
try
{
connection.Close();
sqlconn.Close();
connection.Dispose();
sqlconn.Dispose();
}
catch (Exception ex)
{
Console.WriteLine("Error in destructor:" + ex.Message);
}
}
public double Eval()
{
try
{
//check to see if there are any $RV in the expression
if (ExpressionTxt.Contains("$RV("))
{
//parse and evaluate the $RV's
String[] split = ExpressionTxt.Split(("$".ToCharArray()));
foreach (string s in split){
Console.WriteLine("s=" + s);
if (s.Length > 3)//make sure we have a string with a symbol in it
{
//for each rv we find, create a new expression and evaluate it
if (s.Substring(0, 3).Contains("RV"))
{
int pStart = s.IndexOf("(");
int pEnd = s.IndexOf(")");
string rvSymb = s.Substring(pStart + 1, pEnd - pStart - 1);
System.Console.WriteLine(rvSymb);
Expression oExp = new Expression(rvSymb, Contract_dt, Quote_dt);
double rVal = oExp.Eval();//recursive call
oExp = null;
ExpressionTxt = ExpressionTxt.Replace("$RV(" + rvSymb + ")", rVal.ToString());
}
}
}
}
//replace SV values in formula
if (ExpressionTxt.Contains("$SV("))
{
//find symbols in $SV brackets and collect contract dates
String[] split = ExpressionTxt.Split (("$".ToCharArray()));
foreach (string s in split)
{
if (s.Length > 3)
{//make sure we have a symbol
if (s.Substring(0, 3).Contains("SV"))
{
int pStart = s.IndexOf("(");
int pEnd = s.IndexOf(")");
string svSymb = s.Substring(pStart + 1, pEnd - pStart - 1);
System.Console.WriteLine("sv=" + svSymb);
//replace $SV with numerical values
double sVal = GetQuoteValue(svSymb);
ExpressionTxt = ExpressionTxt.Replace("$SV(" + svSymb + ")", sVal.ToString());
}
}
}
}
//evaluate
double ret = Evaluate(ExpressionTxt);
Console.WriteLine(ExpName + "=" + ret.ToString());
if (SaveToDB)
{
Console.WriteLine(ExpName + " cd:" + Contract_dt.ToShortDateString() + " qd:" + Quote_dt.ToShortDateString() + ": saving to db...");
sql = "delete from exp_quotes where exp_name = " + DBI(ExpName ) ;
sql = sql + " and contract_dt = " + DBI(Contract_dt.ToShortDateString());
sql = sql + " and quote_dt = " + DBI(Quote_dt.ToShortDateString());
WriteData(sql);
sql = "insert into exp_quotes(exp_name, contract_dt, quote_dt, calculated_dt, price) values(";
sql = sql + DBI(ExpName ) + "," + DBI(Contract_dt.ToShortDateString()) + "," + DBI(Quote_dt.ToShortDateString());
sql = sql + ", getdate(), " + ret + ")";
WriteData(sql);
}
connection.Close();//after we evaluate, close down the connection
connection.Dispose();
return ret;
//return value
}
catch (Exception ex)
{
Console.WriteLine("exp:" + ExpName + " cd:" + Contract_dt.ToShortDateString() + " qd:" + Quote_dt.ToShortDateString() + " = " + ex.Message);
}
return 0;
}
private double GetQuoteValue(string symbIn)
{
double ret = 0;
sql = "select close_val from prices_union_all_vw where symbol = " + DBI(symbIn) + " and contract_dt = " + DBI(Contract_dt.ToShortDateString()) + " and quote_dt = " + DBI(Quote_dt.ToShortDateString());
reader = ReadData(sql);
if (reader.Read())
{
ret = Double.Parse(reader[0].ToString());
reader.Close();
}
else
{//we didn't get a record for the specific quote date, try again using the mostrecent view
sql = "select close_val from prices_union_all_mostrecent_vw where symbol = " + DBI(symbIn) + " and contract_dt = " + DBI(Contract_dt.ToShortDateString());
reader = ReadData(sql);
if (reader.Read())
{
ret = Double.Parse(reader[0].ToString());
}
reader.Close();
}
return ret;
}
private static double Evaluate(string expression)
{
var loDataTable = new DataTable();
var loDataColumn = new DataColumn("Eval", typeof(double), expression);
loDataTable.Columns.Add(loDataColumn);
loDataTable.Rows.Add(0);
return (double)(loDataTable.Rows[0]["Eval"]);
}

You are exhausting your available pool of connections because you are creating a connection to the database for every Expression and sub-Expression that you parse, and they are not being cleaned up in time to be re-used.
Solution: Do not make connections recursively, or iteratively, or whatever. Make one for one purpose and just use it. And if you need to release a connection in-time for you to re-use it, do NOT rely on class destructors, because they do not run when you want them to.
In general, classes that try to allocate limited external resources (like connections) implicitly in their Initializers should be pretty static objects, and you certainly do not normally want to inherit them in a class that is intended to create objects as dynamically as a parser.

Have you tried extending the timeout period?
Add a big timeout to the connection string like "Connect Timeout=1800". This usually helps me when I get such messages.
The other thing you can see is if you can improve the query more.

You might check your Max connection setting for the database. Also check how many active connections are open when new connection attempts start to time out.
How to determine total number of open/active connections in ms sql server 2005

Related

Update sql database from datagridview in c#

I'm new here but I need some help. I need to update a SQL Server database from C# with Windows Forms, but I'm having problems. I looked it up but still can't find the right answer. I need to do insert and update by pressing a button for changing or filling the database from the datagridview. I've created a separate function for both I am using this code;
private void InsertPositionen()
{
string qry = "";
SqlCommand insert = new SqlCommand(qry, con);
try
{
for (int i = 0; i < dataGridView1.Rows.Count - 1; i++)
{
qry = "INSERT INTO BelegePositionen (BelID, BelPosId, Artikelnummer, Menge, Preis) VALUES( " + dataGridView1.Rows[i].Cells["BelID"] + ", "
+ dataGridView1.Rows[i].Cells["BelPosId"] + ", "
+ dataGridView1.Rows[i].Cells["Artikelnummer"] + ", "
+ dataGridView1.Rows[i].Cells["Menge"] + ", "
+ dataGridView1.Rows[i].Cells["Preis"];
}
insert.ExecuteNonQuery();
}
catch (Exception ex)
{
MessageBox.Show(ex.Message);
}
}
private void UpdatePositionen()
{
string updt = "";
SqlCommand update = new SqlCommand(updt, con);
try
{
for (int i = 0; i < dataGridView1.Rows.Count -1; i++)
{
updt = "UPDATE BelegePositionen SET BelID = "
+ dataGridView1.Rows[i].Cells["BelID"] +
", BelPosID = "
+ dataGridView1.Rows[i].Cells["BelPosID"] +
", Atrikelnummer = "
+ dataGridView1.Rows[i].Cells["Artikelnummer"] +
", Menge = "
+ dataGridView1.Rows[i].Cells["Menge"] +
", Preis = "
+ dataGridView1.Rows[i].Cells["Preis"];
}
update.ExecuteNonQuery();
con.Close();
MessageBox.Show("Done!");
}
catch (Exception ex)
{
MessageBox.Show(ex.Message);
}
}
You should really NOT do your SQL stuff like this!! This leaves your code wide open for SQL injection vulnerabilities! Stop that - right now!
Instead - use parametrized queries - like this:
private void InsertPositionen()
{
string qry = "INSERT INTO BelegePositionen (BelID, BelPosId, Artikelnummer, Menge, Preis) " +
"VALUES(#BelId, #BelPosId, #ArtNr, #Menge, #Preis);";
SqlCommand insert = new SqlCommand(qry, con);
// define the parameters
insert.Parameters.Add("#BelId", SqlDbType.Int);
insert.Parameters.Add("#BelPosId", SqlDbType.Int);
insert.Parameters.Add("#ArtNr", SqlDbType.Int); // maybe this is a string?
insert.Parameters.Add("#Menge", SqlDbType.Int);
insert.Parameters.Add("#Preis", SqlDbType.Decimal, 20, 4);
try
{
// in the loop, only *set* the parameter's values
for (int i = 0; i < dataGridView1.Rows.Count - 1; i++)
{
insert.Parameters["#BelId"].Value = 1;
insert.Parameters["#BelPosId"].Value = 2;
insert.Parameters["#ArtNr"].Value = 3;
insert.Parameters["#Menge"].Value = 4;
insert.Parameters["#Preis"].Value = 99.95;
insert.ExecuteNonQuery();
}
}
catch (Exception ex)
{
MessageBox.Show(ex.Message);
}
}
Your Question is quite vague as you state you are having problems, but not quite sure what problems you are having. It will help if you can describe what problems you are having.
In addition to what #marc_c said about sql injection, I can't see how you manage your connection to the database.
From the code it looks like you could run into a situation where you are leaving connection strings open, or not opening them at all.
using the using(...) { } will close the connections when you are done with it.
private void InsertPositionen()
{
//using the using statement you will insure that the connection is closed and resources released
using (SqlConnection connection = new SqlConnection(Properties.Settings.Default.db))
{
string cmd = "INSERT INTO BelegePositionen (BelID, BelPosId, Artikelnummer, Menge, Preis) " +
"VALUES(#BelId, #BelPosId, #ArtNr, #Menge, #Preis);";
//using the using statement will ensure any reasources are released when exiting the code block
using (SqlCommand insert = new SqlCommand(cmd, connection))
{
// define the parameters
insert.Parameters.Add("#BelId", SqlDbType.Int);
insert.Parameters.Add("#BelPosId", SqlDbType.Int);
insert.Parameters.Add("#ArtNr", SqlDbType.Int); // maybe this is a string?
insert.Parameters.Add("#Menge", SqlDbType.Int);
insert.Parameters.Add("#Preis", SqlDbType.Decimal, 20, "4");
try
{
//open the connection
insert.Connection.Open();
// in the loop, only *set* the parameter's values
for (int i = 0; i < dataGridView1.Rows.Count - 1; i++)
{
insert.Parameters["#BelId"].Value = dataGridView1.Rows[i].Cells["BelID"];
insert.Parameters["#BelPosId"].Value = dataGridView1.Rows[i].Cells["BelPosId"];
insert.Parameters["#ArtNr"].Value = dataGridView1.Rows[i].Cells["Artikelnummer"];
insert.Parameters["#Menge"].Value = dataGridView1.Rows[i].Cells["Menge"];
insert.Parameters["#Preis"].Value = dataGridView1.Rows[i].Cells["Preis"];
insert.ExecuteNonQuery();
}
}
catch (Exception ex)
{
MessageBox.Show(ex.Message);
}
finally
{
MessageBox.Show("Done!");
}
}
}
}

C# MySQL Parameterized update returning nothing

Whenever I try to update my database, the result ends up being 0.
If I do it in HeidiSQL, it updates just fine, so I know it's not the query.
I have my suspicion that it has to do with the parameters, but I'm unsure regarding that.
I tried with both # and ?, but neither have worked.
MySqlCommand Command = new MySqlCommand("UPDATE `users` SET `cash`=#Cash,
`distance_driven`=#DistanceDriven, `jobs_done`=#JobsDone,
`job_rank`=#JobRank WHERE `username`='#Username';"
, Connection);
Command.Parameters.AddWithValue("#Cash", Cash);
Command.Parameters.AddWithValue("#DistanceDriven", DistanceDriven);
Command.Parameters.AddWithValue("#JobsDone", JobsDone);
Command.Parameters.AddWithValue("#JobRank", JobRank);
Command.Parameters.AddWithValue("#Username", UName);
int result = Command.ExecuteNonQuery(); // result should be 1
Console.WriteLine(result); // ends up being 0
The connection opens fine, but I have no idea why it won't execute the query with the parameters.
Here is the function that requires this update:
public void UpdateUserInfo(object sender, ElapsedEventArgs evt, string uUName)
{
bool cont = false;
Console.WriteLine("UUI 1: " + evt.SignalTime); // gets here fine
try
{
Console.WriteLine("UUI 2: " + evt.SignalTime); // gets here fine
Database database = new Database();
database.Connect();
if (database.UpdateUserData(uUName, TotalCashWallet, TotalDistanceDriven, JobsDone, JobRank))
{
cont = true;
Console.WriteLine("UUI 3: " + evt.SignalTime); // doesn't get here
}
if (cont == true)
{
cont = false;
Console.WriteLine("UUI 4: " + evt.SignalTime);
if (database.UpdateUserBank(uUName, BankInfo.Money, BankInfo.BonusPercentage, BankInfo.BonusLevel))
{
UserInfoUpdated = true;
Console.WriteLine("UUI 5: " + evt.SignalTime);
UserInfoUpdatedTimer.Enabled = true;
return;
}
}
UserInfoUpdated = false;
return;
}
catch (Exception e)
{
Console.WriteLine("UUI 6: " + evt.SignalTime);
Console.WriteLine(e.Message);
ErrorHandler.WriteToLog(e.StackTrace);
ErrorHandler.WriteToLog(e.Message);
ErrorHandler.WriteToLog("------------------------------");
}
return;
}
It doesn't get to the catch part, so it won't log anything.
I tried with both Exception and MysqlException, but it doesn't catch an error.
Doing it the unsafe way works
MySqlCommand Command = new MySqlCommand("
UPDATE `users`
SET `cash`=" + Cash + ",
`distance_driven`=" + DistanceDriven + ",
`jobs_done`=" + JobsDone + ",
`job_rank`=" + JobRank + "
WHERE `username`='" + UName + "';"
, Connection);
You don't need the single quotes around string parameters. Use this query instead:
string query = #"
UPDATE `users` SET
`cash`=#Cash,
`distance_driven`=#DistanceDriven,
`jobs_done`=#JobsDone,
`job_rank`=#JobRank
WHERE
`username`=#Username"
MySqlCommand command = new MySqlCommand(query, Connection);

MS Access Oledb column properties

And I solved this problem in VBA using DAO here
Using the Oledb framework, I created a function that can look up a record value. However it only gets the raw value. I need to find the value of the column property called "Row Source"
Can someone explain to me how to find the foreign key value using Oledb
Below is my function for a traditional look up query.
string IDatabase.LookupRecord(string column, string table, string lookupColumn, string lookUpValue)
{
OleDbCommand cmdLookupColumnValue = new OleDbCommand();
string sqlQuery = "SELECT [" + table + "].[" + column + "] " +
"FROM [" + table + "] " +
"WHERE [" + table + "].[" + lookupColumn + "] = '" + lookUpValue + "'";
cmdLookupColumnValue.CommandText = sqlQuery;
cmdLookupColumnValue.CommandType = CommandType.Text;
cmdLookupColumnValue.Connection = connection;
string result = "";
try
{
result = cmdLookupColumnValue.ExecuteScalar().ToString();
}
catch(Exception ex)
{
MessageBox.Show("Query is not valid :" + ex.ToString());
}
return result;
}
EDIT I found the following code here Its the closest Ive gotten so far. It does get column properties like the column Description but it doesnt work for row Source. Any Ideas?
public void Test()
{
string columnName = "Main Space Category";
ADOX.Catalog cat = new ADOX.Catalog();
ADODB.Connection conn = new ADODB.Connection();
conn.Open(connectionString, null, null, 0);
cat.ActiveConnection = conn;
ADOX.Table mhs = cat.Tables["FI - ROOM"];
var columnDescription = mhs.Columns[columnName].Properties["Description"].Value.ToString();
MessageBox.Show(columnDescription);
conn.Close();
}
I strongly suspect that the RowSource property of a table column is so specific to Access that you will have to use DAO to retrieve it. The following C# code is an example of how you might do that:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace daoConsoleApp
{
class Program
{
static void Main(string[] args)
{
string TableName = "Cars";
string FieldName = "CarType";
// This code requires the following COM reference in your project:
//
// Microsoft Office 14.0 Access Database Engine Object Library
//
var dbe = new Microsoft.Office.Interop.Access.Dao.DBEngine();
Microsoft.Office.Interop.Access.Dao.Database db = dbe.OpenDatabase(#"Z:\_xfer\Database1.accdb");
try
{
Microsoft.Office.Interop.Access.Dao.Field fld = db.TableDefs[TableName].Fields[FieldName];
string RowSource = "";
try
{
RowSource = fld.Properties["RowSource"].Value;
}
catch
{
// do nothing - RowSource will remain an empty string
}
if (RowSource.Length == 0)
{
Console.WriteLine("The field is not a lookup field.");
}
else
{
Console.WriteLine(RowSource);
}
}
catch (Exception ex)
{
Console.WriteLine(ex.ToString());
}
}
}
}

Parallel reading from SQL Server

I was looking through dozens of articles, but couldn't find a solution.
Here is the logic :
I have a Winform (VS2010) application, that needs to read data from SQL Server 2008 R2 Express table A, process some calculations and store in a different table B.
I want to use parallel ForEach in order to shorten execution time (otherwise the calculation + SQL process takes days.....)
I have to read from SQL, because the database has over 5 million rows, each read returns a few hundreds rows.
Lists are defined as :
BindingList<ItemsClass> etqM = new BindingList<ItemsClass>();
BindingList<ItemsClass> etqC = new BindingList<ItemsClass>();
The parallel execution :
Parallel.ForEach(etqC, cv => {
readData(ref etqM, "tableA", "WHERE ID LIKE '" + cv.Name + "%'");
IList<ItemsClass> eResults = etqM.OrderBy(f => f.ID).ToList();
foreach (ItemsClass R in eResults)
{
//calculations comes here
etqM[rID] = R;
}
Parallel.ForEach(etqM, r => {
// part 2 of calculations comes here
}
});
exportList(etqM, "tableB", true);
});
The SQL Read function :
The function gets a List, Table name + conditions for the SQL
read from SQL the records, and transform them to the List format.
public void readData<T>(ref BindingList<T> etqList, string tableName, string conditions)
{
SqlConnection myConnection = new SqlConnection();
SqlCommand myCommand = new SqlCommand();
myCommand.CommandTimeout = 0;
myCommand.Connection = myConnection;
etqList.Clear();
openConn(myConnection);
SqlDataReader myReader = null;
try
{
int totalResults;
myCommand.CommandText = "SELECT COUNT (*) FROM " + tableName + " " + conditions;
totalResults = (int)myCommand.ExecuteScalar();
if (totalResults > 0)
{
myCommand.CommandText = "SELECT * FROM " + tableName + " " + conditions;
myReader = myCommand.ExecuteReader();
etqList = ConvertTo<T>(convertReaderToDT(myReader));
}
}
catch (Exception ex) { }
finally
{
try { myReader.Close(); }
catch { }
}
closeConn(myConnection);
}
The SQL export function : this function exports the given list to the table name.
private void exportListToSql<T>(IEnumerable<T> etqList, string tableName)
{
SqlConnection myConnection = new SqlConnection();
SqlCommand myCommand = new SqlCommand();
myCommand.CommandTimeout = 0;
myCommand.Connection = myConnection;
openConn(myConnection);
try
{
actionTotalCount++;
DataTable dt = new DataTable(tableName);
dt = ToDataTable(etqList);//List Name
var bulkCopy = new SqlBulkCopy(myConnection,
SqlBulkCopyOptions.TableLock |
SqlBulkCopyOptions.FireTriggers |
SqlBulkCopyOptions.UseInternalTransaction,
null
);
bulkCopy.DestinationTableName = tableName;
bulkCopy.BatchSize = BATCH_SIZE;
bulkCopy.WriteToServer(dt);
}
catch (Exception ex) { }
finally { closeConn(myConnection); }
}
SQL openConn and closeConn :
void openConn(SqlConnection myConnection)
{
if (myConnection.State == ConnectionState.Open) return;
myConnection.ConnectionString = "Data Source=" + DB_NAME + ";Initial Catalog=APPDB;Integrated Security=True;Connect Timeout=120;Asynchronous Processing=true;";
try { myConnection.Open(); actionTotalCount++; }
catch (System.Exception ex) { MessageBox.Show(ex.Message); }
}
void closeConn(SqlConnection myConnection)
{
if (myConnection.State == ConnectionState.Fetching || myConnection.State == ConnectionState.Executing || myConnection.State == ConnectionState.Connecting) return;
try { myConnection.Dispose(); }
catch (System.Exception ex) { MessageBox.Show(ex.Message); }
}
The problem is : once I execute, I get this message :
ExecuteScalar requires an open and available connection. The connection's current state is closed.
This message arrives for all threads, except the first one.
Any ideas ?
Apparently the problem was not in the SQL, but the calculations.
Since the List was defined outside the 'Parallel.Foreach', it was accesses by different threads simultaneously, causing a crash.
Once I changed the code as followed, all worked excellent :
Parallel.ForEach(etqC, cv => {
BindingList<ItemsClass> etqM = new BindingList<ItemsClass>();
readData(ref etqM, "tableA", "WHERE ID LIKE '" + cv.Name + "%'");
IList<ItemsClass> eResults = etqM.OrderBy(f => f.ID).ToList();
foreach (ItemsClass R in eResults)
{
//calculations comes here
etqM[rID] = R;
}
Parallel.ForEach(etqM, r => {
// part 2 of calculations comes here
}
});
exportList(etqM, "tableB", true);
});

ORA-01036: illegal variable name/number

I retrieve data from Oracle database and populate a gridview. Next, I try to run a query to select some data but I get an error.
Here is the code:
Db.cs:
public static OracleConnection GetConnection()
{
OracleConnection connection = null;
string connectionString = "Data Source=" + Database +
";User ID=" + UserID +
";Password=" + Password +
";Unicode=True";
try
{
connection = new OracleConnection(connectionString);
}
catch (OracleException ex)
{
throw ex;
}
return connection;
}
Parameters are sent from default.aspx.cs:
new Db(database, userID, password);
OracleConnection connection = Db.GetConnection();
main.aspx.cs retrieves all the data:
private OracleConnection connection = new OracleConnection();
private Select select = new Select();
protected void Page_Load(object sender, EventArgs e)
{
Response.Buffer = true;
if (Db.IsLoggedIn())
{
string selectCommand =
"SELECT " + Settings.TABLE + ".* FROM " + Settings.TABLE + " ORDER BY ";
foreach (string ob in Settings.OB) selectCommand += ob + ", ";
Session["Error"] = null;
connection = Db.GetConnection();
select = new Select(ddlBubID, ddlBusArea, ddlDrillSite, ddlWell, connection);
gvData.DataKeyNames = Settings.PK;
gvData.SelectedIndex = -1;
DS.ConnectionString = connection.ConnectionString;
DS.SelectCommand = selectCommand.Remove(selectCommand.Length - 2, 2);
DS.ProviderName = Settings.PROVIDER_NAME;
PopulateFooter(gvData.FooterRow);
}
else
{
Session["Error"] = Settings.ERROR_MESSAGE[0, 0];
Response.Clear();
Response.Redirect("default.aspx");
}
}
public string ToolTip(string column)
{
string value = "";
OracleCommand cmd = new OracleCommand();
cmd.Connection = connection;
cmd.CommandText = "SELECT DISTINCT COMMENTS " +
"FROM SYS.ALL_COL_COMMENTS " +
"WHERE (TABLE_NAME = 'CTD_PROBLEM_EDIT_V') " +
"AND (COLUMN_NAME = " + column + ")";
cmd.CommandType = CommandType.Text;
OracleDataReader reader = cmd.ExecuteReader(); // I get an error here
reader.Read();
value = reader["COMMENTS"].ToString();
reader.Close();
return value;
}
protected void gvData_RowDataBound(object sender, GridViewRowEventArgs e)
{
if (e.Row.RowType == DataControlRowType.DataRow)
for (int i = 1; i < e.Row.Cells.Count; i++)
{
try
{
LinkButton lb =
(LinkButton)gvData.HeaderRow.Cells[i].Controls[0];
lb.ToolTip = ToolTip(lb.Text);
/* Blah Blah*/
}
catch { }
}
if (e.Row.RowType == DataControlRowType.Footer)
PopulateFooter(e.Row);
}
ToolTip(); throws an error:
Invalid operation. The connection is closed.
EDIT:
This would have been helpful:
Static Classes and Static Class Members
Might not be the problem but this looks weird:
new Db(database, userID, password);
OracleConnection connection = Db.GetConnection();
GetConnection is a static method and thus it does not see any member attributes you might be setting in the constructor (unless they are static as well). If they are all static, consider refactoring your code to use the singleton pattern as it is more readable.
Another thing is that the connection attribute is a member of the page class which is generated for each request (not per application). This means you need either create a new connection in ToolTip method (and any other method that accesses the database) or make the connection attribute static to make it per-application.
Try 2 things:
1.. For your ToolTip() method, the value column to compare for COLUMN_NAME will need to be wrapped properly with single quotes indicating a string/varchar literal value. Likely it's evaluating to COLUMN_NAME = foo when it should be COLUMN_NAME = 'foo'.
cmd.CommandText = "SELECT DISTINCT COMMENTS " +
"FROM SYS.ALL_COL_COMMENTS " +
"WHERE (TABLE_NAME = 'CTD_PROBLEM_EDIT_V') " +
"AND (COLUMN_NAME = '" + column + "')";
2.. Try wrapping your ad-hoc SQL statements in BEGIN and END
3.. Consider refactoring your string building for your SELECT and dynamic ORDER BY clause. That you're doing it on the SelectCommand many lines below isn't obvious to the casual observer or maintainers later in its life.
string selectCommand = string.Format("SELECT {0}.* FROM {0} ORDER BY {1}"
,Settings.TABLE
,string.Join(",",Settings.OB));

Categories

Resources