I'm writing a music player application using WPF (C#). As part of its functionality, I'm populating a music library, where I'm storing the Title and Path to an mp3 file. The user gets to select a root folder for his music library and then the contents are populated in a "Songs" table. This is the code that I've written:
private void Populate_Click(object sender, RoutedEventArgs e)
{
// Folder browser
FolderBrowserDialog dlg = new FolderBrowserDialog();
dlg.ShowDialog();
string DirectoryPath = System.IO.Path.GetDirectoryName(dlg.SelectedPath);
// Get the data directory
string[] A = Directory.GetFiles(DirectoryPath, "*.mp3", SearchOption.AllDirectories);
string[] fName = new string[A.Count()];
// Initialize connection
string connstr = "Data Source=.\\SQLEXPRESS;AttachDbFilename=|DataDirectory|\\Database.mdf;Integrated Security=True;User Instance=True";
SqlConnection conn = new SqlConnection(connstr);
conn.Open();
// Create the SqlCommand
SqlCommand cmd = new SqlCommand();
cmd.Connection = conn;
cmd.CommandType = CommandType.StoredProcedure;
cmd.CommandText = "InsertSongs";
// Create the parameters and execute the command
for (int i = 0; i < A.Count(); i++)
{
fName[i] = System.IO.Path.GetFileName(A[i]);
cmd.Parameters.AddWithValue("#Title", fName[i]);
cmd.Parameters.AddWithValue("#Path", A[i]);
try
{
cmd.ExecuteNonQuery();
}
catch (Exception ex)
{
System.Windows.MessageBox.Show("Error: " + ex.Message);
}
finally
{
listBox1.Items.Add(A[i]);
listBox2.Items.Add(fName[i]);
cmd.Parameters.Clear();
}
}
// Close the connection
cmd.Dispose();
conn.Close();
conn.Dispose();
}
The code for the stored procedure is simple -
ALTER PROCEDURE dbo.InsertSongs
(
#Title nvarchar(50),
#Path nvarchar(50)
)
AS
INSERT INTO Songs(Title, Path) VALUES(#Title, #Path)
Now, when I execute the program, there is no error message thrown (the file names and directory names have size less than 50). However, at the end of execution, no value is inserted in the Songs table.
The Songs table is described as below:
ID int
Title nvarchar(50)
Path nvarchar(50)
I'm not sure where I went wrong: I have also tried using SqlParameter and then defining the type of parameter as NVARCHAR with size 50, but to no avail. May I kindly request you to assist me here? Many thanks in advance.
The whole User Instance and AttachDbFileName= approach is flawed - at best! Visual Studio will be copying around the .mdf file 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. SongsDatabase)
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=SongsDatabase;Integrated Security=True
and everything else is exactly the same as before...
Related
private void button1_Click(object sender, EventArgs e)
{
string CS = ConfigurationManager.ConnectionStrings["connection_string"].ConnectionString;
OleDbConnection C = new OleDbConnection(CS);
C.Open();
OleDbCommand CMD = new OleDbCommand("", C);
CMD.CommandText = "SELECT COUNT(*) FROM Applicants WHERE ApplicantID = ?";
CMD.Parameters.AddWithValue("#ApplicantID", textBox1.Text);
if (Convert.ToInt32(CMD.ExecuteScalar()) > 0)
{
CMD.CommandText = "UPDATE Onboarding SET " +
"BackgroudCheck = #BGC, PhotoID = #PID, " +
"TrainingHoursOutOf40 = #THOO, DrugTestTaken = #DTT, PassedDrugTest = #PDT" +
"WHERE ApplicantID = #AID";
CMD.Parameters.AddWithValue("#AID", textBox1.Text);
CMD.Parameters.AddWithValue("#BGC", CheckBox1);
CMD.Parameters.AddWithValue("#PID", CheckBox2);
CMD.Parameters.AddWithValue("#THOO", TextBox2.Text);
CMD.Parameters.AddWithValue("#DTT", CheckBox3);
CMD.Parameters.AddWithValue("#PDT", CheckBox4);
MessageBox.Show("Applicant Updated Successfully");
}
else
{
MessageBox.Show("Applicant Does Not Exists");
}
C.Close();
}
I am trying to update the data table. Some how when I try to update in the form I do get a messagebox saying "Applicant updated Successfully", but when I go to the data table or view it in another form, the table is not updated.
Several problems here
Ole does not use named parameters. You can give your parameters names but they're ignored. You must add the right number of parameters in the right order
use using to ensure database resources are closed and disposed of when you're done with them
You never actually executed your UPDATE query
You didn't put .Checked to retrieve the Booleans from your check boxes
You don't need to SELECT first. If the update updates no record the applicant doesn't exist. An UPDATE doesn't error if there is nothing to update. ExecuteNonQuery returns an int of how many rows were updated
You really should rename your controls after you drop them on the form. Code that is full of Label57, Button29 is effectively obfuscated (meaningless garbage) that is very hard to maintain
In c# variables declared inside a method are named with camelCaseLikeThis, not ALLCAPS
Be aware that if this is a file based database you're using (it is likely Access if it's ole) that multiple copies of the database file are present on disk. Countless questions are asked "why isn't my db updating" when it is - it's just that the program is updating the db in the bin folder and the dev is looking in the copy of the db in the project folder (which is copied over the top of the bin folder db every time the project is run, which is another reason the program "never remembers anything")
if you're using Access, you would do yourself massive favors by switching to an extensively used commercial grade db (sql server Express is free, and SQLite is definitely worth using over Access) and learning entity framework. I appreciate you're on a learning journey but largely what you're learning now isn't widely used in the real world any more, because it's a tedious waste of time somewhat akin to writing your own graphics drivers or Json parsers. If you want to stick with this approach take a look at Dapper, which takes a lot of the pain out of "data access by SQL strings in button click handlers" - opening and closing connections, filling in parameters and types, pulling data out of readers and casting it; all that work can be done by software and dapper can reduce the code you've written here to a single line like c.Execute("UPDATE ...", new { bgcCheckbox.Checked, ... aidTextbox.Text })
private void button1_Click(object sender, EventArgs e)
{
string cs = ConfigurationManager.ConnectionStrings["connection_string"].ConnectionString;
using(OleDbConnection c = new OleDbConnection(cs)){
c.Open();
using(OleDbCommand cmd = new OleDbCommand("", c)){
cmd.CommandText = "UPDATE Onboarding SET " +
"BackgroudCheck = ?, PhotoID = ?, " +
"TrainingHoursOutOf40 = ?, DrugTestTaken = ?, PassedDrugTest = ?" +
"WHERE ApplicantID = ?";
cmd.Parameters.AddWithValue("#BGC", CheckBox1.Checked);
cmd.Parameters.AddWithValue("#PID", CheckBox2.Checked);
cmd.Parameters.AddWithValue("#THOO", TextBox2.Text);
cmd.Parameters.AddWithValue("#DTT", CheckBox3.Checked);
cmd.Parameters.AddWithValue("#PDT", CheckBox4.Checked);
cmd.Parameters.AddWithValue("#AID", textBox1.Text);
if(cmd.ExecuteNonQuery()>0)
MessageBox.Show("Applicant Updated Successfully");
else
MessageBox.Show("Applicant Does Not Exists");
}
}
}
You have not used ExecuteNonQuery() method of SQL Command class.
int returnValue;
returnValue = CMD.ExecuteNonQuery();
I am having difficulties in finding a solution for opening a stored procedure straight to MSQL management studio for modifying in a new SQLQuery from my C# application (winform).
Here is my code:
Process openSQL = new Process();
openSQL.StartInfo.FileName = "Ssms.exe";
openSQL.StartInfo.Arguments = "dbo.getResults"; //name of the stored procedure I want to open
openSQL.Start();
I am getting error after executing the code :"The following files were specified on the command line: dbo.getResults These files could not be found and will not be loaded."
How am I supposed to "point" to the stored procedure in C# and get its definition displayed and ready to get modifications in MSQL management studio?
This isn't possible I'm afraid. If you run ssms -? from the command line you can see all the parameters that you can pass in:
Some options:
Let users edit procs themselves. After all, anyone capable of doing this will understand how to use SSMS properly.
Make your own UI. You can read the contents of a stored procedure and display them in a text box. The downside is that you lose features such as syntax highlighting (unless you also build that in too)
You could download the procedure and store it in a procedure.sql file and get SSMS to open that. Don't forget to pass in the server, database and credentials.
I found a way to open a stored procedure script straight to MSQL management studio for modifying in a new SQLQuery from my C# application (winform).
I am taking the script of the procedure with EXEC sp_helptext 'procedure_name'
The result set is filled in a DataSet
And the DataSet is getting written in an empty .sql file
The .sql file is getting opened in MSQL Managment Studio with System.Diagnostics;
Here are the steps with code snippets:
private void saveProcToAFile()
{
StreamWriter log;
if (!File.Exists("procedureToBeLoaded.sql"))
{
log = new StreamWriter("procedureToBeLoaded.sql");
}
else
{
log = new StreamWriter(File.Create("procedureToBeLoaded.sql"));
}
SqlConnection conn = new SqlConnection(conString);
SqlDataAdapter da = new SqlDataAdapter();
SqlCommand cmd = conn.CreateCommand();
cmd.CommandText = string.Format("EXEC sp_helptext '{0}'", "procedure_name"); //Step 1.
da.SelectCommand = cmd;
DataSet ds = new DataSet();
conn.Open();
da.Fill(ds); //Step 2.
conn.Close();
foreach (DataRow dr in ds.Tables[0].Rows)
{
log.WriteLine(dr[0]); //Step 3.
}
log.Close();
}
Step 4.
private void contextMenuStripOpenInSqlStudio_Click(object sender, EventArgs e)
{
saveProcToAFile();
Process openSQL = new Process();
openSQL.StartInfo.FileName = "Ssms.exe";
openSQL.StartInfo.Arguments = "procedureToBeLoaded.sql";
openSQL.Start();
}
I have a program which is supposed to open, edit, create and save access databases. For saving I copy an empty database with just the tables (just to avoid going through the hassle of creating every table and column etc) and try to fill it with values via the TableAdapterManager.UpdateAll method.
string _TemplateConnectString = #"Provider=Microsoft.Jet.OLEDB.4.0;Data Source={0};";
_connection = new OleDbConnection(string.Format(_TemplateConnectString, dlg.FileName));
_connection.Open();
DataSet1TableAdapters.TableAdapterManager tam=new TableAdapterManager();
tam.Connection = _connection;
try
{
tam.UpdateAll(dataset);
}
catch (System.Exception ex)
{
MessageBox.Show("Update failed");
}
It finishes with no exceptions but the values don't get inserted into the new database.
Also as far as I know the UpdateAll method only updates modified row so if I open some db and it inserts it's rows, it will not take them into account even though there are not in the database that I am trying to fill.
I have also tried filling the database with the ADODB and ADOX extensions but all the solutions I found with those was a lot of hardcoding and no regards for hierarchy, keys, etc.
Is there a way to force insert everything in the new database?
Is your template database in the Visual Studio project directory? It might have something to do with Visual Studio copying the database to the bin/debug or bin/release folder...
Try to use the right Data source database name, here an
example with an excel file:
cnn.Open "Provider=Microsoft.Jet.OLEDB.4.0;" & _
"Data Source=c:\somepath\ExcelFile.xls;" & _
"Extended Properties=""Excel 8.0;HDR=Yes;"";"
A clumsy solution but it works. I iterate the tables of the dataset and save the via an sql string generator like this:
void SaveTable(DataTable dt)
{
string[] inserts;
try
{
inserts = SqlHelper.GenerateInserts(dt, null, null, null);
foreach (string s in inserts)
{
OleDbCommand cmd = new OleDbCommand();
cmd.CommandText = s;
cmd.Connection = _connection;
int n = cmd.ExecuteNonQuery();
}
}
catch (Exception e)
{
SaveOk = false;
}
}
I found the SqlHelper somewhere on this site, but completely lost where, unforunately. So here is the pastebin with it https://pastebin.com/iCMVuYyu
I have an application that saves and opens data (which is saved as SQL CE database file). Every time the project gets saved, a new .sdf file is generated with table structure defined by my code and I do not need to run any validation against it.
My concern is when user import (open) the .sdf file in a OpenFileDialog, there will be chance user may select a database file generated from a different application (i.e. having a different table schema). I would need to validate the importing database table schema or the application may crash if the wrong database file is opened and processed.
I do not need to compare schema between files. All I need is to check if the database file contain a certain table structure or table names (which I think should be sufficient for my purpose). What is the easiest way to do this?
[EDIT]
I used the following method to validate the database file, which works. I use a string array to checked against a SqlCeDataReader (which stores the Table name). It works but I wonder if there's an even easier way - is there a build in method in .NET to use?
using (SqlCeConnection conn = new SqlCeConnection(validateConnStr))
{
using (SqlCeCommand cmd = new SqlCeCommand(#"SELECT TABLE_NAME FROM INFORMATION_SCHEMA.TABLES", conn))
{
try
{
conn.Open();
SqlCeDataReader rdr = cmd.ExecuteReader();
string[] tableArr = { "FirstTable", "SecondTable" };
int ta = 0;
while (rdr.Read())
{
if (rdr.GetString(0) != tableArr[ta])
{
isValidDbFile = false;
}
else
{
isValidDbFile = true;
}
ta++;
}
}
catch (Exception ex)
{
//MessageBox.Show(ex.ToString());
}
finally
{
conn.Close();
}
}
}
Open the database (make sure to have error handling for this, as the user can point to any file).
run: SELECT TABLE_NAME FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_NAME = N'MyTable'
If this returns data, your table is there.
I got some data inputed by the user that should be added to a Database File (.sdf). I've choose Sql Server CE because this application is quite small, and i didn't saw need to work with a service based database.
Well any way.
Here goes the code:
public class SqlActions
{
string conStr = String.Format("Data Source = " + new System.IO.FileInfo(System.Reflection.Assembly.GetExecutingAssembly().Location).DirectoryName + "\\basedados.sdf");
public SqlCeConnection SQLCEConnect()
{
SqlCeConnection Connection = new SqlCeConnection(conStr);
Connection.Open();
return Connection;
}
public Boolean AdicionarAuditorio(string Nome, int Capacidade)
{
string Query = "INSERT INTO auditorios (nome, capacidade) VALUES (#Nome, #Capacidade)";
using (var SQLCmd = new SqlCeCommand(Query, SQLCEConnect()))
{
SQLCmd.Parameters.AddWithValue("#Nome", Nome);
SQLCmd.Parameters.AddWithValue("#Capacidade", Capacidade);
if (SQLCmd.ExecuteNonQuery() == 1)
{
return true;
} else {
return false;
}
}
}
}
I use the AdicionarAuditorio(string Nome, int Capacidade) function to Insert the data. running ExecuteNonQuery() which is supposed to return the number of affected rows after he as run the query.
So it should return 1 if the query as successful, right?
In the end he returns 1, but if I browser the table data, the data that the query should add isn't there.
So whats wrong here?
NOTE. If your thinking that the
problem is the connection: I can't see
why is the problem once i got some
Select statements that use that
connection function SQLCEConnect()
and they all work pretty well.
Thanks in advance.
Are you sure you are looking at the right file? When you build your app in VS, it copies the SDF file as content to the target folder, so the database in your project will not reflect any updates. Your code is picking up the the file location there.
This is btw not a good practice, because once deployed, the program folders are not writable to your app (could this be the problem - did you already deploy?). Instead, the database file should reside in your appdata folder.
Is it possible that you make the call to AdicionarAuditorio in a TransactionScope without calling transactionScope.Complete()?