Copying tables from one database to another on same server - c#

As the server requires a connection for each database, the answers I've found in SO don't work at all.
For some tables I have to make some calculations before copying the rows, but some I can copy whole table. And finally it's an automation in my program that I've wrote.
Oldcn is the connection to old database, Newcn for the new database.
For the tables that I can copy whole I wrote this procedure below.
Is there a better an short way to do this job? (It works on background)
private string[] CopyTva(MySqlConnection Oldcn, MySqlConnection Newcn, string[] res, DoWorkEventArgs we,string msg)
{
int counter = int.Parse(res[1]);
MySqlCommand cmd = new MySqlCommand("SELECT * FROM tvaval", Oldcn);
MySqlCommand cmd1 = new MySqlCommand("INSERT INTO tvaval (id,tvavalue,cr_user,cr_date,up_user,up_date) VALUES (#id,#tvavalue,#cr_user,#cr_date,#up_user,#up_date)", Newcn);
MySqlDataReader rd = null;
try
{
rd = cmd.ExecuteReader();
while (rd.Read())
{
cmd1.Parameters.AddWithValue("#id", rd["id"].ToString());
//bla bla same as above
try
{
cmd1.ExecuteNonQuery();
}
catch (MySqlException e)
{
rd.Dispose();
res[2] = "Erreur:TVA " + e.Message.ToString();
return res;
}
++counter;
bgw.ReportProgress((counter * 100) / DbTotalRow,msg);
cmd1.Parameters.Clear();
}
rd.Dispose();
}
catch (MySqlException e)
{
res[2] = "Erreur:TVA " + e.Message.ToString();
return res;
}
res[0] = "1";res[1] = counter.ToString();res[2] = "";
return res;
}

MySQL doesn't require a separate connection for each database. A connection has a default database, but you're allowed to specify the database name explicitly before the table name, and this will override the default. So you can do this with a single query:
INSERT INTO newdb.tvaval
SELECT * FROM olddb.tvaval

Related

How To Delete Rows in a SQLite Database that may hold the same data depending on which row is selected in a listbox

As the title suggests, I want to delete rows of a database depending on which row in a listbox the user will select.The Listbox. This is my current code, but when run, there is an SQL Logic Error.
string SelectedItemToDelete = LBoxCurrentBasket.SelectedItem.ToString();
sqlite_conn = new SQLiteConnection("Data Source=RetailSystem.db; Version = 3; New = True; Compress = True;");
sqlite_conn.Open();
try
{
sqlite_cmd = sqlite_conn.CreateCommand();
sqlite_cmd.CommandText = "DELETE * FROM TblBasket WHERE BasketItemName = #ItemToDelete";
sqlite_cmd.Parameters.AddWithValue("#ItemToDelete", SelectedItemToDelete);
SQLiteDataReader sqlite_datareader;
sqlite_datareader = sqlite_cmd.ExecuteReader();
sqlite_conn.Close();
MessageBox.Show("Record Deleted!");
LBoxCurrentBasket.Refresh();
}
catch (Exception ex)
{
MessageBox.Show(ex.ToString());
}
Also is there a way to merge together the T-Shirt Records so there is only one record with a higher quantity?The Database if it helps
I think that you should execute sqlite_cmd.ExecuteNonQuery(); method instead of executing sqlite_cmd.ExecuteReader(); on SqliteCommand object.
As per documentation SqliteCommand.ExecuteNonQuery method return the number of rows inserted, updated, or deleted.
So, in my opinion I will do it like this:
string SelectedItemToDelete = LBoxCurrentBasket.SelectedItem.ToString();
sqlite_conn = new SQLiteConnection("Data Source=RetailSystem.db; Version = 3; New = True; Compress = True;");
sqlite_conn.Open();
try
{
sqlite_cmd = sqlite_conn.CreateCommand();
sqlite_cmd.CommandText = "DELETE FROM TblBasket WHERE BasketItemName = #ItemToDelete";
sqlite_cmd.Parameters.AddWithValue("#ItemToDelete", SelectedItemToDelete);
sqlite_cmd.ExecuteNonQuery();
MessageBox.Show("Record Deleted!");
LBoxCurrentBasket.Refresh();
}
catch (Exception ex)
{
MessageBox.Show(ex.ToString());
}
finally
{
sqlite_conn.Close();
}
Also, don't forget to pass parameters like connection string, and query string to your command object in order to perform the operation on database, as I can see, you did not do that in current state of code .

C# how to check if database is not busy?

My class has a couple of methods going on. The first one is creating a database, that's done. Then, creates stored procedures that is being read from a sql file. then detach that DB. Now it seems that my store procedure query is taking a while to finish and my method to detach is being invoked while the database is busy. So how do I tell if the database is idle. The exception goes "cannot detach the database because it is currently in use"
Methods:
void CreateStoredProcedures(string type)
{
string spLocation = File.ReadAllText("CreateStoredProcedures.sql");
var conn = new SqlConnection(connectionString + ";database=" + type + DateTime.Now.ToString("yyyyMMdd"));
try
{
Server server = new Server(new ServerConnection(conn));
server.ConnectionContext.ExecuteNonQuery(spLocation);
}
catch (Exception ex)
{
MessageBox.Show(ex.ToString());
}
}
bool DetachBackup(string type)
{
var conn = new SqlConnection(connectionString);
SqlCommand command = new SqlCommand("", conn);
command.CommandText = #"sys.sp_detach_db '" + type + DateTime.Now.ToString("yyyyMMdd") + "'";
try
{
conn.Open();
command.ExecuteNonQuery();
}
catch (Exception ex)
{
MessageBox.Show(ex.ToString());
return false;
}
finally
{
if ((conn.State == ConnectionState.Open))
{
conn.Close();
}
}
return true;
}
Click event:
private void btnFullBackup_Click(object sender, EventArgs e)
{
lblStatus.Text = "Starting full backup...";
Execute("FULL");
progressBar.Value = 20;
lblStatus.Text = "Copying tables...";
progressBar.Value = 60;
CopyTables("FULL");
progressBar.Value = 70;
lblStatus.Text = "Creating stored procedures...";
CreateStoredProcedures("FULL");
progressBar.Value = 80;
CheckDBSize(newBackupLocation, "FULL");
progressBar.Value = 100;
MessageBox.Show("Backup was created successfully", "",
MessageBoxButtons.OK, MessageBoxIcon.Information);
lblStatus.Text = "Done";
progressBar.Value = 0;
if (DetachBackup("FULL") == false)
{
DetachBackup("FULL");
}
}
Chances are it's getting hung on its own connection. sp_detach_db's MSDN https://msdn.microsoft.com/en-CA/library/ms188031.aspx has the following suggestion under the section Obtain Exclusive Access:
USE master;
ALTER DATABASE [DBName] SET SINGLE_USER;
You're DetachBackup method will have connect to master, run the ALTER and the sp_detach_db procedure.
You aren't closing the connection in your CreateStoredProcedures method. Put using statements in like I've shown here and it should fix the problem. (Brief using statement explanation from Microsoft.)
Try this code for your methods:
void CreateStoredProcedures(string type)
{
string spLocation = File.ReadAllText("CreateStoredProcedures.sql");
using (var conn = new SqlConnection(connectionString + ";database=" + type + DateTime.Now.ToString("yyyyMMdd")))
{
try
{
Server server = new Server(new ServerConnection(conn));
server.ConnectionContext.ExecuteNonQuery(spLocation);
}
catch (Exception ex)
{
MessageBox.Show(ex.ToString());
}
} // End of using, connection will always close when you reach this point.
}
bool DetachBackup(string type)
{
using (var conn = new SqlConnection(connectionString))
{
SqlCommand command = new SqlCommand(#"sys.sp_detach_db '" + type + DateTime.Now.ToString("yyyyMMdd") + "'", conn);
try
{
conn.Open();
command.ExecuteNonQuery();
}
catch (Exception ex)
{
MessageBox.Show(ex.ToString());
return false;
}
} // End of using, connection will always close when you reach this point.
return true;
}
You shouldn't think of it as the database being "busy", but the error message uses good verbage: in use. To find out if the database is currently in use, the most accurate way would be to find out if any sessions have any lock in the particular database, by querying sys.dm_tran_locks. Here is a helper function to return a bool whether or not the database is in use:
bool IsDatabaseInUse(string databaseName)
{
using (SqlConnection sqlConnection = new SqlConnection("... your connection string ..."))
using (SqlCommand sqlCmd = new SqlCommand())
{
sqlCmd.Connection = sqlConnection;
sqlCmd.CommandText =
#"select count(*)
from sys.dm_tran_locks
where resource_database_id = db_id(#database_name);";
sqlCmd.Parameters.Add(new SqlParameter("#database_name", SqlDbType.NVarChar, 128)
{
Value = databaseName
});
sqlConnection.Open();
int sessionCount = Convert.ToInt32(sqlCmd.ExecuteScalar());
if (sessionCount > 0)
return true;
else
return false;
}
}
Note: Make sure your initial catalog in your connection string isn't the database you're trying to make "not in use", as that'll put your current session in the context of the database, not allowing that operation to complete

How to convert this method to catch the inserted id?

I have a windows form and I'm inserting values in the button click event like this
Candidate CanObj = new Candidate(txtName.Text);
if (new CandidateOP().saveCandidate(CanObj))
{
MessageBox.Show("NEW candidate details added");
}
this is my business layer method.
public Boolean saveCandidate(Candidate CanObj)
{
string query6 = "EXEC insertToCand01'" + CanObj.NIC + "'";
return (new DataAccessLayer().executeNonQueries(query6));
}
This is my data access layer method
public Boolean executeNonQueries(string query02)
{
Boolean flag = false;
SqlConnection con = null;
SqlCommand com = null;
try
{
con = new SqlConnection(DBConnect.makeConnection());
con.Open();
com = new SqlCommand(query02, con);
com.ExecuteNonQuery();
flag = true;
}
catch (Exception ex)
{
flag = false;
throw ex;
}
finally
{
com.Dispose();
con.Close();
}
return flag;
}
This is the query inside my stored procedure to insert.
In my table the ID is set to auto increment.
INSERT INTO Candidate (User_Name) VALUES (#Uname);
Now I want to display the inserted ID to be displayed when it's inserted.
So I changed the query like this.
INSERT INTO Candidate (User_Name) OUTPUT INSERTED.User_ID VALUES (#Uname);
I want to change my data access layer and business layer to get the value back
How to change my data access layer to achieve this?
Thanks in advance.
Just a quick but important note: you should really use parameterized queries to avoid SQL injection problems, and also using a proper ORM system.
About your concrete question: call your procedure with ExecuteScalar, instead of ExecuteNonQuery, and return the generated id from your stored procedure.
You don't actually need an SP, you can just do a select scope_identity() for example. Or you could use an output parameter in your SP. But just returning a scalar is the simplest way.
Something like this:
Candidate CanObj = new Candidate(txtName.Text);
int id = new CandidateOP().saveCandidate(CanObj);
/* You have **id** here, and you can use it. */
if (id >= 0)
{
MessageBox.Show("NEW candidate details added");
}
Business layer:
public Boolean saveCandidate(Candidate CanObj)
{
string query6 = "EXEC insertToCand01'" + CanObj.NIC + "'";
return new DataAccessLayer().executeNonQueries(query6);
}
and your access layer:
public int executeNonQueries(string query02)
{
long id = -1;
SqlConnection con = null;
SqlCommand com = null;
try
{
con = new SqlConnection(DBConnect.makeConnection());
con.Open();
com = new SqlCommand(query02, con);
SqlParameter returnParameter = com.Parameters.Add("RetVal", SqlDbType.Int);
returnParameter.Direction = ParameterDirection.ReturnValue;
com.ExecuteNonQuery();
id = (int) returnParameter.Value;
}
catch (Exception ex)
{
id = -1;
throw ex;
}
finally
{
com.Dispose();
con.Close();
}
return id;
}

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

C# Mysql Insert Data not work

I am Nubie in C#, I Try to learn CRUD. Select data Succes but I cant Save data to mysql.
my table
mahasiswa
ID| namae | jurusan | email
_____________________________
1 | Bill | IT | bill#gmail.com
2 | Tony | IT | Tony#gmail.com
ID is set to auto increment in Mysql
and this my script for btn save
void btnsave_Click(object sender, EventArgs e)
{
try
{
if (txtid.Text != "" && txtnama.Text != "" && txtjurusan.Text != "" && txtemail.Text != "")
{
query = string.Format("INSERT INTO mahasiswa values ('{1}','{2}','{3}');", txtnama.Text, txtjurusan.Text, txtemail.Text);
koneksi.Open();
perintah = new MySqlCommand(query, koneksi);
adapter = new MySqlDataAdapter(perintah);
int res = perintah.ExecuteNonQuery();
koneksi.Close();
if (res == 1)
{
MessageBox.Show("Input Data Sukses...");
}
else
{
MessageBox.Show("Input Data Gagal... ");
}
}
else
{
MessageBox.Show("Data tidak lengkap");
}
}
catch(Exception ex)
{
MessageBox.Show(ex.ToString());
}
}
That Script can run, but after input data and click save buttonm the program stop.
Can anybody help me.
Im very Appreciated your answer
Thanks
form load
void Form1_Load(object sender, EventArgs e)
{
try
{
koneksi.Open();
query = string.Format("SELECT * FROM mahasiswa");
perintah = new MySqlCommand(query, koneksi);
adapter = new MySqlDataAdapter(perintah);
perintah.ExecuteNonQuery();
ds.Clear();
adapter.Fill(ds);
koneksi.Close();
dgv1.DataSource = ds.Tables[0];
dgv1.Columns[0].Width = 50;
dgv1.Columns[0].HeaderText = "ID";
dgv1.Columns[1].Width = 120;
dgv1.Columns[1].HeaderText = "Nama Mahasiswa";
dgv1.Columns[2].Width = 120;
dgv1.Columns[2].HeaderText = "Jurusan";
dgv1.Columns[3].Width = 120;
dgv1.Columns[3].HeaderText = "Email";
//txtid.clear();
txtnama.Clear();
txtjurusan.Clear();
txtemail.Clear();
btnedit.Enabled = false;
btndelete.Enabled = false;
btnsave.Enabled = true;
btnsearch.Enabled = true;
}
catch (Exception ex) {
MessageBox.Show(ex.ToString());
}
}
Also if your learning CRUD it would be helpful if you made the necessary stored procedures within SQL aswell as attempting it this way.
Just create a CREATE, INSERT, UPDATE, DELETE procedure. Then in your code for an insert example you have this:
public bool Add(string example)
{
try
{
using (SqlConnection con = new SqlConnection(connectionString))
{
SqlCommand cmd = new SqlCommand("[Proc name]", con);
cmd.CommandType = CommandType.StoredProcedure;
if (con.State == ConnectionState.Closed)
con.Open();
cmd.Parameters.AddWithValue("#Example", example);
cmd.ExecuteNonQuery();
return true;
}
}
This allows you to view what happens and to ensure your procedures are working correctly. This way allows you to catch exceptions easier, and also validate your inputs easier.
try this
"INSERT INTO mahasiswa (name,jurusan,mail) values ('{1}','{2}','{3}')", txtnama.Text, txtjurusan.Text, txtemail.Text)";
as your query will instruct mysql to look for 4 values whereas you are passing only 3 values.
Do not use string concatenation to build sql command text, use always a parameterized query
query = "INSERT INTO mahasiswa VALUES (#p1,#p2,#p3);";
using(MySqlConnection koneksi = new MySqlConnection(connectionString))
using(MySqlCommand perintah = new MySqlCommand(query, koneksi))
{
koneksi.Open();
perintah.Parameters.AddWithValue("#p1", txtnama.Text);
perintah.Parameters.AddWithValue("#p2", txtjurusan.Text);
perintah.Parameters.AddWithValue("#p3", txtemail.Text);
int res = perintah.ExecuteNonQuery();
if (res == 1)
MessageBox.Show("Input Data Sukses...");
else
MessageBox.Show("Input Data Gagal... ");
}
If you use string concatenation your code will be open to sql injection where a malicious user could wreak havoc with your database (Look at this funny example)
Also your format statement is totally wrong, I doubt that your code reaches the point where the database command is executed because you list the arguments for string.Format from the index 1 to index 3 and you supply 3 arguments, but the index should start from zero and end at two. So you should get an exception on that line.
Another point to keep note is the using statement. As you can see, in my code the using statement will ensure the proper closing and disposing of the connection and command objects. The connection is particularly important to dispose properly because a failure here could break your program later.

Categories

Resources