I am attempting to create a quiz for my C# program using an Access database to hold the question and answers.
In the database table, the questions are in one column, and the answers are in another column. In essence, this is what I would like to happen:
The form loads, and as this happens a question randomly chosen from the database appears on that form. The question itself will be displayed using the label.
Here is my code:
private void WindowsAnalysisQuiz_Load(object sender, EventArgs e)
{
//declare connection string using windows security
string cnString = "Provider=Microsoft.ACE.OLEDB.12.0;Data Source=C:\\Users\\Hannah\\Desktop\\\\WindowsAnalysisQuiz.accdb";
//declare Connection, command and other related objects
OleDbConnection conGet = new OleDbConnection(cnString);
OleDbCommand cmdGet = new OleDbCommand();
try
{
//open connection
conGet.Open();
cmdGet.CommandType = CommandType.Text;
cmdGet.Connection = conGet;
cmdGet.CommandText = "SELECT Question FROM WindowsAnalysisQuiz ORDER BY rand()";
label1.Text = cmdGet.CommandText["Question"];
conGet.Close();
}
catch (Exception ex)
{
//display generic error message back to user
MessageBox.Show(ex.Message);
}
finally
{
//check if connection is still open then attempt to close it
if (conGet.State == ConnectionState.Open)
{
conGet.Close();
}
}
}
}
I am getting a problem at the point where I am trying to assign a random question to be displayed in my label.
As an aside, is this method of using a database to store the questions and answers doable?
Thanks
the function you mean is rnd(), not rand().
but i´m not sure if this is possible via the oledb driver.
One solution is to have an Autonumber field in your questions table. Then you can generate the random value in your code, and then query based on the randomly chosen ID number. If, for instance, your questions were numbered 1 to 100, you'd limit the range of your generated random number to that range.
Related
private void button1_Click(object sender, EventArgs e)
{
string CS = ConfigurationManager.ConnectionStrings["connection_string"].ConnectionString;
OleDbConnection C = new OleDbConnection(CS);
C.Open();
OleDbCommand CMD = new OleDbCommand("", C);
CMD.CommandText = "SELECT COUNT(*) FROM Applicants WHERE ApplicantID = ?";
CMD.Parameters.AddWithValue("#ApplicantID", textBox1.Text);
if (Convert.ToInt32(CMD.ExecuteScalar()) > 0)
{
CMD.CommandText = "UPDATE Onboarding SET " +
"BackgroudCheck = #BGC, PhotoID = #PID, " +
"TrainingHoursOutOf40 = #THOO, DrugTestTaken = #DTT, PassedDrugTest = #PDT" +
"WHERE ApplicantID = #AID";
CMD.Parameters.AddWithValue("#AID", textBox1.Text);
CMD.Parameters.AddWithValue("#BGC", CheckBox1);
CMD.Parameters.AddWithValue("#PID", CheckBox2);
CMD.Parameters.AddWithValue("#THOO", TextBox2.Text);
CMD.Parameters.AddWithValue("#DTT", CheckBox3);
CMD.Parameters.AddWithValue("#PDT", CheckBox4);
MessageBox.Show("Applicant Updated Successfully");
}
else
{
MessageBox.Show("Applicant Does Not Exists");
}
C.Close();
}
I am trying to update the data table. Some how when I try to update in the form I do get a messagebox saying "Applicant updated Successfully", but when I go to the data table or view it in another form, the table is not updated.
Several problems here
Ole does not use named parameters. You can give your parameters names but they're ignored. You must add the right number of parameters in the right order
use using to ensure database resources are closed and disposed of when you're done with them
You never actually executed your UPDATE query
You didn't put .Checked to retrieve the Booleans from your check boxes
You don't need to SELECT first. If the update updates no record the applicant doesn't exist. An UPDATE doesn't error if there is nothing to update. ExecuteNonQuery returns an int of how many rows were updated
You really should rename your controls after you drop them on the form. Code that is full of Label57, Button29 is effectively obfuscated (meaningless garbage) that is very hard to maintain
In c# variables declared inside a method are named with camelCaseLikeThis, not ALLCAPS
Be aware that if this is a file based database you're using (it is likely Access if it's ole) that multiple copies of the database file are present on disk. Countless questions are asked "why isn't my db updating" when it is - it's just that the program is updating the db in the bin folder and the dev is looking in the copy of the db in the project folder (which is copied over the top of the bin folder db every time the project is run, which is another reason the program "never remembers anything")
if you're using Access, you would do yourself massive favors by switching to an extensively used commercial grade db (sql server Express is free, and SQLite is definitely worth using over Access) and learning entity framework. I appreciate you're on a learning journey but largely what you're learning now isn't widely used in the real world any more, because it's a tedious waste of time somewhat akin to writing your own graphics drivers or Json parsers. If you want to stick with this approach take a look at Dapper, which takes a lot of the pain out of "data access by SQL strings in button click handlers" - opening and closing connections, filling in parameters and types, pulling data out of readers and casting it; all that work can be done by software and dapper can reduce the code you've written here to a single line like c.Execute("UPDATE ...", new { bgcCheckbox.Checked, ... aidTextbox.Text })
private void button1_Click(object sender, EventArgs e)
{
string cs = ConfigurationManager.ConnectionStrings["connection_string"].ConnectionString;
using(OleDbConnection c = new OleDbConnection(cs)){
c.Open();
using(OleDbCommand cmd = new OleDbCommand("", c)){
cmd.CommandText = "UPDATE Onboarding SET " +
"BackgroudCheck = ?, PhotoID = ?, " +
"TrainingHoursOutOf40 = ?, DrugTestTaken = ?, PassedDrugTest = ?" +
"WHERE ApplicantID = ?";
cmd.Parameters.AddWithValue("#BGC", CheckBox1.Checked);
cmd.Parameters.AddWithValue("#PID", CheckBox2.Checked);
cmd.Parameters.AddWithValue("#THOO", TextBox2.Text);
cmd.Parameters.AddWithValue("#DTT", CheckBox3.Checked);
cmd.Parameters.AddWithValue("#PDT", CheckBox4.Checked);
cmd.Parameters.AddWithValue("#AID", textBox1.Text);
if(cmd.ExecuteNonQuery()>0)
MessageBox.Show("Applicant Updated Successfully");
else
MessageBox.Show("Applicant Does Not Exists");
}
}
}
You have not used ExecuteNonQuery() method of SQL Command class.
int returnValue;
returnValue = CMD.ExecuteNonQuery();
I'm a beginner.
I already found a way to connect to SQL SERVER using the codes below:
private void getListBtn_Click(object sender, RoutedEventArgs e)
{
SqlConnection con = new SqlConnection("Data Source=.;Initial Catalog=myDB;Integrated Security=true;");
SqlDataAdapter sda = new SqlDataAdapter("SELECT ID,Date,Name,City FROM Info;", con);
DataTable dt = new DataTable();
sda.Fill(dt);
dataGridForm.ItemsSource = dt.DefaultView;
I also wanted to get number of rows from a TABLE and set it to a label, But it's not a good idea to copy and paste this code again, I want to have a method for sqlconnection so i won't rewrite this code again and again for every single query.
Sorry i'm an absolute beginner, 3 days since i started learning C# WPF.
Yes some frameworks and/or ADO's solutions are good and maybe the best "professionnal" approch, you say you're a beginner and I was it not so far ;-).
So the simpliest way is to add a new class for the sql connection. In example add a Sqlconnect.cs class.
using System.Data.SqlClient;
public class Sqlconnect
{
public SqlConnection Con { get; set; }//the object
private string conString { get; set; }//the string to store your connection parameters
}
This class will have a method to open the connection and one to close it.
public void conOpen()
{
conString = "Data Source=..."; //the same as you post in your post
Con = new SqlConnection(conString);//
try
{
Con.Open();//try to open the connection
}
catch (Exception ex)
{
//you do stuff if the connection can't open, returning a massagebox with the error, write the error in a log.txt file...
}
}
public void conClose()
{
Con.Close();//close the connection
}
In your other(s) classe(s) where you need a sql query you first instantiate an new object.
private void getListBtn_Click(object sender, RoutedEventArg e)
{
Sqlconnect con = new Sqlconnect();//instantiate a new object 'Con' from the class Sqlconnect.cs
con.conOpen();//method to open the connection.
//you should test if the connection is open or not
if(con!= null && con.State == ConnectionState.Open)//youtest if the object exist and if his state is open
{
//make your query
SqlDataAdapter sda = new SqlDataAdapter("your query", con);
//etc
con.conClose();//close your connection
}
else
{
//the connection failed so do some stuff, messagebox...as you want
return;//close the event
}
}
this example need some ameliorations, it's evident but I wrote it like this to be clearest.
First thing this is not related to WPF, this is general coding even I would not consider this to be related to .net.
For your current problem to show the count, you dont have to make a call again. You can get the count from the datatable row count. But, I would suggest few things:
You should have one or different separate layers like business, data access etc. as per your needs.
You should not give the connection as the way you have provided here.
You can choose to use any ORMs like entity framework, NHibernate etc based on your needs. This just a direction, you can choose to stick with ADO.Net as you have it your choice. But I would definitely suggest to throw in more layers to avoid duplicate codes and more structured approach.
Best choice if you don't need so much performance is ORM like Entity Framework.
Here is something of basics.
Just use it like in MVC app.
If we copy paste your code, then the error is appearing. I have corrected it and maybe others don't need to struggle like me to find this. :)
// Object exists and State is open
if (Conex != null && Conex.Con.State ==
System.Data.ConnectionState.Open)
{
// Create a String to hold the query
string query = "insert into Xray_Table values
(25,'zzz','hij',3,'uuu',6,'2012-06-18
10:34:09.000')";
// Create a SqlCommand object and pass the constructor the connection string and the query string
SqlCommand queryCommand = new SqlCommand(query, Conex.Con);
// Execute the query to update to the database
queryCommand.ExecuteNonQuery();
// method to close the connection.
Conex.conClose();
}
Closed. This question is not reproducible or was caused by typos. It is not currently accepting answers.
This question was caused by a typo or a problem that can no longer be reproduced. While similar questions may be on-topic here, this one was resolved in a way less likely to help future readers.
Closed 5 years ago.
Improve this question
I am developing a C# Windows application. I have used access database. When I selecting data from database I am getting data, but when inserting data it's not gets inserted and also it's not showing any error.
But when I run the same insert query in Access it gets inserted. Here is my code:
public void connCheck()
{
try
{
cn = new OleDbConnection(#"Provider=Microsoft.Jet.OLEDB.4.0;Data Source=|DataDirectory|\Database\MyDatabase.mdb;Persist Security Info=True;Jet OLEDB:Database Password=2013");
if (cn.State == ConnectionState.Closed)
cn.Open();
}
catch (Exception exp)
{
MessageBox.Show(exp.ToString());
}
}
public bool ExecuteNonQuery()
{
try
{
connCheck();
string sqlQuery = "INSERT INTO tblResult(ExamSet,SetId,FullMarks,ObtainedMarks,MarksPercentage,ElapsedTime,LastQIndex,CreatedDate,Completed)
Values(1,27,'200.00',0,0,0,1,DATE(),'N')";
cmd.CommandType = CommandType.Text;
cmd.Connection = cn;
cmd.CommandText = sqlQuery;
cmd.ExecuteNonQuery();
return true;
}
catch(OleDbException ex)
{
ErrorMsg = ex.ToString();
return false;
}
finally
{
cn.Close();
cn.Dispose();
cmd.Dispose();
}
}
You did not defined your cmd..
add this line
OledbCommand cmd=new OledbCommand();
How about replacing your query code like this
string sqlQuery = "INSERT INTO tblResult([ExamSet],[SetId],[FullMarks],[ObtainedMarks],[MarksPercentage],[ElapsedTime],[LastQIndex],[CreatedDate],[Completed])
Values(1,27,'200.00',0,0,0,1,DATE(),'N')";
Update:
One of the issues could be Security warning that disables the content.
Try and see if this works (Go to your MDB):
Click on 'External Data' tab
There should be a Security Warning that states "Certain content in the database has been disabled"
Click the 'Options' button
Select 'Enable this content' and click the OK button
Try parameterised queries via cmd.Parameters.Add or AddRange. Example
var cmd = new SqlCommand("INSERT INTO tbl_name (a, b, c) VALUES (#a, #b, #c)");
cmd.Parameters.AddRange(new[] { new SqlParameter("#a", field1), new SqlParameter("#b", field2), new SqlParameter("#c", field2) });
(Posted on behalf of the OP).
Thanks everyone for your help, I got the solution. Actually there is no problem in my code. Problem is that I have created database file in a folder. But when I build the project it created a duplicate database with same folder an file name in bin folder.
So every time it gets inserted in that database. And I was checking in the database file which I have created. So I thought it's not working.
Hi i have a login which connects to a server string and executes this when the login button is pushed. It returns the invalid error if the user and password is not stored on the database but it throws a "Index was outside on the bounds of array" error if they are on the database. How would i fix this??
Thanks
My connection string is located in my appconfig file, could the problem be in there?
##########FORM WINDOWS AFTER LOGIN BUTTON CLICK
private void btnOK_Click(object sender, EventArgs e)
{
SqlConnection con = Program.GetConnection;
SqlDataReader dr = null;
try
{
SqlCommand cmd = new SqlCommand("SELECT * FROM Users WHERE UserName='" +
txtName.Text + "'AND Password='" + textpassword.Text + "'", con);
dr = cmd.ExecuteReader();
if (dr.Read())
{
Program.UserLoginName = dr.GetString(3);
this.Close();
}
else
MessageBox.Show("Invalid Username & Password!");
}
catch (Exception ex)
{
MessageBox.Show(ex.Message);
}
}
#######PROGRAM.CS FILE
Using System;
using System.Collections.Generic;
using System.Linq;
using System.Windows.Forms;
using System.Data.SqlClient;
using System.Configuration;
namespace FrontEndV1
{
static class Program
{
/// <summary>
/// The main entry point for the application.
/// </summary>
[STAThread]
static void Main()
{
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
Application.Run(new Login());
}
public static SqlConnection GetConnection
{
get
{
string ConnectionString = ConfigurationManager.ConnectionStrings["FrontEndV1Connection"].ConnectionString;
SqlConnection con = new SqlConnection(ConnectionString);
con.Open();
return con;
}
}
public static string UserLoginName { get; set; }
}
}
I think that mistake lays here: dr.GetString(3); try to change 3 to 2. Numeration begins from 0 in arrays.
You don't say where the error is thrown, but I suspect this line:
Program.UserLoginName = dr.GetString(3);
Would throw the error if the query returns any fewer than 4 columns.
Also, this is vulnerable to Sql injection. Use a stored proc or parameterised query.
This is your problem:
Program.UserLoginName = dr.GetString(3);
You're getting a field whose index is greater than returned fields count.
You must use an index between 0 and dr.FieldCount-1.
Or you can use dr.GetString(dr.GetOrdinal(desired_field_name)): this is better (even if it needs more instructions) because you could swap returning order (maybe you need to change your query) without losing functionality.
i think you only have three columns. The index of the 3rd column is 2, so change this line
Program.UserLoginName = dr.GetString(3);
to
Program.UserLoginName = dr.GetString(2);.
Can you not debug the application? If you can do then try to locate from where the exception is being thrown. As suggested by Marco and other user if you notice exception when executing dr.GetString(3) then problem lies there. Try using correct column ordinal, or use SELECT Column1, Column2, ..., ColumnN FROM Table so that you know exactly which ordinal to specify.
Bad coding:
using select *, you should use the names of the columns
using indexes to retrieve values in a row, you should use the actual column name returned
If the above would have been applied there would be no problem.
I had The Same error using SQL Server Express 2014 with Login Stored Procedure from 3 different tables, I was really confused what was goin on, but finally found that I had more columns Selected from One Table then other two
sometimes its the logic behind it
I'm using Access 2007 and C# to learn Databases. So far it's been rough but I've been able to handle things relatively well. What I need to do though is to query a my database table Accounts for the Amount of money a user has based on their pin. I've placed a button on the Windows Form I am using that will query the database on click. When I run/click the button as per normal I recieve the following error.
Essentially my question is this: How would I go about setting the permissions up so that my program can freely access the Access Database I have?
My Exception Error:
Exception: System.Data.OleDb.OleDbException: The Microsoft Office Access database engine cannot open or write to the file 'C:\Users\Public'. It is already opened exclusively by another user, or you need permission to view and write its data.
My code:
public partial class frmPin : Form
{
static string connString = #"Provider=Microsoft.ACE.OLEDB.12.0;Data Source=C:\Users\Public;Persist Security Info=True";
static private int pin = 11; //The First Pin in my records, for debugging I inserted it directly.
static string selectStatement = "SELECT Amount FROM Accounts WHERE(PIN=" + pin + ")";
OleDbConnection conn = new OleDbConnection(connString);
OleDbCommand cmd = new OleDbCommand(selectStatement);
public frmPin()
{
InitializeComponent();
}
private void btnQry_Click(object sender, EventArgs e)
{
try
{
conn.Open();
OleDbDataReader reader = cmd.ExecuteReader(); // executes query
while (reader.Read()) // if can read row from database
{
txtBx.Text = reader.GetValue(1).ToString();
}
}
catch (Exception ex)
{
txtBx.Text = "Exception: " + ex; // Displays Exception
}
finally
{
conn.Close(); // finally closes connection
}
}
"C:\Users\Public" needs to be changed to the actual path of the *.mdb file you want to access:
"C:\Users\Public.mdb"
OR
"C:\Users\Public\Something.mdb"
Depending on the name of your database:
Provider=Microsoft.Jet.OLEDB.4.0;Data Source=C:\mydatabase.mdb;User Id=admin;Password=;
Or it may be an *.accdb file. Such as:
Provider=Microsoft.ACE.OLEDB.12.0;Data Source=C:\myFolder\myAccess2007file.accdb;Persist Security Info=False;
See http://www.connectionstrings.com/access-2007 and http://www.connectionstrings.com/access
Also, sometimes you will get this kind of problem if you have the file open in another program like Access 2007, the file is marked as Read Only, or the security permissions are such that you don't have Read or Write Access. Note that if you set a "Deny" permission (in the filesystem/NTFS) for a group like Users, then it will override all other permissions, such that an Administrator would be effected by the Deny permission.
Edit: Thanks for comments, added a little clarification.