How can I send response from c# class file to MVC Controller - c#

If my condition fails as rdr.HasRows == true, how can I respond my controller its fails
public Employee DeleteEmpById(int key)
{
try
{
SqlCommand cmd = new SqlCommand("Sp_GetEmployeeById", con);
cmd.CommandType = CommandType.StoredProcedure;
cmd.Parameters.AddWithValue("#EmpId", key);
SqlDataReader rdr = cmd.ExecuteReader();
if (rdr.HasRows == true)
{
}
else
// Here what I mention when rdr.HasRows false
}
Controller
public ActionResult DeleteById(int id)
{
var x = ObjRepo.DeleteEmpById(id);
return View(x);
}

Use While Read
Bool HasData =False ;
SqlDataReader rdr = cmd.ExecuteReader();
while (rdr.Read())
{
// If there is A row sqlDataReader Will read
HasData =true ;
break; // you only have to check one time , performance improve
}
return HasData

Related

Not all code paths return a value in my controller method [duplicate]

This question already has answers here:
C# compiler error: "not all code paths return a value"
(9 answers)
Closed 2 years ago.
i am currently doing a Login page which directs to whichever page according to their StaffRole.
Eg, if StaffRole = Manager, direct to manager page. Here is my code below for my controller method. However my controller method shows an error which says not all code paths return a value. I am unsure how to solve this.
` [HttpPost]
public ActionResult Verify(Account acc)
{
connectionString();
con.Open();
com.Connection = con;
com.CommandText = "select * from Staff where StaffNRIC='" + acc.StaffNRIC + "' and StaffContact='" + acc.StaffContact + "' and StaffAccountStatus = 'Approved'";
dr = com.ExecuteReader();
if (dr.Read())
{
if (dr.HasRows)
{
while (dr.Read())
{
if (dr["StaffRole"].ToString() == "Manager")
{
dr.Close();
return RedirectToAction("Manager/ManagerHome", "ManagerController");//wherever you want to return the user to
}
else if (dr["StaffRole"].ToString() == "Admin")
{
dr.Close();
return RedirectToAction("Admin/AdminHome", "AdminController");
}
else if (dr["StaffRole"].ToString() == "Part-Timer")
{
dr.Close();
return RedirectToAction("PartTimer/PartTimerHome", "PartTimerController");
}
else
{
con.Close();
return View("Login");
}
}
}
}
}`
' SqlConnection con = new SqlConnection(); SqlCommand com = new SqlCommand(); SqlDataReader dr;
Just as the error message shown, not all of the path in your code returns a value. For example, if the dr.Read() is false and the code does not return anything. To solve this error, simply add return View("Login"); after the if (dr.Read()) block
[HttpPost]
public ActionResult Verify(Account acc)
{
connectionString();
con.Open();
com.Connection = con;
com.CommandText = "select * from Staff where StaffNRIC='" + acc.StaffNRIC + "' and StaffContact='" + acc.StaffContact + "' and StaffAccountStatus = 'Approved'";
dr = com.ExecuteReader();
if (dr.Read())
{
if (dr.HasRows)
{
while (dr.Read())
{
if (dr["StaffRole"].ToString() == "Manager")
{
dr.Close();
return RedirectToAction("Manager/ManagerHome", "ManagerController");//wherever you want to return the user to
}
else if (dr["StaffRole"].ToString() == "Admin")
{
dr.Close();
return RedirectToAction("Admin/AdminHome", "AdminController");
}
else if (dr["StaffRole"].ToString() == "Part-Timer")
{
dr.Close();
return RedirectToAction("PartTimer/PartTimerHome", "PartTimerController");
}
else
{
con.Close();
return View("Login");
}
}
}
}
return View("Login");
}
like the answer by #Loong, your controller may not always return something a better way IMO would be to have an object that is set in the if/else etc. then you return that object which can be initialised to the login page. so I have added 'output' and that is what I return, setting it to something other than the login page when I can. You are also reading the same info from the data multiple times using a lookup (see my replacement with a switch)
Also maybe look at refactoring with usings so your connection is automatically disposed as below, I am assuming you are using SQLConnection and SQLCommand but this methodology should work for any iDisposable object
Also when using sql command text, maybe use SQL Variables like #accName or whatever to limit the possibility of someone calling this function and using sql injection (I haven't done that here).
[HttpPost]
public ActionResult Verify(Account acc)
{
ActionResult output = View("Login");
//Usings auto close and dispose of objects once you break out of them
using(var conn = GetNewConnection()) {
using(var cmd = new SQLCommand("select * from Staff where StaffNRIC='" + acc.StaffNRIC + "' and StaffContact='" + acc.StaffContact + "' and StaffAccountStatus = 'Approved'", conn)) {
dr = com.ExecuteReader();
if(dr.Read()) {
bool isFound = false;
if(dr.HasRows()) {
while(dr.read()) {
var role = dr["StaffRole"].ToString();
switch(role) {
case: "Manager": output = RedirectToAction("Manager/ManagerHome", "ManagerController"); isFound=true; break;
case: "Admin": output = RedirectToAction("Admin/AdminHome", "AdminController"); isFound=true; break;
case: "StaffRole": output = RedirectToAction("PartTimer/PartTimerHome", "PartTimerController"); isFound = true; break;
}
if(isFound) { //This bit breaks out of the while->read of the db if the role has been found.
break;
}
}
}
}
}
return output;
}

How to fix code to return full list instead of one row from SqlDataReader in C# Web API

I am building a web API that connects to SQL and am trying to return all rows from the db in which the "StartDateTime" value is equal to today's date. For some reason, I am only getting one row instead of all rows that fit the definition. What do I need to change?
public class EventsController : ApiController
{
public List<tblEventDate> Get()
{
using (CalendarEntities entities = new CalendarEntities())
{
tblEventDate singleEvent = new tblEventDate();
List<tblEventDate> eventList = new List<tblEventDate>();
string strcon = ConfigurationManager.ConnectionStrings["DbConnCalendar"].ConnectionString;
SqlConnection con = new SqlConnection(strcon);
con.Open();
string comm = "SELECT [dbo].[tblEventDates].[EventID], [dbo].[tblEventDates].[StartDateTime], WHERE (CONVERT(date, dbo.tblEventDates.StartDateTime) = CONVERT(date, GETDATE()))";
SqlCommand cmd = new SqlCommand(comm, con);
using (SqlDataReader reader = cmd.ExecuteReader())
{
while (reader.HasRows)
{
while (reader.Read())
{
singleEvent.StartDateTime = (DateTime)(reader["StartDateTime"]);
singleEvent.EventID = (long)reader["EventID"];
eventList.Add(singleEvent);
}
reader.NextResult();
}
con.Close();
}
return eventList;
}
}
}
Try this:
conn.Open();
SqlDataReader reader = cmd.ExecuteReader(CommandBehavior.CloseConnection);
while (reader.Read())
{
if (reader.HasRows)
{
singleEvent.StartDateTime = (DateTime)(reader["StartDateTime"]);
singleEvent.EventID = (long)reader["EventID"];
eventList.Add(singleEvent);
}
}

Exit out of datareader before else, in if-else statement

I would like to find a way to exit out of datareader after the if statement so that I can execute the insert query in else statement. Is there a way to do it?
I am getting the error that dr is still open and hence cannot perform the below query.
sVendorDetails.VendorID = insertcmd.ExecuteNonQuery();
Here is the code:
public class VendorDetails
{
int _VendorID;
string _VendorName;
public int VendorID
{
set { _VendorID = value; }
get { return _VendorID; }
}
public string VendorName
{
set { _VendorName = value; }
get { return _VendorName; }
}
}
public VendorDetails VendorCheck(string sVendorName)
{
SqlCommand cmd = new SqlCommand("dbo.usp_GetVendorByVendorName", myConnection);
cmd.CommandType = CommandType.StoredProcedure;
cmd.Parameters.Add(new SqlParameter("#VendorName", SqlDbType.VarChar));
cmd.Parameters["#VendorName"].Value = sVendorName;
VendorDetails sVendorDetails = null;
try
{
myConnection.Open();
SqlDataReader dr = cmd.ExecuteReader();
if (dr.HasRows)
{
while (dr.Read())
{
sVendorDetails = new VendorDetails();
sVendorDetails.VendorID = ((int)dr["VendorID"]);
sVendorDetails.VendorName = ((string)dr["VendorName"]).ToUpper().Trim();
}
}
else if (dr.HasRows!= true)
{
ClientScript.RegisterStartupScript(this.GetType(), "alert", "alert('VendorName:" + sVendorName + " not found. Inserting Vendor details into Vendor and Invoice table.')", true);
SqlCommand insertcmd = new SqlCommand("dbo.InsertVendorName", myConnection);
insertcmd.CommandType = CommandType.StoredProcedure;
insertcmd.Parameters.Add(new SqlParameter("#VendorName", SqlDbType.VarChar));
insertcmd.Parameters["#VendorName"].Value = sVendorName;
sVendorDetails = new VendorDetails();
sVendorDetails.VendorID = insertcmd.ExecuteNonQuery();
sVendorDetails.VendorName = sVendorName;
}
dr.Close();
return sVendorDetails;
}
catch (SqlException err)
{
throw new ApplicationException("DB usp_GetVendorByVendorName Error: " + err.Message);
}
finally
{
myConnection.Close();
}
}
You will need to close/dispose of your DataReader prior to reusing the connection, as it's still being used.
Maybe something like this?
var readerHasRows = false;
using (var dr = cmd.ExecuteReader())
{
readerHasRows = dr.HasRows;
if(readerHasRows)
{
while (dr.Read())
{
sVendorDetails = new VendorDetails();
sVendorDetails.VendorID = ((int)dr["VendorID"]);
sVendorDetails.VendorName = ((string)dr["VendorName"]).ToUpper().Trim();
}
}
}
if(!readerHasRows)
{
ClientScript.RegisterStartupScript(this.GetType(), "alert", "alert('VendorName:" + sVendorName + " not found. Inserting Vendor details into Vendor and Invoice table.')", true);
SqlCommand insertcmd = new SqlCommand("dbo.InsertVendorName", myConnection);
insertcmd.CommandType = CommandType.StoredProcedure;
insertcmd.Parameters.Add(new SqlParameter("#VendorName", SqlDbType.VarChar));
insertcmd.Parameters["#VendorName"].Value = sVendorName;
sVendorDetails = new VendorDetails();
VendorDetails.VendorID = insertcmd.ExecuteNonQuery();
sVendorDetails.VendorName = sVendorName;
}
There are a few things I would like to mention
Your main issue is that you are not closing your DataReader. You can use the using statement for it
You don't need to explicitly open and close the SqlConnection. The SqlCommand object will do it as needed.
You don't need to check with if (dr.HasRows) and then check again in while (dr.Read()). Also, you don't need to loop to pick up only one row of data.
Ideally, I would put the "Fetch" part in a separate function and the "insert" in a separate function, so the functions stay small and reusable.
Your pattern is superfluous if (flag) {TakeAction();} else if (!flag) {TakeAction2();}. Every time the code hits theelse, it will also hit theif (!flag)`
sVendorDetails.VendorID = insertcmd.ExecuteNonQuery(); line looks fishy. If your Stored Procedure returns the VendorId, then you should use ExecuteScalar. Currently it is just storing 1 in all case since you are presumably inserting one row.
Don't discard the original SqlException when creating a custom ApplicationException. Upstream system might want to know more details than you are passing. Pass it along as the InnerException
I have also changed some stylistic aspects:
The variable names changed to the more commonly used camelCase, instead of the incorrectly used Hungarian Notation (sVendorDetails instead of oVendorDetails)
Brace in K&R style
Used var when the right side is a new statement
Use Object Initializers instead of creation+assignment
Below is the code
public VendorDetails VendorCheck(string vendorName, SqlConnection myConnection) {
try {
return GetVendor(vendorName, myConnection) ?? InsertVendor(vendorName, myConnection);
} catch (SqlException err) {
throw new ApplicationException("DB usp_GetVendorByVendorName Error: " + err.Message, err);
}
}
VendorDetails GetVendor(string vendorName, SqlConnection myConnection) {
using (var cmd = new SqlCommand("dbo.usp_GetVendorByVendorName", myConnection)) {
cmd.CommandType = CommandType.StoredProcedure;
cmd.Parameters.Add(new SqlParameter("#VendorName", SqlDbType.VarChar));
cmd.Parameters["#VendorName"].Value = vendorName;
using (SqlDataReader dr = cmd.ExecuteReader()) {
ClientScript.RegisterStartupScript(this.GetType(), "alert", "alert('VendorName:" + vendorName + " not found. Inserting Vendor details into Vendor and Invoice table.')", true); // TODO: Does this really belong here!?!?
if (dr.Read()) {
return new VendorDetails {
VendorID = ((int)dr["VendorID"]),
VendorName = ((string)dr["VendorName"]).ToUpper().Trim()
};
}
}
}
return null;
}
VendorDetails InsertVendor(string vendorName, SqlConnection myConnection) {
using (var insertcmd = new SqlCommand("dbo.InsertVendorName", myConnection)) {
insertcmd.CommandType = CommandType.StoredProcedure;
insertcmd.Parameters.Add(new SqlParameter("#VendorName", SqlDbType.VarChar));
insertcmd.Parameters["#VendorName"].Value = vendorName;
return new VendorDetails {
VendorID = (int)insertcmd.ExecuteScalar(),
VendorName = vendorName
};
}
}

passing a string to a class

I have a problem with my SQL datareader, i want to make an external class and make the code in my xaml.cs as short as possible, because there are a lot of sqldatareaders needed in my program. for this I want to pass following two strings to the datareader class:
public void refreshcombobox()
{
cbGebruiker.Items.Clear();
database = new DataBase();
string sqlrdr = "(rdr.GetString(1).ToString().Trim())";
List<string> reader = database.ReaderRdr("Select * from Gebruikers", ref sqlrdr);
foreach (String str in reader)
{
cbGebruiker.Items.Add(str);
}
}
however, when I do this this is the result in my program instead of the actual results that are stored in the database:
http://i58.tinypic.com/301j2vo.jpg (I can't post images)
can somebody help me with this? I've searched everywhere...
I don't know how to pass the rdr.GetString(1).ToString().Trim() to make it actually look stuff up in the db. Instead of just copying the string directly into the list.
This is the class:
namespace ClassLib
{
public class DataBase
{
SqlConnection conn = new SqlConnection(ConfigurationManager.ConnectionStrings["kassadatabase"].ConnectionString);
public object ScalarObject(string sql)
{
object value = null;
try
{
conn.Open();
SqlCommand cmd = new SqlCommand(sql, conn);
value = cmd.ExecuteScalar();
}
catch (SqlException ex)
{
MessageBox.Show(ex.Message);
}
finally
{
if (conn != null) conn.Close();
}
return value;
}
public List<string> ReaderRdr(string sql)
{
SqlDataReader rdr = null;
List<string> reader = new List<string>();
try
{
conn.Open();
SqlCommand cmd = new SqlCommand(sql, conn);
rdr = cmd.ExecuteReader();
while (rdr.Read())
{
//reader.Add(rdr.GetString(1).ToString().Trim());
}
}
catch (SqlException ex)
{
MessageBox.Show(ex.Message);
}
finally
{
if (rdr != null) rdr.Close();
if (conn != null) conn.Close();
}
return reader;
}
//public List<string> ReaderRdr(string sql, ref string str)
//{
// SqlDataReader rdr = null;
// List<string> reader = new List<string>();
// try
// {
// conn.Open();
// SqlCommand cmd = new SqlCommand(sql, conn);
// rdr = cmd.ExecuteReader();
// while (rdr.Read())
// {
// //MessageBox.Show(str.ToString());
// //var strRdr = str;
// //MessageBox.Show(strRdr.ToString());
// //reader.Add(rdr.GetString(1).ToString().Trim());
// reader.Add(str);
// Console.WriteLine(String.Format("{0}", rdr[0]));
// }
// }
// catch (SqlException ex)
// {
// MessageBox.Show(ex.Message);
// }
// finally
// {
// if (rdr != null) rdr.Close();
// if (conn != null) conn.Close();
// }
// return reader;
//}
public void ExecuteNQuery(string insertString)
{
try
{
conn.Open();
SqlCommand cmd2 = new SqlCommand(insertString, conn);
cmd2.ExecuteNonQuery();
}
catch (SqlException ex)
{
MessageBox.Show(ex.Message);
}
finally
{
if (conn != null) conn.Close();
}
}
}
}
public List<string> ReaderRdr(string sql)
{
SqlDataReader rdr = null;
List<string> reader = new List<string>();
try
{
conn.Open();
SqlCommand cmd = new SqlCommand(sql, conn);
rdr = cmd.ExecuteReader();
while (rdr.Read())
{
//reader.Add(rdr.GetString(1).ToString().Trim());
}
.....
now in the methode public list i want to replace the //reader.Add(rdr.GetString(1).ToString().Trim()); part(wich works fine)
with a string that is passed to the method.
public List<string> ReaderRdr(string sql, string strRdr)
{
SqlDataReader rdr = null;
List<string> reader = new List<string>();
try
{
conn.Open();
SqlCommand cmd = new SqlCommand(sql, conn);
rdr = cmd.ExecuteReader();
while (rdr.Read())
{
//reader.Add(strRdr);
}
I'm not 100% sure what you're trying to do, but I can tell you right now that this is what you're doing wrong - the string (str) you're passing to ReaderRdr is just a string literal of C# code. There's super hacky (super inadvisable) things you can do to mimic what exists in other languages as eval(), but there's no built-in way to do that in C#. Nothing (sensible) you do to "(rdr.GetString(1).ToString().Trim())" is ever going to get a string, or cast it to string, or trim anything.
Within your ReaderRdr function, all you're accomplishing is just to add the string str to your List<string> reader. This accomplishes nothing and has no bearing whatsoever on the results you get from your database query in your SqlDataReader rdr. If you want to store the data you actually get from your database, use rdr, not the (useless) string argument str.
Also, I feel like you must have left something out of your code - you're instantiating your SqlCommand cmd with conn as your second argument, but I don't see that defined anywhere within your ReaderRdr method, and it's not an argument passed to ReaderRdr. You don't have an SqlConnection object as a field or property within your class, do you?
As far as what you should maybe do, despite lacking much of any context in terms of your actual aims - if you want to get any given column of the result for each row returned by your SqlDataReader:
rdr = cmd.ExecuteReader();
while (rdr.Read())
{
var yourDataCell = rdr[yourColumnIndex];
// or:
var yourDataCellOtherWay = rdr["YourColumnName"];
}
Alternately, you can just iterate through each of the cells in any given row produced by your SqlDataReader like so:
for(int i = 0 ; i < numberOfColumns; i++) {
// do something with rdr[i] here
}
I'm not sure if there's anything you can do establish numberOfColumns based on the state of your SqlDataReader, but others might know better.
You actually adding the String that you passed to a function to your reader reader.Add(str); You get the response from SQL I your rdr.
This item will show you something from your database:
Console.WriteLine(String.Format("{0}", rdr[0]));

Using parameters with a database connection class

I am trying to add Sql Parameters to my project but i have the database connections in a class. How would i go about adding them as the code is trying to read employerId as a column name
I have this code in a class to read and return from a database:
public SqlDataReader ExecuteQuery(String query)
{
SqlCommand cmd = new SqlCommand(query,sqlConn);
SqlDataReader reader = cmd.ExecuteReader();
return reader;
}
and this code in a web service:
[WebMethod]
public string CheckTime1(string employerId)
{
try
{
UseDatabase useDb = new UseDatabase("database.mdf");
string queryString = "SELECT * FROM [employer] WHERE [employerId] =" + employerId;
useDb.ConnectToDatabase();
SqlDataReader dbReader = useDb.ExecuteQuery(queryString);
if (dbReader != null && dbReader.HasRows)
{
return "RECORDS EXIST";
}
else if (dbReader == null)
{
return "RECORDS DONT EXIST";
}
else
{
return "Error";
}
useDb.DisconectDatabase();
}
catch (Exception exq)
{
return exq.ToString(); ;
}
}
Although I strongly encourage you to rethink your data access layer from scratch, here is an easy solution to your problem:
public SqlDataReader ExecuteQuery(String query, params object[] p)
{
SqlCommand cmd = new SqlCommand(query, sqlConn);
for (int i = 0; i < p.Length; i++)
{
cmd.Parameters.Add(new SqlParameter("#p"+i, p[i]));
}
SqlDataReader reader = cmd.ExecuteReader();
return reader;
}
Then call it like this:
public string CheckTime1(string employerId)
{
...
string queryString = "SELECT * FROM [employer] WHERE [employerId] = #p0";
SqlDataReader dbReader = useDb.ExecuteQuery(queryString, employerId);
...
}

Categories