c# Windows form not updating values to SQL database - c#

I have a problem in my program that's supposed to store projects given by the user in a database. I'm stuck on the edit project button. After entering new values in the program and hitting the button to save the values everything runs successfully with no errors. The messagebox that says "project edited" appears, I hit ok but the database stays the same. There is no error in the code, the SQL code that gets sent to update the database values is also correct but it doesn't work. Can anyone help with this because I am lost.
Here is the method that creates and executes the SQL code to update the database.
enter image description here

Wow man that code is wrong in so many ways according to code standards and principles most popular :) but that is not what the question is about directly, though getting you past lost we have to start at the basic tbh:
Suggestions
when you catch that exception if it comes, show that in a messagebox also you can even add an error icon as part of the .Show command, it's build in.
Move the connection.Close to the finally block instead of having it replicated
Consider making an SQL procedure instead and just parse the parameter into that, this code is prone to sql injection that you pose
Consider not making the procedure and familiarize Yourself with entity framework, it's going to make your life so much easier
do not concatenate like that, use interpolation or string.Combine or you'll be copying stuff all around on the stack, for each + a new copy one and two into third, it is super inefficient
When You write the code works and the sql is correct, consider that the outcome is not the desired and therefore it doesn't technically ;) the best and the worst about computers, is that they do what you ask.
Don't write Your DAL code in the form at all
Consider checking your parameters for default values
You do not have data to say 'project was updated' only 'values were saved', you do not check the old values in the code
Still besides that I do not see why what you wrote wouldn't work, provided the resulting sql is valid in what db you use, but i suppose if you do some of these things the error will present itself

I don't think it's a connection problem because I have a function that updates only the finishdate of the project and that works completely fine.
Here is the function:
public static MySqlCommand FinishProject(int projID, string finishdate) {
try {
if (connection != null) {
connection.Open();
cmd = connection.CreateCommand();
cmd.CommandType = CommandType.Text;
cmd.Parameters.AddWithValue("#value", projID);
cmd.Parameters.AddWithValue("#finishdate", finishdate);
cmd.CommandText = "UPDATE `b1c`.`projects` SET `finishdate` = (#finishdate) WHERE (`projectid` = (#value));";
int i = cmd.ExecuteNonQuery();
connection.Close();
if (i != 0) {
MessageBox.Show("Project finalized.");
i = 0;
}
}
} catch (Exception ex) {
MessageBox.Show("Catch");
connection.Close();
}
return cmd;
}
You can see it's basically the same the only difference are the values.
So it shouldn't be a connection thing because this one works fine I think.
I also don't think it's a problem in the SQL database because all the problems
I've had up until now that had anything to do with the database have shown as errors in visual studio.
If anyone can help I will provide screenshots of anything you need and thank you all once again for trying to help.
Here is the screenshot of the function I've pasted previously so it's easier to look at.
finishprojectfunction

Related

Validate Microsoft Access SQL

I have a long set of SQL scripts. They are all update statements. It's for an access database. I want to validate the script before I run it. Firstly, I'd like to make sure that the query can be parsed. I.e. that the SQL is at least syntactically correct. Secondly, I'd like to make sure that the query is valid in terms of database structure - i.e. there are no missing columns or the columns are of the wrong type etc. But, I don't want the query to be actually executed. The aim of this is to do a quick validation before the process kicks off because the process takes several hours and one syntactical error can waste a day of someone's time.
I will probably write the tool in C# with .net but if there's a pre-built tool that would be even better. I will probably use the Access API. In SQL Server this is very straight forward. You can just validate the query in SQL Server management studio before running it. It will give you a good indication of whether the SQL will complete or not.
How would I go about doing this?
Edit: an answer below solves the issue of checking syntax. However, I'd still like to be able to validate the semantic content of the query is OK. However, I think this might be impossible in Access without actually running the query. Please tell me I'm wrong.
I'm not 100% sure if Access works the same way as a traditional database, but with a mainstream RDMBS, there are actually three distinct steps that happen when you run a query:
Prepare
Execute
Fetch
Most are oblivious to the distinction because they just hit "run" and see results come back.
It's the "Execute" that actually compiles the statement before going off and pulling data.
When you use ADO, you can actually see the three events as three separate calls to the database. What this means is you can trap the execute step to see if it fails, and if it succeeds, there is nothing requiring you to actually get the results.
OleDbConnection conn = new OleDbConnection();
conn.ConnectionString = String.Format("{0}{1}",
#"Provider=Microsoft.ACE.OLEDB.12.0;Data Source=", #"c:\Access\MyDb.accdb");
conn.Open();
bool valid;
using (OleDbCommand cmd = new OleDbCommand("select [Bad Field] from [Table]", conn))
{
try
{
OleDbDataReader reader = cmd.ExecuteReader();
valid = true;
reader.Close(); // Did not ever call reader.Read()
}
catch (Exception ex)
{
valid = false;
}
}
And now valid indicates whether or not the statement compiled.
If you want to get really fancy, you can parse the exception results to find out why the command failed.
Access supports transactions on its Connection object. Try to execute your SQL statement inside a transaction and always call Rollback. Wrap the whole attempt in a Try/Catch block to assess whether the statement executed successfully or not.

C# - Using database table to populate variables

EDIT: Thank you everyone, I figured out how to get it to work now! Details below...
I'm kind of a newbie to C#, and I'm trying to teach myself the language by programming a really simple RPG game.
Right now, I'm at the point where I want to start adding different enemies to fight (up until now I just used a single one hardcoded in for testing).
I've started setting up a database with enemy info (one column for name, one for HP, one for common stats and attacks, etc.). I have it so that when you start combat with an enemy, the player is able to select a creature from a dropdown, and whichever creature he has will set a variable called "EnemyID".
What I want to do is use that EnemyID variable to correspond to a row in my database, then pull the value of each column into variables that I can then reference during combat.
Is this something that's possible to do? If so, could someone explain the method to me in relatively simple terms? Even just a small example of how to import row data from any kind of database will do, I'm good at understanding code once I see it in use a couple of times.
(Oh yeah, if it matters, I'm using Visual Studio Express 2013, and my database is a SQL Server Express 2014 database.)
Thanks in advance!
EDIT:
After finding a simple tutorial for ADO.NET, and following a suggestion from one of the posters, I've come up with the following code.
public void DataPoll()
{
SqlConnection MonDat = new SqlConnection("Data Source=(local);
Initial Catalog=TestDatabase;Integrated Security=SSPI");
SqlDataReader rdr = null;
try
{
MonDat.Open();
SqlCommand cmd = new SqlCommand(
"select * from Monsters where Id = EnemyID", MonDat);
rdr = cmd.ExecuteReader();
while (rdr.Read())
{
EnemyIDBuffer = (int)rdr["Id"];
EnemyName = (string)rdr["Name"];
EnemyHPBase = (int)rdr["HP"];
EnemyAtkBase = (int)rdr["Atk"];
EnemyDefBase = (int)rdr["Def"];
EnemyMagBase = (int)rdr["Mag"];
PrimAtk = (string)rdr["PrimAtk"];
SecoAtk = (string)rdr["SecoAtk"];
TertAtk = (string)rdr["TertAtk"];
RareAtk = (string)rdr["RareAtk"];
}
}
finally
{
if (rdr != null)
{
rdr.Close();
}
if (MonDat != null)
{
MonDat.Close();
}
}
}
However, when I try to run it, my program stalls and crashes. I'm guessing I have something configured wrong (I just took script from the tutorial and tweaked it slightly). Can anyone give me a hand figuring out where I went wrong?
EnemyID is a variable I used to assign what enemy is fought, based on a menu selection. I'm trying to use that variable to generate the row ID to pull the rest of the row data from, but I think that might be causing an issue.
EDIT2: It took me longer than it really should have, but I figured it out. I had to change my code a little tiny bit.
SqlCommand cmd = new SqlCommand(
"select * from Monsters where Id = " + EnemyID, MonDat);
I have a habit of forgetting that you're able to join statements like this. I made a new project that only polled data and threw it into my variables, and from there put it into text boxes, and with this method I was able to poll two different sets of enemy stats by assigning different EnemyID values to two different buttons. Proof of concept, right there.
Thanks to both people who replied, both suggestions were equally useful to getting this working. :)
There's numerous tutorials out there on how to use a database, the first two use straight ADO.NET which is pure data access, making you responsible for its interaction in your code:
ADO.NET Overview
ADO.NET Tutorial for Beginners
The next two, one is for Entity, and the other for nHibernate, they connect to SQL databases and convert the objects there to usable code in your program through a process called object relational mapping.
Entity Framework Tutorials
nHibernate Tutorials
These are all relevant links to stuff in the most current years, with VS 2013; hopefully that provides you a good starting point.
You can do something like this:
Your SQL should pass in the procedure name and EnemyId.
The stored procedure would do a select * from Enemies where EnemyId = #EnemyId
DataSet dataSet = HSPDataAccessProxy.Instance.ExecuteDataSet(sql);
The dataSet has the table that is returned by the store procedure and you can retrieve the columns you need from that table.

Insert SQL Statement into SQL Server column

I've inherited an application with a lot of ADO work in it, but the insert/update helper method that was written returns void. We've also been experiencing a lot of issues with data updates/inserts not actually happening. My goal is to update all of them to check rows affected and depending on the results, act accordingly, but for the time being of finding what may be causing the issue, I wanted to log SQL statements that are called against the server and the number of rows affected by the statement.
This is the statement I'm attempting:
SqlCommand com = new SqlCommand(String.Format("'INSERT INTO
SqlUpdateInsertHistory(Statement, AffectedRows) VALUES (''{0}'', {1});'",
statement.Replace("'", "''"), rows), con);
but it seems to constantly break somewhere in the sql that is being passed in (some cases on single quotes, but I imagine there are other characters that could cause it as well.
Is there a safe way to prep a statement string to be inserted?
I just can't rightly propose a solution to this question without totally modifying what you're doing. You're currently wide open to SQL Injection. Even if this is a local application, practice how you want to play.
using (SqlCommand com = new SqlCommand("INSERT INTO SqlUpdateInsertHistory(Statement, AffectedRows) VALUES (#Statement, #AffectedRows)", con))
{
com.Parameters.AddWithValue("#Statement", statement);
com.Parameters.AddWithValue("#AffectedRows", rows);
com.ExecuteNonQuery();
}
Have you tried SQL Server Profiler? It's already been written and logs queries, etc.
Someone else tried this and got a lot of decent answers here.

how to get exec string for sql management studio from .net code

I am debugging code someone else wrote that calls a lot of stored procedures (sql server 2008 r2) from C# code. The C# code looks like this
SqlCommand sqlCommand = new SqlCommand(strSP, ConnectionOpen());
sqlCommand.CommandType = CommandType.StoredProcedure;
sqlCommand.CommandTimeout = intTimeOut;
//System.Data.SqlClient.SqlParameter[] prmSQL
if (prmSQL != null)
{
while (i < prmSQL.Length)
{
sqlCommand.Parameters.Add(prmSQL[i]);
i = i + 1;
}
}
SqlDataReader sqlReader = sqlCommand.ExecuteReader();
For debugging my stored procedures I really need the string that sql management studio needs which is like
exec sp_name param one, param two (with quotes if needed for strings and dates..)
The sql command object does not provide this string via some property. The only way I know is to run the sql profiler on sql server and grab the string. Unfortunately the DBA's do not like this since they say running the profiler impacts performance. Is there any addin or code snippet you guys use to get the sp exec string from c# code ? Whats the best way to get this string ? Thanks
You could use a tool like mvc-mini-profiler available on NuGet (note: the name is misleading; it isn't limited to MVC). Minor clarification - since it wraps the connection, you would need to use the abstract DbConnection rather than SqlConnection, and then you just tweak the one line of code (probably in a utility class somewhere) that creates your connection, i.e. instead of:
var conn = new SqlConnection(someString);
return conn;
you might use:
var conn = new SqlConnection(someString);
return new StackExchange.Profiling.Data.ProfiledDbConnection(
conn, MiniProfiler.Current);
There's a couple of other steps to enable it (all shown on the site page), but it literally takes 2 minutes to add to an MVC application. The output is that it monitors, in real time, for enabled users (developers etc), all the activity. We use it 24x7 on stackoverflow/stackexchange (meaning: we made very sure it didn't impact performance). A live demo is available on https://data.stackexchange.com/ - just log in, and the profiling data is visible top-left. It automatically presents the data in a form runnable from SSMS, because that is how we often use it - so: it presents parameters as though they were variable declarations / initializations.
It also plays nicely with ORMs such as LINQ-to-SQL and dapper-dot-net (and many others).
Rep is too low (still a noob to StackOverflow)to comment so I'm posting this as an answer. My apologies. However, you might consider looking at SMO. SMO is a .NET object model that can be used to interact with SQL Server. Using SMO you can get a reference to a specific Stored Procedure
and then enumerate it's parameters.
That might help you get started.
In order to construct the EXEC command, you will need to know the parameter names used by the procedure. I believe you can find them by using the GetDbSchemaTable method, whcih will retrieve stored procedure SQL (I have done this using MS-Access/OLEDB and am assuming it works the same for MS-SQL/SqlClient):
using (conn == new OleDb.OleDbConnection(DBConnection)) {
conn.Open();
DataTable DBObject = conn.GetOleDbSchemaTable(OleDb.OleDbSchemaGuid.Procedures, null);
}
The column named "PROCEDURE_DEFINITION" contains the procedure's SQL and hopefully the parameter list.
You may also want to have a look at Obtaining Schema Information from a Database.
HTH

Why won't this C# database application with parameterized sql work?

I have C# forms application with a TextBox called ageTextBox;
After I press a button, the application should update one or more values from my MySQL database, but it doesn't.
Here's the code:
private void button2_Click(object sender, EventArgs e)
{
// this works perfectly if I put an actual number instead of #ag
string sql = "update persons set age = 30 where age = #ag";
OdbcCommand cmd = new OdbcCommand(sql, conn);
cmd.Parameters.Add("#ag", OdbcType.Int);
cmd.Parameters["#ag"].Value = ageTextBox.Text;
int aff = cmd.ExecuteNonQuery();
if (aff == 0)
MessageBox.Show("No rows afected");
else
MessageBox.Show("Everything went as planned");
}
}
It always shows "No rows affected"! (unless I enter something that's not a number, in which case, an exception is thrown)
Does anyone know what's going on?
cmd.Parameters.Add is obsolete you should use cmd.Parameters.AddWithValue try using this instead:
cmd.Parameters.AddWithValue("#ag", int.Parse(ageTextBox.Text));
it is possible that ODBC isn't reporting rowcounts (the equivalent of SET NOCOUNT ON). You might try adding a select ##rowcount as a final statement (or the equivalent for your particular DB), and using ExecuteScalar() (which will read that value).
This is not a solution but rather a debugging tip. Since you said it works ok when you enter a number in your code, can you try and fire a SQL tracer tool for MySQL (I suppose there is one available somwhere) and see what query is actually executed on the DB in the "working" and in the non working case (and in the exception case maybe)?
This can give you a good insight on what is going on...

Categories

Resources