I made a program, that reads data in the database I use the OleDbDataReader but the problem is I have different tables, this codes works perfectly but I found it a little bit "hardcoded" or recursive here is my sample code
private void loadMilk()
{
cn.Open();
OleDbDataReader reader = null;
OleDbCommand cmd = new OleDbCommand("select* from Milk", cn);
reader = cmd.ExecuteReader();
while (reader.Read())
{
Milk.Add(reader["Product"].ToString());
}
cn.Close();
}
I need to repeat this again and again just to read what's on the other table (e.g., "select* from Fruit then "select* from Classics....) Is there any way so that I will not repeat this code again and again?
thanks.:)
You can refactor that method into something like this:
private IList<string> Load(string tableName, string columnName)
{
var result = new List<string>();
cn.Open();
OleDbDataReader reader = null;
OleDbCommand cmd = new OleDbCommand(string.Format("select* from {0}", tableName), cn);
reader = cmd.ExecuteReader();
while (reader.Read())
{
result.Add(reader[columnName].ToString());
}
cn.Close();
return result;
}
Your code sample will be:
var milkItems = Load("Milk", "Product");
var classicItems = Load("Classics", "..."); //Enter the column here.
Edit:
You might want something a little more specific (eg. storing a List<SomeObject> instead of just List<string>). Let's suppose you sometimes you want to return a list of Person, and also you want to read a list of Building. Then you can write something like this (not compiled & tested):
private IList<T> Load<T>(string tableName, Func<OleDbDataReader, T> selector)
{
IList<T> result = new List<T>();
cn.Open();
OleDbDataReader reader = null;
OleDbCommand cmd = new OleDbCommand(string.Format("select* from {0}", tableName), cn);
reader = cmd.ExecuteReader();
while (reader.Read())
{
result.Add(selector(reader));
}
cn.Close();
return result;
}
and you can call it like:
Func<OleDbDataReader, Person> selector = x => new Person { Name = x["Person"].ToString() };
Load("People", selector);
private void loadMilk(string TableName, string itemValue)
{
string SQLString = String.Format("select * from {0}",TableName);
cn.Open();
OleDbDataReader reader = null;
OleDbCommand cmd = new OleDbCommand(SQLString, cn);
reader = cmd.ExecuteReader();
while (reader.Read())
{
Milk.Add(reader[ItemValue].ToString());
}
cn.Close();
}
Not sure what type "Milk" is.
Try:
private void loadObjectsFrom(string tableName, object obj, string column)
{
cn.Open();
OleDbDataReader reader = null;
OleDbCommand cmd = new OleDbCommand("select* from " + tableName, cn);
reader = cmd.ExecuteReader();
while (reader.Read())
{
obj.Add(reader[column].ToString());
}
cn.Close();
}
Just pass a table name as a parameter:
private void loadMilk(string tableName)
{
cn.Open();
OleDbDataReader reader = null;
OleDbCommand cmd = new OleDbCommand(string.Format("select* from {0}",tableName), cn);
reader = cmd.ExecuteReader();
while (reader.Read())
{
Milk.Add(reader["Product"].ToString());
}
cn.Close();
}
Related
I have this class that tries to read from the sql reader
using Microsoft.Data.SqlClient;
using MinimalAPI.Models.ConnectUI;
namespace ConnectAPI.SQL.BAL
{
public class ConnectData
{
public static Form Get_Froms_Data(int form_Id, string page_Id = null)
{
Form form = new Form();
SqlDataReader reader = ConnectAPI.SQL.DAL.ConnectData.Get_Froms_Data(form_Id, page_Id);
foreach(var row in reader) <-- where the error occurs
{
var t = "";
}
reader.Close();
return form;
}
}
}
And this class to access dal call:
using Microsoft.Data.SqlClient;
using MinimalAPI.Models.ConnectUI;
using System.Data;
namespace ConnectAPI.SQL.DAL
{
public class ConnectData
{
static string sqlconnectionstring = "xxx";
public static SqlDataReader Get_Froms_Data(int form_Id, string page_Id = null)
{
string procedurename = "getFormData";
SqlDataReader reader = null;
using (SqlConnection con = new SqlConnection(sqlconnectionstring))
{
con.Open();
using (SqlCommand cmd = new SqlCommand(procedurename, con))
{
cmd.CommandType = System.Data.CommandType.StoredProcedure;
cmd.Parameters.Add("#formId", SqlDbType.Int).Value = form_Id;
cmd.Parameters.Add("#pageId", SqlDbType.NVarChar, 50).Value = page_Id;
reader = cmd.ExecuteReader();
}
con.Close();
}
return reader;
}
}
}
but i keep getting the error:
System.InvalidOperationException: 'Invalid attempt to call FieldCount when reader is closed.'
The reader needs an open connection. Therefore, closing the connection effectively closes the reader, too. To get around it, you can start by changing it to return IEnumerable<IDataRecord> via an iterator block, like this:
public class ConnectData
{
static string sqlconnectionstring = "xxx";
public static IEnumerable<IDataRecord> Get_Froms_Data(int form_Id, string page_Id = null)
{
string procedurename = "getFormData";
using var con = new SqlConnection(sqlconnectionstring);
using var cmd = new SqlCommand(procedurename, con);
cmd.CommandType = System.Data.CommandType.StoredProcedure;
cmd.Parameters.Add("#formId", SqlDbType.Int).Value = form_Id;
cmd.Parameters.Add("#pageId", SqlDbType.NVarChar, 50).Value = page_Id;
con.Open();
using var reader = cmd.ExecuteReader();
while (rdr.Read())
{
yield return reader;
}
}
}
But there is still an issue here, in that we are yielding the same object over and over as it mutates. This can have some strange or unexpected consequences. We can fix this by making sure to construct a new object before returning to other code and yielding the new object. We can also improve this to reduce the amount of boilerplate needed for each method.
public class ConnectData
{
static string sqlconnectionstring = "xxx";
// notice this is private
private static IEnumerable<IDataRecord> GetSQLData(string sql, Action<SqlParameterCollection> addParams, bool AsProcedure = true)
{
using var con = new SqlConnection(sqlconnectionstring);
using var cmd = new SqlCommand(sql, con);
if (AsProcedure) cmd.CommandType = System.Data.CommandType.StoredProcedure;
if (addParams is object) addParams(cmd.Parameters);
con.Open();
using var reader = cmd.ExecuteReader();
while (rdr.Read())
{
yield return reader;
}
}
// I don't know what kind of item you're returning here, had to make it up
public static IEnumerable<FormItem> Get_Forms_Data(int form_Id, string page_Id = null)
{
string procedurename = "getFormData";
var data = GetSqlData(procedureName, p => {
p.Add("#formId", SqlDbType.Int).Value = form_Id;
p.Add("#pageId", SqlDbType.NVarChar, 50).Value = page_Id;
}, true);
foreach(var row in data)
{
// again: I don't know what your records look like
yield return new FormItem( row["column"]);
}
}
}
I was reading the example here:
https://msdn.microsoft.com/en-us/library/fksx3b4f.aspx
And wanted to do a test reading that select and writing it into a file:
SqlConnection sqlConnection1 = new SqlConnection("Your Connection String");
SqlCommand cmd = new SqlCommand();
SqlDataReader reader;
cmd.CommandText = "SELECT * FROM Customers";
cmd.CommandType = CommandType.Text;
cmd.Connection = sqlConnection1;
sqlConnection1.Open();
reader = cmd.ExecuteReader();
// Data is accessible through the DataReader object here.
System.IO.File.WriteAllText(#"C:\stupidtest\customers.txt", reader.ReadToEnd());
sqlConnection1.Close();
But i can't because 'SqlDataReader' does not contain a definition for 'ReadToEnd' and no extension method 'ReadToEnd' accepting a first argument of type 'SqlDataReader' could be found.
So how can i get that simple select into a txt file with an output like this one?
dasdgdsgsdg asgasg sadgasdgasdg agdsfg
sdasdgasdgasgg sdfasdfa sadfasdfasdgasdgasdg sadgasgdgda
a asd gdgasdg asdfgghh
If i use:
using (System.IO.StreamWriter file = new System.IO.StreamWriter(#"C:\stupidtest\customers.txt"))
{
while (reader.HasRows)
{
while (reader.Read())
{
file.WriteLine(reader.GetString());
}
reader.NextResult();
}
could i achieve it?
something like this:
static string ReadToEnd(this SqlDataReader rdr){
StringBuilder MyStringBuilder = new StringBuilder();
while (rdr.Read())
{
String line = "";
for(int i=0;i<rdr.FieldCount;i++)
{
line+=rdr.GetString(i)+#"\t";
}
MyStringBuilder.AppendLine(line);
}
return MyStringBuilder.ToString();
}
I have a SQL query. Just i want to check query returning a values or not using c#. Can any one help on this to fix it. Thanks in advance.
Sqlcommand cmd = new Sqlcomman("select Name from Engdetails",con)
if (query != 0)
{
some coding..
}
else
{
coding...
}
SqlCommand cmd = new SqlCommand("select Name from Engdetails",con)
SqlDataReader reader = cmd.ExecuteReader();
if (reader.Read())
{
// The command returns Row(s)
}
else
{
// No Row has been returned.
}
There are a number of ways to work with sqlCommand; some examples:
using (SqlDataReader reader = cmd.ExecuteReader())
{
if (reader.HasRows)
{
reader.Read();
...
or
using (SqlCommand cmd = new SqlCommand(query, connection))
{
using (SqlDataAdapter adapter = new SqlDataAdapter(cmd))
{
adapter.Fill(data);
}
if it has data, the data will be in data.Tables
SqlCommand cmd = new SqlCommand("select Name from Engdetails", con);
int i = cmd.ExecuteNonQuery();
if (i > 0)
{
// somecoding
}
else
{
// somecoding
}
a example in this case rdr.GetString is Name value of the query.
using (MySqlConnection conn = new MySqlConnection(constr))
{
using (MySqlCommand cmd = new MySqlCommand())
{
MySqlDataReader rdr = null;
string[] dados_bd = new string[2];
conn.Open();
cmd.Connection = conn;
cmd.CommandText = sql;
rdr = cmd.ExecuteReader();
while (rdr.Read())
{
if (estado == 1)
{
dados_bd[0] = rdr.GetString(0);
cmd.ExecuteNonQuery();
For the UPDATE, INSERT, and DELETE statements, the return value is the number of rows affected by the SQL statement.
For all other types of statements, the return value is -1.
How can I add values that a SqlDataReader returns to a generic List? I have a method where I use SqlDataReader to get CategoryID from a Category table. I would like to add all the CategoryID a generic List.
This dose not work because it returns only one categoryID and that is the last one. I want to add all the categoryID to the list and then return them.
How do I do that?
SqlConnection connection = null;
SqlDataReader reader = null;
SqlCommand cmd = null;
try
{
connection = new SqlConnection(connectionString);
cmd = new SqlCommand("select CategoryID from Categories", connection );
connection.Open();
List<int> catID = new List<int>();
dr = cmd.ExecuteReader();
while (dr.Read())
{
catID.Add(Convert.ToInt32(dr["CategoryID"].ToString()));
}
}
finally
{
if (connection != null)
connection.Close();
}
return catID;
Try like this, it's better, safer, uses lazy loading, less code, working, ...:
public IEnumerable<int> GetIds()
{
using (var connection = new SqlConnection(connectionString))
using (var cmd = connection.CreateCommand())
{
connection.Open();
cmd.CommandText = "select CategoryID from Categories";
using (var reader = cmd.ExecuteReader())
{
while (reader.Read())
{
yield return reader.GetInt32(reader.GetOrdinal("CategoryID"));
}
}
}
}
and then:
List<int> catIds = GetIds().ToList();
Your current code should work, assuming catID is really declared before the try block, otherwise this won't compile.
AS BrokenGlass explained this is the demonstration
SqlConnection connection = null;
SqlDataReader dr= null;
SqlCommand cmd = null;
List<int> catID = new List<int>();
try
{
connection = new SqlConnection(connectionString);
cmd = new SqlCommand("select CategoryID from Categories", connection );
connection.Open();
dr = cmd.ExecuteReader();
while (dr.Read())
{
catID.Add(Convert.ToInt32(dr["CategoryID"].ToString()));
}
}
finally
{
if (connection != null)
connection.Close();
}
return catID;
as well as you change the declaration
SqlDataReader reader = null;
to
SqlDataReader dr= null; // Because you are using dr in the code not reader
This should work but I suggest you to use using with your connections
SqlConnection connection = null;
SqlDataReader reader = null;
SqlCommand cmd = null;
List<int> catID = new List<int>();
try
{
connection = new SqlConnection(connectionString);
cmd = new SqlCommand("select CategoryID from Categories", connection );
connection.Open();
dr = cmd.ExecuteReader();
while (dr.Read())
{
catID.Add(Convert.ToInt32(dr["CategoryID"].ToString()));
}
}
finally
{
if (connection != null)
connection.Close();
}
return catID;
List<int> s = new List<int>();
conn.Open();
SqlCommand command2 = conn.CreateCommand();
command2.CommandText = ("select turn from Vehicle where Pagged='YES'");
command2.CommandType = CommandType.Text;
SqlDataReader reader4 = command2.ExecuteReader();
while (reader4.Read())
{
s.Add(Convert.ToInt32((reader4["turn"]).ToString()));
}
conn.Close();
It's easy to bind a data source to something like a gridview or repeater, but how would I do it with a label? Heres the sql connection that I want to modify. By the way, I don't need 2 way binding.
public void Sql_Connection(string queryString)
{
SqlConnection conn = new SqlConnection(System.Configuration.ConfigurationManager.ConnectionStrings["RBConnectionString"].ConnectionString);
SqlCommand cmd = new SqlCommand(queryString, conn);
conn.Open();
cmd.ExecuteNonQuery();
conn.Close();
}
The query I'm using:
SELECT Description FROM RbSpecials WHERE Active=1
public string SqlConnection(string queryString)
{
using (var conn = new SqlConnection(System.Configuration.ConfigurationManager.ConnectionStrings["RBConnectionString"].ConnectionString))
using (var cmd = conn.CreateCommand())
{
conn.Open();
cmd.CommandText = queryString;
using (var reader = cmd.ExecuteReader())
{
while (reader.Read())
{
// This will return the first result
// but there might be other
return reader.GetString(0);
}
}
return null;
}
}
This will also ensure that in case of exception all disposable objects are disposed and will properly return the SQLConnection to the connection pool in order to be reused.
And finally assign the Text property of the label:
lblTest.Text = SqlConnection("SELECT Description FROM RbSpecials WHERE Active=1");
use ExecuteReader rather than ExecuteNonQuery
public void Sql_Connection(string queryString)
{
using(SqlConnection conn = new SqlConnection(System.Configuration.ConfigurationManager.ConnectionStrings"RBConnectionString"].ConnectionString))
{
using(SqlCommand cmd = new SqlCommand(queryString, conn))
{
conn.Open();
using(SqlDataReader rdr = cmd.ExecuteReader())
{
while(rdr.Read())
{
lblDescription.Text = rdr.GetString(0);
}
}
}
}
}
using (SqlConnection con = new SqlConnection(Connection_String))
{
SqlCommand cmd = new SqlCommand("select * from Customers", con);
cmd.CommandType = CommandType.StoredProcedure;
SqlDataReader adpt = cmd.ExecureReader();
if(rdr.Read())
{
lblName.Text = rdr[0].ToString();
}
}