SQL get to C# with SqlDataReader - c#

I have a problem. I want to get data from my SQL Server database. When the code is running, the first row isn't getting added to my arraylist. All other rows get added successfully. In SQL Server, the query works fine, but in VS, it doesn't work.
private void button1_Click(object sender, EventArgs e)
{
SqlConnection baglanti = new SqlConnection("server=.; Initial Catalog=TripData;Integrated Security=SSPI");
baglanti.Open();
SqlCommand komut = new SqlCommand();
komut.CommandText = "select top 50 trip_ID from Sayfa1$";
komut.Connection = baglanti;
komut.ExecuteNonQuery();
SqlDataReader oku = komut.ExecuteReader();
while (oku.Read())
{
foreach (var item in oku)
{
gecici.Add(oku["trip_ID"].ToString());
}
}
}

You're trying to iterate over the reader in two different ways - using both a foreach loop and using while (reader.Read()). You should do one or the other - I've personally seen more code using while (reader.Read()) than the foreach approach.
Additionally I'd suggest using using statements for the disposable objects in your code - and not calling ExecuteNonQuery first. (It's not clear why you're doing that at all). So you could write:
// Note that this looks like a mixture of UI and non-UI code; consider separating
// them for greater code reuse, separation of concerns etc.
private void button1_Click(object sender, EventArgs e)
{
// Declare connectionString elsewhere, or have a common method to open the connection.
// You're likely to need that in multiple places.
using (var connection = new SqlConnection(connectionString))
{
connection.Open();
using (var command = new SqlCommand("select top 50 trip_ID from Sayfa1$", connection))
{
using (var reader = command.ExecuteReader())
{
while (reader.Read())
{
gecici.Add(oku["trip_ID"].ToString());
}
}
}
}
}
(Also if you're really using ArrayList as your post suggests, I'd definitely urge you to start using the generic collections, e.g. List<string> in this case.)

Related

Update if disabled = 0 in C#

I am making a project in C#- in which one can "vote".
When you run the program you first log in. After you've logged in you have to select a value out of a dropdownlist. After you've selected the teacher you press on a button which votes.
The problem is I don't really know how to let this validate properly. And to check if the person has already voted.
It has to check the column in the database named "disabled" if the value = 1 or 0. If the value = 1 they can't vote and if it's 0 they can.
When the person votes it increases the column aantalStemmen by 1. and the disabled column to 1 aswell. Which gets shown in a datagridview.
And the values in the dropdownlist has to match the 1 in the database.
I have this code:
private void db_connection()
{
try
{
conn = "Data Source=localhost;Initial Catalog=docent;Integrated Security=True";
connect = new SqlConnection(conn);
connect.Open();
}
catch (SqlException e)
{
throw;
}
}
private bool validate_disabled(string favoriet)
{
db_connection();
SqlCommand cmd = new SqlCommand();
cmd.CommandText = "Select disabled from leerling";
cmd.Connection = connect;
SqlDataReader disabled = cmd.ExecuteReader();
if (disabled.Read())
{
connect.Close();
return true;
}
else
{
connect.Close();
return false;
}
}
private void btnStem_Click(object sender, EventArgs e)
{
string favoriet = cmbFavoriete.Text;
db_connection();
SqlCommand cmd = new SqlCommand();
bool r = validate_disabled(favoriet);
if(r){
cmd.CommandText = "UPDATE docent SET aantalStemmen = aantalStemmen + 1 where docentid=#id";
cmd.Parameters.AddWithValue("#id", cmbFavoriete.Text);
}
else
{
MessageBox.Show("You have already voted.");
}
}
my tables in my database looks like this:
Thanks in advance, I've been struggling really hard with this as I'm still a rookie in C#.
I will try an answer to cover more aspects of your code (many already mentioned in comments):
1) Declare your connection string outside of your methods. Also choose meaningful variable names - you will than yourself in a few months when you revisit the code.
private const String ConnectionStr = "Data Source=localhost;Initial Catalog=docent;Integrated Security=True";
2. Appropriate names for methods - also, try to use Camel or Pascal case for method names.
3. Pay attention to possible exceptions. SQLException is not the only possible exception when constructing or opening an SqlConnection, so it is better to catch anything that might occur
private SqlConnection createConnection
{
try
{
connect = new SqlConnection(ConnectionStr);
connect.Open();
}
// this is laziness, but it is better than before
catch (Exception e)
{
// best to log the real error somewhere
throw;
}
}
4. Dispose connection and other disposables like SqlCommand. Also var might save some typing (just hover your mouse over the keyword and you will see the actual type).
SqlConnection allows to directly create a command to be executed using that particular connection by using CreateCommand.
Since your are expecting a single value (scalar) (or a single row with a single column), you can use ExecuteScalar method. So, no more reader.
private bool isDisabled(string favoriet)
{
using (var connection = createConnection())
{
using (var cmd = new connection.CreateCommand())
{
cmd.CommandText = "Select disabled from leerling where leerlingnummer = #number";
cmd.Parameters.AddWithValue("#number", favoriet);
// for simplicity I have assumed that it will always find a value. This should be checked
var disabled = Convert.ToBoolean(cmd.ExecuteScalar());
return disabled;
}
}
}
5. Try not to mix UI logic with database logic (they are usually put in different assemblies)
private void castVote(String favoriete)
{
using (var connection = createConnection())
{
using (var cmd = new connection.CreateCommand())
{
cmd.CommandText = "UPDATE docent SET aantalStemmen = aantalStemmen + 1 where docentid = #id";
cmd.Parameters.AddWithValue("#id", cmbFavoriete.Text);
// command must be actually executed, otherwise nothing happens
cmd.ExecuteNonQuery();
}
}
}
private void btnStem_Click(object sender, EventArgs e)
{
string favoriet = cmbFavoriete.Text;
bool r = isDisabled(favoriet);
if (r)
castVote(favoriet);
// maybe, it would make sense to also notify the user that the vote has been cast
else
MessageBox.Show("You have already voted.");
}
6. Use EntityFramework - in order to avoid the troubles related to handling commands and readers, you can use an ORM to do the dirty work for you.
I would suggest you use bit Data Type (0 - false, 1 - true) instead of int Data Type in your table. It does exactly what you need and you don't have to use int for this.
This means you could change your validate_disabled method to use something like this:
cmd.CommandText = "SELECT disabled FROM leerling WHERE disabled = 1 AND leerlingnummer = #favoriet";
cmd.Parameters.AddWithValue("#favoriet", favoriet);
I've assumed string favoriet is equal to leerlingnummer in your table. After you've executed that query, you would simply check if the query contains more than 0 records - if more than 0 records that means the person does not have permission to vote.

How do I properly use a SqlDataReader?

I have 2 methods as below :
internal static SqlDataReader SelectData(string sql)
{
using (var sqlConnection = new SqlConnection(Constant.ConnectionString))
{
sqlConnection.Open();
var sqlCommand = new SqlCommand(sql, sqlConnection);
var dataReader = sqlCommand.ExecuteReader();
return dataReader;
}
}
============
And using this method as :
var dataReader = SelectData(---some sql ---);
private void AddData(dataReader)
{
while (dataReader.Read())
{
Employee e = new Employee();
e.FirstNamei = dataReader["Name"].ToString();
}
dataReader.Close();
}
I know we can merge this two method, but I am looking at better way write this, OR this can cause some problem??
Actually you are in fact leaving yourself open a bit. You really want to write it like this:
using (SqlConnection cnn = new SqlConnection(cnnString))
using (SqlCommand cmd = new SqlCommand(sql, cnn))
{
// use parameters in your SQL statement too, so you can do this
// and protect yourself from SQL injection, so for example
// SELECT * FROM table WHERE field1 = #parm1
cmd.Parameters.AddWithValue("#parm1", val1);
cnn.Open();
using (SqlDataReader r = cmd.ExecuteReader())
{
}
}
because you need to make sure these objects get disposed. Further, by going this direction you don't need dataReader.Close(). It will get called when it gets automatically disposed by the using statement.
Now, wrap that collection of statements inside a try...catch and you're in business.
A couple of things
1) Since you're closing your connection on SelectData, dataReader should blow up on AddData as it requires an open connection
2) AddData shouldn't close dataReader as he didn't open it.
3) Maybe you're hiding some code but I don't see that you use Employee instance created on AddData
Technically, first method would be correct if you would do
sqlCommand.ExecuteReader(CommandBehavior.CloseConnection);
Then, your client would close the reader and your connection will be closed as well.
Second example would also be correct if you didn't close the reader inside of it. There is no criminal in passing the reader to a method just to iterate it. but it has to be controlled from where it was created. How you open and dispose of it - this is different question.

How to display data in gridview from MS Access?

I want to display information of user stored in a MS Access database. The user enters his userid and on clicking a button following function is called. But no data is being displayed. What am I doing wrong ?
System.Data.OleDb.OleDbConnection con;
System.Data.OleDb.OleDbDataAdapter da;
protected void Button1_Click(object sender, EventArgs e)
{
con = new System.Data.OleDb.OleDbConnection();
con.ConnectionString = "Provider=Microsoft.Jet.OLEDB.4.0;"
+ "Data Source=C:\\Users\\sam\\Desktop\\mydb.mdb";
con.Open();
string sql = "SELECT * From Leave where userid="+Textbox1.Text;
da = new System.Data.OleDb.OleDbDataAdapter(sql, con);
DataTable t = new DataTable();
da.Fill(t);
GridView1.DataSource = t;
con.Close();
}
You need to call GridView1.DataBind()
GridView1.DataSource = t;
GridView1.DataBind();
Just a side-note, it is good practice to wrap your connection with using
using(con = new System.Data.OleDb.OleDbConnection())
{
con = new System.Data.OleDb.OleDbConnection();
con.ConnectionString = "Provider=Microsoft.Jet.OLEDB.4.0;"
+ "Data Source=C:\\Users\\sam\\Desktop\\mydb.mdb";
con.Open();
...
...
}
This ensures your connection is properly disposed after use
You should use bind function:
protected void Button1_Click(object sender, EventArgs e)
{
con = new System.Data.OleDb.OleDbConnection();
con.ConnectionString = "Provider=Microsoft.Jet.OLEDB.4.0;"
+ "Data Source=C:\\Users\\sam\\Desktop\\mydb.mdb";
con.Open();
string sql = "SELECT * From Leave where userid="+Textbox1.Text;
da = new System.Data.OleDb.OleDbDataAdapter(sql, con);
DataTable t = new DataTable();
da.Fill(t);
GridView1.DataSource = t;
GridView1.DataBind();
con.Close();
}
First off, please, please please don't concatenate your WHERE parameters in your SQL. Use Parameters. Second, Add a "using System.Data.OleDb" statement at the top of your module, so that you are not having to type things like:
System.Data.OleDb.OleDbDataAdapter
Over and over again.
Try the following code. Personally, when I have to work with data tables and such, I prefer to avoid all the DataAdapter nonsense, and keep it as simple as possible.
Note in the code below:
the "using" blocks. These place the variables created within them inside their own scope, and take care of disposal and such for you.
I used an OleDb Parameter instead of concatenating criteria. This is a much safer way to do things, and creates much cleaner and more readable code as well, especially in cases where you have several criteria in your WHERE clause.
I assume your UserID input is a string, since you are grabbing the value from a Textbox. If it is in fact an int value (such as an auto-incrementing id in MS Access) you will need to use an int data type instead. You may have to mess with it a little. When you are still figuring this stuff out, it can be a bit painful. However, using parameters increases security and maintainability.
Once you have obtained a data table as the return from the MyUsers method, you should be able to simply set the data source of your Gridview. If you have difficulties still, do as Steve suggests and check the Autogenerate columns property in the designer, or set it in code.
Not that I have moved the connection string to the project Properties/Settings. You should find this in the solution designer. Place your connection string there, in one spot, and you can obtain it from anywhere in your code. If you later change the connection string (such as moving your Db to another computer, server share, etc) you need only change it in one place.
SAMPLE CODE:
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.Windows.Forms;
using System.Data.OleDb; // put this here, and stop writing long namespaces inline
namespace WindowsFormsApplication3
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
private void button1_Click(object sender, EventArgs e)
{
// Where possible, move code out of specific event handlers
// into methods which can be re-used from other client code.
// Here, I pulled the actual data access out into separate methods,
// and simply call it from the event handler:
this.LoadGridView(textBox1.Text);
}
private void LoadGridView(string UserID)
{
// Now we can load the gridview from other places in our
// code if needed:
this.dataGridView1.DataSource = this.MyUsers(UserID);
}
private DataTable MyUsers(string UserID)
{
var dt = new DataTable();
// Use a SQL Paramenter instead of concatenating criteria:
string SQL = "SELECT * FROM Leave WHERE userid = #UserID";
// The "using" statement limits the scope of the connection and command variables, and handles disposal
// of resources. Also note, the connection string is obtained from the project properties file:
using(OleDbConnection cn = new OleDbConnection(Properties.Settings.Default.MyConnectionString))
{
using (var cmd = new OleDbCommand(SQL, cn))
{
// For simpler things, you can use the "AddWithValue" method to initialize a new parameter,
// add it to the Parameters collection of the OleDBCommand object, and set the value:
cmd.Parameters.AddWithValue("#UserID", UserID);
// Get in, get out, get done:
cn.Open();
dt.Load(cmd.ExecuteReader());
cn.Close();
}
}
return dt;
}
}
}
Hope that helps. It's not how everyone might do it, but I have found it provides maximum flexibility, when you must work with MS Access.

It don't get any data from DataReader

i work with N tiers tec in C# for ado, trying to make it easy to use and capable to change any database kind with out write all the cod all over again ,
my code here doesn't get any error but it doesn't get any values to my textbox
(i am trying to get data from table to many textboxs to update it later)
and here how code works:{
at first i make some functions to take any set any kind of parameters or set any command and then i make other function to to execute what ever i set or get from database all that Function i build it in folder name (Data Access Layer)
then i made other folder (Data Build layer)to take use all those function for what ever i want to do in any page (insert , update , delete , Select),
the last think i do it to call the function i made at at (Data Build layer) to my page or control ,
i do all that because if i Change the database Type ,i change only one class and other classes still the same
i hope i explain enough (sorry for my English not good enough)}
Code :
Class DataAccessLayer
public static void Setcommand (SqlCommand cmd,CommandType type,string commandtext)
{
cmd.CommandType=type;
cmd.CommandText=commandtext;
}
public static void AddSQLparameter(SqlCommand cmd, int size,SqlDbType type,object value,string paramName,ParameterDirection direction)
{
if (cmd == null)
{
throw (new ArgumentException("cmd"));
}
if (paramName == null)
{
throw (new ArgumentException("paramName"));
}
SqlParameter param=new SqlParameter();
param.ParameterName= paramName;
param.SqlDbType=type;
param.Size=size;
param.Value=value;
param.Direction=direction;
cmd.Parameters.Add(param);
}
public static SqlDataReader ExecuteSelectCommand(SqlCommand cmd)
{
if (cmd == null)
{
throw (new ArgumentNullException("cmd"));
}
SqlConnection con = new SqlConnection();
cmd.Connection = con;
con.Open();
SqlDataReader dr = cmd.ExecuteReader();
con.Close();
return dr ;
}
Class DatabuildLayer
SqlCommand com;
public DatabuildLayer()
{
com = new SqlCommand();
//
// TODO: Add constructor logic here
//
}
public SqlDataReader SelectCatalog(int catid)
{
DataAccessLayer.Setcommand(com, CommandType.Text, "select catname,catdescription,photo from category where catid=#catid" );
DataAccessLayer.addSQLparameter(com,16,SqlDbType.Int,catid,"#catid",ParameterDirection.Input);
return DataAccessLayer.ExecuteSelectCommand(com);;
}
and here my last code that retrieve my data to some textbox
in my Pageload :
protected void Page_Load(object sender, EventArgs e)
{
DatabuildLayer= new DatabuildLayer();
SqlDataReader dr ;
dr = obj.SelectCatalog(catselectddl.SelectedIndex);
if (dr.Read())
{
catnametxt.Text = dr["catname"].ToString();
catdestxt.Text = dr["catdescription"].ToString();
}
}
Is it possible that the query is returning nothing, and dr.Read() is returning false? Assuming the code actually executes (it is hard to tell from here) that is probably the only thing that would stop it working - either that or empty columns.
For what it is worth I think that your code needs to be tidied up a bit from a structural and conventions point of view. You should probably look through your code and consider the naming guidelines for the .NET framework. When others read your code they will want it formatted and consistent with this documentation. http://msdn.microsoft.com/en-us/library/xzf533w0(v=vs.71).aspx
Further, most people doing ASP.NET these days try to look for some way to inject external dependencies (such as databases) into their code using a framework like WebFormsMVP available at
http://webformsmvp.com/ in conjunction with an IoC container like autofac available at http://code.google.com/p/autofac/.
Using this approach you can push all external dependencies out of your application behind interfaces which would make it fairly trivial to plug in a different database engine.
Your current wrapper code is not doing anything particularly useful (just subsituting the existing methods or your own tht do the same thing), and it is not closing the connections correctly. It is... a bit of a mess.
If you aren't already massively familiar with the raw ADO.NET interfaces, then maybe consider something like "dapper" which will do all this for you, with a sane API:
short catid = 16;
using(var conn = GetOpenConnection()) {
var row = conn.Query(
"select catname,catdescription,photo from category where catid=#catid",
new { catid }).FirstOrDefault();
if(row != null) {
string name = row.catname, desc = row.catdescription;
// ...
}
}
Or if you have a class with CatName / CatDescription properties:
var obj = conn.Query<Catalogue>(
"select catname,catdescription,photo from category where catid=#catid",
new { catid }).FirstOrDefault();
from my experience, when you close a connection associated with a DataReader, nothing can be retrieved from the reader anymore.
//You closed the connection before returning the dr in the your method below:
public static SqlDataReader ExecuteSelectCommand(SqlCommand cmd)
{
if (cmd == null)
{
throw (new ArgumentNullException("cmd"));
}
SqlConnection con = new SqlConnection();
cmd.Connection = con;
con.Open();
SqlDataReader dr = cmd.ExecuteReader();
con.Close(); //here your connection was already closed
return dr ; //this dr is disconnected
}

Multiple "Insert Into" operation under same event

Guys I searched around like hell but nothing could help me so I think it's time to ask. Before I write to problem, I need to say that I need it's solution asap because it's a project that I have to give tomorrow and I stuck on the same subject since ages and still losing time.
OK here it is;
I need to add a book to a library system, at first phase I add the standard book features which has only "one value" like (name, page number, publishing time, publisherID etc) but as wanted by me book MAY HAVE MULTIPLE WRITERS AND CATEGORIES which killed me and still I can't resolve. I tried to add book to it's (books) table then with the information i got from that i did an other insert op. to (bookWriters) table. While I check it, compiler does everything in order without error but when I check table from SQL Server there is nothing.
Here is what I tried to do;
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.IO;
using System.Data.SqlClient;
namespace Project_
{
public partial class addBook: Form
{
public addBook()
{
InitializeComponent();
}
public main refForm;
int chosenWritersNumber; //how many writers have selected on listbox
int[] writers= { }; // an array list that i keep writerIDs that comes from class
int ind = 0;
int insertedBookID; // to catch latest added book's ID
int chosenWriterID; // writer that will be added
private void bookAddingPreps()
{
chosenWritersNumber = lstWriters.SelectedItems.Count;
Array.Resize<int>(ref writers, chosenWritersNumber );
for (int i = 0; i < chosenWritersNumber ; i++)
{
writers[i] = ((X_Writers)lstWriters.SelectedItems[i]).XWriterID;
}
}
private void addMainBookInfos()
{
SqlConnection con = new SqlConnection(Conn.Activated);
SqlCommand com = new SqlCommand("AddBook", con);
com.CommandType = CommandType.StoredProcedure;
com.Parameters.AddWithValue("#BookISBN", txtISBN.Text);
con.Close();
}
private void catchAddedBookID()
{
SqlConnection con = new SqlConnection(Conn.Activated);
SqlCommand com = new SqlCommand("catchBookID", con);
com.CommandType = CommandType.StoredProcedure;
con.Open();
SqlDataReader dr = com.ExecuteReader();
if (dr.HasRows)
{
while (dr.Read())
{
insertedBookID = dr.GetInt32(0);
}
}
dr.Close();
con.Close();
}
private void addWritersOfTheBook()
{
chosenWriterID = writers[ind];
SqlConnection con = new SqlConnection(Conn.Activated);
SqlCommand com = new SqlCommand("addBookWriters", con);
com.CommandType = CommandType.StoredProcedure;
com.Parameters.AddWithValue("#BookID", insertedBookID);
com.Parameters.AddWithValue("#WriterID", chosenWriterID);
con.Close();
}
I call these methods on click of a button. You see also stored procedure names but as I checked they all correct, there must be a mistake in this page that I still cant see but if it's needed I can add what procedures writes but they all tested and seems working.
So as i said, when i do this, as ind = 0, a writer should have been added, break point shows everything is ok and compiler doesnt show any errors but when I check sql server table, its empty.
Written in C# with using Visual Studio 2010 Ultimate and SQL Server 2008 Dev.
Thanks
You forget to execute your SqlCommand's. Make a call to command.ExecuteNonReader(); to execute it without expecting any results. see: http://msdn.microsoft.com/en-us/library/system.data.sqlclient.sqlcommand.aspx
Apart form that, dont forget to dispose the resources acquired in your methods. Something like:
private void addMainBookInfos()
{
using (SqlConnection con = new SqlConnection(Conn.Activated))
using (SqlCommand com = new SqlCommand("AddBook", con))
{
com.CommandType = CommandType.StoredProcedure;
com.Parameters.AddWithValue("#BookISBN", txtISBN.Text);
com.ExecuteNonQuery()
// close can be omitted since you are already using the 'using' statement which automatically closes the connection
con.Close();
}
}

Categories