C# getAll Function advice - c#

Hi I am trying to create CRUD functions in C# but am stuck on my first one which is FetchALL, as so far it says not all code path returns a value.
Heres my code so far
public SqlDataReader FetchAll(string tableName)
{
using (SqlConnection conn = new SqlConnection(_ConnectionString,))
{
string query = "SELECT * FROM " + tableName;
SqlCommand command = new SqlCommand(query, conn);
using (SqlDataReader reader = command.ExecuteReader())
conn.Open();
conn.Close();
}
}
}
}
I can give you more information, thanks

You have a return type of SqlDataReader, but you aren't returning anything anywhere in your code. At the very least you should declare your data reader and return it like this:
public SqlDataReader FetchAll(string tableName)
{
SqlDataReader reader;
using (SqlConnection conn = new SqlConnection(_ConnectionString))
{
string query = "SELECT * FROM " + tableName;
// added using block for your command (thanks for pointing that out Alex K.)
using (SqlCommand command = new SqlCommand(query, conn))
{
conn.Open(); // <-- moved this ABOVE the execute line.
reader = command.ExecuteReader(); // <-- using the reader declared above.
//conn.Close(); <-- not needed. using block handles this for you.
}
}
return reader;
}
Note, I've noted a few other problems I saw as well, which you can see by my comments.
Also, I want to point out something very important: you should always avoid string concatenation in queries as this opens you up to the risk of a SQL injection attack (as gmiley has duly pointed out). In this case, you should create an enum which contains values associated with all the possible table names, and then use a dictionary to look up the table names based on their enum values. If a user provides an invalid/unknown value, you would then thrown an argument exception.
This isn't the end of your problems, though (as Default has pointed out). You can't create the connection in a using block, which disposes and closes as soon as it exits the block, and then use the SqlDataReader that is returned from the method. If I were you, I'd return a DataSet instead of a SqlDataReader. Here's how I'd do it:
First, create your enum of possible table values:
public enum Table
{
FirstTable,
SecondTable
}
And a dictionary that maps table enum values to the table names (which you will populate in your static constructor):
private static Dictionary<Table, string> _tableNames = new Dictionary<Table, string>(); // populate this in your static constructor.
And then here is your method to fetch the data:
public static System.Data.DataSet FetchAll(Table fromTable)
{
var ret = new System.Data.DataSet();
using (var conn = new System.Data.SqlClient.SqlConnection(_connectionString))
{
string tableName = "";
if (!_tableNames.TryGetValue(fromTable, out tableName)) throw new ArgumentException(string.Format(#"The table value ""{0}"" is not known.", fromTable.ToString()));
string query = string.Format("SELECT * FROM {0}", tableName);
using (var command = new System.Data.SqlClient.SqlCommand(query, conn))
{
using (var adapter = new System.Data.SqlClient.SqlDataAdapter(command))
{
adapter.Fill(ret);
}
}
}
return ret;
}
One final note, I'd advise you name your class-level variables with lower camel case per convention, e.g. _connectionString.

Firstly you aren't returning anything from the method. I'd add, are you sure you want to return a SqlDataReader? It is declared within a using block, so it will be closed by the time you return it anyway. I think you should re-evaluate what this function should return.

You need a return statment for the method to return a value.

Related

Invalid Column Name | C#

I am trying to figure out how to collect data from a database with c#.
I am stuck on a SQL command, and I can't really figure out how to fix it.
My error is: Invalid Column Name
This is my database:
MyDatabase
And this is my connection class:
namespace CarDAL
{
public class ConnectionClass
{
private string Connectionstring =
"MYCONNECTIONSTRING";
public List<string> SoortSelectList(string KarakterSoort)
{
KarakterSoort = "Defensive";
List<string> soortList = new List<string>();
using (SqlConnection connection = new SqlConnection(Connectionstring))
{
connection.Open();
using (SqlCommand cmd = new SqlCommand("SELECT * FROM dbo.Karakter WHERE KarakterSoort = Defensive", connection))
{
using (IDataReader dr = cmd.ExecuteReader())
{
while (dr.Read())
{
soortList.Add(dr.GetValue(0).ToString());
soortList.Add(dr.GetValue(1).ToString());
}
}
}
}
return soortList;
}
I think after WHERE that the problem is, but I don't know (and can't find) the right solution for my problem.
Your WHERE clause here:
WHERE KarakterSoort = Defensive
compares the value in the KarakterSoort column to the value in the Defensive column.
Is that really what you want???
Quite possibly, you want to compare to a string literal - then you need to put this into single quotes like this:
WHERE KarakterSoort = 'Defensive'
Now you're selecting all rows where the KarakterSoort column contains the value Defensive
Or if you might want compare to some other value in the future - use a parameter in your query string:
WHERE KarakterSoort = #DesiredValue
and declare it
cmd.Parameters.Add("#DesiredValue", SqlDbType.VarChar, 100);
and set its value before your run the command:
cmd.Parameters["#DesiredValue"].Value = "Defensive";

Read records from one table , and write to another table. Exception occurs procedure or function has too many arguments specified?

I am trying to retrieve list of records from one table , and write to another table. I've used a simple query to retrieve the values to SqlDataReader,then load them to a DataTable. Using the DataTableReader , I am going through the entire data set which is Saved in DataTable. The problem is, while reading each and every record I am trying to insert those values to another table using a Stored Procedure.But it only insert the first row of values,and for the second row onward giving some Exception saying."procedure or function has too many arguments specified".
string ConStr = ConfigurationManager.ConnectionStrings["ConString"].ConnectionString;
SqlConnection NewCon = new SqlConnection(ConStr);
NewCon.Open();
SqlCommand NewCmd3 = NewCon.CreateCommand();
NewCmd3.CommandType = CommandType.Text;
NewCmd3.CommandText ="select * from dbo.Request_List where group_no ='" +group_no+ "'";
NewCon.Close();
NewCon.Open();
SqlDataReader dr = (SqlDataReader)NewCmd3.ExecuteReader();
DataTable dt = new DataTable();
dt.Load(dr);
DataTableReader reader = new DataTableReader(dt);
NewCmd.Dispose();
NewCon.Close();
NewCon.Open();
SqlCommand NewCmdGrpReqSer = NewCon.CreateCommand();
NewCmdGrpReqSer.CommandType = CommandType.StoredProcedure;
NewCmdGrpReqSer.CommandText = "Voucher_Request_Connection";
if (reader.HasRows)
{
int request_no = 0;
while (reader.Read())
{
request_no = (int)reader["request_no"];
NewCmdGrpReqSer.Parameters.Add("#serial_no", serial_no);
NewCmdGrpReqSer.Parameters.Add("#request_no", request_no);
try
{
NewCmdGrpReqSer.ExecuteNonQuery();
MessageBox.Show("Connection Updated");//just to check the status.tempory
}
catch (Exception xcep)
{
MessageBox.Show(xcep.Message);
}
MessageBox.Show(request_no.ToString());//
}
NewCmdGrpReqSer.Dispose();
NewCon.Close();
}
Any Solutions ?
As #Sparky suggests, the problem is that you continue to add parameters to the insertion command. There are several other ways in which the code could be improved, however. These improvements would remove the need to clear the parameters and would help to make sure you don't leave disposable resources undisposed.
First - use the using statement for your disposable objects. This removes the need for the explicit Close (btw, only one of Close/Dispose is needed for the connection as I believe Dispose calls Close). Second, simply create a new command for each insertion. This will prevent complex logic around resetting the parameters and, possibly, handling error states for the command. Third, check the results of the insertion to make sure it succeeds. Fourth, explicitly catch a SqlException - you don't want to accidentally hide unexpected errors in your code. If it's necessary to make sure all exceptions don't bubble up, consider using multiple exception handlers and "doing the right thing" for each case - say logging with different error levels or categories, aborting the entire operation rather than just this insert, etc. Lastly, I would use better variable names. In particular, avoid appending numeric identifiers to generic variable names. This makes the code harder to understand, both for others and for yourself after you've let the code sit for awhile.
Here's my version. Note there are several other things that I might do such as make the string literals into appropriately named constants. Introduce a strongly-typed wrapper around the ConfigurationManager object to make testing easier. Remove the underscores from the variable names and use camelCase instead. Though those are more stylistic in nature, you might want to consider them as well.
var connectionString = ConfigurationManager.ConnectionStrings["ConString"].ConnectionString;
using (var newConnection = new SqlConnection(connectionString))
{
newConnection.Open();
using (var selectCommand = newConnection.CreateCommand())
{
selectCommand.CommandType = CommandType.Text;
select.CommandText ="select request_no from dbo.Request_List where group_no = #groupNumber";
selectCommand.Parameters.AddWithValue("groupNumber", group_no);
using (dataReader = (SqlDataReader)newCommand.ExecuteReader())
{
while (reader.HasRows && reader.Read())
{
using (var insertCommand = newConnection.CreateCommand())
{
insertCommand.CommandType = CommandType.StoredProcedure;
insertCommand.CommandText = "Voucher_Request_Connection";
var request_no = (int)reader["request_no"];
insertCommand.Parameters.Add("#serial_no", serial_no);
insertCommand.Parameters.Add("#request_no", request_no);
try
{
if (insertCommand.ExecuteNonQuery() == 1)
{
MessageBox.Show("Connection Updated");//just to check the status.tempory
}
else
{
MessageBox.Show("Connection was not updated " + request_no);
}
}
catch (SqlException xcep)
{
MessageBox.Show(xcep.Message);
}
MessageBox.Show(request_no.ToString());//
}
}
}
}
}
Try clearing your parameters each time...
while (reader.Read())
{
request_no = (int)reader["request_no"];
// Add this line
NewCmdGrpReqSer.Parameters.Clear();
NewCmdGrpReqSer.Parameters.Add("#serial_no", serial_no);
NewCmdGrpReqSer.Parameters.Add("#request_no", request_no);
try
{

asp.net C# database table column to list

I have an asp.net project done in C# (my C# syntax is very rusty) and am using the built in database it creates with the project. I've created a table called aspnet_Tutorials that (for now) stores two columns of user submitted data: TutorialName and TutorialContent. Very simple, it's a learning project.
What I need to do is create a list from the first column of aspnet_Tutorials to use it to create a "directory" of the tutorials on a page. The part I'm having trouble with, mostly syntactically, is connecting to and iterating over the column to get the values into a list. Could anyone provide a straight forward example of this? And possibly explain what's going on in the code.
public class TutorialsDirDAL
{
SqlConnection conn = new SqlConnection(ConfigurationManager.ConnectionStrings["ApplicationServices"].ConnectionString);
SqlCommand cmd = new SqlCommand();
SqlDataAdapter da = new SqlDataAdapter();
DataSet ds = new DataSet();
public List<string> DisplayTutorials() //parameters? String qry?
{
//query the database table, foreach loop over the data, place it into a list?
}
}
I know how to write simple sql queries. But I've seen a couple different set ups for this in my Googling spree. I currently have the following for a query, feel free to pick it apart or offer a better solution than using a query.
cmd.CommandText = "SELECT * FROM ASPNET_TUTORIALS (TutorialTitle)"
+ "VALUES (#tutorialTitle)";
Thank you!
ebad86's answer is acceptable but since you are obviously learning I think introducing OO principals muddy the water with what you are trying to learn at this point.
Here is a basic method:
private void GetData()
{
//The object that will physically connect to the database
using(SqlConnection cnx = new SqlConnection("<your connection string>")
{
//The SQL you want to execute
SqlCommand cmd = new SqlCommand("SELECT * FROM ASPNET_TUTORIALS");
//Open the connection to the database
cnx.Open();
//execute your command
using (IDataReader dataReader = cnx.ExecuteReader(cmd))
{
//Loop through your results
while(dataReader.Read())
{
//do whatever to the data
ListItem item = new ListItem(Convert.ToString(dataReader["TutorialName"]));
lst.Items.Add(item);
}
}
}
}
This is all very straightforward. The part you are most interested in is the while loop though. The loop will go through all of the returned records and you can do whatever you need to do with them. In my example I have assumed that there is a ListBox named 'lst' and I am simply adding ListItems to it that will have the name of whatever 'TutorialName' is. You can make literally do whatever you need to do with the data at this point. To fit your example (returning a List) you would do this:
private List<string> GetData()
{
List<string> lst = new List<string>();
//The object that will physically connect to the database
using(SqlConnection cnx = new SqlConnection("<your connection string>")
{
//The SQL you want to execute
SqlCommand cmd = new SqlCommand("SELECT * FROM ASPNET_TUTORIALS");
//Open the connection to the database
cnx.Open();
//execute your command
using (IDataReader dataReader = cnx.ExecuteReader(cmd))
{
//Loop through your results
while(dataReader.Read())
{
lst.Add(Convert.ToString(dataReader["TutorialName"]));
}
}
}
return lst;
}
Please respond if you have any questions.
Well you can fetch using data reader and map to the object. I can give you some rough code, which could be like this:
using (IDataReader objDataReader = objDB.ExecuteReader(objCMD))
{
while (objDataReader.Read())
{
DataBaseObject obj = new DataBaseObject();
obj = MapObjectToList(objDataReader);
ObjectList.Add(obj);
}
objDataReader.Dispose();
}
// Mapping Function can be called somewhat like this:
private DataBaseObject MapObjectToList(IDataReader objDataReader)
{
DataBaseObject obj = new DataBaseObject();
obj.Prop1Name = base.GetDataValue<string>(objDataReader, "Column1Name");
obj.Prop2Name = base.GetDataValue<string>(objDataReader, "Column2Name");
return obj;
}
But this is just a rough idea how I would do it.

C# List<int> populated from SQL Stored Procedure results

I'm using C# in VS 2005 (.NET 2.0) and SQL Studio 2005 on an older CMS made in the mid-'00s. I'm tasked with creating a new permission gate that allows only certain users to see certain parts of the site.
I need help populating a List list based on feedback I got when I posted this question: Populate ArrayList from Stored Procedure result set
So, now, how do get get the values from the stored procedure into a List? I realize this is a novice question but I'm a novice...
Any help is greatly appreciated.
Assuming you are getting your results from a DataReader, all you have to do is read each row to add the value to a list.
List<int> ReadList(IDataReader reader)
{
List<int> list = new List<int>();
int column = reader.GetOrdinal("MyColumn");
while (reader.Read())
{
list.Add(reader.GetInt32(column));
}
return list;
}
Remember to dispose of the DataReader when you are done with it.
You can try using the model located on this MSDN page under Using Parameters with a SqlCommand and a Stored Procedure. The example is shown here:
static void GetSalesByCategory(string connectionString, string categoryName)
{
using (SqlConnection connection = new SqlConnection(connectionString))
{
// Create the command and set its properties.
SqlCommand command = new SqlCommand();
command.Connection = connection;
command.CommandText = "SalesByCategory"; //Stored Procedure Name
command.CommandType = CommandType.StoredProcedure;
// Add the input parameter and set its properties.
SqlParameter parameter = new SqlParameter();
parameter.ParameterName = "#CategoryName";
parameter.SqlDbType = SqlDbType.NVarChar;
parameter.Direction = ParameterDirection.Input;
parameter.Value = categoryName;
// Add the parameter to the Parameters collection.
command.Parameters.Add(parameter);
// Open the connection and execute the reader.
connection.Open();
SqlDataReader reader = command.ExecuteReader();
if (reader.HasRows)
{
while (reader.Read())
{
//Instead of displaying to console this is where you would add
// the current item to your list
Console.WriteLine("{0}: {1:C}", reader[0], reader[1]);
}
}
else
{
Console.WriteLine("No rows found.");
}
reader.Close();
}
}
it depends on how you have retreived the results
reader?
dataset?
something else?
walk through the results using
foreach (int item in object...) {
List.Add(item);
}
or possibly (I dont remember the exact DataRow syntax off the top of my head...)
foreach (datarow row in object.table[0].rows) {
List.Add(row[0]);
}
IList<int> myInts = new List<int>();
using (IDbConnection connection = new SqlConnection("yourConnectionStringGoesHere"))
{
using (IDbCommand command = new SqlCommand("spName", connection))
{
command.CommandType = CommandType.StoredProcedure;
//command.Parameters.Add(...) if you need to add any parameters to the SP.
connection.Open();
using (IDataReader reader = command.ExecuteReader(CommandBehavior.CloseConnection))
{
myInts.Add(Int32.Parse(reader["someIntField"].ToString()));
}
}
}
Since you already have the table the idea would be to iterate over that table while adding the IDs of the vendor into a list.
List<VendorID_Data_Type> myList = new List<VendorID_Data_Type>();
foreach(DataRow r in GetAllVendors().Rows)
{
myList.Add(r["VendorID"]);
}
What I ended up doing is using a DataTable as an intermediary data type, which is populated by the stored procedure. Then, refactoring the DataTable as the data-source in a foreach loop, I populated the List. I needed to open a second question to get to this conclusion: 2-Column DataTable to List<int> .NET 2.0

Retrieving records from a database in C# 2008

I need syntax help with the following code logic:
I have a code block that gets email address from the database. The email addresses need to be assigned to a string variable strEmailAddress with a comma seperation
My code is:
SqlConnection conn = new SqlConnection(strConn);
string sqlEmailAddress = "usp_Get_Email_Address";
SqlCommand cmdEmailAddr = new SqlCommand(sqlEmailAddress, conn);
cmdEmailAddr.CommandType = CommandType.StoredProcedure;
con.Open();
SqlDataReader sqlDREmailAddr = cmdEmailAddr.ExecuteReader();
How can I loop through the records and store the results in strEmailAddress seperated by comma?
while (sqlDREmailAddr.Read())
{
//...process each row here
}
I would also wrap the reader in a using statement to make sure it is closed properly:
using (SqlDataReader sqlDREmailAddr = cmdEmailAddr.ExecuteReader())
{
}
Depending on what the columns in your dataset is named, reading values from each record will look something like this (update: now with all addresses merged):
var emailAddress = new StringBuilder();
var emailAddressOrdinal = sqlDREmailAddr.GetOrdinal("EmailAddress");
while (sqlDREmailAddr.Read())
{
if (emailAddress.Length > 0)
emailAddress.Append(',');
emailAddress.Append(sqlDREmailAddr.GetString(emailAddressOrdinal));
}
Use the SqlDataReader.Read method:
while (sqlDREmailAddr.Read())
{
...
// Assumes only one column is returned with the email address
strEmailAddress = sqlDREmailAddr.GetString(0);
}
while (sqlDREmailAddr.Read())
{
// handle row here
}
This is what you're looking for....
using (SqlConnection conn = new SqlConnection(strConn)){
string sqlEmailAddress = "usp_Get_Email_Address";
using (SqlCommand cmdEmailAddr = new SqlCommand(sqlEmailAddress, conn)){
cmdEmailAddr.CommandType = CommandType.StoredProcedure;
conn.Open(); // Typo Glitch!
using (SqlDataReader sqlDREmailAddr = cmdEmailAddr.ExecuteReader()){
while(sqlDREmailAddr.Read()){
if (!sqlDREmailAddr.IsDBNull(sqlDREmailAddr.GetOrdinal("emailAddr"))){
// HANDLE THE DB NULL...
}else{
strEmailAddress = sqlDREmailAddr.GetSqlString(sqlDREmailAddr.GetOrdinal("emailAddr"));
// Do something with strEmailAddr...
}
}
}
}
}
Notice:
A typo glitch on the conn variable...
A check is made to ensure that the Database value returned is not NULL
A call is made to GetOrdinal to return the column based on emailAddr string value that corresponds to the column from the query for SQL Select...which is an int type) as the parameter for GetSqlString..
Edit: Thanks to John Saunders for pointing out a blooper!
Edit#2: Thanks to Peter Lillevold for pointing out a mis-spelling...
Hope this helps,
Best regards,
Tom.

Categories

Resources