OledbException - Field too small to accept amount of data - c#

I am trying to use OleDb to insert a new record into an Access database using an SQL command into an entity called 'tblThread' (containing discussion posts, if you are wondering); this is done via a button that will take values from two controls (both being textboxes).
Here's the layout if you would like to see: https://gyazo.com/c43abf4ce055ff997b908badb57f549a
However, after clicking on the button 'Submit Discussion', the control that inserts a new record I get an error display:
https://gyazo.com/1dbdb33290649af04f092533560b1d8c
Now here's the code for the Click event of this button:
Please Note:
absDefault._memberType = 'Teacher' (in this scenario)
private void btnCreate_Click(object sender, EventArgs e)
{
OleDbConnection objConnection = new OleDbConnection(absDefault.conString);
OleDbCommand objCommand = new OleDbCommand();
objCommand.Connection = objConnection;
if (MessageBox.Show("[Piltover]: Are you sure you would like to create this thread", "", MessageBoxButtons.YesNo) == DialogResult.No)
{
return; // Does not execute remaining code
}
else if (txtTitle.TextLength == 0)
{
MessageBox.Show("[Piltover]: You have not created a title");
}
else if (mtxtDescription.TextLength == 0)
{
MessageBox.Show("[Piltover]: You have not added description to your thread");
}
else
{
// DBConnection class is only used within this else block and is not needed anywhere else in this form
DataSet ds; DataRow dRow;
DatabaseConnection objConnect = new DatabaseConnection(); // Instantiating an object from DBConnectionClass and checking if an identical title exist is much faster than the OLEDB process (shown within try block below)
objConnect.Connection_String = absDefault.conString;
objConnect.SQL = "SELECT * FROM tblThread"; ds = objConnect.GetConnection;
for (int i = 0; i < ds.Tables[0].Rows.Count; i++)
{
dRow = ds.Tables[0].Rows[i];
if (txtTitle.Text.ToUpper() == dRow.ItemArray.GetValue(1).ToString())
{
MessageBox.Show("[Piltover]: Thread already exist with the title name given");
return;
}
}
}
// FIX - test to see if it works
try
{
objConnection.Open();
// Insert new thread record; avoids SQL injection
objCommand.CommandText = String.Format("INSERT INTO tblThread ([Title], [Description], [ID], [Username], [TeacherBool]) VALUES (#title, #desc, #id, #username, #teacherbool)");//, absDefault.newThreadMemberType);
objCommand.Parameters.AddWithValue("#title", txtTitle.Text);
objCommand.Parameters.AddWithValue("#desc", mtxtDescription.Text);
objCommand.Parameters.AddWithValue("id", absDefault._idNumber);
if (absDefault._memberType == "Teacher")
{
currentTeacher = new csTeacher(absDefault._idNumber, "Teacher");
objCommand.Parameters.AddWithValue("#teacherbool", "True");
objCommand.Parameters.AddWithValue("#username", currentTeacher.Username);
}
else // else 'Student'
{
currentStudent = new csStudent(absDefault._idNumber, "Student");
objCommand.Parameters.AddWithValue("#teacherbool", "False");
objCommand.Parameters.AddWithValue("#username", currentStudent.Username);
}
objCommand.ExecuteNonQuery();
MessageBox.Show("[Piltover]: Thread created");
objConnection.Close();
}
catch (Exception Ex)
{
MessageBox.Show(Ex.ToString());
}
}
I am guessing the problem lies in the attribute [Description], although, I have set the data type to long text:
https://gyazo.com/2d99c945a0a0b98a1e48e8abaf043c2f
If you are wondering what contains within my DatabaseConnection class:
http://pastebin.com/RQs6qPEz
What I am confused is, my inputs are within boundaries (being under 255 characters, if that is the problem):
For example, https://gyazo.com/c43abf4ce055ff997b908badb57f549a
As you can see, the 'masked textbox' besides label 'Description' contains values less than 255 characters.
I have tried debugging to try and find a solution/answer.

System.Data.OleDb allows us to use #names for parameters (and their placeholders), but it ignores the names and treats parameters as strictly positional. Therefore the parameters must be declared in the same order that they appear in the command text.
In your command text you specify
... VALUES (#title, #desc, #id, #username, #teacherbool)
but when you create the parameters via AddWithValue you do so in the following order ...
#title
#desc
id
#teacherbool
#username
... which is not the same.
You need to swap the order of declaring the #teacherbool and #username parameters in your if block.

Related

Compare a value in a table in SQL to an entry in a textbox

I have a table EmployeeRank1 in SQL Server that has a column Name. Under column Name there are two pre-defined names of employees. Moreover, in the table there is a column Password, which contains a generic password, which is "123456".
In WPF I have a textbox and that asks for name and one password box that asks for password. Underneath them, there is a button that says "Login".
The questions is how do I compare the content of Name and Pasword in my table to the input in the text box and the password box?
If the Name entered exists and the Password is correct, a new WPF page will be opened. Otherwise, a message stating that either the name or the password is incorrect will be printed.
This is what I have until now:
// check if the input matches and open the new WPF Page
private void EmployeeRank1Button_Click(object sender, RoutedEventArgs e)
{
try
{
// create a query and select everything from the EmployeeRank1 table
string query = "select * from EmployeeRank1";
// create a connection to the database and run the query
SqlDataAdapter sqlDataAdapter = new SqlDataAdapter(query, sqlConnection);
// use the sqlDataAdapter
using(sqlDataAdapter)
{
// create a new DataTable that allows us
// to store data from tables within objects
DataTable employeeRank1Table = new DataTable();
// fill the sqlDataAdapter with all the
// information from the query(from the employeeRank1Table)
sqlDataAdapter.Fill(employeeRank1Table);
// TODO: compare Name and Password entered in the TextBox and PasswordBox to the data in the table
if (tbName.Text == *Name in Table* && pbPassword.Password == *Password in Table*)
{
EmployeeRank1 employeeRank1 = new EmployeeRank1();
employeeRank1.Show();
}
}
}
catch(Exception exception)
{
MessageBox.Show(exception.ToString());
}
}
You don't need to retrieve the whole table in memory. Just use a WHERE statement in your sql command with Name = #nameparam AND Password = #passparam, use an SqlCommand to retrieve a SqlDataReader and if the reader has a row, then bingo, the user exists.
Said that, remember that storing passwords in clear text is a big NO NO in a security concerned application. See this q/a for the reasons
private void EmployeeRank1Button_Click(object sender, RoutedEventArgs e)
{
try
{
// create a query and select just the record we need
string query = "select * from EmployeeRank1 where Name = #name AND Password = #pass";
// A local sqlconnection in a using statement ensure proper disposal at the end of this code
using SqlConnection con = new SqlConnection(connectionstring);
con.Open();
// Let's the database do the work to search for the password and name pair
SqlCommand cmd = new SqlCommand(query, con);
cmd.Parameters.Add("#Name", SqlDbType.NVarChar).Value = tbName.Text ;
cmd.Parameters.Add("#pass", SqlDbType.NVarChar).Value = tbPassword.Text ;
SqlDataReader reader = cmd.ExecuteReader();
// If the reader has rows then the user/pass exists in the db table
if(reader.HasRows)
{
EmployeeRank1 employeeRank1 = new EmployeeRank1();
employeeRank1.Show();
}
}
catch(Exception exception)
{
MessageBox.Show(exception.ToString());
}
}
Note also that I used a local SqlConnection and not a global one inside a using statement. This is the correct way to use a Disposable object like a connection. Keeping a global connection is prone to resource leaks and all sorts of problems if something fails.

Connecting to a database and inserting data into a table

I'm attempting to connect to a database and insert data into the pre-existing table. I'm able to connect to the database it seems but am having trouble getting the data to insert into the table. How do I insert
data into a database in visual studio?
I've already learned how to pass parameters and attempted that, but when I run the program I still receive exceptions. I've attached a screenshot of the error when I try and add a new record. I've looked up multiple different syntaxes for the insert statement, but not sure what I am doing wrong. Below I've included three screenshots one is the form itself, the error I receive, and at the bottom the table structure.
Insert Exception
Form
private void btnAccept_Click(object sender, EventArgs e)
{
if (IsValidData())
{
if (addProduct)
{
product = new Product();
this.PutProductData(product);
try
{
SqlConnection sqlConn = new SqlConnection("Data Source= (LocalDB)\\MSSQLLocalDB;AttachDbFilename=|DataDirectory|\\MMABooks.mdf;Integrated Security=True");
SqlCommand sqlComm = new SqlCommand();
sqlComm = sqlConn.CreateCommand();
sqlComm.CommandText = #"INSERT INTO Products (paramColum) VALUES
(#ProductCode, #Description,
#UnitPrice, #OnHandQuantity)";
sqlComm.Parameters.Add("#ProductCode", SqlDbType.VarChar);
sqlComm.Parameters.Add("#Description", SqlDbType.VarChar);
sqlComm.Parameters.Add("#UnitPrice", SqlDbType.VarChar);
sqlComm.Parameters.Add("#OnHandQuantity", SqlDbType.VarChar);
sqlConn.Open();
sqlComm.ExecuteNonQuery();
sqlConn.Close();
// Add code here to call the AddProduct method of the ProductDB class.
}
catch (Exception ex)
{
MessageBox.Show(ex.Message, ex.GetType().ToString());
}
}
}
}
private void btnAdd_Click(object sender, EventArgs e)
{
frmAddModifyProduct addProductForm = new
frmAddModifyProduct();
addProductForm.addProduct = true;
DialogResult result = addProductForm.ShowDialog();
if (result == DialogResult.OK)
{
product = addProductForm.product;
txtCode.Text = product.Code;
this.DisplayProduct();
}
}
It should enter a record into the Products table. If I get it down for the insert statement, I'll figure out the retrieve, update, and delete.
TableStructure
You need to add the parameter values, something like:
command.Parameters.Add("#LastName", SqlDbType.VarChar, 30).Value = "Smith";
command.Parameters.Add("#GenderCode", SqlDbType.Char, 1).Value = "M";.
Original answer below, but as pointed in comments below, please avoid it, reasons
cmd.Parameters.AddWithValue("#ProductCode", product.Code);
cmd.Parameters.AddWithValue("#Description", product.Description);
In the current code you have just setup the parameters but not passed the value.
EDIT: Based on #MaxSzczurek comments above
Your INSERT INTO columns don't match your VALUES clause.
INSERT INTO Products (paramColumn) should be changed to:
INSERT INTO Products(ProductCode, Description, UnitPrice, OnHandQuantity)

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 to avoid entering duplicate values into table through winform?

in my project I have set the client name as primary key and if I enter the same value, I will get exception, now I want to write the validation, i.e if I re enter the primary key value then I should get a message like "Data already exists", Please help me to do that, The code I am using to insert value is:
private void btnInsert_Click(object sender, EventArgs e)
{
if (txtName.Text == string.Empty)
{
MessageBox.Show("Please enter a value to Project Name!");
txtName.Focus();
return;
}
if (txtContactPerson.Text == string.Empty)
{
MessageBox.Show("Please enter a value to Description!");
txtContactPerson.Focus();
return;
}
SqlConnection con = Helper.getconnection();
con.Open();
string commandText = "InsertClient";
SqlCommand cmd = new SqlCommand(commandText, con);
cmd.Parameters.AddWithValue("#Name", txtName.Text);
cmd.Parameters.AddWithValue("#ContactPerson", txtContactPerson.Text);
cmd.CommandType = CommandType.StoredProcedure;
MessageBox.Show("Client details are inserted successfully");
txtName.Clear();
txtContactPerson.Clear();
object Name = cmd.ExecuteNonQuery();
con.Close();
BindData();
}
First, you can prevent a duplicate from ever occurring in the table by using a unique index or constraint. An index/constraint can work in concert with the suggestions below. If you only use a unique index and not one of the below solutions, inserting a duplicate record will throw an error and you will need to handle that on the other end.
you could check for the records existence and insert or update manually:
create procedure MyProcedure
(
#Name nvarchar(100),
...
)
as
if not exists (select * from MyTable where Name = #Name)
begin
insert into MyTable (Name,...) values (#Name,...)
end
else
begin
update MyTable
set ...
where Name = #Name
end
I would tend to allow the user to try to enter any superficially valid primary key, If it is a duplicate then there will be an exception that you can catch and display to the user.
The reason for this is you would have to check the database for an existing key so you might as well do this by trying to insert it and handling any errors.
You could probably improve the validation and error handling a lot more, popping up a message box on every individual problem is annoying, better to have a summary with all the problems. Also holding open a database connection while displaying a message box probably isn't advisable either.
private void btnInsert_Click(object sender, EventArgs e)
{
if (txtName.Text == string.Empty)
{
MessageBox.Show("Please enter a value to Project Name!");
txtName.Focus();
return;
}
if (txtContactPerson.Text == string.Empty)
{
MessageBox.Show("Please enter a value to Description!");
txtContactPerson.Focus();
return;
}
SqlConnection con = Helper.getconnection();
con.Open();
string commandText = "InsertClient";
SqlCommand cmd = new SqlCommand(commandText, con);
cmd.Parameters.AddWithValue("#Name", txtName.Text);
cmd.Parameters.AddWithValue("#ContactPerson", txtContactPerson.Text);
cmd.CommandType = CommandType.StoredProcedure;
try
{
object Name = cmd.ExecuteNonQuery();
MessageBox.Show("Client details are inserted successfully");
txtName.Clear();
txtContactPerson.Clear();
BindData();
}
catch(Exception ex)
{
//Handle exception, Inform User
}
finally
{
con.Close();
}
}
I understand your requirement, I see that you are asking about using of your own code instead of the exception. You can get it by using the try catch block. Try the following code:
try
{
object Name = cmd.ExecuteNonQuery();
MessageBox.Show("Client details are inserted successfully");
txtName.Clear();
txtContactPerson.Clear();
BindData();
}
catch(Exception ex)
{
//Handle exception, Inform User
}
finally
{
con.Close();
}
I tend to use Entity Framework as it will throw an exception in this case, however I suppose you could run an sql query first to check whether it exists or not, or though there may be a significant performance overhead with that

Adapt beginner C# SQL Server INSERT example to work with my database

I have read TONS of tutorials, articles and whatever regarding my issue and honestly, due to my lack of experience I can't twist my fingers around this one so I hope some of you guys can help me out :)
I am working on a project (simply to learn how to program so it's probably very basic), but I have this "News" page where I can update and delete data using a GridView.
Now I would like to INSERT something into my database using 3 textboxes and 1 submit button.
I have 3 rows that has to be inserted:
Headline
Date
Content/the news itself.
Which are stored under NyhedTB from the connectionstring: BoligStjernenConnectionString
My query looks like this:
INSERT INTO [NyhedTB] ([NyhedDato], [NyhedTitel], [NyhedTekst])
VALUES (#NyhedDato, #NyhedTitel, #NyhedTekst)
I read on the internet that this code should do the magic for me (I will have to insert my own values ofc.):
static void Insert()
{
try
{
string connectionString =
"server=.;" +
"initial catalog=employee;" +
"user id=sa;" +
"password=sa123";
using (SqlConnection conn =
new SqlConnection(connectionString))
{
conn.Open();
using (SqlCommand cmd =
new SqlCommand("INSERT INTO EmployeeDetails VALUES(" +
"#Id, #Name, #Address)", conn))
{
cmd.Parameters.AddWithValue("#Id", 1);
cmd.Parameters.AddWithValue("#Name", "Amal Hashim");
cmd.Parameters.AddWithValue("#Address", "Bangalore");
int rows = cmd.ExecuteNonQuery();
//rows number of record got inserted
}
}
}
catch (SqlException ex)
{
//Log exception
//Display Error message
}
}
I looked at this code and thought it should be easy enough but really, I can't figure it out.
Here is some advice to get you going, learning programming is a lot of
trial and error.
Start off basic, litrally put three textboxes on a form/page and a
button.
Double click the button to go the code-behind and view the buttons
click event.
Paste in the body of code included with your question (everything in the try-catch).
Put a break-point on the Public Void Button_Click line of code and press F11 to
step through the code.
"one thing is having the code-behind working but how to make the buttons and textboxes working is still a misery"*
Put the textbox as the value rather than your hardcoded values:
cmd.Parameters.AddWithValue("#Address", textBox1.Text);
You also should not insert the Id value, instead modify the EmployeeDetails table and set the ID column to in the properties set Identity Specification (IS Identity) = True. Then right click the ID column and set Primary Key.
Post any error messages you encounter here and when you do get get it working, an additional exercise (that will be very valuable for you) would use a database stored procedure rather than ad-hoc SQL, to safe-guard against sql-injection attacks.
I'm assuming you have SQL Server installed and have a 'employee' database with a table called EmployeeDetails.
protected void GvManualShows_RowDataBound(object sender, GridViewRowEventArgs e)
{
if (e.Row.RowType == DataControlRowType.DataRow)
{
//label lbl = (label)e.Row.FindControl("lblHidden");
if (e.Row.Cells[14].Text == "Y")
{
// CheckBox cb = (CheckBox)e.Row.FindControl("chk");
CheckBox chk = (CheckBox)e.Row.Cells[0].FindControl("chkBox");
chk.Checked = true;
}
}
}
It's fairly simple. You just have to modify the connection string, the query and its parameters:
private void button1_Click(object sender, EventArgs e)
{
try
{
string connectionString =
"server=SQLServer;" + // SQLServer is your SQL server machine
"initial catalog=employee;" + // employee is your database
"user id=sa;" + // sa is the login to connect the database
"password=sa123"; // sa123 is the password of the login
using (SqlConnection conn =
new SqlConnection(connectionString))
{
conn.Open();
using (SqlCommand cmd = new SqlCommand(
"INSERT INTO [NyhedTB] ([NyhedDato], [NyhedTitel], [NyhedTekst]) " +
"VALUES (#NyhedDato, #NyhedTitel, #NyhedTekst)", conn))
{
cmd.Parameters.AddWithValue("#NyhedDato", textBoxDate.Text);
cmd.Parameters.AddWithValue("#NyhedTitel", textBoxTitle.Text);
cmd.Parameters.AddWithValue("#NyhedTekst", textBoxBody.Text);
int rows = cmd.ExecuteNonQuery(); // Inserted rows number
}
}
}
catch (SqlException ex)
{
//Log exception
//Display Error message
}
}
I made changed example code with your requirements and added comments, hope it would be a bit clearer for you to understand whats going on:
static void Insert()
{
try
{
string connectionString =
"server=.;" +
"initial catalog=MyDatabaseName;" + //here you write database name where your NyhedTB table is
"user id=sa;" + //user name to connect to database
"password=sa123"; //password
using (SqlConnection conn = new SqlConnection(connectionString))
{
conn.Open();
using (SqlCommand cmd =
new SqlCommand("INSERT INTO NyhedTB (NyhedDato, NyhedTitel, NyhedTekst) VALUES (#NyhedDato, #NyhedTitel, #NyhedTekst)", conn))
{
//all "things" in your sql command what beggins with #
//means that it is parameter and you need to pass values for these parameters:
//For #NyhedDato parameter you set text from your textbox
cmd.Parameters.AddWithValue("#NyhedDato", txtDate.Text);
//For #NyhedTitel parameter you set text from title textbox
cmd.Parameters.AddWithValue("#NyhedTitel", txtTitle.Text);
//For #NyhedTekst parameter you set text from content textbox
cmd.Parameters.AddWithValue("#NyhedTekst", txtContent.Text);
//Execute insert command and get how many records was efected, in this case it should be rows = 1 because you inserting just one record
int rows = cmd.ExecuteNonQuery();
}
}
}
catch (SqlException ex)
{
//Log exception
//Display Error message
}
}
P.s. code not tested. And when you say
I have 3 rows that has to be inserted:
Headline
Date
Content/the news itself.
actually you mean you want to insert record with fields

Categories