Invalid attempt to read data when no data is present - c#

I have a SQL Server database in C# [built before I got to my present job, creator is gone], and it was fine until last week. On the first page clerk_search.aspx it searches SQL Server for people and posts back to a datagrid that's fine.
There is a ASP Image button that's clicked on and it goes forward to the next page, to enter the reason the for the customers visit with loaded fields about the customer that post back. For some persons the next page populates, for others it does not. The SQL statement used checks out fine in query analyzer, I don't understand. I don't think its the reader because others are logged in fine, and the other customers are present in the rows in SQL and can be queried just fine. All is posted below, I am not savvy with coding, please assist.
System.InvalidOperationException: Invalid attempt to read when no data is present.
SqlDataReader reader2 = cmd.ExecuteReader();
reader2.Read();
[InvalidOperationException: Invalid attempt to read when no data is present.]
Here is the actual: ....clerk_create.aspx.cs
public partial class clerk_create : System.Web.UI.Page
{
protected void Page_Load(object sender, EventArgs e)
{
if (Request.Cookies["us"] == null)
{
Response.Write("Sorry, you do not have access to this page. Please see
data systems.");
Response.End();
}
if (!IsPostBack)
{
using (SqlConnection connection = new SqlConnection
(WebConfigurationManager.ConnectionStrings["walkin2"].ConnectionString))
{
TextBox txtsct = (TextBox)Page.PreviousPage.FindControl("Txtsct");
Txtsct.Text = txtsct.Text;
TextBox txt = (TextBox)Page.PreviousPage.FindControl("Txtssn");
Txtssn.Text = "" + txt.Text;
connection.Open();
string strsql2 = "SELECT dbo.table_name.SSN,
dbo.table_name.LAST_NAME,
dbo.table_name.FIRST_NAME, dbo.table_name.MIDDLE_INITIAL,
dbo.table_name.COMPONENT_CODE, dbo.table_name.PRESENT_CODE FROM
dbo.table_name INNER JOIN dbo.table_name ON dbo.table_name.SSN = '" +
Txtssn.Text + "')";
SqlCommand cmd = new SqlCommand(strsql2, connection);
SqlDataReader reader2 = cmd.ExecuteReader();
reader2.Read();
LblLName.Text = "" + reader2["LAST_NAME"];
LblFName.Text = "" + reader2["FIRST_NAME"];
}
}
}
...
}

You should check the return value of Read method.
If read method returns false then there is no more data. In that case you should not read the data from reader. Doing so will cause this exception.
If you're sure that you'll get only one record try this
if(reader2.Read())
{
LblLName.Text = "" + reader2["LAST_NAME"];
LblFName.Text = "" + reader2["FIRST_NAME"];
}
usually DataReader is used as below, since it can contain number of records
while (reader2.Read())
{
//Consume reader using reader2["Column"] etc
}

Your code is not properly disposing some objects and it is vulnerable to SQL injection.
DTO:
public class Employee
{
public string FirstName { get; set; }
public string LastName { get; set; }
}
Code:
private static readonly Lazy<string> ConnectionString = new Lazy<string>(() => WebConfigurationManager.ConnectionStrings["walkin2"].ConnectionString);
private const string GetEmployeeBySSNQuery = "SELECT dbo.table_name.SSN, dbo.table_name.LAST_NAME, dbo.table_name.FIRST_NAME, dbo.table_name.MIDDLE_INITIAL, dbo.table_name.COMPONENT_CODE, dbo.table_name.PRESENT_CODE FROM dbo.table_name INNER JOIN dbo.table_name ON dbo.table_name.SSN = #SSN";
protected void Page_Load(object sender, EventArgs e)
{
// ...
if(!IsPostBack)
{
GetEmployeeInformation();
}
}
private void GetEmployeeInformation()
{
var sctTextBox = (TextBox)Page.PreviousPage.FindControl("Txtsct");
Txtsct.Text = txtsct.Text;
var ssnTextBox = (TextBox)Page.PreviousPage.FindControl("Txtssn");
Txtssn.Text = ssnTextBox.Text;
var ssn = ssnTextBox.Text;
var employee = GetEmployeeBySSN(ConnectionString.Value, ssn);
if(employee != null)
{
LblFName.Text = employee.FirstName;
LblLName.Text = employee.LastName;
}
}
private Employee GetEmployeeBySSN(string connectionString, string ssn)
{
Employee employee = null;
using(var connection = new SqlConnection(connectionString))
{
connection.Open();
using(var command = new SqlCommand(GetEmployeeBySSNQuery, connection)
{
command.Parameters.AddWithValue("#SSN", ssn);
using(var reader = command.ExecuteReader())
{
if(reader.Read())
{
employee = new Employee
{
FirstName = Convert.ToString(reader["FIRST_NAME"]),
LastName = Convert.ToString(reader["LAST_NAME"])
};
}
}
}
}
return employee;
}

Related

Wrong Logic of Auto Incrementing of string?

Below these code I'm getting the wrong output in incrementing the string value in my Database column "SupplierID". I'm transferring the string value to my lbl_id in ADDSupplier Form and That's what i used to insert value to my "SupplierID".
Desired Output:
SPPL-0001
SPPL-0002
SPPL-0003
etc
Currently Output (Below these code):
SPPL-0001
SPPL-00012
SPPL-00013
etc
NOTE: When i repeat inserting data i get the currently output that i stated above but when i restart the program and the last inserted value, For example is SPPL-00013. When i open my adding form, lbl_id display the id as SPPL-0004. If i continue, it become SPPL-00045.
PS: SupplierID is varchar(50) in my database and also PRIMARY_KEY
These image shows the wrong output of mine
What i want to get help with is to correct my logic and get that desired output. Please help me. Thank you
public partial class SIMSSupplier : UserControl
{
ADDSupplier supply;
public SIMSSupplier()
{
InitializeComponent();
}
public string ID = "SPPL-000";
public void GenerateAutoID()
{
using (var con = SQLConnection.GetConnection())
{
using (var select = new SqlCommand("Select Count(SupplierID) from admin_supplier", con))
{
int i = Convert.ToInt32(select.ExecuteScalar());
i++;
supply.lbl_id.Text = ID + i.ToString();
}
}
}
private void btn_register_Click(object sender, EventArgs e)
{
supply = new ADDSupplier(this);
supply.Show();
GenerateAutoID();
}
}
public partial class ADDSupplier : MetroForm
{
SIMSSupplier _view;
public ADDSupplier(SIMSSupplier _view)
{
InitializeComponent();
this._view = _view;
}
string date = DateTime.Now.ToString("MMMM-dd-yyyy");
private void btn_ok_Click(object sender, EventArgs e)
{
_view.ID = lbl_id.Text;
using (var con = SQLConnection.GetConnection())
{
if (string.IsNullOrEmpty(txt_name.Text) || string.IsNullOrEmpty(txt_contact.Text) || string.IsNullOrEmpty(cbox_remark.Text) || string.IsNullOrEmpty(txt_address.Text))
{
CustomNotifcation.Show("Please input the required fields", CustomNotifcation.AlertType.warning);
}
else
{
using (var select = new SqlCommand("Insert into admin_supplier (SupplierID, Companyname, Contactnumber, Date, Remarks, Address) Values (#SupplierID, #Companyname, #Contactnumber, #Date, #Remarks, #Address)", con))
{
select.Parameters.Add("#SupplierID", SqlDbType.VarChar).Value = lbl_id.Text;
select.Parameters.Add("#Companyname", SqlDbType.VarChar).Value = txt_name.Text;
select.Parameters.Add("#Contactnumber", SqlDbType.VarChar).Value = txt_contact.Text;
select.Parameters.Add("#Date", SqlDbType.VarChar).Value = date;
select.Parameters.Add("#Remarks", SqlDbType.VarChar).Value = cbox_remark.Text;
select.Parameters.Add("#Address", SqlDbType.VarChar).Value = txt_address.Text;
select.ExecuteNonQuery();
CustomMessage.Show("Message: Supplier successfully added!", CustomMessage.Messagetype.Success2);
_view._Supplier();
}
}
}
}
}
You just need to use a format string instead:
string ID = "SPPL-"
supply.lbl_id.Text = ID + i.ToString("0000");
Which will result in the format being applied correctly. Right now you are appending the i variable to the ID, which is already SPPL-000, so the next one becomes SPPL-0001, etc.

get all row and column data using SELECT - C#

I'm trying to get all data from an SQL table and store it in a List using the C# programming language.
the SQL statement I'm using is:
private string cmdShowEmployees = "SELECT * FROM Employees;";
This is being used in the same class as a function
public List<string> showAllIdData()
{
List<string> id = new List<string>();
using (sqlConnection = getSqlConnection())
{
sqlCommand.Connection = sqlConnection;
sqlCommand.CommandText = cmdShowEmployees;
SqlDataReader reader = sqlCommand.ExecuteReader();
while (reader.Read()) {
id.Add(reader[0].ToString());
}
return id;
}
}
and here
public List<string> showAllActiveData()
{
List<string> active = new List<string>();
using (sqlConnection = getSqlConnection())
{
sqlCommand.Connection = sqlConnection;
sqlCommand.CommandText = cmdShowEmployees;
SqlDataReader reader = sqlCommand.ExecuteReader();
while (reader.Read()) {
active.Add(reader[1].ToString());
}
return active;
}
I would have to create 9 more functions this way in order to get all the data out of the Employees table. This seems very inefficient and I was wondering if there was a more elegant way to do this.
I know using an adapter is one way to do it but I don't think it is possible to convert a filled adapter to a list, list list etc.
SqlDataAdapter adapter = sqlDataCollection.getAdapter();
DataSet dataset = new DataSet();
adapter.Fill(dataset, "idEmployees");
dataGridView1.DataSource = dataset;
dataGridView1.DataMember = "idEmployees";
Any ideas?
If you must use the reader in this way, why not create an object which holds the table row data.
public class SomeComplexItem
{
public string SomeColumnValue { get; set;}
public string SomeColumnValue2 { get; set;}
public string SomeColumnValue3 { get; set;}
public string SomeColumnValue4 { get; set;}
}
That way you can loop through with your reader as follows:
public List<SomeComplexItem> showAllActiveData()
{
List<SomeComplexItem> active = new List<SomeComplexItem>();
using (sqlConnection = getSqlConnection())
{
sqlCommand.Connection = sqlConnection;
sqlCommand.CommandText = cmdShowEmployees;
SqlDataReader reader = sqlCommand.ExecuteReader();
while (reader.Read())
{
var someComplexItem = new SomeComplexItem();
someComplexItem.SomeColumnValue = reader[1].ToString();
someComplexItem.SomeColumnValue2 = reader[2].ToString();
someComplexItem.SomeColumnValue3 = reader[3].ToString();
active.Add(someComplexItem);
}
return active;
}
You could use two select statements to populate two List<string> as shown in the example below where the key between reads is reader.NextResult();.
The database used is the standard Microsoft NorthWind database.
using System;
using System.Collections.Generic;
using System.Data.SqlClient;
using System.Linq;
namespace SQL_Server_TwoList
{
public class DataOperations
{
public List<string> Titles { get; set; }
public List<string> Names { get; set; }
/// <summary>
/// Trigger code to load two list above
/// </summary>
public DataOperations()
{
Titles = new List<string>();
Names = new List<string>();
}
public bool LoadData()
{
try
{
using (SqlConnection cn = new SqlConnection(Properties.Settings.Default.ConnectionString))
{
string commandText = #"
SELECT [TitleOfCourtesy] + ' ' + [LastName] + ' ' + [FirstName] As FullName FROM [NORTHWND.MDF].[dbo].[Employees];
SELECT DISTINCT [Title] FROM [NORTHWND.MDF].[dbo].[Employees];";
using (SqlCommand cmd = new SqlCommand(commandText, cn))
{
cn.Open();
SqlDataReader reader = cmd.ExecuteReader();
// get results into first list from first select
if (reader.HasRows)
{
while (reader.Read())
{
Names.Add(reader.GetString(0));
}
// move on to second select
reader.NextResult();
// get results into first list from first select
if (reader.HasRows)
{
while (reader.Read())
{
Titles.Add(reader.GetString(0));
}
}
}
}
}
return true;
}
catch (Exception)
{
return false;
}
}
}
}
Form code
namespace SQL_Server_TwoList
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
private void button1_Click(object sender, EventArgs e)
{
DataOperations dataOps = new DataOperations();
if (dataOps.LoadData())
{
listBox1.DataSource = dataOps.Names;
listBox2.DataSource = dataOps.Titles;
}
}
}
}
You could always add it all to a dataset or datatable instead of looping through using datareader to add to an array, dataset allows you to access data in similar way to array anyway.
Connstr = "Data Source = " + SelectedIP + "; Initial Catalog = " + dbName + "; User ID = " + txtUsername.Text +"; Password = "+ txtPassword.Text +"";
conn = new SqlConnection(Connstr);
try
{
string contents = "SELECT * FROM ..."
conn.Open();
SqlDataAdapter da_1 = new SqlDataAdapter(contents, conn); //create command using contents of sql file
da_1.SelectCommand.CommandTimeout = 120; //set timeout in seconds
DataSet ds_1 = new DataSet(); //create dataset to hold any errors that are rturned from the database
try
{
//manipulate database
da_1.Fill(ds_1);
if (ds_1.Tables[0].Rows.Count > 0) //loop through all rows of dataset
{
for (int i = 0; i < ds_1.Tables[0].Rows.Count; i++)
{
//rows[rownumber][column number/ "columnName"]
Console.Write(ds_1.Tables[0].Rows[i][0].ToString() + " ");
}
}
}
catch(Exception err)
{}
conn.Close();
}
catch(Exception ex)
{}

Can't log into website

Im trying to create a login form for a website using ms access database. I'm using visual studio 2010 c# and access 2013. For some reason I can't get it to log in. I'm really new to this so any help is appreciated.
DataLayer:
public class DataConnector
{
protected OleDbDataAdapter DataAdapter1 = new OleDbDataAdapter();
public string ErrorMessage = "";
public DataConnector(string ConnectionString)
{
OleDbConnection Connection1 = new OleDbConnection(ConnectionString);
this.DataAdapter1.SelectCommand = new OleDbCommand("", Connection1);
this.DataAdapter1.InsertCommand = new OleDbCommand("", Connection1);
}
public DataTable DataSelect(string query)
{
DataTable dt = new DataTable();
try
{
DataAdapter1.SelectCommand.CommandText = query;
DataAdapter1.SelectCommand.Connection.Open();
DataAdapter1.Fill(dt);
DataAdapter1.SelectCommand.Connection.Close();
ErrorMessage = "";
}
catch(Exception err)
{
ErrorMessage = err.Message;
DataAdapter1.SelectCommand.Connection.Close();
}
return dt;
}
public int DataInsert(string query)
{
int Result = 0;
try
{
DataAdapter1.InsertCommand.CommandText = query;
DataAdapter1.InsertCommand.Connection.Open();
Result = DataAdapter1.InsertCommand.ExecuteNonQuery();
DataAdapter1.InsertCommand.Connection.Close();
ErrorMessage = "";
return Result;
}
catch (Exception err)
{
ErrorMessage = err.Message;
DataAdapter1.InsertCommand.Connection.Close();
return 0;
}
}
public int DataUpdate(string query)
{
return DataInsert(query);
}
public int DataDelete(string query)
{
return DataInsert(query);
}
}
Default.aspx.cs:
public partial class Default : System.Web.UI.Page
{
protected void Page_Load(object sender, EventArgs e)
{
}
protected void btnLogin_Click(object sender, EventArgs e)
{
DataLayer.DataConnector dat = new DataLayer.DataConnector("Provider=Microsoft.ACE.OLEDB.12.O;"+"Data Source='"+Server.MapPath("site_database.accdb")+"'; Persist Security Info=False;");
DataTable dt = dat.DataSelect("select UserID from tbl_login where Username = '" + txtUsername.Text + "' and Password = '"+ txtPassword.Text +"' ");
if (dt.Rows.Count > 0)
{
Response.Redirect("members_area.aspx");
}
else
lblerror.Text = "Login failed";
}
}
I'm not getting any errors and I just can't figure it out. When I try to log in it just stays on the default.aspx page.
Part of the problem could very well be that PASSWORD is a reserved word in Access SQL, so if you want to use it as a field name in a query you should surround it in square brackets, e.g.
... WHERE Username = ... AND [Password] = ...
Note also that you really should be using a parameterized query in case Little Bobby Tables tries to log in.

Drop Down List Selected Item

I am trying to select a dynamic data from drop down list and view the details of selected items. I have no problem in populating the drop down list with data from database. However, when I selected some items, it does not shows up the detail.
In my presentation layer, when drop down list item is selected:
protected void ddlScheduleList_SelectedIndexChanged(object sender, EventArgs e)
{
string address = ddlScheduleList.SelectedItem.ToString();
Distribution scheduledIndv = new Distribution();
scheduledIndv = packBLL.getDistributionDetail(address);
if (scheduledIndv == null)
{
Console.Out.WriteLine("Null");
}
else
{
tbScheduleDate.Text = scheduledIndv.packingDate.ToString();
tbBeneficiary.Text = scheduledIndv.beneficiary;
}
}
In my business logic layer, I get the selected address and pass it to data access layer:
public Distribution getDistributionDetail(string address)
{
Distribution scheduledIndv = new Distribution();
return scheduledIndv.getDistributionDetail(address);
}
In my data access layer, I tested out the SQL statement already. It gives me what I wanted. But it just won't show up in web page.
public Distribution getDistributionDetail(string address)
{
Distribution distributionFound = null;
using (var connection = new SqlConnection(FoodBankDB.GetConnectionString())) // get your connection string from the other class here
{
SqlCommand command = new SqlCommand("SELECT d.packingDate, b.name FROM dbo.Distributions d " +
" INNER JOIN dbo.Beneficiaries b ON d.beneficiary = b.id " +
" WHERE b.addressLineOne = '" + address + "'", connection);
connection.Open();
using (var dr = command.ExecuteReader())
{
if (dr.Read())
{
DateTime packingDate = DateTime.Parse(dr["packingDate"].ToString());
string beneficiary = dr["beneficiary"].ToString();
distributionFound = new Distribution(packingDate, beneficiary);
}
}
}
return distributionFound;
}
And my execute Reader method in another separated class:
public static string connectionString = Properties.Settings.Default.connectionString;
public static string GetConnectionString()
{
return connectionString;
}
public static SqlDataReader executeReader(string query)
{
SqlDataReader result = null;
System.Diagnostics.Debug.WriteLine("FoodBankDB executeReader: " + query);
SqlConnection connection = new SqlConnection(connectionString);
SqlCommand command = new SqlCommand(query, connection);
connection.Open();
result = command.ExecuteReader();
connection.Close();
return result;
}
I wonder what went wrong. Is it about the (!IsPostBack) or?
Thanks in advance.
You found your mistake, but to avoid Sql Injection, modify your code like this:
SqlCommand command = new SqlCommand("SELECT d.packingDate, b.name FROM dbo.Distributions d " +
" INNER JOIN dbo.Beneficiaries b ON d.beneficiary = b.id " +
" WHERE b.addressLineOne = #address", connection);
command.Parameters.AddWithValue("#address", address);

When dynamically assigning values to an ASP DropDownList using LINQ, I get a literal string returned for DataValueField

So I've been working on learning LINQ, and I think I'm doing this correctly, but when I spit out the value of the DropDownList's DataValueField property, it comes back as the string "mId" rather than the actual value (the menu_id). Even more strange, the DataTextField is being populated correctly, using the same syntax. Anyone have any ideas?
Here's my code:
protected void Page_Load(object sender, EventArgs e)
{
List<RobDAL.Menu.menuObj> menuInfo = new List<RobDAL.Menu.menuObj>();
menuInfo = RobDAL.Menu.GetMenuText();
menu.DataSource = from myMenu in menuInfo
select new { Text = myMenu.menuText,
mId = myMenu.menuId };
menu.DataValueField = "mId";
menu.DataTextField = "Text";
menu.DataBind();
}
Here's my Menu class:
public class Menu
{
public static int GetMainMenuByContentId(int contentid)
{
//SqlConnection connection = new SqlConnection(Configuration.ConnectionInfo);
Content myContent = new Content();
int menuid;
string queryString = "SELECT menu_id FROM menu_to_item_tbl where content_id = " + contentid + ";";
using (SqlConnection connection = new SqlConnection(Configuration.ConnectionInfo))
{
SqlCommand command = new SqlCommand(queryString, connection);
connection.Open();
try
{
menuid = (int)command.ExecuteScalar();
}
finally
{
// Always call Close when done reading.
connection.Close();
}
return menuid;
}
}
public static List<menuObj> GetMenuText()
{
//SqlConnection connection = new SqlConnection(Configuration.ConnectionInfo);
List<menuObj> allMenus = new List<menuObj>();
string queryString = "SELECT DISTINCT menu_id, menu_title FROM menu_to_item_tbl;";
using (SqlConnection connection = new SqlConnection(Configuration.ConnectionInfo))
{
SqlCommand command = new SqlCommand(queryString, connection);
connection.Open();
SqlDataReader reader = command.ExecuteReader();
try
{
while (reader.Read())
{
menuObj myMenu = new menuObj();
myMenu.menuId = Convert.ToInt16(reader[0]);
myMenu.menuText = reader[1].ToString();
allMenus.Add(myMenu);
}
}
finally
{
reader.Close();
}
return allMenus;
}
}
public class menuObj
{
public string menuText { get; set; }
public int menuId { get; set; }
}
}
Thanks!
Change
menu.DataSource = from myMenu in menuInfo
select new { Text = myMenu.menuText,
mId = myMenu.menuId };
to
menu.DataSource = (from myMenu in menuInfo
select new { Text = myMenu.menuText,
mId = myMenu.menuId }).ToList();;
That is because you have assigned a string to the DataValue property of your drop down list.
menu.DataValueField = "mId".
You might also want to check to see what your linq query is returning for mId.

Categories

Resources