I have a datatable with 5 columns, (Song, Artist, Album, Genre, Time) the table allows for me to enter as many rows as i want to create a playlist of music, when the user sees fit they can click the button export the data to access. My access database has a table named "Playlist" with the same 5 columns as the data table. When trying to transfer the data, i keep getting the exception error for the Insert INTO statement and I have no idea why because i am using a commandBuilder. I have attached my class and method thats performing this action.
Please advise!
public void ExportPlaylistToAccess(DataTable playlist)
{
// open connection to the database pathed to
String connection = #"Provider=Microsoft.ACE.OLEDB.12.0;" +
#"Data source= D:\CIS 465\Final Project\VirtualiPod\iTunesPlaylistDatabase.accdb";
using (OleDbConnection con = new OleDbConnection(connection))
{
var adapter = new OleDbDataAdapter();
adapter.SelectCommand = new OleDbCommand("SELECT * from [Playlist]", con);
var cbr = new OleDbCommandBuilder(adapter);
cbr.GetDeleteCommand();
cbr.GetInsertCommand();
cbr.GetUpdateCommand();
try
{
con.Open();
adapter.Update(playlist);
}
catch (OleDbException ex)
{
MessageBox.Show(ex.Message, "Database Error");
}
catch (Exception x)
{
MessageBox.Show(x.Message, "Exception Error");
}
}
dataTable creation
private void createPlaylist_Click(object sender, EventArgs e)
{
if (playlist.Rows.Count == 0)
{
playlist.Columns.Add("Song");
playlist.Columns.Add("Artist");
playlist.Columns.Add("Album");
playlist.Columns.Add("Genre");
playlist.Columns.Add("Time");
dataGridView1.DataSource = playlist;
}
else if (playlist.Rows.Count > 0)
{
MessageBox.Show("Please clear your current playlist to create a new one.");
}
}
// adds song to playlist for user upon click
private void addToPlaylist_Click(object sender, EventArgs e)
{
IITTrackCollection tracks = app.LibraryPlaylist.Tracks;
IITTrack currentTrack = app.CurrentTrack;
DataRow newRow;
newRow = playlist.NewRow();
newRow["Song"] = currentTrack.Name;
newRow["Artist"] = currentTrack.Artist;
newRow["Album"] = currentTrack.Album;
newRow["Genre"] = currentTrack.Genre;
newRow["Time"] = currentTrack.Time;
playlist.Rows.Add(newRow);
dataGridView1.DataSource = playlist;
}
Time is a reserved word. For some reason the command builder does not surround fields that are database reserved words (time, date, long etc.) with brackets [time] which would allow the insert query to work correctly. Without the brackets the insert will fail as the SQL compiler does not know if the string time is a sql command or a field name. The only solution I've found is to rename your database fields so that they are not in conflict with the database reserved names. Hopefully MS will eventually fix this mistake.
Related
I have a table from which I want to take all fields and convert them in an object, I want to pass from a data to another instead of just show the first one.
This code makes the query and it's supposed to take ALL the table fields.
public static DataTable Search()
{
DataTable db = new DataTable();
try
{
NpgsqlConnection connection;
connection = new NpgsqlConnection("Server=localhost;Port=5432;User Id=postgres;Password=root;Database=test;");
connection.Open();
string consultation = "SELECT boxnum, partnum, quantity, date, nivel, row, deep FROM market ma INNER JOIN connection cn ON ma.boxnumm = cn.boxnum;";
NpgsqlCommand com = new NpgsqlCommand(consultation, connection);
NpgsqlDataAdapter adap = new NpgsqlDataAdapter(com);
adap.Fill(db);
connection.Close();
}
catch (Exception e)
{
MessageBox.Show(e.Message);
}
return db;
}
Then in a timer I try to start the object and reload the object from the database, but it just shows the first data and then it creates infinite objects with it.
private void timer2_Tick(object sender, EventArgs e)
{
DataTable dt = getTable.search();
if (dt.Rows.Count > 0)
{
DataRow row = dt.Rows[0];
partnum = Convert.ToString(row["partnum"]);
quantity = Convert.ToInt32(row["quantity"]);
deep = Convert.ToInt32(row["deep"]);
row = Convert.ToInt32(row["row"]);
boxnum = Convert.ToInt32(row["boxnum"]);
aux = Convert.ToDateTime(row["date"]);
boxs.Add(new Box(partnum,quantity,deep,aux,row,boxnum));
}
else
{
}
}
I want to check the table and create an object from each field of it, until now, my code check the table and create the object but it's creating a new one over the old each second.
I am working on my simple task in c# with service based database. I have a service-based database where I have table staff with columns id, name and password. I am trying to insert new record into that table, with C# code, but it's not inserting, just telling me "No Record ADDED" even there is no error.
My code is:
private void button5_Click(object sender, EventArgs e)
{
try
{
connetionString = Properties.Settings.Default.testdbConnectionString;
cnn = new SqlConnection(connetionString);
cnn.Open();
SqlCommand command6;
string sql6 = null;
sql6 = "insert into staff (name,pwd,id) values(#n,#p,#fid)";
command6 = new SqlCommand(sql6, cnn);
command6.Parameters.AddWithValue("#n", "jhon");
command6.Parameters.AddWithValue("#p", "test");
command6.Parameters.AddWithValue("#fid", 1);
int result = command6.ExecuteNonQuery();
if (result == 0)
{
MessageBox.Show("Record ADDED");
}
else
{
MessageBox.Show("No Record ADDED");
}
}
catch (Exception ex)
{
MessageBox.Show(ex.ToString());
}
}
If you need more detail you my ask but please correct my mistake. Thanks
The result of ExecuteNonQuery is the number of records affected. Your if statement is the wrong way round... if the result doesn't equal zero then something was inserted.
I hope this makes sense. I'm familiar with using DataReaders, however I think using a DataTable in this instance makes sense. I have a database table that includes 'questions' and I want to implement a facility to be able to browse through the questions on a website.
So, simplified, there's a label to output the question (lblQuestion) and a back button and a forward button to go to the previous/next question.
Is the following code/saving the DataTable in a Session object the most efficient way to do this?
protected void Page_Load(object sender, EventArgs e)
{
if (!(Page.IsPostBack))
{
getQuestions();
int questionCounter = 1;
ViewState["questionCounter"] = questionCounter;
lblCounter.Text = questionCounter.ToString();
}
}
protected void getQuestions()
{
string connStr = ConfigurationManager.ConnectionStrings["myConnectionString"].ConnectionString;
MySqlConnection conn = new MySqlConnection(connStr);
MySqlDataReader reader;
string cmdText = "SELECT * FROM questions WHERE approved='Y' AND module_id=1";
MySqlCommand cmd = new MySqlCommand(cmdText, conn);
try
{
conn.Open();
reader = cmd.ExecuteReader();
DataTable dt1 = new DataTable();
dt1.Load(reader);
reader.Close();
Session["dt1"] = dt1;
lblQuestion.Text = dt1.Rows[0]["question"].ToString();
}
catch
{
lblError.Text = "Database connection error - failed to get questions.";
}
finally
{
conn.Close();
}
}
protected void btnNext_Click(object sender, EventArgs e)
{
int questionCounter = Convert.ToInt32(ViewState["questionCounter"]);
DataTable dt1 = (DataTable)Session["dt1"];
if (questionCounter < dt1.Rows.Count)
{
questionCounter++;
lblQuestion.Text = dt1.Rows[questionCounter-1]["question"].ToString();
ViewState["questionCounter"] = questionCounter;
lblCounter.Text = questionCounter.ToString();
}
else
{
lblQuestion.Text = "the end of questions.";
}
}
protected void btnBack_Click(object sender, EventArgs e)
{
int questionCounter = Convert.ToInt32(ViewState["questionCounter"]);
DataTable dt1 = (DataTable)Session["dt1"];
if (questionCounter > 1)
{
questionCounter--;
lblQuestion.Text = dt1.Rows[questionCounter-1]["question"].ToString();
ViewState["questionCounter"] = questionCounter;
lblCounter.Text = questionCounter.ToString();
}
else
{
lblQuestion.Text = "the beginning of questions.";
}
}
In general you shouldn't really store data in the session object. The reason for this is that every user will have that datatable stored against them. That means if the table is 1MB and you have 100 users, then you will have 100MB of session objects. Obviously this is not very good.
Instead what you can do is use the Application Cache. This is different to the session store as it is shared across all users (and is cleared upon IIS Application Pool recycle). It's as easy as saving to the session object, but you just use the Cache instead.
In your code you should check to see if the cache contains the questions table already. If it does then just return it, otherwise do your SQL query to populate it. If your questions tend to change regularly then consider using expiration timers that will automatically remove the object after a period of time you define. Then the next time a user queries the question table, your code will detect that it has been removed and request it again.
I create table called Department with 2 columns Department ID which is auto increment and Department Name
I create Navigate_Department() in order to walk through the department rows
System.Data.SqlClient.SqlConnection con;
DataSet Dep_ds;
System.Data.SqlClient.SqlDataAdapter Dep_da;
int Dep_MaxRows = 0;
int Dep_inc = 0;
private void ILS_Load(object sender, EventArgs e)
{
con = new System.Data.SqlClient.SqlConnection();
con.ConnectionString = "Data Source=.\\SQLEXPRESS;AttachDbFilename=|DataDirectory|\\ILS_DB.mdf;Integrated Security=True;Connect Timeout=30;User Instance=True";
con.Open();
Dep_ds = new DataSet();
string sql2 = "select * from Department order by DepartmentID";
Dep_da = new System.Data.SqlClient.SqlDataAdapter(sql2, con);
Dep_da.Fill(Dep_ds, "Department");
Navigate_Department();
Dep_MaxRows = Dep_ds.Tables["Department"].Rows.Count;
}
private void Navigate_Department()
{
DataRow dRow = Dep_ds.Tables["Department"].Rows[Dep_inc];
Dep_ID.Text =dRow.ItemArray.GetValue(0).ToString();
Dep_Name.Text = dRow.ItemArray.GetValue(1).ToString();
}
private void Move_Next_Click(object sender, EventArgs e)
{
if (Dep_inc != Dep_MaxRows-1)
{
Dep_inc++;
Navigate_Department();
}
else
{
MessageBox.Show("No More Records");
}
}
private void Move_back_Click(object sender, EventArgs e)
{
if (Dep_inc > 0)
{
Dep_inc--;
Navigate_Department();
}
else
{
MessageBox.Show("First Record");
}
}
private void Dep_Clear_Click(object sender, EventArgs e)
{
Dep_ID.Clear();
Dep_Name.Clear();
}
private void Dep_Add_Click(object sender, EventArgs e)
{
try
{
SqlCommand insCmd = new SqlCommand("insert into dbo.Department (DepartmentName) values ('" + Dep_Name.Text + "')", con);
Dep_da.InsertCommand = insCmd;
Dep_MaxRows = Dep_MaxRows + 1;
Dep_inc = Dep_MaxRows - 1;
Dep_Max.Text = Dep_MaxRows.ToString();
Dep_Current.Text = (Dep_MaxRows).ToString();
}
catch (Exception exceptionObject)
{
MessageBox.Show(exceptionObject.Message);
}
The problem is:
After I click clear button, I insert the department name into Dep_Name textbox then click add button. The name that I inserted didn’t get saved in the database, and if I click move back then move next in order to see what I inserted, I get a Index out of range exception in the Navigate_Department() method.
So did I make any mistake?
The reason the name you're inserting isn't saved in the database is because you never execute the insert command. Add:
int ret = Dep_da.Update(Dep_ds);
after the
Dep_da.InsertCommand = insCmd;
The variable ret will contain the number of rows successfully updated (inserted) - which in your case should be 1.
To add to what #N. Warfield wrote, if you simply append raw data into your SQL string that a user (or another system, for that matter) provides, you leave yourself wide-open to SQL injection attacks.
Rather than create the insert statement like this you should use the data adapter with an insert command, add a new DataRow instance to the table then use the data adapter to execute the update.
Alternatively you could execute the insert command within Dep_Add_Click by replacing the call to "Dep_da.InsertCommand = insCmd" with "insCmd.ExecuteNonQuery", however this would mean that you would need to re-run the select statement and repopulate the dataset from the database to get the data from the database into the dataset.
How do you programmatically check for MS Access database table, if not exist then create it?
You could iterate though the table names to check for a specific table. See the below code to get the table names.
string connectionstring = "Your connection string";
string[] restrictionValues = new string[4]{null,null,null,"TABLE"};
OleDbConnection oleDbCon = new OleDbConnection(connectionString);
List<string> tableNames = new List<string>();
try
{
oleDbCon.Open();
DataTable schemaInformation = oleDbCon.GetSchema("Tables", restrictionValues);
foreach (DataRow row in schemaInformation.Rows)
{
tableNames.Add(row.ItemArray[2].ToString());
}
}
finally
{
oleDbCon.Close();
}
To check if a table exists you can extend DbConnection like this:
public static class DbConnectionExtensions
{
public static bool TableExists(this DbConnection conn, string table)
{
conn.open();
var exists = conn.GetSchema("Tables", new string[4] { null, null, table, "TABLE" }).Rows.Count > 0;
conn.close();
return exists;
}
}
Then you can call TableExists in any derived class like OleDbConnection, SQLiteConnection or SqlConnection.
Simply execute following code if table will exist it will return error other wise it will create a new one:
try
{
OleDbConnection myConnection = new OleDbConnection("Provider=Microsoft.Jet.OLEDB.4.0; Data Source=" + frmMain.strFilePath + "\\ConfigStructure.mdb");
myConnection.Open();
OleDbCommand myCommand = new OleDbCommand();
myCommand.Connection = myConnection;
myCommand.CommandText = "CREATE TABLE <yourtable name>(<columns>)";
myCommand.ExecuteNonQuery();
myCommand.Connection.Close();
}
catch(OleDbException e)
{
if(e.ErrorCode == 3010 || e.ErrorCode == 3012)
// if error then table exist do processing as required
}
Those error codes are returned if a table already exists - check here for all.
an easy way to do this is
public bool CheckTableExistance(string TableName)
{
// Variable to return that defines if the table exists or not.
bool TableExists = false;
// Try the database logic
try
{
// Make the Database Connection
ConnectAt();
// Get the datatable information
DataTable dt = _cnn.GetSchema("Tables");
// Loop throw the rows in the datatable
foreach (DataRow row in dt.Rows)
{
// If we have a table name match, make our return true
// and break the looop
if (row.ItemArray[2].ToString() == TableName)
{
TableExists = true;
break;
}
}
//close database connections!
Disconnect();
return TableExists;
}
catch (Exception e)
{
// Handle your ERRORS!
return false;
}
}
For completeness sake, I'll point out that a while back I posted 4 different ways of coding up a TableExists() function within Access. The version that runs a SQL SELECT on MSysObjects would work from outside Access, though in some contexts, you might get a security error (because you're not allowed to access the Jet/ACE system tables).