OLE DB overwriting old database - c#

I'm trying to use a MS Access database in C# using OLE DB, but every time the database loads it does not keep the old data.
This is my code:
string connectionString = "Provider=Microsoft.ACE.OLEDB.12.0;Data Source=Databases\\Database.accdb;Persist Security Info=False;";
OleDbConnection connection = new OleDbConnection(connectionString);
OleDbCommand command = connection.CreateCommand();
command.CommandText = "INSERT INTO test (userID, name) VALUES(?, ?)";
// Setting parameters to random integer and string
command.Parameters.Add(new OleDbParameter("#userID", randomID));
command.Parameters.Add(new OleDbParameter("#name", randomName));
command.ExecuteNonQuery();
For testing purposes I use a randomly generated ID and name. If I check the database in MS Access the data is overwritten every time. Am I missing something?
I use this code for creating the table:
OleDbCommand command = connection.CreateCommand();
command.CommandText = "CREATE TABLE test (" +
"userID INTEGER NOT NULL," +
"name TEXT(20) NOT NULL," +
"PRIMARY KEY(userID)" +
")";
command.ExecuteNonQuery();

This typically is associated with the properties of the Database.accdb file as it exists in Visual Studio.
By default, the "Copy to output directory" field for the file is set to "Copy always". So, this means that every time to launch the application in Visual Studio, it will completely replace the working copy of Database.accdb with the prototype version.
So, the solution is kinda simple... change the field to "Copy if newer" (or "Do not copy")

Related

OLEDB commands aren't being saved in access database

I'm working in Windows Forms and trying to use OLEDB to connect to an access .accdb file.
I can SELECT data without issue.
I can execute Insert and Create commands with no error.
But when I check the database afterward the data is not showing.
For example, when I create a new Table, the code will say the table was created and if I try to create the table again without closing the Windows Form it will throw an error saying the table already exists, but if I close and restart the program it will let me create the table once more.
Also, if I look into the Access file I wont see the table.
I've tried multiple tests both with Access open and closed. The Connection String is correct as I have made changes to tables in the Access file and they are reflected in the SELECT queries I've sent.
I suspect there must be a setting in Access I must enable for it to autocommit changes. But I haven't found it.
OleDbConnection conn = new OleDbConnection(#"Provider = Microsoft.ACE.OLEDB.12.0; Data Source =Database2.accdb");
string query = "INSERT INTO [TestTable] ([Test_Name], [Test_Number]) VALUES (?, ?)";
try
{
OleDbCommand cmd = new OleDbCommand();
cmd.CommandType = CommandType.Text;
cmd.CommandText = query;
cmd.Parameters.AddWithValue("Test_Name", list_all_meters[0][0].Name);
cmd.Parameters.AddWithValue("Test_Number", list_all_meters[0][0].Value);
cmd.Connection = conn;
conn.Open();
cmd.ExecuteNonQuery();
conn.Close();
MessageBox.Show("An Item has been successfully added", "Caption", MessageBoxButtons.OKCancel, MessageBoxIcon.Information);
}catch(Exception ex)
{
Debug.WriteLine(ex.Message);
}
Looks like the issue was I had set the Database "Copy to Output Directory" to Copy Always, which overwrote my changes every time I ran the program. Changing it to Copy if Newer fixed the issue.

C# mdf local database

I googled for half a day how to set the path of my database so if I put it on an other computer it will work. I would keep googling but I really need the answer really fast... I'll have to use it to a competition in few hours.
string path = Path.Combine(Application.StartupPath, "Database1.mdf");
SqlConnection conn = new SqlConnection(#"Data Source=(LocalDB)\v11.0;AttachDbFilename=" + path + ";");
conn.Open();
SqlCommand command = new SqlCommand("SELECT NAME FROM DATA", conn);
SqlDataReader reader = command.ExecuteReader();
while(reader.Read())
{
string text = reader.GetString(0);
MessageBox.Show(text);
}
SqlCommand c = new SqlCommand("INSERT INTO DATA (id, name) VALUES(i, v)", conn);
c.Parameters.AddWithValue("#i", 1);
c.Parameters.AddWithValue("#v", "Jack");
c.ExecuteNonQuery();
conn.Dispose();
This code is working for selection but not for insertion. Then I hardcoded the path into:
String s = #"C:\Users\Radu\Documents\Visual Studio 2013\Projects\WindowsFormsApplication7\WindowsFormsApplication7\Database1.mdf";
and it works for both so it's not the SQL statement that is wrong.
So my question is: what is the path I should put into my SqlConnection object so that when they get my source code on my competition and test it on another pc it will work.
LocalDB is meant exclusively for development. You cannot use it in production. In your case, 'production' means the competition. Unless the competition organizer specifies that they support a SQL Server instance for you to connect to, and give out the connection parameters (ie. very unlikely), you shouldn't use use SQL Server in your project.
You can put the MDF file on any file share that your computer has access to. Just alter the path variable to point at the correct file share.
See answers to your question here Can SQL Server Express LocalDB be connected to remotely?

Creating dBase-file sporadically throws exception

I'm having trouble creating dbf-files while exporting shapefile data. Most of the times it works, but sometimes it'll just trow the following error, even though the file doesn't exist yet:
The Microsoft Jet database engine cannot open the file 'C:\Test\258ba2f1-cc05-4a21-a047-ef060c46a3ca\data\tablename.DBF'. It is already opened exclusively by another user, or you need permission to view its data.
The code looks something like this:
using (var dBaseConnection = new OleDbConnection("Provider=Microsoft.Jet.OLEDB.4.0;Data Source=" + databasePath + ";Extended Properties=dBASE IV;"))
{
var createTableString = "Create Table " + tableName + ".dbf (p_id char(10), answered char(20), mnote char(50), descr char(50), grade char(50))";
var cmd = new OleDbCommand(createTableString, dBaseConnection);
dBaseConnection.Open();
cmd.ExecuteNonQuery();
This only happens when i use Microsoft Jet database engine. Using Visual FoxPro creates an additional column named "_NullFlags" and the dbf-file doesn't work with any GIS-software.
Any ideas?
What you may want to do is to have a "template" table structure always available and never used in production. Then, just copy that template table to whatever your new table name would need to be. Then, you can query and connect and do whatever with that file version. In addition, you can rename the file extension from .DBF to anything, such as YourTable.GISDBF so no other application would even accidentally open it.
However, if that doesn't work for you, you may want to look at another post I answered quite a while back was issues with Jet engine too. In this case, I am using VFP OleDb driver and using ExecScript(). You can write command line statements and then execute them as if it were a program. As far as creating the table, you could always do something like creating a CURSOR, and then copying out to the destination table as "TYPE FOXPLUS" which would put it into an older supported file format which might also be readable by GIS.
string VFPScript = "ExecScript( "
+ "[create cursor C_Tmp ( fld1 i, fld2 c(50), fld3 c(10) )] +chr(13)+chr(10)+ "
+ "[copy to '" + YourFileNameVariable + "' type FoxPlus] ";
// put this script into command object, then execute it...
using (OleDbCommand comm = new OleDbCommand( VFPScript, connection))
{
comm.ExecuteNonQuery();
}

How to Create Access DB on the fly from contents of MySQL database and save Locally

I have a remote MySQL database for my company's inventory. The inventory database is the master database for all of the locations we subcontract equipment for. Each property has its own inventory, and for quarterly inventory each location needs to take a laptop and a scanner, and scan their inventory, then sync it to the master database.
The problem is that internet access isn't readily available in all locations, so I need to copy the database to a local file. Concurrency isn't an issue because only one client will ever be connected to the database simultaneously, and each location's database is relatively small, composed of basically <1000 rows of 7 columns.
I have gotten as far as creating an Access file on the HD, but I can't really divine from MSDN how to create a file with a specific schema or how to insert the relevant data from my SELECT statement into said database. I'd been looking onto creating a table adapter on the fly and using .NET's built in methods to do the data transfer, but I still can't find how to create an MS Access file with a specific schema programatically. If anyone has encountered such a problem before, I'd appreciate any insight that could be offered. I basically need to copy the results of a SELECT statement into an MS Access database which I will store locally. All the other code I've got in place.
I'm presently using a rather unwieldy query and foreach loop to do my dirty work, but I was hoping for a more elegant solution, perhaps using a data source created on the fly.
ADOX.Catalog cat = new ADOX.Catalog();
cat.Create("Provider=Microsoft.Jet.OLEDB.4.0;" + "Data Source="+ fileName + ";" + "Jet OLEDB:Engine Type=5");
string conString = #"Provider=Microsoft.Jet.OLEDB.4.0;Data Source=" + fileName + ";" + "User Id=admin;Password=;";
OleDbConnection con = new OleDbConnection(conString);
con.Open();
//create command to generate database schema
OleDbCommand command = new OleDbCommand();
command.CommandText = #"CREATE TABLE items (
[category] VARCHAR(16) NOT NULL,
[manufacturer] VARCHAR(32) NOT NULL,
[model] VARCHAR(32),
[description] TEXT NOT NULL,
[serial_number] VARCHAR(64),
[barcode] VARCHAR(8) NOT NULL PRIMARY KEY,
[property] VARCHAR(4) NOT NULL,
[present] TINYINT
)";
command.Connection = con;
command.ExecuteNonQuery();
OleDbCommand cmdInsert = new OleDbCommand();
cmdInsert.CommandText = "INSERT INTO items([category],[manufacturer],[model],[description],[serial_number],[barcode],[property],[present]) VALUES (#cat,#man,#mod,#desc,#ser,#bar,#prop,#pres)";
cmdInsert.Connection = con;
foreach (DataRow row in itemsTableAdapter1.GetData())
{
cmdInsert.Parameters.AddWithValue("#cat",row.ItemArray[0].ToString());
cmdInsert.Parameters.AddWithValue("#man", row.ItemArray[1].ToString());
cmdInsert.Parameters.AddWithValue("#mod", row.ItemArray[2].ToString());
cmdInsert.Parameters.AddWithValue("#desc", row.ItemArray[3].ToString());
cmdInsert.Parameters.AddWithValue("#ser", row.ItemArray[4].ToString());
cmdInsert.Parameters.AddWithValue("#bar", row.ItemArray[5].ToString());
cmdInsert.Parameters.AddWithValue("#prop", row.ItemArray[6].ToString());
cmdInsert.Parameters.AddWithValue("#pres", row.ItemArray[7]);
cmdInsert.ExecuteNonQuery();
cmdInsert.Parameters.Clear();
}
con.Close();
cat = null;
I tried to do this previously but found that in order to create a new AccessDB I actually had to copy an existing database with all the tables etc that I required.
Would you be able to use sqlite? It is tiny, stable and libraries are available for most languages. You will be able to create whatever structure you like on the client machine.

Why doesn't it work (SQL command in C#?

I'd like to ask you why doesn't this code work? It goes without any error, even cmd.ExecuteNonQuery(); returns 1 (is it if changes one row in the database), but in the actual database, there's absolutely no change. With other database tables, this code works properly, but I'm also not able to remove a row from this table - it behaves asi it if was "read-only", but I have no idea why - yesterday, everything worked fine and now, it's suddenly stopped working :-(
string sConnectionString;
sConnectionString = "Data Source=.\\SQLEXPRESS; AttachDbFilename=\"" + zdielaneInfo.Adresar + "\\rozvrh.mdf\";";
sConnectionString += "Integrated Security=True;User Instance=True";
SqlConnection objConn
= new SqlConnection(sConnectionString);
objConn.Open();
SqlCommand cmd = new SqlCommand("", objConn);
if (zdielaneInfo.Edit)
cmd.CommandText = "UPDATE subject " +
"SET name = #name, day = #day, timeStart = #timeStart, timeEnd = #timeEnd "
+ "WHERE id = #id";
else
cmd.CommandText = "INSERT INTO subject (name, day, timeStart, timeEnd) " +
"Values (#name, #day, #timeStart, #timeEnd)";
cmd.Parameters.Add(new SqlParameter("#name", txbName.Text));
cmd.Parameters.Add(new SqlParameter("#day", dniNaInt(cbDen.Text)));
cmd.Parameters.Add(new SqlParameter("#timeStart", DateTime.Parse(txbStart.Text)));
cmd.Parameters.Add(new SqlParameter("#timeEnd", DateTime.Parse(txbEnd.Text)));
cmd.Parameters.Add(new SqlParameter("#id", zdielaneInfo.Id));
cmd.ExecuteNonQuery();
objConn.Close();
Your problem looks like mdf file overwrite problem.
You are accessing mdf files that are put in the debug folder and replaced every time you run the application.
Be sure that in your project, if you have the database attached within your solution that you are not overwriting it. So select the mdf file in your solution explorer and make sure that its "Copy to output" is set to "Do not copy", then manually copy over the mdf file to the project\bin\debug folder then run the application.
Hope it helps.
Maybe the table is locked.
From HERE, try this:
select
object_name(P.object_id) as TableName,
resource_type, resource_description
from
sys.dm_tran_locks L
join sys.partitions P on L.resource_associated_entity_id = p.hobt_id
If your table is in the result set you have your answer.
Another possibility is the user that you are using to run. Maybe he got privileges revoked.
STOP using the user instance / attachdbfilename options (user instance is deprecated!). Create your database on a real SQL Server, then connect to it directly with your connection string. Using this deprecated feature means that every time you start up your program you're starting with a new copy of the database, and what you inserted yesterday is no longer there - and if you connect to the database using that connection string from two different applications, one is not going to see the data that the other one is changing.

Categories