i have a C# Windows Form Application. I push a button it should create a Table and insert a value (int).
I create the initial database as a Service-Database (Add New Item > Data > Service-Database).
The code for the button is (output follows below it):
private void button1_Click(object sender, EventArgs e)
{
SqlConnection thisConnection = new SqlConnection(Properties.Settings.Default.Database1ConnectionString);
SqlCommand nonqueryCommand = thisConnection.CreateCommand();
try
{
thisConnection.Open();
nonqueryCommand.CommandText = "CREATE TABLE MyTable1 (intColumn int)";
Console.WriteLine(nonqueryCommand.CommandText);
Console.WriteLine("Number of Rows Affected is: {0}", nonqueryCommand.ExecuteNonQuery());
nonqueryCommand.CommandText = "INSERT INTO MyTable1 VALUES (99)";
Console.WriteLine(nonqueryCommand.CommandText);
Console.WriteLine("Number of Rows Affected is: {0}",
nonqueryCommand.ExecuteNonQuery());
}
catch (SqlException ex)
{
Console.WriteLine(ex.ToString());
}
finally
{
thisConnection.Close(); // close connection
Console.WriteLine("Connection Closed.");
}
}
OUTPUT:
CREATE TABLE MyTable1 (intColumn int)
Number of Rows Affected is: -1
INSERT INTO MyTable1 VALUES (99)
Number of Rows Affected is: 1
Connection Closed.
Nothing Shows up on Server Explorer Though No additional Tables even if I close it down and reconnect.
If i push the button to make it issue the same again i get:
System.Data.SqlClient.SqlException (0x80131904): There is already an object named 'MyTable1' in the database.
but still nothing on server explorer.
The exception told you exactly what's going on. Your table already exists. You can't create it again. You need to DROP the table if it already exists.
Nothing Shows up on Server Explorer Though No additional Tables even if I close it down and reconnect.
Whenever you execute your program, Visual Studio's project management automatically deploy (copy that database) .mdf database file at deployment folder Debug\Bin. I think your code uses a database which is located at Debug\Bin folder (which will be not shown in server explorer) and Server Explorer shows a database (.mdf) which is located at root of project folder and it is empty.
Try spceifying the commandType property of the SqlCommand = CommandType.Text
Also make sure that you are connecting to the same instance of SQL. You can get your code's by breakpointing the line after you open the connection (for it's when you know it works) and going looking for the servername.
Note that you can have multiple SQL instances in one machine... so you could be working on the right server (say localhost) and yet not be accessing the correct instance (say SQLEXPRESS instead of MSSQLSERVER).
Related
Basically every time I run my game MS SQL database crashes and returns this error message.
Cannot open database "C:\USERS\ME\SOURCE\REPOS\A GIRL CALLED LORRY\A GIRL CALLED LORRY\DATABASE.MDF" requested by the login. The login failed.
Login failed for user 'me-PC\me'.
I did not change any of the SQL or C# code in my project to cause this error. All I did was simply modify a table within my database by adding a new column of type string.
I've tried using SMSS to open my DataBase.mdf file within my project to see if my user has privileges to access it, however I was unable to open my DataBase.mdf file because it wouldn't even show up within SMSS. So I'm not sure how I can get privileges to access my database again. I also tried removing all the changes I've added to the DB which caused the error in the first place however the error still persists.
As I've said, the error was caused by modifying a table within my database, but there is a small piece of code where the game crashes as soon as I attempt to open the database to remove data:
//this method is used to initialize the database.
public static void createSave() {
//database stuff:
con = new SqlConnection("Data Source=(LocalDB)\\MSSQLLocalDB;AttachDbFilename=C:\\Users\\me\\source\\repos\\A Girl Called Lorry\\A Girl Called Lorry\\Database.mdf;Integrated Security=True");
adp = new SqlDataAdapter();
ds = new DataSet();
Console.WriteLine("we are in!");
//the below code only initializes if isNewGame is set to true.
removeAllFromInventory();
rewriteCurrentObjects();
loadDefaultNpcs();
}
//removeAllFromInventory is where it crashes.
//removes all items from inventory:
public static void removeAllFromInventory() { //this only applies if
//isNewGame is set to true since we want to wipe the inventory in a new game
if (!isNewGame) return;
con.Open(); //here is where it crashes.
adp.SelectCommand = new SqlCommand("DELETE FROM curInventoryItems", con);
adp.SelectCommand.ExecuteNonQuery();
con.Close();
}
However I was unable to open my DataBase.mdf file because it wouldn't even show up within SMSS. So I'm not sure how I can get privileges to access my database again. I also tried removing all the changes I've added to the DB which caused the error in the first place however the error still persists.
There is confusing part in your question, when you unable to connect .MDF how could you remove changes that was added into DB.
However, following steps might be helpful to get your database back to normal:
Verify the account (me-PC\me) has permissions on C:\USERS\ME\SOURCE\REPOS\A GIRL CALLED LORRY\A GIRL CALLED LORRY\DATABASE.MDF
If doesn't work after the permissions, you can troubleshoot the SQL Localdb connections using these steps
Install SQL Express (as it's difficult to manage with LocalDB database engine), and attach Database.mdf into SQL Express engine. You can do this using following command via SSMS
Once your database ready at SQL Express, you can change your connection string to "Data Source=Localhost\\SQLEXPRESS;Initial Catalog=YourNewDBName;Integrated Security=True"
In case issue even with SQL Express, you may follow these steps..
--- You need to move "Database.mdf" and ".ldf" files into "C"\SQLData" folder before executing the command
CREATE DATABASE YourDatabase
ON (FILENAME = 'C:\SQLData\Database.mdf'),
(FILENAME = 'C:\SQLData\Database_log.ldf')
FOR ATTACH;
I'm trying to insert a record into a table in a local SQL DB using Visual Studio 2015. The code never returns an error, but yet the record is never actually inserted.
try
{
conn.Open();
SqlCommand inscmd = new SqlCommand();
inscmd.Connection = conn;
inscmd.CommandText = "INSERT INTO Attendance (StudentID,DatePresent) VALUES (#StudentID, #DatePresent)";
inscmd.Parameters.AddWithValue("#StudentID", intStudentId);
inscmd.Parameters.AddWithValue("#DatePresent", DateTime.Now.ToString());
inscmd.ExecuteNonQuery();
MessageBox.Show(((ExtendedButton)sender).Text + " has been marked as present.");
conn.Close();
}
catch(SqlException ex)
{
MessageBox.Show(ex.ToString());
}
When I run the code, the message box pops up stating that the student has been added to the attendance record. When I close the app to look at the actual data in the table, though; that data is not present.
My "Catch" message box never appears.
If the ExecuteNonQuery returns 1, that means it has affected 1 row. So, it looks like the command is working and something else is occurring. Either you're not looking at the right place, or the right table or something; or the row is being deleted by either a trigger that removes it, or a rollback transaction later on - either explicitly or implicitly. You could try explicitly committing before closing.
So, you need to check further into your code or DB.
Here is everything that I did:
In a visual studio 2013 C# project, I created a service database (.mdf file). Note: I changed the name from Database1.mdf to fghLocalDB.mdf.
I opened this database in the server explorer.
I created 2 tables called Country and CarbonDioxide using the table designer.
I added an entry to the Country table as shown by the Data Table of the Country table.
I did the following to create a DataSet my application can use. I created a Data Source by clicking on the "Project" option on the top menu bar and clicking on the "Add New Data Source ..." option from the drop down.
This is what my project files looked like at this point.
I wrote the following code in the main method thinking that this would be all I need to write to the database.
// Create a connection to the DataSet and TableAdapters that will communicate with our
// local database to handle CRUD operations.
fghLocalDBDataSet dataSet = new fghLocalDBDataSet();
fghLocalDBDataSetTableAdapters.CountryTableAdapter countryTableAdapter =
new fghLocalDBDataSetTableAdapters.CountryTableAdapter();
try
{
// Insert a row into Country table. EDIT 1 Will comment after first program run.
Console.WriteLine(countryTableAdapter.Insert("United States"));
// Actually writeback information to the database?
// dataSet.AcceptChanges(); EDIT 2 commented this as LeY suggested it was not needed.
// EDIT 3 Validation code as suggested by Ley.
var dt = new fghLocalDBDataSet.CountryDataTable();
var adapter = new fghLocalDBDataSetTableAdapters.CountryTableAdapter();
adapter.Fill(dt);
foreach (var row in dt)
{
// This does not get executed after a second run of the program.
// Nothing is printed to the screen.
Console.WriteLine("Id:" + row.Id + "----Name: " + row.Name);
}
Console.Read();
}
catch(SqlException exception){
Console.WriteLine("ERROR: " + exception.ToString());
}
Console.ReadLine();
I ran the program and everything seemed fine.
I opened the tables by right clicking on these tables in the server explorer and pressing "Show Data Table".
The "United States" row was not added as wanted.
I think it has to do with the connectionstring. I right clicked on my project and opened properties.
Here I made sure the connection string matched that of the local database by looking at the string in the properties of the database. They are the same.
I copied and pasted the actual text for each connection string:
Connection string of project:
Data Source=(LocalDB)\v11.0;AttachDbFilename=|DataDirectory|\fghLocalDB.mdf;Integrated Security=True
Connection string of actual database (.mdf file):
Data Source=(LocalDB)\v11.0;AttachDbFilename=C:\Users\gabriel\Source\Workspaces\Capstone\Sandbox\aduclos\QueryDataMarketConsole\QueryDataMarketConsole\fghLocalDB.mdf;Integrated Security=True
I am assuming |DataDirectory| is equal to C:\Users\gabriel\Source\Workspaces\Capstone\Sandbox\aduclos\QueryDataMarketConsole\QueryDataMarketConsole\fghLocalDB.mdf; since in the picture above when I clicked on the button to expand the Value of the connection string the connection properties window opened up and had this path for the database file name.
My question in a nutshell is does instantiating a DataSet object in the code automatically create a connection to a SQL service-based database for CRUD operations?
If not how do I connect my DataSet object to my sql database so that way I can actually write to the database when using the TableAdapters?
I read the following links:
Insert method of TableAdapter not working?
TableAdapter Insert not persisting data
Use connectionstring from web.config in source code file
Do I need an actual SqlConnection object? and how to I connect this to the DataSet & TableAdapters?
I never used tableadpter.insert() method. But I tried it on my local machine, and it works.
I can't figure out your problem based on the information you provided, sorry, but I can point you a direction.
If you created everything from wizard, you don't need to worry about the connection, the table Adapters will handle the connection for you. The connection string (you circled) will be added to your app.config file as well as your setting class automaticly. That is how your application (or you) uses it.
var countryTableAdapter = new CountryTableAdapter();
countryTableAdapter.Insert("United States");
This 2 lines of code are enough to insert the row into database if there is no exception thrown, I don't know why it doesn't work for you. Maybe the way you verify it somehow goes wrong, but you can verify it in another way.
The countryTableAdapter.Insert method will return the number of row get affected, in your case , should be one. So put the following code in , and set a breakpoint after it. if the rowAffected == 1, then the insertion works.
var rowAffected = countryTableAdapter.Insert("Test2")
If you need more confirmation , try this.
var dt = new fghLocalDBDataSet.CountryDataTable();
var adapter = new CountryTableAdapter();
adapter.fill(dt);
foreach (var row in dt){
Console.WriteLine("Id:" + row.Id + "----Name: " + row.Name);
}
Console.Read();
you will see all the records in your table.
I hope this will help.
By the way, from your code
dataSet.AcceptChanges();
The line of code above doesn't update the database at all. It only modify your local data storage.
it overwrites your dataRow original version using current version and change the current version row state to unchanged.
Only the tableadapters can talk to database (not true I know, but I just want to make a point that Dataset can not talk to database directly).
And I usually only need tableadapte.Update method and pass the dataSet or dataTable in with correct RowState.
The tableAdapter.update method will call AcceptChanges on each row eventually if it successfully updated the database.
You should never need to call AcceptChanges explicitly unless you only want update your dataset in memory.
I recommend you to read ADO.NET Architecture to get the big picture how DataSet and TableAdapter worked.
It was my connection string after all. In my original post, I said I had two connection strings:
Connection string in project settings:
Data Source=(LocalDB)\v11.0;AttachDbFilename=|DataDirectory|\fghLocalDB.mdf;Integrated Security=True
Actual connection string in fghLocalDB.mdf file:
Data Source=(LocalDB)\v11.0;AttachDbFilename=C:\Users\gabriel\Source\Workspaces\Capstone\Sandbox\aduclos\QueryDataMarketConsole\QueryDataMarketConsole\fghLocalDB.mdf;Integrated Security=True
Something went wrong with
|DataDirectory| = C:\Users\gabriel\Source\Workspaces\Capstone\Sandbox\aduclos\QueryDataMarketConsole\QueryDataMarketConsole\fghLocalDB.mdf;
in my App.config.
My Solution:
What I did was copy the actual connection string of the .mdf file from the .mdf properties panel and paste it into the project properties => Settings => Value field of the connection string set up.
Afterwards I ran my code again and sure enough the data persisted in the tables.
I did not need dataSet.AcceptChanges(); as #LeY pointed out. I also did not need a TableAdapter.Update(dataset) call as posted in other solutions. I just needed the TableAdapter.Insert("...") call.
EDIT: ALSO Most importantly to answer my original question, instantiation a DataSet does not create a connection with the local database. Instead instantiating a TableAdapter does establish a connection with the database!
Note: Relevant question over here has no solution
Keep in mind that I am no expert on Oracle or programming against Oracle. This is my test environment. I have a single table in the schema STVM called STVM_NOTIFICATION. This is what it looks like:
CREATE TABLE STVM_NOTIFICATION
(
"ID" NUMBER NOT NULL,
"PROPERTYNAME" VARCHAR2(16 BYTE) NOT NULL,
"PROPERTYVALUE" VARCHAR2(16 BYTE) NOT NULL,
"ACTION" VARCHAR2(32 BYTE) NOT NULL,
"POSTDATE" TIMESTAMP (6) NOT NULL,
"SENT" CHAR(1 BYTE) NOT NULL,
ADD CONSTRAINT "PK_ID" PRIMARY KEY ("ID")
)
I have created the following sequence and trigger to create a unique identity for each row:
CREATE SEQUENCE STVM_NOTIF_SEQ
START WITH 1
INCREMENT BY 1
CACHE 100;
CREATE OR REPLACE TRIGGER STVM_NOTIF_ID_TRG BEFORE INSERT ON STVM_NOTIFICATION
FOR EACH ROW
BEGIN
:NEW.ID := STVM_NOTIF_SEQ.NEXTVAL;
END;
I then set the following grants for STVM:
GRANT CREATE SESSION TO STVM;
GRANT CREATE TABLE TO STVM;
GRANT CREATE VIEW TO STVM;
GRANT CREATE ANY TRIGGER TO STVM;
GRANT CREATE ANY PROCEDURE TO STVM;
GRANT CREATE SEQUENCE TO STVM;
GRANT CREATE SYNONYM TO STVM;
GRANT CHANGE NOTIFICATION TO STVM;
Inserting into the table works just fine. Below is the simple test app provided by the Oracle documentation on OracleDependency (with tiny modifications) that I'm using to test notifications:
namespace SqlDependencyTest
{
class Program
{
private static string oraConnectionString = #"Data Source=(DESCRIPTION=(ADDRESS=(PROTOCOL=TCP)(HOST=192.168.0.164)(PORT=1521))(CONNECT_DATA=(SERVICE_NAME=XE)));User Id=STVM;Password=STVM;";
private static string oraQuery = "SELECT ID FROM STVM_NOTIFICATION";
private static OracleDependency oraDependency;
static void Main(string[] args)
{
using (OracleConnection oraConnection = new OracleConnection(oraConnectionString))
{
try
{
// Open the connection
oraConnection.Open();
// Create the Select command retrieving all data from the STVM_NOTIFICATION table.
OracleCommand selectCommand = new OracleCommand(oraQuery, oraConnection);
// Create an OracleDependency object and set it to track the result set returned by selectCommand.
oraDependency = new OracleDependency(selectCommand);
// Setting object-based change notification registration
oraDependency.QueryBasedNotification = false;
// When the IsNotifiedOnce property is true, only the first change
// of the traced result set will generate a notification.
// Otherwise, notifications will be sent on each change
// during the selectCommand.Notification.Timeout period.
selectCommand.Notification.IsNotifiedOnce = true;
// Set the event handler to the OnChange event.
oraDependency.OnChange += new OnChangeEventHandler(OnChange);
// When the select command is executed at the first time, a notification
// on changes of the corresponding result set is registered on the server.
//selectCommand.CommandTimeout = 5;
OracleDataReader reader = selectCommand.ExecuteReader(CommandBehavior.Default);
// Set and execute an insert command. The Dept table data will be changed,
// and a notification will be sent, causing the OnChange event of the 'dependency' object.
OracleCommand insertCommand = new OracleCommand
("INSERT INTO STVM_NOTIFICATION (PROPERTYNAME, PROPERTYVALUE, ACTION, POSTDATE, SENT) VALUES ('Heartbeat', 'NOK', 'REFRESH', SYSDATE, 'N')", oraConnection);
insertCommand.ExecuteNonQuery();
// Pause the current thread to process the event.
Console.Read();
}
catch (Exception e)
{
Console.WriteLine("Exception encountered: {0}", e.Message);
}
// Always try to both remove the notification registration
// oraConnection.Close() is autimatically called by .Dispose at the end of our 'using' statement
finally
{
try
{
oraDependency.RemoveRegistration(oraConnection);
}
catch (Exception e)
{
Console.WriteLine("Exception encountered: {0}", e.Message);
}
}
}
}
// A simple event handler to handle the OnChange event.
// Prints the change notification details.
private static void OnChange(Object sender, OracleNotificationEventArgs args)
{
DataTable dt = args.Details;
Console.WriteLine("The following database objects were changed:");
foreach (string resource in args.ResourceNames)
{
Console.WriteLine(resource);
}
Console.WriteLine("\n Details:");
Console.Write(new string('*', 80));
for (int rows = 0; rows < dt.Rows.Count; rows++)
{
Console.WriteLine("Resource name: " + dt.Rows[rows].ItemArray[0]);
string type = Enum.GetName(typeof(OracleNotificationInfo), dt.Rows[rows].ItemArray[1]);
Console.WriteLine("Change type: " + type);
Console.Write(new string('*', 80));
}
}
}
}
This actually works! However: only until another process performs an insert on the same table, at least, that is my observation. I performed the insert multiple times from SQL Developer, the issue is recreatable and I have done so for over 10 times.
As soon as another process performs said insert, my application hangs on the following statement:
OracleDataReader reader = selectCommand.ExecuteReader(CommandBehavior.Default);
I can clearly see the notification callback being registered in DBA_CHANGE_NOTIFICATION_REGS:
net8://(ADDRESS=(PROTOCOL=tcp)(HOST=192.168.0.226)(PORT=64268))?PR=0
The connection remains open on the Oracle server for 30 minutes until it times out:
SELECT USERNAME, PROGRAM, BLOCKING_SESSION_STATUS, BLOCKING_INSTANCE, BLOCKING_SESSION, EVENT FROM V$SESSION
WHERE USERNAME = 'STVM'
USERNAME PROGRAM BLOCKING_SESSION_STATUS BLOCKING_INSTANCE BLOCKING_SESSION EVENT
STVM SQL Developer NO HOLDER (null) (null) SQL*Net message from client
STVM OracleDependencyTest.vshost.exe VALID 1 50 enq: TM - contention
Whenever this happens, the only solution is to kill the sessions, to REVOKE CHANGE NOTIFICATION and to GRANT it again. After this, my application will work again, until another process performs an insert.
The only clue I have is the event enq: TM - contention, but most people refer to this as an indicator of non-indexed foreign keys in the table. Considering that I currently only have a single table for testing purposes, there aren't a whole lot of foreign keys to go around here.
Does anyone have any ideas as to the relevance of enq: TM - contention?
I am using:
(Server side)
Oracle Database 11g Express Edition Release 11.2.0.2.0 - 64bit Production
PL/SQL Release 11.2.0.2.0 - Production
"CORE 11.2.0.2.0 Production"
TNS for Linux: Version 11.2.0.2.0 - Production
NLSRTL Version 11.2.0.2.0 - Production
Oracle.DataAccess
(Client Side)
Oracle Call Interface (OCI) 11.2.0.1.0
Oracle Client 11.2.0.1.0
Oracle Data Provider for .NET 11.2.0.1.0
Oracle JDBC/OCI Instant Client 11.2.0.1.0
Oracle JDBC/THIN Interfaces 11.2.0.1.0
Oracle SQL Developer 11.2.0.1.0
SQL*Plus 11.2.0.1.0
SQL*Plus Files for Instant Client 11.2.0.1.0
UPDATE: After days of trying to find out what the problem is and not finding the issue, I've decided to move on and look for a different technique. The great suggestion by Christian did not yield any results, and resolving the in-doubt transaction like Justin suggested didn't get me any further either unfortunately. I know a couple of Oracle DBA's over at work who were initially willing to help, but they quickly shoo'd me away as soon as I mentioned .NET.
There's a bug in the version of the database that you are using that may be related. You can check to see if this is the case by executing the following as SYSDBA:
alter system set events '10867 trace name context forever, level 1';
This will last until shutdown. If the problem goes away you are hitting the bug.
You should not leave this turned on, rather you should upgrade the database and and also patch ODP.NET.
I have a Winforms application and database to save data from user.
When I insert data everything works fine but when I clean the solution and load the GUI of the database to see the old data.. I don't see the datam the datagridview is empty.
using (SqlConnection con = new SqlConnection(dataBase.Connection.ConnectionString))
{
using (SqlCommand wow = new SqlCommand("insert into GamesTbl(Type,Date,Time) Values(#type,#date,#time)", con))
{
wow.Parameters.AddWithValue("#type", "vsPC");
wow.Parameters.AddWithValue("#date", DateTime.Now.Date);
wow.Parameters.AddWithValue("#time", DateTime.Now.TimeOfDay);
try
{
con.Open();
wow.ExecuteNonQuery();
con.Close();
}
catch (Exception ex)
{
MessageBox.Show(ex.Message);
}
}
}
What is wrong?
EDIT: binding data on DBGui_load
private void DBGui_Load(object sender, EventArgs e)
{
dataGridView1.DataSource = playersTblBindingSource;
playersTblBindingSource.DataSource = DB.GamesTbls;
}
EDIT: my connection string:
"Data Source=.\\SQLEXPRESS;AttachDbFilename=|DataDirectory|\\Database1.mdf;Integrated
Security=True;User Instance=True"
The whole User Instance and AttachDbFileName= approach is flawed - at best! When running your app in Visual Studio, it will be copying around the .mdf file (to the output directory - typically .\bin\debug - where you app runs) and most likely, your INSERT works just fine - but you're just looking at the wrong .mdf file in the end!
If you want to stick with this approach, then try putting a breakpoint on the myConnection.Close() call - and then inspect the .mdf file with SQL Server Mgmt Studio Express - I'm almost certain your data is there.
The real solution in my opinion would be to
install SQL Server Express (and you've already done that anyway)
install SQL Server Management Studio Express
create your database in SSMS Express, give it a logical name (e.g. Database1 - or while you're at it - give it a more sensible name...)
connect to it using its logical database name (given when you create it on the server) - and don't mess around with physical database files and user instances. In that case, your connection string would be something like:
Data Source=.\\SQLEXPRESS;Database=YourDatabase;Integrated Security=True
and everything else is exactly the same as before...
Seems liks you are missing DataBind.
private void DBGui_Load(object sender, EventArgs e)
{
dataGridView1.DataSource = playersTblBindingSource;
dataGridView1.DataBind(); // you are missing this
playersTblBindingSource.DataSource = DB.GamesTbls;
}
As an alternative solution, what you can do to fix the problem is to set the property of your database file in your solution as follows
Copy To Output Directory: do not copy