SQL CE Not updating database values from windows forms - c#

I am building a inventory based application that can be directly run from any pc without any installation and so i am using SQL CE.. On Start, I am checking if database is present. If Not i am creating new database as :
try
{
string conString = "Data Source='ITM.sdf';LCID=1033;Password=ABCDEF; Encrypt = TRUE;";
SqlCeEngine engine = new SqlCeEngine(conString);
engine.CreateDatabase();
return true;
}
catch (Exception e)
{
//MessageBox.Show("Database Already Present");
}
The database is created properly and i can access the database to create tables as well.. The Problem i am facing is - I am inserting and updating records in windows form on button click with code :
using (SqlCeConnection connection = new SqlCeConnection(DatabaseConnection.connectionstring))
{
connection.Open();
String Name = NameTxt.Text.ToString();
String Phone = PhoneTxt.Text.ToString();
double balance = Double.Parse(BalanceTxt.Text.ToString());
String City = CityTxt.Text.ToString();
string sqlquery = "INSERT INTO Customers (Name,Phone,Balance,City)" + "Values(#name,#phone, #bal, #city)";
SqlCeCommand cmd = new SqlCeCommand(sqlquery, connection);
cmd.Parameters.AddWithValue("#name", Name);
cmd.Parameters.AddWithValue("#phone", Phone);
cmd.Parameters.AddWithValue("#bal", balance);
cmd.Parameters.AddWithValue("#city", City);
int x = cmd.ExecuteNonQuery();
if (x > 0)
{
MessageBox.Show("Data Inserted");
}
else
{
MessageBox.Show("Error Occured. Cannot Insert the data");
}
connection.Close();
}
and Updation Code is
using (SqlCeConnection connection = new SqlCeConnection(DatabaseConnection.connectionstring))
{
connection.Open();
int idtoedit = select_id_edit;
String Name = NameEditTxt.Text.ToString();
String Phone = metroTextBox1.Text.ToString();
String City = CityEditTxt.Text.ToString();
string sqlquery = "Update Customers Set Name = #name, Phone = #phone,City = #city where Id = #id";
SqlCeCommand cmd = new SqlCeCommand(sqlquery, connection);
cmd.Parameters.AddWithValue("#name", Name);
cmd.Parameters.AddWithValue("#phone", Phone);
cmd.Parameters.AddWithValue("#id", idtoedit);
cmd.Parameters.AddWithValue("#city", City);
int x = cmd.ExecuteNonQuery();
if (x > 0)
{
MessageBox.Show("Data Updated");
}
else
{
MessageBox.Show("Error Occured. Cannot Insert the data");
}
loadIntoGrid();
connection.Close();
}
Whenever i execute code for inserting and updating records - Records are reflected in datagrid filled with adapter from database table. But once i restart the application, values do not appear in database. Once in a million, values are reflected in database. I cannot understand the reason behind this issue.
I have reffered to these articles :
C# - ExecuteNonQuery() isn't working with SQL Server CE
Insert, Update, Delete are not applied on SQL Server CE database file for Windows Mobile
But since i am creating database programmatically - It is getting created directly to bin/debug directory and i cannot see it in solution explorer in visual studio for changing copy options

You probably rewrite your database file with a blank copy from your project.
See this answer. You should not store your database in a bin folder, rather you should find a place in user's or public profile in AppData or another folder, depending on your needs.
The connection string would look like this:
<connectionStrings>
<add name="ITMContext" connectionString="data source=|DataDirectory|\ITM.sdf';LCID=1033;Password=ABCDEF; Encrypt = TRUE;" providerName="System.Data.SqlServerCe.4.0">
You shuld deploy your db file with your custom code run at app's starup to a chosen location, see this ErikEJ blog: http://erikej.blogspot.cz/2013/11/entity-framework-6-sql-server-compact-4_25.html
private const string dbFileName = "Chinook.sdf";
private static void CreateIfNotExists(string fileName)
{
string path = Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData);
// Set the data directory to the users %AppData% folder
// So the database file will be placed in: C:\\Users\\<Username>\\AppData\\Roaming\\
AppDomain.CurrentDomain.SetData("DataDirectory", path);
// Enure that the database file is present
if (!System.IO.File.Exists(System.IO.Path.Combine(path, fileName)))
{
//Get path to our .exe, which also has a copy of the database file
var exePath = System.IO.Path.GetDirectoryName(
new Uri(System.Reflection.Assembly.GetExecutingAssembly().CodeBase).LocalPath);
//Copy the file from the .exe location to the %AppData% folder
System.IO.File.Copy(
System.IO.Path.Combine(exePath, fileName),
System.IO.Path.Combine(path, fileName));
}
}
Check also this post.
You have several options to change this behavior. If your sdf file is
part of the content of your project, this will affect how data is
persisted. Remember that when you debug, all output of your project
(including the sdf) if in the bin/debug folder.
You can decide not to include the sdf file as part of your project and manage the file location runtime.
If you are using "copy if newer", and project changes you make to the database will overwrite any runtime/debug changes.
If you are using "Do not copy", you will have to specify the location in code (as two levels above where your program is running).
If you have "Copy always", any changes made during runtime will always be overwritten
The database file in your project can be different when debugging or not. Check also this answer. You might be writting your records to another copy of the database file.

Related

Restore Database from bak file

I'm trying to restore a database from a bak file. I found some code on how to do it grammatically but I'm not sure what I'm doing wrong. I'm getting an error:
Error:
Restore failed for Server 'www.freegamedata.com'.
I assume because i'm remotely connected? I'm not sure. The bak file is not on the server machine. I'm trying to build a desktop application that will install my database on the users server using my file. Here is my code:
private void Restore_Database()
{
try
{
Server server = new Server(Properties.Settings.Default.SQL_Server);
string filename = "Test.bak";
string filepath = System.IO.Directory.GetCurrentDirectory() + "\\file\\" + filename;
Restore res = new Restore();
res.Database = Properties.Settings.Default.SQL_Database;
res.Action = RestoreActionType.Database;
res.Devices.AddDevice(filepath, DeviceType.File);
res.PercentCompleteNotification = 10;
res.ReplaceDatabase = true;
res.PercentComplete += new PercentCompleteEventHandler(res_PercentComplete);
res.SqlRestore(server);
}
catch(Exception ex)
{
}
}
I'm not sure if I'm going about this the correct way. I'd like to add my database with my data to the users server as a base database. Am I doing something wrong? My connection string is good so I know its not a connection issue.
I have found a workaround for those whom do not have local access. This is a bit involved so I hope I explain this correctly and it makes sense.
Also note you will need to export your data to an excel spreadsheet before you do the steps listed below.
Exporting Data
Part 1:
Backup Your DATA!
This is a pretty simple process. Open SQL Management Studio and right click on your database. Choose export data and export it as an excel spreadsheet 2007. I'm not going to give detailed steps on this part because its pretty basic and you can google it. Sorry for the inconvenience.
Part 2:
Delete your database for testing purposes but make sure you have a working backup before you delete your database.
Importing Data
Part 1:
You need to create a script that will build your database for you automatically. You can do this by logging into SQL management Studio and right click on the database and choose:
Task -> Generate scripts
you should only need the default information. However, if your like me, I excluded the users in the list. This will generate a large SQL script.
Part 2:
Next you will want to store this file in your solution/project. Make sure you right click it and choose always copy or or copy if newer. I think that's the options. Basically it just copies your file when you debug or build it. This is critical because you will need to access this file to execute the script. Next you need to make a SQL function similar to mine to execute the script:
public bool SQLScript_ExecuteSQLScript(string ScriptLocation)
{
try
{
//5 min timeout
SqlConnection SQLConn = new SqlConnection(cn + "; Connection Timeout = 300;");
string script = File.ReadAllText(ScriptLocation);
Server server = new Server(new ServerConnection(SQLConn));
server.ConnectionContext.ExecuteNonQuery(script);
return true;
}
catch (Exception ex)
{
return false;
}
}
In my code sample please note I changed my timeout to 5 minutes. In the event you have a large script you may need to adjust the timeout to make sure your script fully executes.
Congrats you have rebuilt your database.
Part 3:
Load SQL Management Studio and make sure your database has been rebuilt successfully. You should see all your tables and Stored Procs but no data. If this is true, great you can continue. If not please go back and review your script. If you have SQL comments in your script, you may need to remove them. I had to in order for my script to execute without errors.
Part 4:
Now you need to import your data from your excel spreadsheet you created earlier. If your like me, you had multipal sheets. If you have multipal sheets then you will want to make a list to loop through each item in your list to import the sheets. If not then you can ignore my code on the list. I also put mine in a background worker but you don't need to depending on the size of your data. Also note I created a separate class containing my list but you dont have to do that if you don't want too. My sheet names are Table_1, Table_2 and Table_3 your will be differently most likely.
Sample Sheet List:
public List<string> GetTestTableList()
{
try
{
List<string> testlist = new List<string>();
testlist.Add("Table_1");
testlist.Add("Table_2");
testlist.Add("Table_3");
return testlist;
}
catch (Exception ex)
{
return null;
}
}
Part 5:
Next we will import the data from excel into SQL. This is a function I made but you can modify this to meet your needs.
Function:
private bool Import_Data_Into_SQL(string filepath, string SheetName, string Database, string Schema)
{
try
{
// sql table should match your sheet name in excel
string sqltable = SheetName;
// select all data from sheet by name
string exceldataquery = "select * from [" + SheetName + "$]";
//create our connection strings - Excel 2007 - This may differ based on Excel spreadsheet used
string excelconnectionstring = #"Provider=Microsoft.ACE.OLEDB.12.0; Data Source='" + filepath + " '; Extended Properties=Excel 8.0;";
string sqlconnectionstring = Properties.Settings.Default.SQL_Connection;
//series of commands to bulk copy data from the excel file into our sql table
OleDbConnection oledbconn = new OleDbConnection(excelconnectionstring);
OleDbCommand oledbcmd = new OleDbCommand(exceldataquery, oledbconn);
oledbconn.Open();
OleDbDataReader dr = oledbcmd.ExecuteReader();
SqlBulkCopy bulkcopy = new SqlBulkCopy(sqlconnectionstring);
bulkcopy.DestinationTableName = Database + "." + Schema +"." + sqltable;
while (dr.Read())
{
bulkcopy.WriteToServer(dr);
}
dr.Close();
oledbconn.Close();
return true;
}
catch (Exception ex)
{
return false;
}
}
I hope this helps. This was my workaround solution. Originally I wanted/tried to import my data using the .bak file but as pointed out above you can only do that if the sql server is local. So I hope this work around helps those who where faced with a similar issue as me. I'm not marking this as the answer because the above post answers the question but I'm posting this in case someone else needs this workaround. Thanks
Restore file must be on server. For installation use SQL script. This can be generated by SQL Server Management Studio (including data).
Right click on database. Choose "Tasks" - "Generate scripts". On second page of wizard choose "Advanced" and find "Types of data to script". Select "Schema and data" and save script to file.
Then use this code to run script on database
string scriptText = File.ReadAllText(scriptFile, Encoding.Default);
ExecuteBatch executeBatch = new ExecuteBatch();
StringCollection commandTexts = executeBatch.GetStatements(scriptText);
using (SqlConnection sqlConnection = new SqlConnection(conn))
{
sqlConnection.InfoMessage += SqlConnection_InfoMessage;
sqlConnection.Open();
for (int i = 0; i < commandTexts.Count; i++)
{
try
{
log.InfoFormat("Executing statement {0}", i + 1);
string commandText = commandTexts[i];
using (SqlCommand sqlCommand = sqlConnection.CreateCommand())
{
log.Debug(commandText);
sqlCommand.CommandText = commandText;
sqlCommand.CommandTimeout = 300;
int r = sqlCommand.ExecuteNonQuery();
log.DebugFormat("{0} rows affected", r);
}
}
catch (Exception ex)
{
log.Warn("Executing command failed", ex);
try
{
sqlConnection.Open();
}
catch (Exception ex2)
{
log.Error("Cannot reopen connection", ex2);
}
}
}
sqlConnection.Close();
}

Cannot create new record to the database; no error message

I'm trying to add new record to trans_daily table, however, the code snippet below executed on button click doesn't work.
THE PROBLEMATIC CODE
private void button1_Click(object sender, EventArgs e)
{
try
{
SqlConnection connection = new SqlConnection(conString);
connection.Open();
string strcom = "INSERT INTO trans_daily (retail_id, cust_name, quantity, " +
"price, date, visibility, remarks_id) VALUES (#RetailID, #CustomerName, " +
"#Quantity, #Price, #Date, #Visibility, #RemarksID)";
SqlCommand cmd = new SqlCommand(strcom, connection);
cmd.Parameters.AddWithValue("#RetailID", ddRetailType.SelectedValue);
cmd.Parameters.AddWithValue("#CustomerName", tbCustomer.Text);
cmd.Parameters.AddWithValue("#Quantity", float.Parse(tbQuantity.Text));
cmd.Parameters.AddWithValue("#Price", float.Parse(tbPrice.Text));
cmd.Parameters.AddWithValue("#Date", DateTime.Now);
cmd.Parameters.AddWithValue("#Visibility", 1);
cmd.Parameters.AddWithValue("#RemarksID", 1);
cmd.ExecuteNonQuery();
}
catch (Exception err)
{
Console.WriteLine(err.Message);
}
}
The following are the data types:
retail_id (int)
cust_name (varchar50)
quantity (float)
price (float)
date (datetime)
visibility (int)
remarks_id (int)
It's also worth to point out that no exception is being thrown.
What could have gone wrong?
THE WORKING CODE
In a separate function, I was able to pull out data from retail table on form load and placed the pulled out data to a dropdown list.
private void formAddTransaction_Load(object sender, EventArgs e)
{
try
{
objConnect = new DatabaseConnection();
conString = Properties.Settings.Default.MVGasConnectionString;
objConnect.Sql = "SELECT * FROM retail";
objConnect.connection_string = conString;
ds = objConnect.GetConnection;
MaxRows = ds.Tables[0].Rows.Count;
FillRetailTypes(conString);
}
catch (Exception err)
{
MessageBox.Show(err.Message);
}
}
public void FillRetailTypes(string constring)
{
ddRetailType.DataSource = ds.Tables[0];
ddRetailType.ValueMember = "id";
ddRetailType.DisplayMember = "type";
}
Try this code and you may find your error:
try
{
using(SqlConnection connection = new SqlConnection(conString))
using(SqlCommand cmd = new SqlCommand())
{
connection.Open();
string strcom = "INSERT INTO trans_daily ([retail_id], [cust_name], [quantity], " +
"[price], [date], [visibility], [remarks_id]) VALUES (#RetailID, #CustomerName, " +
"#Quantity, #Price, #Date, #Visibility, #RemarksID)";
cmd.CommandText = strcom;
cmd.Connection = connection;
cmd.Parameters.AddWithValue("#RetailID", SqlDbType.Int);
cmd.Parameter["#RetailID"].Value = ddRetailType.SelectedValue;
cmd.Parameters.AddWithValue("#CustomerName", SqlDbType.VarChar);
cmd.Parameter["#CustomerName"].Value = tbCustomer.Text;
cmd.Parameters.AddWithValue("#Quantity", SqlDbType.Float);
cmd.Parameter["#Quantity"].Value = float.Parse(tbQuantity.Text);
cmd.Parameters.AddWithValue("#Price", SqlDbType.Float);
cmd.Paramter["#Price"].Value = float.Parse(tbPrice.Text);
cmd.Parameters.AddWithValue("#Date", SqlDbType.DateTime);
cmd.Parameter["#Date"].Value = DateTime.Now;
cmd.Parameters.AddWithValue("#Visibility", SqlDbType.Int);
cmd.Parameter["#Visibility"].Value = 1;
cmd.Parameters.AddWithValue("#RemarksID", SqlDbType.Int);
cmd.Parameter["#RemarksID"].Value = 1;
int affectedRows = cmd.ExecuteNonQuery();
Console.WriteLine("You have inserted {0} rows", affectedRows);
}
}
catch(Exception e)
{
Console.WriteLine(e.Message);
}
This code will...
... automatically open and close your database connection and command object
... log the amount of affected rows in the database to the console
... log exception messages to the console. You may add a breakpoint to this line if you want to see the whole exception (if one occures)
As explained in this blog, it seems like the problem is in the connection string.
Inside the project folder, 2 .mdf files were created: one is found at the root of the folder (let's call it mdf_1) and the other is inside the bin\Debug folder (let's call it mdf_2).
Now, taking a look inside the Visual Studio (VS) editor, there are 2 .mdf files shown: one under the Server Explorer, and another under the Solution Explorer. Not taking note of the location (from the properties section) of these .mdf files made me think these 2 .mdf files were the same. The thing is, the one under the Server Explorer is mdf_1 while mdf_2 is the one under the Solution Explorer.
VS has a behavior that copies mdf_1 and overwrites mdf_2 everytime the program is run (because by default, .mdf is set to Copy always mdf_1 to mdf_2). My connection string was pointing to the mdf_2 which explains why despite cmd.ExecuteNonQuery() command returns 1, my successfully inserted records are always erased because of the behavior VS has. And since it is mdf_1 that is under Server Explorer, I could not verify the changes in DB. Simply put, I was making changes in mdf_2 while trying to look for the changes in mdf_1.
So to avoid this, I modified my connection string by changing the relative path |DataDirectory| in the connection string to the absolute path of mdf_1 so that no matter how often VS overwrites mdf_2, the changes I make during runtime in mdf_1 aren't overwritten. This was, changes are also reflected in the Server Explorer (where I verify if changes were actually made).
tl;dr : I was updating the .mdf file under bin\Debug folder during runtime while physically looking for the updates in the .mdf file located in the root of the project.

Empty database table

I want to insert values in "Navn" row and "Varenr" row in the DB table, when I'm clicking on a button. I have following code:
private void button2_Click(object sender, EventArgs e)
{
using (SqlConnection cn = new SqlConnection(#"Data Source=(LocalDB)\v11.0;AttachDbFilename=|DataDirectory|\Produkt.mdf;Integrated Security=True"))
{
try
{
SqlCommand cm = new SqlCommand();
cm.Connection = cn;
string col1 = textBox2.Text;
string col2 = textBox3.Text;
//generate sql statement
cm.CommandText = "INSERT INTO ProduktTable (Navn,Varenr) VALUES (#col1,#col2)";
//add some SqlParameters
SqlParameter sp_add_col1 = new SqlParameter();
sp_add_col1.ParameterName = "#col1";
//data type in sqlserver
sp_add_col1.SqlDbType = SqlDbType.NVarChar;
//if your data type is not number,this property must set
//sp_add_col1.Size = 20;
sp_add_col1.Value = textBox2.Text;
//add parameter into collections
cm.Parameters.Add(sp_add_col1);
//in your insert into statement, there are how many parameter, you must write the number of parameter
SqlParameter sp_add_col2 = new SqlParameter();
sp_add_col2.ParameterName = "#col2";
//data type in sqlserver
sp_add_col2.SqlDbType = SqlDbType.NVarChar;
//if your data type is not number,this property must set
//sp_add_col2.Size = 20;
sp_add_col2.Value = textBox2.Text;
//add parameter into collections
cm.Parameters.Add(sp_add_col2);
//open the DB to execute sql
cn.Open();
cm.ExecuteNonQuery();
cn.Close();
}
catch (Exception ex)
{
MessageBox.Show("Error\n" + ex.Message, "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
}
}
}
But unfortunately, my data table is still empty:
I have set a breakpoint on the ExecuteNonQuery function, and it is triggered, when pressing on the button:
My table definition:
Your connection string is causing this:
Data Source=(LocalDB)\v11.0;AttachDbFilename=|DataDirectory|\Produkt.mdf;Integrated Security=True"
|DataDirectory| Your database that is being updated in this method is in your App Data Directory while the one you are trying to retrieve data from is in your project folder...
|DataDirectory| is a substitution string that indicates the path to the database. DataDirectory also makes it easy to share a project and also to deploy an application. For my PC my App Data Directory is:
C:\Users\MyUserName\AppData\...
If you browse to this location and then go to following folders
...\Local\Apps\2.0\Data
You will be able to find your particular application directory probably stored with your assembly name, or some hash when you go there you will find it the database there is being updated just fine. This connection string is best for deployment.
You can also try this:
If you notice that Server Explorer is detecting all the databases on my PC and you can notice that there are couple of MINDMUSCLE.MDF files but all are at different paths, this is because there is one file in DEBUG directory, one in my PROJECT directory, one in my APP DATA directory. The ones starting with the numbers are stored in my APP DATA directories... If you select your respective database file and then run the SELECT query against it, you will get your data.
I made a tutorial some time ago. May be it will help you:
Check the value that ExecuteNonQuery is returning. It should return an int with the number of records affected by the SQL statement.
If it comes back with a value other than 0, then you know a record is being inserted somewhere. Before you close the connection, run a SQL query against the table to select all of the records and see if they come back through the code.
SELECT * FROM ProduktTable
If you get some records, then you may want to double check the database you're looking at through the IDE and the one your inserting records into through the code. It could be possible that you've got two different databases and you're querying one while inserting into another one.
Those are the steps that I would go through to help narrow down the issue and sounds like something I've probably done before. I hope it helps!

How am i using the SclCeCommand and ExecuteNonQuery method wrong?

I'm trying to make a method in my Admin class (for a small course project) which should INSERT a new movie into my database.
I don't get any errors, but the new data is not inserted into the database.
Here is my code:
public void AddMovieToDB(int mCodeLable, string title, int yearOfMovie, int lengthInMinutes, string dvdOrVhs, string genreOfMovie)
{
int movieCodeLable = mCodeLable;
string movieTitle = title;
int year = yearOfMovie;
int length = lengthInMinutes;
string typeOf = dvdOrVhs;
string genre = genreOfMovie;
string connectionString = #"Data Source=|DataDirectory|\VideoStoreDB.sdf";
SqlCeConnection connection = new SqlCeConnection(connectionString);
connection.Open();
SqlCeCommand command = new SqlCeCommand(
"INSERT INTO Movie(MovieCodeLable, Title, Year,
LengthMinutes, TypeOf, Genre)
VALUES(#mcl, #title, #year, #length, #typeOf, #genre)", connection);
command.Parameters.AddWithValue("#mcl", movieCodeLable);
command.Parameters.AddWithValue("#title", movieTitle);
command.Parameters.AddWithValue("#year", year);
command.Parameters.AddWithValue("#length", length);
command.Parameters.AddWithValue("#typeOf", typeOf);
command.Parameters.AddWithValue("#genre", genre);
command.ExecuteNonQuery();
connection.Close();
Console.WriteLine("Movie added to the DB!");
}
And this is how i call it from the Main:
Admin admin1 = new Admin();
admin1.AddMovieToDB(0151, "Play ball!", 2012, 124, "DVD", "Drama");
This is a possible scenario.
Your connection string use |DataDirectory|. This means that at RUNTIME, inside VS debug session, the substitution string points to the folder BIN\DEBUG where is located the file sdf copied by VS when it starts the debug session (Check the property Copy to Output directory for your sdf file).
The insert works flawlessy. (you can check that looking at the return value of ExecuteNonQuery()).
You stop the debug and check the content of your table using Server Explorer but you don't find anything.
The only problem is the connection used by your Server Explorer window that point to a different database. The one in the project folder.
I suggest to create two connections on Server Explorer. Leave the current one as is (so this db is your main empty copy ready to be deployed with your application) and add another connection that points to the db in the PROJECTFOLDER\BIN\DEBUG where is located the db used during the debug sessions (Right click 'Add Connections', Select Sql Server Compact Edition and browse to the BIN\DEBUG folder)

C# Cannot save data in Access 2007

I cannot save data in access 2007. I tried the following:
Add a password to my DB; didn't work
Saved the db as a 2003 file; didn't work
Here is my code:
public bool ExecuteUDI(string query)
{
Command = new OleDbCommand();
Command.Connection = Connection;
Command.CommandText = query;
Command.CommandType = System.Data.CommandType.Text;
try
{
// Open connection
Open();
if (Command.ExecuteNonQuery() != -1)
return true;
else
return false;
}
catch (Exception e)
{
mError = "ExecuteUDI - " + e.Message;
return false;
}
finally
{
// Always close connection
Close();
}
}
When I add breakpoints, I see my query looks good:
INSERT INTO DVD (Titel) VALUES ('Elegy')
I don't get any errors, but the affected rows is 0. How come? I dont understand..
Where is your mdb file located in relation to your code? I have had issues in the past that having the mdb file in the project folder will in essence create a local copy of the db in memory when the app is running, but nothing is actually written back to the mdb in the folder...
I recommend putting the mdb file outside your project's folder. That should work.

Categories