C# Oracle ODP.net periodic querying causes ORA-00604 - c#

I need to execute the same query every second in GetStuff function, but after a minute or two Oracle throws ORA-00604 and runs out of cursors, I guess I need somehow to close open cursor after I return result. However I don't like the idea of re-connecting every time I need to query, my code is below:
public MyStuff GetStuff(string paramValue)
{
OracleCommand command = connection.CreateCommand();
command.CommandText = "select XXX from YY where param = ? ";
command.Parameters.Add(":param ", OracleDbType.Varchar2).Value = paramValue;
IDataReader reader = command.ExecuteReader();
while (reader.Read())
{
...
}
command.Dispose();
return stuff;
}

reader also needs to be disposed:
public MyStuff GetStuff(string paramValue)
{
using (OracleCommand command = connection.CreateCommand())
{
command.CommandText = "select XXX from YY where param = ? ";
command.Parameters.Add(":param ", OracleDbType.Varchar2).Value = paramValue;
using (IDataReader reader = command.ExecuteReader())
{
while (reader.Read())
{
...
}
}
return stuff;
}
}
Have a look at the using statement which is highly advised way to interact with IDisposables.

Related

Create an ADO.NET read only SQL Server data set using a stored procedure in VS2015/C#

I want to create an ADO.NET read only SQL Server data set using a stored procedure in VS2015 with C#. Is there a way to do this?
The problem is when I try to create the command object to set the stored procedure I want to use, it throws errors. I know I am missing something but I am unable to find anything in MS help files that give an example of how to do this. I do not want to use Linq! Any help you can provide will be greatly appreciated.
try
{
string connString = AdoHelper.ConnectionString;
var myConnection = new SqlConnection(connString);
CommandType myCommand = System.Data.CommandType.StoredProcedure;
using (myConnection)
{
myConnection.Open();
// myCommand. = myConnection;
// myCommand.CommandType = CommandType.StoredProcedure;
// myCommand.CommandTimeout = 540;
if (this.optInStockOnly.Checked == true)
{
myCommand.CommandText = "InventoryGetLookupDataInStockOnly"; // Stored procedure Name
}
else
{
myCommand.CommandText = "InventoryGetLookupData"; // Stored procedure name
}
myCommand.Parameters.AddWithValue(parameterName: "#CurrentWareHouseCode", value: MyGlobals.CurrentUsersInfo.CurrentUserWarehousecode);
SqlDataReader reader = myCommand.ExecuteReader();
if (reader.Read())
{
// set recordset here and do rest of the stuff I want
}
}
}
As mentioned in the comment you did not link the command to the connection object.
check out this example:
private static void CreateCommand(string queryString,
string connectionString)
{
using (SqlConnection connection = new SqlConnection(
connectionString))
{
SqlCommand command = new SqlCommand();
command.Connection = connection;
command.CommandTimeout = 15;
command.CommandType = CommandType.Text; // CommandType.StoredProcedure; in case this was a Proc
command.CommandText = queryString; // Proc name
connection.Open();
SqlDataReader reader = command.ExecuteReader();
while (reader.Read())
{
Console.WriteLine(String.Format("{0}, {1}",
reader[0], reader[1]));
}
}
}
More on this

Parameter SQL in C# doesn't work

I have this code and it does not work. Does anyone know why?
It did not return any data, but if run the query in SQL Server it returns the data.
using (SqlConnection connection = new SqlConnection(_dbContext.GetConnectionString()))
{
using (SqlCommand command = new SqlCommand())
{
StringBuilder stringQuery = new StringBuilder();
stringQuery.Append(" SELECT cd_material, ds_material");
stringQuery.Append(" FROM tbl_materiais");
stringQuery.Append(" WHERE ds_material like #Name");
command.Parameters.AddWithValue("#Name", "%" + name + "%");
command.CommandText = stringQuery.ToString();
command.CommandType = System.Data.CommandType.Text;
command.Connection = connection;
connection.Open();
using (SqlDataReader reader = command.ExecuteReader())
{
while (reader.Read())
{
_product = new ProductSell();
((IProduct)_product).ID = reader.GetFieldValue<int>(0);
((IProduct)_product).Name = reader.GetFieldValue<string>(1);
listProduct.ToList<IProduct>().Add(_product);
}
}
}
}
What is listProduct and why do you call its ToList<>()?
listProduct.ToList<IProduct>() returns a new instance of List<IProduct> that is forgotten after this line executes. Calling .Add(_product) on this returned list does not affect listProduct.
My problem stay here
while (reader.Read())
{
DoSomething();
}
reader.Read() never is read, my table is simple, have only attributes: cd_material(int), ds_material(varchar). And Exception not are triggered.
This query :
SELECT cd_material, ds_material FROM tbl_materiais WHERE ds_material = '%produto%'
Many rows are returned if in owner database ( sql management)

How to Simplify C# query Execution?

I am programmer in asp.net. I am using C#. I have written very lengthy code for query execution in each time. How to re-factor and organize the following code?
MySqlConnection connection = new MySqlConnection(connstring);
string query = "Select fo_region_Name from fo_region where fo_region_DeleteStatus=0";
MySqlCommand command = new MySqlCommand(query, connection);
MySqlDataReader reader;
connection.Open();
reader = command.ExecuteReader();
while (reader.Read())
{
ddl_Country.Items.Add(UppercaseFirst(reader[0].ToString()));
}
connection.Close();
query = "Select Fo_Nationality_Name from fo_Nationality a, Fo_region b where a.Fo_Nationality_Type=1 and "
+ "LEFT(a.Fo_Nationality_Code,2)=LEFT(b.fo_region_Name,2) and a.Fo_Nationality_DeleteStatus=0 and "
+ "b.fo_region_DeleteStatus=0 Union Select Fo_Nationality_Name from fo_nationality where Fo_Nationality_DeleteStatus=0";
command = new MySqlCommand(query, connection);
connection.Open();
reader = command.ExecuteReader();
while (reader.Read())
{
ddl_Nationality.Items.Add(UppercaseFirst(reader[0].ToString()));
}
connection.Close();
query = "select mcs_CreditCard_CardName from mcs_creditcard where mcs_CreditCard_DeleteStatus=0";
command = new MySqlCommand(query, connection);
connection.Open();
reader = command.ExecuteReader();
while (reader.Read())
{
ddl_CreditCard.Items.Add(UppercaseFirst(reader[0].ToString()));
}
connection.Close();
Some thoughts:
Use multiline strings to format your SQL statements.
There is no need to close and reopen the connection betwween each command execution.
There is also no need to create new connection and command objects (in this case)
If you have parameters on the command objects, it is easier to create new command objects, rather than clearing out the old parameters
Use var statements to have the C# compiler automatically determine the variable type for you.
Wrap objects that need to be disposed, in a using block.
using (var connection = new MySqlConnection(connstring)) {
connection.Open();
using (var command = new MySqlCommand()) {
MySqlDataReader reader;
command.CommandText = #"
SELECT fo_region_Name
FROM fo_region
WHERE fo_region_DeleteStatus=0
";
using (reader = command.ExecuteReader()) {
while (reader.Read()) {
ddl_Country.Items.Add(UppercaseFirst(reader[0].ToString()));
}
}
command.CommandText = #"
SELECT Fo_Nationality_Name
FROM fo_Nationality a,
Fo_region b
WHERE a.Fo_Nationality_Type = 1
AND LEFT(a.Fo_Nationality_Code,2) = LEFT(b.fo_region_Name,2)
AND b.fo_region_DeleteStatus=0
UNION SELECT Fo_Nationality_Name
FROM fo_nationality
WHERE Fo_Nationality_DeleteStatus=0
";
using (reader = command.ExecuteReader()) {
while (reader.Read()) {
ddl_Nationality.Items.Add(UppercaseFirst(reader[0].ToString()));
}
}
command.CommandText = #"
SELECT mcs_CreditCard_CardName
FROM mcs_creditcard
WHERE mcs_CreditCard_DeleteStatus = 0
";
using (reader = command.ExecuteReader()) {
while (reader.Read()) {
ddl_Nationality.Items.Add(UppercaseFirst(reader[0].ToString()));
}
}
}
}
With LINQ (add a using System.Data.Common statement):
using (reader = command.ExecuteReader()) {
/*while (reader.Read()) {
ddl_Country.Items.Add(UppercaseFirst(reader[0].ToString()));
}*/
ddl_Country.Items.AddRange((
from DbDataRecord row in reader
select new ListItem(
UppercaseFirst(reader.GetString(0))
)
).ToArray());
}
Maybe use can use EnterpriseLibrary, to reduce amount of code that deals with database.

SQL Data Reader: Invalid attempt to read when no data is present

I am trying to use a SqlDataReader to run a query and then display the results in a messagebox, but I keep getting the error
Invalid attempt to read when no data is present.
Here is my code.
public void button1_Click(object sender, EventArgs e)
{
string results = "";
using (SqlConnection cs = new SqlConnection(#"Server=100-nurex-x-001.acds.net;Database=Report;User Id=reports;Password=mypassword"))
{
cs.Open();
string query = "select stationipaddress from station where stationname = #name";
using (SqlCommand cmd = new SqlCommand(query, cs))
{
// Add the parameter and set its value --
cmd.Parameters.AddWithValue("#name", textBox1.Text);
using (SqlDataReader dr = cmd.ExecuteReader())
{
while (dr.Read())
{
label3.Text = dr.GetSqlValue(0).ToString();
results = dr.GetValue(0).ToString();
//MessageBox.Show(dr.GetValue(0).ToString());
//MessageBox.Show(results);
}
MessageBox.Show(results);
}
}
}
}
That's correct.
When you exit from the while loop the DataReader has reached the end of the loaded data and thus cannot be used to get the value of a non-existant current record.
The Read method advances the SqlDataReader (dr) to the next record and it returns true if there are more rows, otherwise false.
If you have only one record you could use the results variable in this way
MessageBox.Show(results);
Now, this will work because you have a TOP 1 in your sql statement, but, if you have more than one record, it will show only the value of the last record.
Also as noted by marc_s in its comment, if your table is empty, your code doesn't fall inside the while loop, so probably you could initialize the results variable with a message like:
results = "No data found";
EDIT: Seeing your comment below then you should change your code in this way
.....
// Use parameters **ALWAYS** -- **NEVER** cancatenate/substitute strings
string query = "select stationipaddress from station where stationname = #name";
using (SqlCommand cmd = new SqlCommand(query, cs))
{
// Add the parameter and set its value --
cmd.Parameters.AddWithValue("#name", textBox1.Text);
using (SqlDataReader dr = cmd.ExecuteReader())
{
while (dr.Read())
{
label3.Text = dr.GetSqlValue(0).ToString();
results = dr.GetValue(0).ToString();
}
}
}
.....
I ran into a similar issue trying to get a GUID I knew was there - I could run the same SQL directly in SQL Management Studio and get my result. So instead of trying to bring it back as a GUID (it was saved in a char(35) field, even though it really was a GUID!), I brought it back as a string, instead:
SqlConnection sqlConn = null;
string projId = String.Empty;
string queryString = "SELECT * FROM project WHERE project_name='My Project'";
try
{
sqlConn = new SqlConnection(connString);
SqlCommand cmd = new SqlCommand(queryString, sqlConn);
sqlConn.Open();
SqlDataReader reader = cmd.ExecuteReader();
if (reader.HasRows)
{
while (reader.Read())
{
projId = reader.GetSqlValue(0).ToString(); // <-- safest way I found to get the first column's parameter -- increment the index if it is another column in your result
}
}
reader.Close();
sqlConn.Close();
return projId;
}
catch (SqlException ex)
{
// handle error
return projId;
}
catch (Exception ex)
{
// handle error
return projId;
}
finally
{
sqlConn.Close();
}

How do I return the result of a SELECT COUNT statement as a string in C#?

I'm wondering how to return the result from a SELECT COUNT statement in C#.
I have a sql statement that returns the count of 15.
Currently, I'm returning the datareader. Can I somehow return the result of that as a string?
static public SqlDataReader FillDataReader(string sql, SqlParameter[] parms)
{
SqlConnection conn = new SqlConnection(ConnectionString);
SqlCommand cmd = new SqlCommand(sql, conn);
SqlDataReader dr = null;
conn.Open();
cmd.CommandTimeout = 120; //120 seconds for the query to finish executing
foreach (SqlParameter p in parms)
{
cmd.Parameters.Add(p);
}
try
{
dr = cmd.ExecuteReader(CommandBehavior.CloseConnection);
}
catch (SqlException ex)
{
if (dr != null)
{
dr.Close();
}
conn.Close();
//DBUtilExceptionHandler(ex, sql);
throw ex;
}
finally
{
}
return dr; //This could be null...be sure to test for that when you use it
}
Or I could use a different method. I just don't know what it should be.
Any help is appreciated.
This is my select statement:
select count(LeadListID) from LeadLists WHERE SalesPersonID = 1
AND LeadListDateCreated BETWEEN '9/1/11' AND '10/1/11 23:59:59'
Sure - just use:
int count = (int) query.ExecuteScalar();
// TODO: Decide the right culture to use etc
return count.ToString();
Notes:
Use using statements instead of manual try/catch/finally blocks
You should close the connection whether or not there was an error
Given that the natural result of the query is an integer, I would change it to return an int, not a string. Let the caller make that conversion if they want to
If there's an error, you should almost certainly let the exception bubble up, rather than returning null
I would write the code as:
public static int ExecuteScalarInt32(string sql, SqlParameter[] parms)
{
using (SqlConnection conn = new SqlConnection(ConnectionString))
using (SqlCommand command = new SqlCommand(sql, conn) { Parameters = parms })
{
conn.Open();
command.CommandTimeout = 120;
return (int) command.ExecuteScalar();
}
}
If you really needed a version to work on an arbitrary data reader, you could write it as:
public static T ExecuteQuery<T>(string sql, SqlParameter[] parms,
Func<SqlDataReader, T> projection)
{
using (SqlConnection conn = new SqlConnection(ConnectionString))
using (SqlCommand command = new SqlCommand(sql, conn) { Parameters = parms })
{
conn.Open();
command.CommandTimeout = 120;
return projection(command.ExecuteReader());
}
}
And then call it with:
int count = ExecuteQuery<int>(sql, parms, reader => {
if (!reader.MoveNext()) {
throw new SomeGoodExceptionType("No data");
}
return reader.GetInt32(0);
});
Sure, you can always call the ToString() method in .NET on the single field when reading it:
dr[0].ToString()
Are there many records that you want to concat as a string? Then you loop through each row, grab the value as a string, and create a master string in a for loop fashion.
Since you're expecting only a single value, a better alternative to ExecuteReader is the ExecuteScalar method:
try
{
var count = cmd.ExecuteScalar().ToString();
}
Either cast it as a varchar in your sql:
select cast(count(LeadListID) as varchar(10))
from LeadLists
WHERE SalesPersonID = 1
AND LeadListDateCreated BETWEEN '9/1/11' AND '10/1/11 23:59:59'
or just call .ToString() on the result, as shown in other answers.
Additionally, I'm not a fan of relying on CommandBehavior.CloseConnection for DataReaders. I much prefer code like this:
static public IEnumerable<IDataRecord> GetDataReader(string sql, SqlParameter[] parms)
{
using (var conn = new SqlConnection(ConnectionString))
using (var cmd = new SqlCommand(sql, conn))
{
cmd.CommandTimeout = 120; //120 seconds for the query to finish executing
foreach (SqlParameter p in parms)
{
cmd.Parameters.Add(p);
}
conn.Open();
using (var dr= cmd.ExecuteReader())
{
while (dr.Read())
{
yield return dr;
}
}
}
}
Use ExecuteScalar instead, that will return the first field from the first record of the returned recordset, which is what you want. That will return to you an object that is really an integer. Add a ToString to that and you should be good.

Categories

Resources