Create database with variable name in sql server - c#

This must be very simple but I can't figure it out, or maybe it is not possible.
I have the next function:
private static bool createDB(SqlConnection dbConn, string dbName)
{
string sqlString = "CREATE DATABASE #dbname";
using (dbConn)
{
using (SqlCommand cmd = new SqlCommand(sqlString, dbConn))
{
cmd.Parameters.AddWithValue("#dbname", dbName);
cmd.CommandType = CommandType.Text;
dbConn.Open();
try
{
cmd.ExecuteNonQuery();
MessageBox.Show("Se creo la DB");
return true;
}
catch (Exception ex)
{
MessageBox.Show("No se creo la DB");
return false;
}
finally
{
//dbConn.Close();
}
}
}
}
But apparently the #dbname is not getting the value, dbName does gets the name I want when I call it, but the exception says incorrect syntax near '#dbname'.
I'm new to C#, please be nice :) I got this from many other posts with prepared statements, but I couldn't find any with a CREATE DATABASE, but I'm assuming this should be very similar.

You aren't allow to do that. Database names and field names will not work this way.
string sqlString = "CREATE DATABASE " + dbname";
Only parameters are allow. Example
string sqlString = "update test set myField = #myVal"
you can then use
cmd.Parameters.AddWithValue("#myVal", yourVar);
You also don't need to add # in Parameters.AddWithValue as it's just implied already.
You always want to add parameters with Parameters.AddWithValue to avoid people from escaping and performing sql injection.

You don't need to use SqlParameters for this, just add the dbName variable to your command text.
private static bool createDB(SqlConnection dbConn, string dbName)
{
string sqlString = "CREATE DATABASE " + dbname;
using (dbConn)
{
using (SqlCommand cmd = new SqlCommand(sqlString, dbConn))
{
cmd.CommandType = CommandType.Text;
dbConn.Open();
try
{
cmd.ExecuteNonQuery();
MessageBox.Show("Se creo la DB");
return true;
}
catch (Exception ex)
{
MessageBox.Show("No se creo la DB");
return false;
}
finally
{
//dbConn.Close();
}
}
}
}
As a side note I wouldn't put a messagebox (I assume this is test code) in a CRUD method like this not to mention this leaves the db connection open until the messagebox is acknowledged.

If you must "paramertize" the database name, then I'd suggest trying something like this...
string sqlString = string.Format("CREATE DATABASE {0}", dbName.Trim().Replace(" ",""));
It will also help guard against SQL injection, help not prevent, but at least you'd be ok with the littlebobbytables exploits.

Related

C# select from SQL Server database

I want to make a extra control in my C# application if the record exist.
I have got the following code - but it keeps returning a result of -1 even though the record does exist in the SQL Server database.
Can someone help me with this? I have added --> for where it went wrong
private void btnVerwijderen_Click(object sender, RoutedEventArgs e)
{
if (autonrTextBox.Text == "")
{
MessageBox.Show("Waarschuwing u kunt geen auto verwijderen indien er GEEN autonr is ingevuld");
}
else
{
--> SqlConnection con = new SqlConnection(#"Data Source=DESKTOP-RSEBNR7;Initial Catalog=AudiDealer;Integrated Security=True");
--> string check = "SELECT autonr FROM auto WHERE autonr =#autonr";
--> SqlCommand command1 = new SqlCommand(check, con);
--> command1.Parameters.AddWithValue("#autonr", autonrTextBox.Text);
con.Open();
int auto = command1.ExecuteNonQuery();
con.Close();
--> X - 1 MessageBox.Show(auto.ToString());
if (auto > 0)
{
try
{
con.Open();
using (SqlCommand command = new SqlCommand("DELETE FROM auto WHERE autonr =" + autonrTextBox.Text, con))
{
command.ExecuteNonQuery();
}
con.Close();
}
catch (SystemException ex)
{
MessageBox.Show(string.Format("An error occurred: {0}", ex.Message));
}
}
else
{
MessageBox.Show("Het opgegeven autonr komt niet voor in de database. controleer deze.");
}
}
}
The ExecuteNonQuery() method doesn't work like you think it does. The return value for this method is the number of rows changed, not anything from the result set. SELECT queries don't change rows, so -1 is the expected result. 0 rows would imply a WHERE clause that matched no rows in an UPDATE, DELETE, or INSERT. -1 is used to indicate a different situation... either a statement that doesn't change rows or a rollback. Check the remarks section in the documentation for the method.
You want to use the ExecuteScalar() method instead.
int auto = -1;
using (var con = new SqlConnection(#"Data Source=DESKTOP-RSEBNR7;Initial Catalog=AudiDealer;Integrated Security=True"))
using (var cmd = new SqlCommand("SELECT autonr FROM auto WHERE autonr =#autonr", con))
{
cmd.Parameters.Add("#autonr", SqlDbType.Int).Value = int.Parse(autonrTextBox.Text);
con.Open();
auto = (int)cmd.ExecuteScalar();
}
Finally... why check before deleting? This is just wasteful. Just issue the DELETE statement. There's no need to do a SELECT first. Your try/catch and the if() checks already handle situations where the record doesn't exist just fine.
int autonr = 0;
if (!int.TryParse(autonrTextBox.Text, autonr))
{
MessageBox.Show("Waarschuwing u kunt geen auto verwijderen indien er GEEN autonr is ingevuld");
}
else
{
try
{
using (var con = new SqlConnection(#"Data Source=DESKTOP-RSEBNR7;Initial Catalog=AudiDealer;Integrated Security=True"))
using (var cmd = new SqlCommand("DELETE FROM auto WHERE autonr = #autonr;", con))
{
cmd.Parameters.Add("#autonr", SqlDbType.Int).Value = autonr;
con.Open();
int result = cmd.ExecuteNonQuery();
if (result <= 0)
{
MessageBox.Show("Het opgegeven autonr komt niet voor in de database. controleer deze.");
}
}
}
catch (SystemException ex)
{
MessageBox.Show(string.Format("An error occurred: {0}", ex.Message));
}
}
Please use ExecuteScalar, ExecuteNonQuery will not return the result.
ExecuteNonQuery return only the the row that was change/add/remove
if you want to know how many you have use in the query Count and get the rows'number
SELECT Count(*) as CountAutonr FROM auto WHERE autonr =#autonr
and then you will get the from the CountAutonr the number of Rows
There're many things wrong in that piece of code, I really recommend you to encapsulate those database queries inside a business class that will connect to the database, retrieve the data and return as a DAO object... but that won't answer your question.
The issue is in the select command execution, ExecuteNonQuery is meant for executing UPDATE, INSERT and DELETE statements, returning the number of affected rows:
con.Open();
**int auto = command1.ExecuteNonQuery();**
con.Close();
You must use ExecuteReader method to retrieve the SELECT results as explained in the following article:
Retrieving Data Using a DataReader
The problem is in command1.ExecuteNonQuery() which returns the number of modified rows. Your query doesn't modify anything but only reads data from database, so the return value will be always -1.
So use ExecuteScalar instead - it will return your autonr value. Just remember to check it for null and cast it to correct type:
int auto = 0;
object result = command1.ExecuteScalar();
if (result != null)
auto = (int)result;

How to get alert when Unique key is violated

protected void Button1_Click(object sender, EventArgs e)
{
SqlConnection myConnection = new SqlConnection("server=VIVID-PC;Integrated Security = True;Database=SchoolDb");
SqlCommand myCommand = new SqlCommand("Command String", myConnection);
myConnection.Open();
string firstText = TextBox1.Text;
string SecondText = TextBox2.Text;
string thirdText = TextBox3.Text;
string fourthText = TextBox4.Text;
myCommand = new SqlCommand("INSERT INTO SchoolDb_Student(StudentName,RollNo,Session,MobileNo)values('" + firstText + "','" + SecondText + "' , '" + thirdText + "','" + fourthText + "')", myConnection);
myCommand.ExecuteNonQuery();
myConnection.Close();
Response.Redirect("/view.aspx");
}
Use command with parameters to pass data to server.
Make sure you dispose connection and command (via using statement)
Store connection strings in config file
Do not create dummy command objects
Here is complete code:
using(var connection = new SqlConnection(connectionString))
using(var command = connection.CreateCommand())
{
command.CommandText =
#"INSERT INTO SchoolDb_Student(StudentName,RollNo,Session,MobileNo)
VALUES (#studentName, #rollNo, #session, #mobileNo)";
command.Parameters.AddWithValue("studentName", TextBox1.Text);
command.Parameters.AddWithValue("rollNo", TextBox2.Text);
command.Parameters.AddWithValue("session", TextBox3.Text);
command.Parameters.AddWithValue("mobileNo", TextBox4.Text);
connection.Open();
try
{
command.ExecuteNonQuery();
}
catch(SqlException e)
{
if (e.Message.Contains("Violation of UNIQUE KEY constraint"))
// you got unique key violation
}
}
Further considerations - improve naming in your code - TextBox1, TextBox2 etc says nothing to reader. Give them appropriate names, like StudentNameTextBox, RollNoTextBox etc. Also good practice is splitting data access and UI logic.
If the database detects a unique key violation, this line
myCommand.ExecuteNonQuery();
will throw an exception. You can catch that exception and proceed with your own code:
try
{
myCommand.ExecuteNonQuery();
}
catch(Exception e)
{
// right here, "something" went wrong. Examine e to check what it was.
}
Please note that your code is vulnerable to SQL injection attacks. You should be using command paramaters instead of building the SQL manually. In addition, you should be using using blocks (see here for details)
ExecuteNonQuery will throw an exception if it's unable to INSERT row into database. In your case, it's most likely an SqlException. Catch it.
use your returnType from ExecuteNonQuery() (Read the remarks part) to detect failure in insertion. you can use the exception or the no. of rows affected part
Try this :
try
{
... your rest of the code
...
int rowsAffected = myCommand.ExecuteNonQuery(); // Most probaboly it will throw exception in case of Unique key violation. If not, still no rows have been affected
if(rowsAffected<1)
{
//your Alert for no records inserted
}
else
{
//your alert for successful insertion
}
}
catch(SqlException ex)
{
//check the exception and display alert
}
finally
{
//release connection and dispose command object
}
As suggested in comment use command param.
try
{
//Your other code
_myCommand.ExecuteNonQuery();
myConnection.Close();
Response.Redirect("/view.aspx");
}
catch(SqlException sqlExc)
{
// Your popup or msg.
}
You also loop for different sql error in catch block.

Why is my SQL Server CE code failing?

In my WindowsCE / Compact Framework (.NET1.1) project, I need to create a new table in code. I thought I could do it this way:
if (! TableExists("table42"))
{
CreateTable42();
}
public static bool TableExists(string tableName)
{
try
{
using (SqlCeConnection sqlConn = new SqlCeConnection(#"Data Source=\my documents\Platypus.SDF"))
{
sqlConn.Open();
string qryStr = "SELECT COUNT(*) FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_NAME = ?";
SqlCeCommand cmd = new SqlCeCommand(qryStr, sqlConn);
cmd.Parameters[0].Value = tableName;
cmd.CommandType = CommandType.Text;
int retCount = (int)cmd.ExecuteScalar();
return retCount > 0;
}
}
catch (Exception ex)
{
MessageBox.Show("TableExists ex.Message == " + ex.Message);
MessageBox.Show("TableExists ex.ToString() == " + ex.ToString());
MessageBox.Show("TableExists ex.GetBaseException() == " + ex.GetBaseException());
return false;
}
}
...but the call to TableExists() fails; and shows me:
TableExists ex.Message ==
TableExists ex.ToString() == System.Data.SqlServerCe.SqlCeException at System.Data.SqlServerCe.SqlConnection.ProcessResults(Int32 hr) at ...at Open(boolean silent) ...
TableExists ex.GetBaseException() == [same as ex.ToString() above]
"Int32 hr" ... ??? What the Hec Ramsey is that?
As documented previously in these environs, I can't step through this projct, so I rely on those calls to MessageBox.Show().
The rest of the related code, if it may be of interest, is:
public static void CreateTable42()
{
try
{
using (SqlCeConnection con = new SqlCeConnection(#"Data Source=\my documents\Platypus.SDF"))
{
con.Open();
using (SqlCeCommand com = new SqlCeCommand(
"create table table42 (setting_id INT IDENTITY NOT NULL PRIMARY KEY, setting_name varchar(40) not null, setting_value(63) varchar not null)", con))
{
com.ExecuteNonQuery();
WriteSettingsVal("table42settingname","table42settingval");
}
}
}
catch (Exception ex)
{
MessageBox.Show("CreateTable42 " + ex.Message);
}
}
public static void WriteSettingsVal(string settingName, string settingVal)
{
using (SqlCeConnection sqlConn = new SqlCeConnection(#"Data Source=\my documents\Platypus.SDF"))
{
sqlConn.Open();
string dmlStr = "insert into tabld42 (setting_name, setting_value) values(?, ?)";
SqlCeCommand cmd = new SqlCeCommand(dmlStr, sqlConn);
cmd.CommandType = CommandType.Text;
cmd.Parameters[0].Value = settingName;
cmd.Parameters[1].Value = settingVal;
try
{
cmd.ExecuteNonQuery();
}
catch (Exception ex)
{
MessageBox.Show("WriteSettingsVal " + ex.Message);
}
}
}
UPDATE
Answer to Brad Rem's comment:
I don't think it's necessary to encase the param in quotes, as other working code is like:
cmd.Parameters.Add("#account_id", Dept.AccountID);
-and:
cmd.Parameters[0].Value = Dept.AccountID;
(it does it one way the first time when in a loop, and the other way thereafter (don't ask me why).
Anyway, just for grins, I did change the TableExists() parameter code from this:
cmd.Parameters[0].Value = tableName;
...to this:
cmd.Parameters.Add("#TABLE_NAME", tableName);
...but I still get the exact same result.
UPDATE 2
Here (http://msdn.microsoft.com/en-us/library/aa237891(v=SQL.80).aspx) I found this: "Caution You must specify the SQL Server CE provider string when you open a SQL Server CE database."
They give this example:
cn.ConnectionString = "Provider=Microsoft.SQLSERVER.OLEDB.CE.2.0; data source=\Northwind.sdf"
I'm not doing that; my conn str is:
using (SqlCeConnection sqlConn = new SqlCeConnection(#"Data Source=\my documents\CCRDB.SDF"))
Could that be my problem?
UPDATE 3
I took this gent's advice (http://www.codeproject.com/Answers/629613/Why-is-my-SQLServer-CE-code-failing?cmt=487657#answer1) and added a catch for SqlCeExcpetions so that it is now:
public static bool TableExists(string tableName)
{
try
{
using (SqlCeConnection sqlConn = new SqlCeConnection(#"Data Source=\my documents\CCRDB.SDF"))
{
sqlConn.Open();
string qryStr = "SELECT COUNT(*) FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_NAME = #TABLE_NAME";
SqlCeCommand cmd = new SqlCeCommand(qryStr, sqlConn);
cmd.Parameters.Add("#TABLE_NAME", tableName);
cmd.CommandType = CommandType.Text;
int retCount = (int)cmd.ExecuteScalar();
return retCount > 0;
}
}
catch (SqlCeException sqlceex)
{
MessageBox.Show("TableExists sqlceex.Message == " + sqlceex.Message);
MessageBox.Show("TableExists sqlceex.ToString() == " + sqlceex.ToString());
return false;
. . .
The SqlCeException message is: "There is a file sharing violation. A different process might be using the file [,,,,,]" then "...processresults ... open ... getinstance ..."
UPDATE 4
Trying to use ctacke's sample code, but: Is Transaction absolutely necessary? I had to change the code to the following for my scenario/milieu, and don't know what Transaction should be or how to build it:
public static bool TableExists(string tableName)
{
string sql = string.Format("SELECT COUNT(*) FROM information_schema.tables WHERE table_name = '{0}'", tableName);
try
{
using (SqlCeConnection sqlConn = new SqlCeConnection(#"Data Source=\my documents\HHSDB.SDF"))
{
SqlCeCommand command = new SqlCeCommand(sql, sqlConn);
//command.Transaction = CurrentTransaction as SqlCeTransaction;
command.Connection = sqlConn;
command.CommandText = sql;
int count = Convert.ToInt32(command.ExecuteScalar());
return (count > 0);
}
}
catch (SqlCeException sqlceex)
{
MessageBox.Show("TableExists sqlceex.Message == " + sqlceex.Message);
return false;
}
}
UPDATE 5
With this code, the err msg I get is, "An err msg is available for this exception but cannot be displayed because these messages are optional and are not currently insallted on this device. Please install ... NETCFv35.Messages.EN.cab"
UPDATE 6
All too typically, this legacy, ancient-technology project is giving me headaches. It seems that only one connection is allowed to be open at a time, and the app opens one from the outset; so, I have to use that connection. However, it is a DBConnection, not a SqlCeConnection, so I can't use this code:
using (SqlCeCommand com = new SqlCeCommand(
"create table hhs_settings (setting_id int identity (1,1) Primary key, setting_name varchar(40) not null, setting_value(63) varchar not null)", frmCentral.dbconn))
{
com.ExecuteNonQuery();
WriteSettingsVal("beltprinter", "ZebraQL220");
}
...because the already-open connection type passed as an arg to the SqlCeCommand constructor is DBCommand, not the expected/required SqlCeConneection.
The tentacles of this code are far too wide and entrenched to rip out by the roots and refactor to make it more sensible: a single tentative step in the foothills causes a raging avalanche on Everest.
For fun I'd try two things. First, replace the '?' parameter with a named parameter like '#tablename' and see if that changes things. Yes, I know '?' should work, but it's a confusing, ugly precedent and maybe since it's a system table it's wonky. Yes, it's a stretch, but worth a try just to know.
The second thing I'd do is something like this method from the SQLCE implementation of the OpenNETCF ORM:
public override bool TableExists(string tableName)
{
var connection = GetConnection(true);
try
{
using (var command = GetNewCommandObject())
{
command.Transaction = CurrentTransaction as SqlCeTransaction;
command.Connection = connection;
var sql = string.Format("SELECT COUNT(*) FROM information_schema.tables WHERE table_name = '{0}'", tableName);
command.CommandText = sql;
var count = Convert.ToInt32(command.ExecuteScalar());
return (count > 0);
}
}
finally
{
DoneWithConnection(connection, true);
}
}
Note that I didn't even bother parameterizing, largely because I doubt it will provide any perf benefit (queue the hordes whining about SQL injection). This way definitely works - we've got it deployed and in use in many live solutions.
EDIT
For completeness (though I'm not sure it adds to clarity).
protected virtual IDbConnection GetConnection(bool maintenance)
{
switch (ConnectionBehavior)
{
case ConnectionBehavior.AlwaysNew:
var connection = GetNewConnectionObject();
connection.Open();
return connection;
case ConnectionBehavior.HoldMaintenance:
if (m_connection == null)
{
m_connection = GetNewConnectionObject();
m_connection.Open();
}
if (maintenance) return m_connection;
var connection2 = GetNewConnectionObject();
connection2.Open();
return connection2;
case ConnectionBehavior.Persistent:
if (m_connection == null)
{
m_connection = GetNewConnectionObject();
m_connection.Open();
}
return m_connection;
default:
throw new NotSupportedException();
}
}
protected virtual void DoneWithConnection(IDbConnection connection, bool maintenance)
{
switch (ConnectionBehavior)
{
case ConnectionBehavior.AlwaysNew:
connection.Close();
connection.Dispose();
break;
case ConnectionBehavior.HoldMaintenance:
if (maintenance) return;
connection.Close();
connection.Dispose();
break;
case ConnectionBehavior.Persistent:
return;
default:
throw new NotSupportedException();
}
}
wow... still struggling... I did too when I first got started on a handheld device SQL-CE. My current project is running with C#.Net 3.5 but I think the principles you are running into are the same. Here is what is working for my system in it's close parallels to yours.
First, the connection string to the handheld. It is just
string myConnString = #"Data Source=\MyFolder\MyData.sdf";
no reference to the sql driver
Next, the TableExists
SqlCeCommand oCmd = new SqlCeCommand( "select * from INFORMATION_SCHEME.TABLES "
+ " where TABLE_NAME = #pTableName" );
oCmd.Parameters.Add( new SqlCeParameter( "pTableName", YourTableParameterToFunction ));
The "#pTableName" is to differentiate between the "TABLE_NAME" column and to absolutely prevent any issues about ambiguity. The Parameter does NOT get the extra "#". In SQL, the # indicates to look for a variable... The SqlCeParameter of "pTableName" must match as it is in the SQL Command (but without the leading "#").
Instead of issuing a call to ExecuteScalar, I am actually pulling the data down into a DataTable via
DataTable oTmpTbl = new DataTable();
SqlCeDataAdapter da = new SqlCeDataAdapter( oCmd );
da.Fill( oTmpTbl );
bool tblExists = oTbl.Rows.Count > 0;
This way, I either get records back or I dont... if I do, the number of records should be > 0. Since I'm not doing a "LIKE", it should only return the one in question.
When you get into your insert, updates and deletes, I have always tried to prefix my parameters with something like "#pWhateverColumn" and make sure the SqlCeParameter is by the same name but without the "#". I haven't had any issues and this project has been running for years. Yes it's a .net 3.5 app, but the fundamental basics of connecting and querying SHOULD be the same.
If it IS all within your application, I would try something like creating a single global static "Connection" object. Then, a single static method to handle it. Then, instead of doing a NEW connection during every "using" attempt, change it to something like...
public static class ConnectionHandler
{
static SqlCeConnection myGlobalConnection;
public static SqlCeConnection GetConnection()
{
if( myGlobalConnection == null )
myGlobalConnection = new SqlCeConnection();
return myGlobalConnection;
}
public static bool SqlConnect()
{
GetConnection(); // just to ensure object is created
if( myGlobalConnection.State != System.Data.ConnectionState.Open)
{
try
{
myGlobalConnection.ConnectionString = #"Data Source=\MyFolder\MyDatabase.sdf";
myGlobalConnection.Open();
}
catch( Exception ex)
{
// optionally messagebox, or preserve the connection error to the user
}
}
if( myGlobalConnection.State != System.Data.ConnectionState.Open )
MessageBox.Show( "notify user");
// return if it IS successful at opening the connection (or was already open)
return myGlobalConnection.State == System.Data.ConnectionState.Open;
}
public static void SqlDisconnect()
{
if (myGlobalConnection!= null)
{
if (myGlobalConnection.State == ConnectionState.Open)
myGlobalConnection.Close();
// In case some "other" state, always try to force CLOSE
// such as Connecting, Broken, Fetching, etc...
try
{ myGlobalConnection.Close(); }
catch
{ // notify user if issue}
}
}
}
... in your other class / function...
if( ConnectionHandler.SqlConnect() )
Using( SqlCeConnection conn = ConnectionHandler.GetConnection )
{
// do your stuff
}
... finally, when your app is finished, or any other time you need to...
ConnectionHandler.SqlDisconnect();
This keeps things centralized, and you don't have to worry about open/close, what the connection string is buried all over the place, etc... If you can't connect, you can't run a query, don't try to run the query if it can't even get that far.
I think it may be a permission issue on INFORMATION_SCHEMA system views. Try the following.
GRANT VIEW DEFINITION TO your_user;
See here for more details

How to autofill a radio_button, a few combo_boxes, many text_boxes, and a calendar FROM a combo_box selection

I am creating a tool that will allow a Human Resource employee to input various information about a new employee into an access database(for academic purposes). So far I have the layout set-up (as you will be able to see shortly), validation is in a place, and a dataGridView gets populated by using an Access Database I created. Then I have 3 buttons, Submit (Insert), Update and Delete.
PS: I know that the table I am trying to update is huge, but that's what our team decided to do.
Image of my layout:
Human Resource employee tool
The submit and delete works, BUT the update only works if all of the fields are filled with data. The code I wrote tries to update all the fields WHERE the EMPLOYEE_ID equals the value that's selected on the combo_box, so if I try to update only one field I get an error saying "No value given for one or more required parameters". I think that by auto-filling all the field on the left when a value from a combo_box is selected will fix my problem. The thing is that I have no idea on how to accomplish this. Any help would be appreciate it!!
UPDATE STATEMENT.
private void cmdModify_Click(object sender, EventArgs e)
{
//Setting up Connection String
string connectionString = GetConnectionString();
string SqlString = "UPDATE Employee SET FIRST_NAME = #FirstName , LAST_NAME= #LastName, MIDDLE_NAME = #MiddleName, DATE_HIRED =#DateHired, WAGE_TYPE =#WageType, WAGE = #Wage, GENDER =#Gender, MARTIAL_STATUS =#MartialStatus, UNIT_NUMBER =#UnitNumber, STREET_NUMBER =#StreetNumber, STREET_NAME =#StreetName, CITY =#City, PROVINCE =#Province, POSTAL_CODE =#PostalCode, HOME_NUMBER =#HomeNumber, CELL_NUMBER =#CellNumber, JOB_TITTLE =#JobTittle, END_DATE=7/24/2013, DPT_NAME =#Department, NOTES =#Notes WHERE [EMPLOYEE_ID] = #EMPLOYEE_ID";
using (OleDbConnection conn = new OleDbConnection(connectionString))
{
using (OleDbCommand cmd = new OleDbCommand(SqlString, conn))
{
cmd.CommandType = CommandType.Text;
cmd.Parameters.AddWithValue("FirstName", txtFname.Text);
cmd.Parameters.AddWithValue("LastName", txtLname.Text);
cmd.Parameters.AddWithValue("MiddleName", txtMname.Text);
cmd.Parameters.AddWithValue("DateHired", dateTimePicker1.Text);
cmd.Parameters.AddWithValue("WageType", cmbType.SelectedItem);
cmd.Parameters.AddWithValue("Wage", txtWage.Text);
if (rbMale.Checked == true)
{
cmd.Parameters.AddWithValue("Gender", rbMale.Text);
}
else if (rbFemale.Checked == true)
{
cmd.Parameters.AddWithValue("Gender", rbFemale.Text);
}
cmd.Parameters.AddWithValue("MartialStatus", cmbStatus.SelectedItem);
cmd.Parameters.AddWithValue("UnitNumber", txtUnit.Text);
cmd.Parameters.AddWithValue("StreetNumber", txtStreetNo.Text);
cmd.Parameters.AddWithValue("StreetName", txtStreet.Text);
cmd.Parameters.AddWithValue("City", txtCity.Text);
cmd.Parameters.AddWithValue("Province", cmbState.SelectedItem);
cmd.Parameters.AddWithValue("PostalCode", txtPostal.Text);
cmd.Parameters.AddWithValue("HomeNumber", txtHphone.Text);
cmd.Parameters.AddWithValue("CellNumber", txtCphone.Text);
cmd.Parameters.AddWithValue("JobTittle", cmbJobTitle.SelectedItem);
cmd.Parameters.AddWithValue("Department", cmbDepartment.SelectedItem);
cmd.Parameters.AddWithValue("Notes", txtNotes.Text);
cmd.Parameters.AddWithValue("EMPLOYEE_ID", comboBox1.SelectedValue);
try
{
// openning a connection to the database / table
conn.Open();
// SQL commnd class
cmd.ExecuteNonQuery();
//Closing Database connection
conn.Close();
//Console.WriteLine("Data was added to the table !!!");
MessageBox.Show("Data was added to the table !!!");
}
catch (Exception ex)
{
MessageBox.Show(ex.Message);
//Console.WriteLine(ex.Message); // printing exception message to default output
}
}
}
Refresh();
clearText();
}
INSERT STATEMENT.
private void Insert_Data()
{
string connectionString = GetConnectionString();
string SqlString = "INSERT INTO Employee (FIRST_NAME, LAST_NAME, MIDDLE_NAME, DATE_HIRED, WAGE_TYPE, WAGE, GENDER, MARTIAL_STATUS,UNIT_NUMBER, STREET_NUMBER, STREET_NAME, CITY ,PROVINCE, POSTAL_CODE, HOME_NUMBER, CELL_NUMBER, JOB_TITTLE, END_DATE, DPT_NAME, NOTES) VALUES (#FirstName,#LastName,#MiddleName,#DateHired,#WageType,#Wage,#Gender,#MartialStatus,#UnitNumber,#StreetNumber,#StreetName,#City,#Province,#PostalCode,#HomeNumber,#CellNumber,#JobTittle,7/24/2013,#Department,#Notes)";
using (OleDbConnection conn = new OleDbConnection(connectionString))
{
using (OleDbCommand cmd = new OleDbCommand(SqlString, conn))
{
cmd.CommandType = CommandType.Text;
cmd.Parameters.AddWithValue("FirstName", txtFname.Text);
cmd.Parameters.AddWithValue("LastName", txtLname.Text);
cmd.Parameters.AddWithValue("MiddleName", txtMname.Text);
cmd.Parameters.AddWithValue("DateHired", dateTimePicker1.Text);
cmd.Parameters.AddWithValue("WageType", cmbType.SelectedItem);
cmd.Parameters.AddWithValue("Wage", txtWage.Text);
if (rbMale.Checked == true)
{
cmd.Parameters.AddWithValue("Gender",rbMale.Text);
}
else if (rbFemale.Checked == true)
{
cmd.Parameters.AddWithValue("Gender", rbFemale.Text);
}
cmd.Parameters.AddWithValue("MartialStatus", cmbStatus.SelectedItem);
cmd.Parameters.AddWithValue("UnitNumber", txtUnit.Text);
cmd.Parameters.AddWithValue("StreetNumber", txtStreetNo.Text);
cmd.Parameters.AddWithValue("StreetName", txtStreet.Text);
cmd.Parameters.AddWithValue("City", txtCity.Text);
cmd.Parameters.AddWithValue("Province", cmbState.SelectedItem);
cmd.Parameters.AddWithValue("PostalCode", txtPostal.Text);
cmd.Parameters.AddWithValue("HomeNumber", txtHphone.Text);
cmd.Parameters.AddWithValue("CellNumber", txtCphone.Text);
cmd.Parameters.AddWithValue("JobTittle", cmbJobTitle.SelectedItem);
cmd.Parameters.AddWithValue("Department", cmbDepartment.SelectedItem);
cmd.Parameters.AddWithValue("Notes", txtNotes.Text);
try
{
// openning a connection to the database / table
conn.Open();
// SQL commnd class
cmd.ExecuteNonQuery();
//Closing Database connection
conn.Close();
//Console.WriteLine("Data was added to the table !!!");
MessageBox.Show("Data was added to the table !!!");
}
catch (Exception ex)
{
MessageBox.Show(ex.Message);
//Console.WriteLine(ex.Message); // printing exception message to default output
}
}
}
Refresh();
clearText();
}
DELETE STATEMENT
private void cmdDelete_Click_1(object sender, EventArgs e)
{
//Setting up Connection String
string connectionString = GetConnectionString();
string SqlString = "DELETE * FROM Employee WHERE [EMPLOYEE_ID] = #EMPLOYEE_ID ";
using (OleDbConnection conn = new OleDbConnection(connectionString))
{
using (OleDbCommand cmd = new OleDbCommand(SqlString, conn))
{
cmd.CommandType = CommandType.Text;
cmd.Parameters.AddWithValue("EMPLOYEE_ID", comboBox1.SelectedValue);
try
{
// openning a connection to the database / table
conn.Open();
// SQL commnd class
cmd.ExecuteNonQuery();
//Closing Database connection
conn.Close();
//Console.WriteLine("Data was added to the table !!!");
MessageBox.Show("Data was deleted from the table !!!");
}
catch (Exception ex)
{
MessageBox.Show(ex.Message);
//Console.WriteLine(ex.Message); // printing exception message to default output
}
}
}
Refresh();
clearText();
}
You are getting this error because the AddWithValue method is adding null to the Parameters collection. What you need is for it to add DBNull instead.
cmd.Parameters.AddWithValue("FirstName", txtFname.Text ?? DBNull.Value);
Those SelectedItem values might cause you problems too if they are complex types:
cmd.Parameters.AddWithValue("Province", cmbState.SelectedItem);
You might have to specify a property on the instance to make it work
cmd.Parameters.AddWithValue("Province", cmbState.SelectedItem.MyIdProperty);

Guide to enhance my code

This program will copy all records inside the table 1 into table 2 and also write into a text file. After it finishes copied all the records, the records will be delete make the table1 empty before new record is added. i like to enhance my code for example :
like inserting code to verify if records empty or not, if got problem in copying the file, or if it is EOF, what should i do??
This code was in form_load() and running in win form application, what if, if i run the program exe, i dont what the form to be appeared? i want to make this program like it was running on windows behind. Only error or successful messagebox will appeared?
Any help in solution, guidance or reference are very very thankful.
Thank you in advance!
//create connection
SqlConnection sqlConnection1 =
new SqlConnection("Data Source=.\SQLEXPRESS;Database=F:\Test2.mdf;Integrated Security=True;User Instance=True");
//command insert into queries
SqlCommand cmdCopy = new SqlCommand();
cmdCopy.CommandType = System.Data.CommandType.Text;
cmdCopy.CommandText = "INSERT INTO tblSend (ip, msg, date) SELECT ip, msg, date FROM tblOutbox";
cmdCopy.Connection = sqlConnection1;
//insert into text file
SqlCommand cmd = new SqlCommand();
cmd.CommandType = CommandType.Text;
cmd.CommandText = "SELECT * FROM tblOutbox";
cmd.Connection = sqlConnection1;
sqlConnection1.Open();
StreamWriter tw = File.AppendText("c:\INMS.txt");
SqlDataReader reader = cmd.ExecuteReader();
tw.WriteLine("id, ip address, message, datetime");
while (reader.Read())
{
tw.Write(reader["id"].ToString());
tw.Write(", " + reader["ip"].ToString());
tw.Write(", " + reader["msg"].ToString());
tw.WriteLine(", " + reader["date"].ToString());
}
tw.WriteLine("Report Generate at : " + DateTime.Now);
tw.WriteLine("---------------------------------");
tw.Close();
reader.Close();
//command delete
String strDel = "DELETE tblOutbox";
SqlCommand cmdDel = new SqlCommand(strDel, sqlConnection1);
//sqlConnection1.Open(); //open con
cmdCopy.ExecuteScalar();
cmd.ExecuteNonQuery(); //execute insert query
cmdDel.ExecuteScalar();//execute delete query
sqlConnection1.Close(); //close con
//*****************************************************
}
catch (System.Exception excep)
{
MessageBox.Show(excep.Message);
}
A few suggestions:
Move it out of the form. Business logic and data access does not belong in the form (View). Move it to a separate class.
Keep the MessageBox code in the form. That's display logic. The entire try..catch can be moved out of the method; just have the method throw exceptions. And don't catch System.Exception - catch the database one(s) you expect.
I echo Ty's comments on IDisposable and using statements.
Read up on Extract Method and the Single Responsibility Principle. This method does a lot, and it's long. Break it up.
Move some of the string hardcodes out. What if your connection string or file paths change? Why not put those in a configuration file (or at least use some constants)?
For starters, anyway. :)
That sure is some code and I sure could recommend a lot of things to improve it if you care.
First thing I would do is read up on IDisposable then I would re-write that DataReader as following.
using(StreamWriter tw = File.AppendText("c:\INMS.txt"))
{
using(SqlDataReader reader = cmd.ExecuteReader())
{
tw.WriteLine("id, ip_add, message, datetime");
while (reader.Read())
{
tw.Write(reader["id"].ToString());
tw.Write(", " + reader["ip_add"].ToString());
tw.Write(", " + reader["message"].ToString());
tw.WriteLine(", " + reader["datetime"].ToString());
}
tw.WriteLine(DateTime.Now);
tw.WriteLine("---------------------------------");
}
}
Then after your catch, put the following and remove the close call.
finally
{
sqlConnection1.Dispose(); //close con
}
In addition to some of the other answers already given, you might also want to consider protecting the data operation with a Transaction.
I assume that you don't want any of the following operation to partially complete:
cmdCopy.ExecuteScalar();
cmd.ExecuteNonQuery(); //execute insert query
cmdDel.ExecuteScalar();//execute delete query
If you are processing MANY rows you might want to batch your updates but that is a whole different issue.
Firstly kudos to you for trying to improve your skill and being open to publish your code like this. I believe that is the first step to being a better programmer, is to have this type of attitude.
Here is an implementation that answers some of your questions.
I have extracted some of the old code into methods and also moved some of the responsibilities to their own classes.
Disclaimer:
Although the code compiles I didn't run it against a database, therefore there might be a couple of small things I missed.
I had to stop short on certain refactorings not knowing the exact requirements and also to still try and keep some of the concepts simple.
.
using System;
using System.Configuration;
using System.Data.SqlClient;
using System.IO;
// Program.cs
static class Program
{
[STAThread]
static void Main()
{
try
{
MailArchiver.Run();
Console.WriteLine("Application completed successfully");
}
catch (Exception ex)
{
Console.WriteLine("Unexpected error occurred:");
Console.WriteLine(ex.ToString());
}
}
}
// Reads new messages from DB, save it to a report file
// and then clears the table
public static class MailArchiver
{
public static void Run()
{
// Might be a good idea to a datetime suffix
ReportWriter.WriteFile(#"c:\INMS.txt");
CopyAndClearMessages();
}
private static void CopyAndClearMessages()
{
SqlConnection cn = DbConnectionFactory.CreateConnection();
cn.Open();
try
{
SqlTransaction tx = cn.BeginTransaction();
try
{
CopyMessages(cn, tx);
DeleteMessages(cn, tx);
tx.Commit();
}
catch
{
tx.Rollback();
throw;
}
}
finally
{
cn.Close();
}
}
private static void DeleteMessages(SqlConnection cn, SqlTransaction tx)
{
var sql = "DELETE FROM tblOutbox";
var cmd = new SqlCommand(sql, cn, tx);
cmd.CommandTimeout = 60 * 2; // timeout 2 minutes
cmd.ExecuteNonQuery();
}
private static void CopyMessages(SqlConnection cn, SqlTransaction tx)
{
var sql = "INSERT INTO tblSend (ip, msg, date) SELECT ip, msg, date FROM tblOutbox";
var cmd = new SqlCommand(sql, cn, tx);
cmd.CommandTimeout = 60 * 2; // timeout 2 minutes
cmd.ExecuteNonQuery();
}
}
// Provides database connections to the rest of the app.
public static class DbConnectionFactory
{
public static SqlConnection CreateConnection()
{
// Retrieve connection string from app.config
string connectionString = ConfigurationManager.ConnectionStrings["MailDatabase"].ConnectionString;
var cn = new SqlConnection(connectionString);
return cn;
}
}
// Writes all the data in tblOutbox to a CSV file
public static class ReportWriter
{
private static SqlDataReader GetData()
{
SqlConnection cn = DbConnectionFactory.CreateConnection();
cn.Open();
try
{
var cmd = new SqlCommand();
cmd.CommandText = "SELECT * FROM tblOutbox";
cmd.Connection = cn;
return cmd.ExecuteReader();
}
finally
{
cn.Close();
}
}
public static void WriteFile(string filename)
{
if (File.Exists(filename))
{
// This might be serious, we may overwrite data from the previous run.
// 1. You might want to throw your own custom exception here, should want to handle this
// condition higher up.
// 2. The logic added here is not the best and added for demonstration purposes only.
throw new Exception(String.Format("The file [{0}] already exists, move the file and try again"));
}
var tw = new StreamWriter(filename);
try
{
// Adds header record that describes the file contents
tw.WriteLine("id,ip address,message,datetime");
using (SqlDataReader reader = GetData())
{
while (reader.Read())
{
var id = reader["id"].ToString();
var ip = reader["ip"].ToString();
//msg might contain commas, surround value with double quotes
var msg = reader["msg"].ToString();
var date = reader["data"].ToString();
if (IfValidRecord(id, ip, msg, msg, date))
{
tw.WriteLine(string.Format("{0},{1},{2},{3}", id, ip, msg, date));
}
}
tw.WriteLine("Report generated at : " + DateTime.Now);
tw.WriteLine("--------------------------------------");
}
}
finally
{
tw.Close();
}
}
private static bool IfValidRecord(string id, string ip, string msg, string msg_4, string date)
{
// this answers your question on how to handle validation per record.
// Add required logic here
return true;
}
}
Use a SELECT query to find the non-empty rows (you seem to get along with the EOF issue).
On form_load event make the form invisible by program arguments.
Why not to use INSERT INTO (and then DELETE)?

Categories

Resources