Resetting OracleDataReader reader and calling SQL inside C# foreach loop - c#

How can I reset a dataReader inside a foreach loop? I am trying to run a select query inside a loop but reader is always having the records from the first select. I tried reader.Dispose() and reader.Close() methods but still the value is not resetting to contain the next set of data.
here is my code sample:
using (OracleCommand cmd = con.CreateCommand())
{
if (getqMidLid != null)
{
foreach (var item in getqMidLid)
{
cmd.BindByName = true;
cmd.InitialLONGFetchSize = -1;
try
{
cmd.CommandText = "select Question_mid, " +
" question_lid," +
" max_score," +
" actual_score," +
" topic," +
" answer_full" +
" from QnA where Question_mid = :mid and Question_lid = :lid" +
" and (max_score = actual_score)";
OracleParameter mid = new OracleParameter("mid", item.QMID);
OracleParameter lid = new OracleParameter("lid", item.QLID);
cmd.Parameters.Add(mid);
cmd.Parameters.Add(lid);
using (OracleDataReader reader = cmd.ExecuteReader())
{
if (reader.HasRows)
{
while (reader.Read())
{
qna.Add(new QuestionAnswer
{
QMID = reader.GetInt32(0),
QLID = reader.GetInt32(1),
MaxScore = reader.GetInt16(2),
ActualScore = reader.GetInt16(3),
Topic = reader.GetString(4),
AnswerFull = reader.GetString(5)
});
}
}
}
}
catch (Exception sql)
{
Console.WriteLine(sql.Message);
throw;
}
}
}
}

Solved it by moving the OracleCommand object inside the result loop.

Related

Fetch all needed data from 2 different databases

[UPDATED]
I got a situation here where I need to fetch data from 2 different databases and then combine it into a model. I have an API method I made here that takes care of that but the moment I started working with a second database I got really confused on how I can retrieve more than one item. I'll explain. Here is the code to that method:
private List<FidelityModel> models;
public List<FidelityModel> getFidelityInfo2(string jobID) {
FidelityModel fidelityInfo;
SqlCommand command;
SqlConnection conn;
SqlDataReader reader;
string cjsJobName, ipwNumber, overnight, site;
int packageCount;
DateTime sla;
models = new List<FidelityModel>();
using (conn = new SqlConnection(#"server = [servername]; database = Dropoff; Integrated Security = true;")) {
conn.Open();
command = new SqlCommand("SELECT " +
"[Job Name], " +
"[Job ID], " +
"[Package Count], " +
"[Ship Method] " +
"FROM [cjs_data] " +
"WHERE [File Name] LIKE '%FDY%' AND [JOB ID] = #jobID", conn);
command.Parameters.Add("#jobID", SqlDbType.VarChar);
command.Parameters["#jobID"].Value = jobID;
//restructure to assign search results to string to later assign to model, as we will search again for SLA in a different database
using (reader = command.ExecuteReader()) {
if (reader.HasRows) {
while (reader.Read()) {
fidelityInfo = new FidelityModel();
fidelityInfo.cjsJobName = reader.GetString(0);
fidelityInfo.ipwNumber = reader.GetString(1);
fidelityInfo.packageCount = reader.GetInt32(2);
if (fidelityInfo.cjsJobName.Contains("OVN")) { fidelityInfo.overnight = "Yes"; } else {
fidelityInfo.overnight = (reader.GetString(3).Equals("Overnight")) ? "Yes" : "No";
}
//site = (cjsJobName.Contains("EDG")) ? "EDGEWOOD" : "Other Site"; //not always the case
fidelityInfo.site = "EDGEWOOD";
models.Add(fidelityInfo);
}
}
}
}
//How to incorporate this following block of code into the same model?
using (conn = new SqlConnection(#"server = [servername]; database = MustMail; Integrated Security = true;")) {
conn.Open();
command = new SqlCommand("SELECT [SLA] FROM [Job] WHERE [JobID] = #jobID", conn);
command.Parameters.Add("#jobID", SqlDbType.VarChar);
command.Parameters["#jobID"].Value = jobID;
using (reader = command.ExecuteReader()) {
if (reader.HasRows) {
while (reader.Read()) {
//fidelityInfo.sla = reader.GetDateTime(0);
}
}
}
}
return models;
}
As you can see right now I just have it working without fetching the SLA because I have no idea how to actually add the result I am fetching from the second database to the same model.
For each row in the DataReader create a new FidelityModel and add it to the list. Something like:
while (reader.Read())
{
var m = new FidelityModel()
{
cjsJobName = reader.GetString(0),
ipwNumber = reader.GetString(1),
packageCount = reader.GetInt32(2),
sla = DateTime.Now
};
if (m.cjsJobName.Contains("OVN"))
{
m.overnight = "Yes";
}
else
{
m.overnight = (reader.GetString(3).Equals("Overnight")) ? "Yes" : "No";
}
models.Add(m);
}

If there is no row in database sum command return an error

An error is thrown when there is no data in data base while converting a string value into int.
try {
SqlCommand cmdc = new SqlCommand("SELECT SUM(Credited_amount) FROM IMS_Credit_Dir WHERE Credit_comp_id=1 AND Crdt_typ_id=1", con);
string companya_credit_amount = null, comapnyb_credit_amount = null;
con.Open();
SqlDataReader drc = cmdc.ExecuteReader();
if (drc.HasRows)
{
while (drc.Read())
{
companya_credit_amount = drc[0].ToString();
}
drc.Close();
con.Close();
}
SqlCommand cmdcp = new SqlCommand("SELECT SUM(Credited_amount) FROM IMS_Credit_Dir WHERE Credit_comp_id=2 AND Crdt_typ_id=1", con);
con.Open();
SqlDataReader drcp = cmdcp.ExecuteReader();
if (drcp.HasRows)
{
while (drcp.Read())
{
companyb_credit_amount = drcp[0].ToString();
}
drcp.Close();
con.Close();
}
if (!Page.IsPostBack)
{
int companyA = 0,companyB=0;
if (companya_credit_amount != "") { companyA = Convert.ToInt32(credit_amount.ToString()); }
if (companyb_credit_amount != ""){ companyB = Convert.ToInt32(companyb_credit_amount); }
int total = (companyA+companyB);
count_total_lbl.Text = "Rs." + " " + total.ToString();
count_comapnya_lbl.Text = "Rs." + " " + companya_credit_amount.ToString();
count_companyb_lbl.Text ="Rs."+" "+ companyb_credit_amount.ToString();
}
}
catch(Exception ex) { Label2.Text = ex.ToString(); }
If there is value its working fine.but when there is no value in data base there is an error msg.
System.FormatException: Input string was not in a correct format.
Use IsDBNull to check for null values
Create and destroy all your type instances that implement IDisposable in using blocks. This ensures that connections are always released and resources are cleaned up.
Do not use connections across a class. Create them when needed and then dispose of them. Sql Server will handle connection pooling.
Get the native types directly, not the string equivalent! See changes to GetInt32 instead of ToString on the data reader.
You should refactor this to use SqlParameter's and make the retrieval statement generic OR get both SUM values in 1 sql call.
There is an if (!Page.IsPostBack) statement, if none of this code does anything if it is a postback then check at the top of the page and do not execute the sql statements if it is a postback. Otherwise the code is making (possibly) expensive sql calls for no reason.
try
{
int companyA = 0,companyB=0;
using(var con = new SqlConnection("connectionStringHere"))
{
con.Open();
using(SqlCommand cmdc = new SqlCommand("SELECT SUM(Credited_amount) FROM IMS_Credit_Dir WHERE Credit_comp_id=1 AND Crdt_typ_id=1", con))
using(SqlDataReader drc = cmdc.ExecuteReader())
{
if (drc.Read() && !drc.IsDBNull(0))
companyA = drc.GetInt32(0);
}
using(SqlCommand cmdcp = new SqlCommand("SELECT SUM(Credited_amount) FROM IMS_Credit_Dir WHERE Credit_comp_id=2 AND Crdt_typ_id=1", con))
using(SqlDataReader drcp = cmdcp.ExecuteReader())
{
if (drcp.Read() && !drcp.IsDBNull(0))
companyB = drcp.GetIn32(0);
}
}
// if you are not going to do anything with these values if its not a post back move the check to the top of the method
// and then do not execute anything if it is a postback
// ie: // if (Page.IsPostBack) return;
if (!Page.IsPostBack)
{
int total = (companyA+companyB);
count_total_lbl.Text = "Rs." + " " + total.ToString();
count_comapnya_lbl.Text = "Rs." + " " + companyA.ToString();
count_companyb_lbl.Text ="Rs."+" "+ companyB.ToString();
}
}
catch(Exception ex) { Label2.Text = ex.ToString(); }
Try to replace this
SELECT SUM(Credited_amount)
WITH
SELECT ISNULL(SUM(Credited_amount),0)
Also find one confusing code while converting Credited amount values
if (companya_credit_amount != "") { companyA = Convert.ToInt32(credit_amount.ToString()); }
---------^^^^^
if (companyb_credit_amount != ""){ companyB = Convert.ToInt32(companyb_credit_amount); }
I don't know about your business requirement but What i think Instead of using credit_amount value companya_credit_amount should be use to show value for companyA variable right?
You should do 2 things:
string companya_credit_amount = "", comapnyb_credit_amount = "";
Before assigning the value to these string variable you should check for db null as following:
while (drc.Read())
{
companya_credit_amount = (drc[0] != DbNull.Value) ? drc[0].ToString() : "" ;
}
Similarely
while (drcp.Read())
{
companyb_credit_amount = (drcp[0] != DbNull.Value) ? drcp[0].ToString() : "";
}
Try it.
You need to initialize credit_amount to empty and check if db value is null as shown below:
try {
companya_credit_amount = string.Empty;
companyb_credit_amount = string.Empty;
SqlCommand cmdc = new SqlCommand("SELECT SUM(Credited_amount) FROM IMS_Credit_Dir WHERE Credit_comp_id=1 AND Crdt_typ_id=1", con);
string companya_credit_amount = null, comapnyb_credit_amount = null;
con.Open();
SqlDataReader drc = cmd
c.ExecuteReader();
if (drc.HasRows)
{
while (drc.Read())
{
companya_credit_amount = drcp.IsDBNull(0)?string.Empty:Convert.ToString(drcp[0]);
}
drc.Close();
con.Close();
}
SqlCommand cmdcp = new SqlCommand("SELECT SUM(Credited_amount) FROM IMS_Credit_Dir WHERE Credit_comp_id=2 AND Crdt_typ_id=1", con);
con.Open();
SqlDataReader drcp = cmdcp.ExecuteReader();
if (drcp.HasRows)
{
while (drcp.Read())
{
companyb_credit_amount = drcp.IsDBNull(0)?string.Empty:Convert.ToString(drcp[0]);
}
drcp.Close();
con.Close();
}
if (!Page.IsPostBack)
{
int companyA = 0,companyB=0;
if (companya_credit_amount != "") { companyA = Convert.ToInt32(credit_amount.ToString()); }
if (companyb_credit_amount != ""){ companyB = Convert.ToInt32(companyb_credit_amount); }
int total = (companyA+companyB);
count_total_lbl.Text = "Rs." + " " + total.ToString();
count_comapnya_lbl.Text = "Rs." + " " + companya_credit_amount.ToString();
count_companyb_lbl.Text ="Rs."+" "+ companyb_credit_amount.ToString();
}
}
catch(Exception ex) { Label2.Text = ex.ToString(); }

How can i log SqlCommand queries to analyze at SQL server tuning advisor

I have a DB connection class which executes all of my DB connections
I want to capture the queries and run them on SQL server tuning advisor to find out missing indexes etc
The SQL server profiler tuning takes forever to process. So i want to compose my own file to analyze
The issue is i don't know how should i capture query to properly analyze
Here my SqlCommand function
SQL server 2014 , c# .net 4.5
My question is what parameters, values etc i should log to analyze them perfectly
public static DataTable cmd_SelectQuery(string srCommandText, List<string> lstParameterNames, List<object> lstParameters)
{
DataTable dsCmdPara = new DataTable();
try
{
using (SqlConnection connection = new SqlConnection(DbConnection.srConnectionString))
{
using (SqlCommand cmd = new SqlCommand(srCommandText, connection))
{
cmd.CommandTimeout = PublicSettings.irCommandTimeOutSettings_Second;
cmd.CommandType = CommandType.Text;
object objParameter;
for (int i = 0; i < lstParameterNames.Count; i++)
{
objParameter = lstParameters[i];
if (objParameter == null)
objParameter = "n";
cmd.Parameters.AddWithValue(lstParameterNames[i], lstParameters[i].ToString());
}
using (SqlDataAdapter sqlDa = new SqlDataAdapter(cmd))
{
sqlDa.Fill(dsCmdPara);
return dsCmdPara;
}
}
}
}
catch (Exception E)
{
Interlocked.Increment(ref GlobalStats.long_GlobalSQLErrorCount);
StringBuilder srParameters = new StringBuilder();
if (PublicSettings.blLogSqlParametersOnErrors == true)
{
srParameters.AppendLine("");
srParameters.AppendLine("error at : cmd_UpdateDeleteQuery");
foreach (var vrItem in lstParameters)
{
srParameters.AppendLine("per parameter: " + vrItem + " \r\n\r\n");
}
}
if (PublicSettings.blLogSqlErrors)
ErrorLogger.LogSQL_Error("Error at: cmd_SelectQuery " + srCommandText + " " + E.Message.ToString() + " \r\n" + srParameters.ToString());
}
return dsCmdPara;
}
public static bool cmd_UpdateDeleteQuery(string srCommandText, List<string> lstParameterNames, List<object> lstParameters)
{
try
{
using (SqlConnection connection = new SqlConnection(DbConnection.srConnectionString))
{
using (SqlCommand cmd = new SqlCommand(srCommandText, connection))
{
cmd.CommandTimeout = PublicSettings.irCommandTimeOutSettings_Second;
cmd.CommandType = CommandType.Text;
object objParameter;
for (int i = 0; i < lstParameterNames.Count; i++)
{
objParameter = lstParameters[i];
if (objParameter == null)
objParameter = "n";
cmd.Parameters.AddWithValue(lstParameterNames[i], objParameter);
}
connection.Open();
cmd.ExecuteNonQuery();
return true;
}
}
}
catch (Exception E)
{
Interlocked.Increment(ref GlobalStats.long_GlobalSQLErrorCount);
StringBuilder srParameters = new StringBuilder();
if (PublicSettings.blLogSqlParametersOnErrors == true)
{
srParameters.AppendLine("");
srParameters.AppendLine("error at : cmd_UpdateDeleteQuery");
foreach (var vrItem in lstParameters)
{
srParameters.AppendLine("per parameter: " + vrItem + " \r\n\r\n");
}
}
if (PublicSettings.blLogSqlErrors)
ErrorLogger.LogSQL_Error("Error at: cmd_UpdateDeleteQuery " + srCommandText + " " + E.Message.ToString() + srParameters.ToString());
}
return false;
}

SqlDataReader in C#

I have a problem with SqlDataReader.
Here's my code. the problem is when I debug it it doesn't go further than
while(dr.read())
it means the value returned by dr.Read() is false. I don't know what's wrong.
if (CS_time_date[i].Substring(0, 2) == "CS")
{
string cardserial = CS_time_date[i].Substring(4, 5);
try
{
using (SqlConnection con = new SqlConnection(WindowsAppEmp.Properties.Settings.Default.Database1ConnectionString))
{
con.Open();
SqlCommand cmd = new SqlCommand("select * from Card_reg ", con);
using (SqlDataReader dr = cmd.ExecuteReader())
{
while (dr.Read())
{
if ((dr["Cardserial"].ToString() == cardserial))
{
flag = 1;
string EmpID = dr["Id"].ToString();
string F_Name = dr["fname"].ToString();
string L_Name = dr["lname"].ToString();
// Insert_EmpReport(EmpID, F_Name, L_Name, cardserial, CS_time_date,con);
string strsql1 = "Insert into Emp_Report (EmpId,CS,fname,lname,CheckIn,CheckOut,Date,Status) values (#EmpID,#Cs,#fname,#lname,#CheckIn,#CheckOut,#Date,#Status)";
SqlCommand report_cmd = new SqlCommand(strsql1, con);
report_cmd.Parameters.AddWithValue("#EmpID", EmpID);
report_cmd.Parameters.AddWithValue("#Cs", cardserial);
report_cmd.Parameters.AddWithValue("#fname", F_Name);
report_cmd.Parameters.AddWithValue("#lname", L_Name);
if (CS_time_date[i].Substring(9, 10) == "56")
if (CS_time_date[i + 2] == DateTime.Now.ToString("dd/mm/yyyy"))
{
report_cmd.Parameters.AddWithValue("#CheckIn", CS_time_date[i + 1]);
report_cmd.Parameters.AddWithValue("#Status", "Present");
}
else
report_cmd.Parameters.AddWithValue("#Status", "Absent");
else
report_cmd.Parameters.AddWithValue("#CheckOut", CS_time_date[i + 1]);
report_cmd.Parameters.AddWithValue("#Date", CS_time_date[i + 2]);
}
else
flag = 0;
}
}
}
}
catch (Exception ex)
{
MessageBox.Show(ex.Message);
}
}
} while (reader.Peek() != -1);
reader.Close();
It looks like you have the Card_reg table defined in your database but this table doesn't contain any values in it - it is empty. That's why the select * from Card_reg query doesn't return any results and the data reader has nothing to read.

How to retrieve all fields for a given record using OracleDataReader?

My question, which is similar to this one, is how can I use OracleDataReader to retrieve all the fields for a given record? Currently, I've been using this method, which returns only one column value at a time:
public string Select_File(string filename, string subdirectory, string envID)
{
Data_Access da = new Data_Access();
OracleConnection conn = da.openDB();
OracleCommand cmd = new OracleCommand();
cmd.Connection = conn;
cmd.CommandText = "SELECT * FROM EIP_Deployment_Files"
+ " WHERE Filename ='" + filename + "'"
+ " AND Subdirectory = '" + subdirectory + "'"
+ " AND Environment_ID = '" + envID + "'";
cmd.CommandType = CommandType.Text;
string x;
OracleDataReader dr = cmd.ExecuteReader();
if (dr.HasRows) // file exists in DB
{
dr.Read();
x = dr.GetString(2).ToString(); // return baseline filename (index 2)
}
else
{
x = "New File";
}
cmd.Dispose();
da.CloseDB(conn);
return x;
}
I'm sure that this method is far from perfect and ppl will be quick to point that out (I was basically given it by my supervisor since I didn't have any prior experience in ASP.NET) but all I really care about is that it works. My question is: how can it be modified to return all the fields for a given record?
The fields will be of either VARCHAR2, CHAR, or DATE datatypes, (if that makes a difference) and some of these values may be null. I'm thinking I could convert them to strings and return them as a list?
if u want something like this:
List<User> lstUser = new List<User>();
string sqlQuery = "Select * from User_T where User_Name='" + oUser.UserName + "' And Password='" +oUser.Password + "' AND IsActive='"+1+"' AND IsDelete='"+0+"'";
string connectionString = "Data Source=ORCL;User Id=ACCOUNTS;Password=ACCOUNTS";
using (DBManager dbManager = new DBManager(connectionString))
{
try
{
dbManager.Open();
OracleDataReader dataReader = dbManager.ExecuteDataReader(sqlQuery);
while (dataReader.Read())
{
oUser = new User();
oUser.Id = Convert.ToInt32(dataReader["ID"]);
oUser.CompanyId = Convert.ToInt32(dataReader["Company_ID"]);
oUser.BranchId = Convert.ToInt32(dataReader["Branch_ID"]);
oUser.UserName = Convert.ToString(dataReader["User_Name"]);
lstUser.Add(oUser);
}
dataReader.Close();
dataReader.Dispose();
}
catch
(Exception)
{
}
finally
{
dbManager.Close();
dbManager.Dispose();
}
To read all the data from the columns of the current row in a DataReader, you can simply use GetValues(), and extract the values from the array - they will be Objects, of database types.
Object[] values;
int numColumns = dr.GetValues(values); //after "reading" a row
for (int i = 0; i < numColumns; i++) {
//read values[i]
}
MSDN - "For most applications, the GetValues method provides an efficient means for retrieving all columns, rather than retrieving each column individually."
Sorry for posting an answer to a very old question. As none of the answers are correct (either they have security issues or not checking for DBNull), I have decided to post my own.
public async Task<StringBuilder> FetchFileDetailsAsync(string filename, string subdirectory, string envId)
{
var sb = new StringBuilder();
//TODO: Check the parameters
const string connectionString = "user id=userid;password=secret;data source=" +
"(DESCRIPTION=(ADDRESS=(PROTOCOL=tcp)(HOST=10.0.0.8)(PORT=1521))(CONNECT_DATA=(SERVICE_NAME=xe)))";
const string selectQuery = "SELECT * FROM EIP_Deployment_Files"
+ " WHERE Filename = :filename"
+ " AND Subdirectory = :subdirectory"
+ " AND Environment_ID = :envID"
+ " AND rownum<=1";
using (var connection = new OracleConnection(connectionString))
using (var cmd = new OracleCommand(selectQuery, connection) {BindByName = true, FetchSize = 1 /*As we are expecting only one record*/})
{
cmd.Parameters.Add(":filename", OracleDbType.Varchar2).Value = filename;
cmd.Parameters.Add(":subdirectory", OracleDbType.Varchar2).Value = subdirectory;
cmd.Parameters.Add(":envID", OracleDbType.Varchar2).Value = envId;
//TODO: Add Exception Handling
await connection.OpenAsync();
var dataReader = await cmd.ExecuteReaderAsync(CommandBehavior.CloseConnection);
var rowValues = new object[dataReader.FieldCount];
if (dataReader.Read())
{
dataReader.GetValues(rowValues);
for (var keyValueCounter = 0; keyValueCounter < rowValues.Length; keyValueCounter++)
{
sb.AppendFormat("{0}:{1}", dataReader.GetName(keyValueCounter),
rowValues[keyValueCounter] is DBNull ? string.Empty : rowValues[keyValueCounter])
.AppendLine();
}
}
else
{
//No records found, do something here
}
dataReader.Close();
dataReader.Dispose();
}
return sb;
}

Categories

Resources