Changes not saving to database using SqlDataAdapter - c#

I'm stuck with my changes not getting saved to the SQL Server database.
I can read the database properly, and when calling RefreshGrid() that refreshes from the database, the gridview updates correctly. But not when restarting the program or checking the actual database, then the changes are gone.
I would normally use Entity Framework for this, but sometimes one needs to learn other ways.
private string conString = ConfigurationManager.ConnectionStrings["RewardsConnectionString"].ConnectionString;
private RewardsDS rewardsDset = new RewardsDS();
private SqlDataAdapter CreateDataAdapter(SqlConnection conn)
{
// Build the selection query.
SqlDataAdapter rewardsAdapter = new SqlDataAdapter();
SqlCommand selectCommand = new SqlCommand("SELECT * FROM Purchases", conn);
rewardsAdapter.SelectCommand = selectCommand;
// Build the insertion query
SqlCommand insertCommand = new SqlCommand(
#"INSERT INTO Purchases (PurchaseDate, Amount, CustomerId)
VALUES (#PurchaseDate, #Amount, #CustomerId)", conn);
insertCommand.Parameters.Add("#PurchaseDate", SqlDbType.DateTime, 0, "PurchaseDate"); // Not sure about this zero ...
insertCommand.Parameters.Add("#Amount", SqlDbType.Decimal, 0, "Amount");
insertCommand.Parameters.Add("#CustomerId", SqlDbType.Int, 0, "CustomerId");
rewardsAdapter.InsertCommand = insertCommand;
// Build the update query
SqlCommand updateCommand = new SqlCommand(
#"UPDATE Purchases SET Amount = #Amount, PurchaseDate = #PurchaseDate WHERE PurchaseId = #PurchaseId", conn);
updateCommand.Parameters.Add("#Amount", SqlDbType.Decimal, 0, "Amount");
updateCommand.Parameters.Add("#PurchaseDate", SqlDbType.DateTime, 0, "PurchaseDate");
SqlParameter param = updateCommand.Parameters.Add("#PurchaseId", SqlDbType.Int, 0, "PurchaseId");
param.SourceVersion = DataRowVersion.Original;
rewardsAdapter.UpdateCommand = updateCommand;
// Build the delete query
SqlCommand deleteCommand = new SqlCommand(
"DELETE FROM Purchases WHERE PurchaseId = #PurchaseId", conn);
param = deleteCommand.Parameters.Add("#Id", SqlDbType.Int, 0, "PurchaseId");
param.SourceVersion = DataRowVersion.Original;
rewardsAdapter.DeleteCommand = deleteCommand;
return rewardsAdapter;
}
// Gets changes and saves them to the database.
private void SaveChanges()
{
using (SqlConnection conn = new SqlConnection(conString))
{
var fadapter = CreateDataAdapter(conn);
conn.Open();
DataSet changes = rewardsDset.GetChanges();
try
{
fadapter.Update(changes, "Purchases");
}
catch (Exception ex)
{
MessageBox.Show("There are no updates to be saved");
}
conn.Close();
rewardsDset.AcceptChanges();
}
}
// Refresh the dataGridView from the database
private void RefreshGrid()
{
rewardsDset.Clear();
using (SqlConnection conn = new SqlConnection(conString))
{
conn.Open();
SqlDataAdapter myAdapter = new SqlDataAdapter("SELECT * FROM Purchases", conn);
myAdapter.Fill(rewardsDset, "Purchases");
conn.Close();
dataGridView1.DataSource = null;
this.dataGridView1.DataSource = rewardsDset.Tables["Purchases"];
}
}

You simply have to execute the queries:
rewardsAdapter.InsertCommand.ExecuteNonQuery();

I will start by apologizing for wasting anyone's time. Finally found what was causing this error and it was far more basic than I thought and not at all where I've been trying to look for solutions.
I've made an embarrassing mistake regarding the connection string, but if someone repeats my mistake this was it:
I've been using the connection string to the DataSet, and not to the actual database ...
Adding the proper connection string certainly solved my problem, and was of course impossible for anyone to see with only the code I posted above.

Related

C# SQL INSERT INTO command doesn't work

I have this code:
private void FirmaEkleB_Click(object sender, EventArgs e)
{
string query = "INSERT INTO FIRMATABLE VALUES (#CompanyName)";
SqlConnection sqlconnection = new SqlConnection(connectionString);
SqlCommand command = new SqlCommand(query, sqlconnection);
Form1 LoginForm = new Form1();
sqlconnection.Open();
command.Parameters.AddWithValue("#CompanyName", FirmaIsmiTextbox.Text);
command.ExecuteScalar();
SqlCommand com2 = new SqlCommand("Select FirmaIsmi FROM FIRMATABLE WHERE ID = 9", sqlconnection);
MessageBox.Show(com2.ExecuteScalar().ToString());
LoginForm.fillFirmaList();
}
fillFirmaList() looks like this:
public void fillFirmaList()
{
connection = new SqlConnection(connectionString);
SqlCommand command = new SqlCommand("SELECT * FROM FirmaTable", connection);
SqlDataAdapter adapter = new SqlDataAdapter(command);
DataTable firmaTable = new DataTable();
adapter.Fill(firmaTable);
FirmaCombo.DataSource = firmaTable;
FirmaCombo.DisplayMember = "FirmaIsmi";
FirmaCombo.ValueMember = "Id";
}
I don't know what I'm doing wrong but I can't seem get my combobox to update from the table I have. The manually added rows show up but not the one that I add
Keep in mind that I'm just starting out in SQL Server and database stuff.
If more info is needed tell me.
Change your Insert query to
INSERT INTO FIRMATABLE (FirmaIsmi) VALUES (#CompanyName)
You need to include all your column names for which you are adding the VALUES.
And
change ExecuteScalar to command.ExecuteNonQuery().
Add try-catch block and see what exception does it throws after ExecuteNonQuery

SQL Performance Issue ASP.Net App

We have a performance Issue in our ASP.NET based web App and it's visible only once when we login in the morning. As per Log looks like below query takes more than 1 minute 20 secs. Next time onward when user login to the app and try to access same page doesn't find any issue. Can you please let me know how to optimize this query ? Any thoughts how we can fix this problem ?
Log -
"11/13/15","08:38:27","ExecuteSql - ---3---- ","8",""
"11/13/15","08:38:27","ExecuteSql - ---4---- : SQL : SELECT TOP 1 CONVERT(varchar(15), Period_End_Date, 107) as PDate FROM PBHISTORY..STATEMENT_OF_CHANGE
ORDER BY Period_End_Date DESC","8",""
"11/13/15","08:39:48","ExecuteSql - ---5---- ","8",""
SQL :
SELECT TOP 1
CONVERT(varchar(15), Period_End_Date, 107) as PDate
FROM
PBHISTORY..STATEMENT_OF_CHANGE
ORDER BY
Period_End_Date DESC
C# ASP.NET -
public string GetDateRangeReportingDate(int reportId)
{
var report = GetReportInfoById(reportId);
string sql = string.Format(#"SELECT TOP 1 CONVERT(varchar(15), Period_End_Date, 107) as PDate FROM {0}..{1} ORDER BY Period_End_Date DESC", _historyDatabase, report.SourceTableName);
var data = ExecuteSql(sql);
while (data.Read())
{
return data["PDate"].ToString();
}
return null;
}
private SqlDataReader ExecuteSql(string sql)
{
SqlDataReader reader;
SqlConnection conn;
var commandTimeOut = ConfigurationManager.AppSettings["PBReportCommandTimeout"].ToString();
string connString = ConfigurationManager.ConnectionStrings["PBReportCS"].ConnectionString;
conn = new SqlConnection(connString);
conn.Open();
SqlCommand cmd = new SqlCommand(sql, conn);
cmd.CommandTimeout = int.Parse(commandTimeOut);
reader = cmd.ExecuteReader();
return reader;
}
I found solution of my performance issue I mentioned above. Issue was wrong indexing in table and I fixed this issue by changing the indexing of table where from we are fetching records in production.
Also, I fixed Framework level entity class by using SQL Data Adapter and using statements. App runs super fast in production. Thanks for your help.
private string ExecuteSqlNew(string sql)
{
string connectionString = ConfigurationManager.ConnectionStrings["PBReportCS"].ConnectionString;
string commandTimeOut = ConfigurationManager.AppSettings["PBReportCommandTimeout"].ToString();
DataSet result = new DataSet();
string pDate = "";
try
{
using (SqlConnection conn = new SqlConnection(connectionString))
{
using (SqlCommand cmd = new SqlCommand(sql, conn))
{
conn.Open();
cmd.CommandTimeout = int.Parse(commandTimeOut);
SqlDataAdapter adapter = new SqlDataAdapter();
adapter.SelectCommand = cmd;
adapter.Fill(result);
adapter.Dispose();
conn.Close();
pDate = result.Tables[0].Rows[0]["PDate"].ToString();
}
}
}
catch(Exception ex)
{
throw ex;
}
return pDate;
}

ADO select statement with full text search with SQL injection

The database that I am connecting to has a table with a Full Text Search index. This works correctly.
select * from MyTable where contains(*, 'value')
In WPF if I send that exact command down it works. However value is not hard coded it is something an user types in so it needs to be protected for SQL injection. The issue is that in doing so it does not return results. Here is my code;
DataTable dt = new DataTable();
string ConString = "Data Source=127.0.0.1,1433;Initial Catalog=MyDB;User Id=sa;Password=amazingSecurePassword;";
using (SqlConnection con = new SqlConnection(ConString))
{
string sqlCMD = "select * from MyTable where contains(*, #s1)"
SqlCommand cmd = new SqlCommand(sqlCMD, con);
SqlDataAdapter da = new SqlDataAdapter();
try
{
con.Open();
cmd = new SqlCommand(sqlCMD, con);
cmd.Parameters.Add(new SqlParameter("#s1", "value"));
da.SelectCommand = cmd;
da.Fill(dt);
con.Close();
}
catch (Exception x)
{
//Error logic
}
finally
{
cmd.Dispose();
con.Close();
}
}
Edit: #Mike comment worked. Change the SqlDbType.NVarChar fixed the issue
As noted in the above comment, setting the SQlDbType to NVarChar during the creation of the SqlParameter helps the CLR determine the right data type. More info about the SqlParameter constructor at MSDN.

SQL DataTable Update?

I'm not sure, but I think I may have taken a wrong path here. I am trying to update my customer table on my SQL Server. I Connected with a SQLDatareader and then loaded that into my Datatable. I have made all the changes I wanted and now I can't figure out how to get the changes back up. I thought that the "myDataTable.AcceptChanges();" would trigger that to happen but it doesn't.
SqlConnection myConnection = new SqlConnection();
SqlCommand myCommand;
DataTable myDataTable;
SqlDataReader myReader;
myCommand = new SqlCommand();
myCommand.CommandText = " SELECT * FROM customer";
myCommand.CommandType = CommandType.Text;
myCommand.Connection = myConnection;
myCommand.Connection.Open();
myReader = myCommand.ExecuteReader(CommandBehavior.CloseConnection);
myDataTable = new DataTable();
myDataTable.Load(myReader);
// Make Data changes here
myDataTable.AcceptChanges();
MyDataTable.Dispose();
MyCommand.Dispose();
MyConnection.Dispose();
You can use a TableAdapter to commit your changes back to the database. Check out this link for details.
TableAdapter.Update()
In such case you need to use a DataAdapter which has an Update property that takes your Update Query Command.
Even you can use Command Builder and then get the UpdateCommand from CommandBuilder.
Sample Code from MSDN
SqlDataAdapter catDA = new SqlDataAdapter("SELECT CategoryID, CategoryName FROM Categories", nwindConn);
catDA.UpdateCommand = new SqlCommand("UPDATE Categories SET CategoryName = #CategoryName " +
"WHERE CategoryID = #CategoryID" , nwindConn);
catDA.UpdateCommand.Parameters.Add("#CategoryName", SqlDbType.NVarChar, 15, "CategoryName");
SqlParameter workParm = catDA.UpdateCommand.Parameters.Add("#CategoryID", SqlDbType.Int);
workParm.SourceColumn = "CategoryID";
workParm.SourceVersion = DataRowVersion.Original;
DataSet catDS = new DataSet();
catDA.Fill(catDS, "Categories");
DataRow cRow = catDS.Tables["Categories"].Rows[0];
cRow["CategoryName"] = "New Category";
catDA.Update(catDS);
MSDN Link

update table in database from datatable

I load data from database table like this...
using (view_adapter = new SqlDataAdapter("select * from TVServiceProvider", connection_string))
{
using (dt = new DataTable())
{
view_adapter.Fill(dt);
for (int i = 0; i < dt.Columns.Count; i++)
{
if (dt.Columns[i].ColumnName.Substring(0, 2).Equals("id"))
dt.Columns[i].ReadOnly = false;
}
bs.DataSource = dt;
}
}
Where SqlDataAdapter view_adapter and DataTable dt. To apply changes to database I've created method
void View_Adapter_Click(object sender, EventArgs e)
{
try
{
view_adapter.Update(dt);
dt.AcceptChanges();
}
catch (Exception exc)
{
this.radLabelElement1.Text = exc.Message;
}
}
But when I click the button I've got an exception. It requires update command. Where and what command I should use?
You must create UpdateCommand and DeleteCommand for you view_adapter.
EDIT:
The code must look like this:
SqlDataAdapter view_adapter = new SqlDataAdapter();
view_adapter .SelectCommand = new SqlCommand(queryString, connection);
view_adapter .UpdateCommand = new SqlCommand(updateCommadString, connection);
view_adapter .DeleteCommand = new SqlCommand(deleteCommadString, connection);
using (SqlConnection connection = new SqlConnection(connectionString))
{
view_adapter.Fill(dt);
return dt;
}
Well, something is wrong or not clear in your code.
The view_adapter variable is initialized within a using block statement.
Thus, when exiting from the using block, the view_adatpter will be disposed by the framework and unusable in the click event. (like you have never called new to initialize it).
I suspect that you have another problem here. Using statement
A part from this, to automatically create the UpdateCommand, InsertCommand and DeleteCommand required to perform CRUD operations with a DataAdapter you could use a SqlCommandBuilder.
(This is possible only if you use one table in the select statement and that table has a primary key defined)
So to summarize everything:
string queryString = "select * from TVServiceProvider";
view_adapter = new SqlDataAdapter(queryString, connection_string);
SqlCommandBuilder builder = new SqlCommandBuilder(view_adapter)
builder.GetUpdateCommand(); // Force the building of commands
view_adapter.Fill(dt);
then your click event should works as is now.
This code is not related to yours, but may help you, If you give it a look. I got it from MSDN
public static SqlDataAdapter CreateCustomerAdapter(
SqlConnection connection)
{
SqlDataAdapter adapter = new SqlDataAdapter();
// Create the SelectCommand.
SqlCommand command = new SqlCommand("SELECT * FROM Customers " +
"WHERE Country = #Country AND City = #City", connection);
// Add the parameters for the SelectCommand.
command.Parameters.Add("#Country", SqlDbType.NVarChar, 15);
command.Parameters.Add("#City", SqlDbType.NVarChar, 15);
adapter.SelectCommand = command;
// Create the InsertCommand.
command = new SqlCommand(
"INSERT INTO Customers (CustomerID, CompanyName) " +
"VALUES (#CustomerID, #CompanyName)", connection);
// Add the parameters for the InsertCommand.
command.Parameters.Add("#CustomerID", SqlDbType.NChar, 5, "CustomerID");
command.Parameters.Add("#CompanyName", SqlDbType.NVarChar, 40, "CompanyName");
adapter.InsertCommand = command;
// Create the UpdateCommand.
command = new SqlCommand(
"UPDATE Customers SET CustomerID = #CustomerID, CompanyName = #CompanyName " +
"WHERE CustomerID = #oldCustomerID", connection);
// Add the parameters for the UpdateCommand.
command.Parameters.Add("#CustomerID", SqlDbType.NChar, 5, "CustomerID");
command.Parameters.Add("#CompanyName", SqlDbType.NVarChar, 40, "CompanyName");
SqlParameter parameter = command.Parameters.Add(
"#oldCustomerID", SqlDbType.NChar, 5, "CustomerID");
parameter.SourceVersion = DataRowVersion.Original;
adapter.UpdateCommand = command;
// Create the DeleteCommand.
command = new SqlCommand(
"DELETE FROM Customers WHERE CustomerID = #CustomerID", connection);
// Add the parameters for the DeleteCommand.
parameter = command.Parameters.Add(
"#CustomerID", SqlDbType.NChar, 5, "CustomerID");
parameter.SourceVersion = DataRowVersion.Original;
adapter.DeleteCommand = command;
return adapter;
}
What actually worked for me from Steve and Hamlet's suggestions is the following. I had one hiccup because I tried to do an accept changes on my rows and table before doing the view adapter update. The accept changes in only needed to save the changes to the datatable before reusing the datatable for displaying in a gridview or other operations.
SqlDataAdapter viewAdapter = new SqlDataAdapter("Select * From Users", DBConn);
SqlCommandBuilder builder = new SqlCommandBuilder(viewAdapter);
viewAdapter.UpdateCommand = builder.GetUpdateCommand();
DataTable Users = new DataTable();
viewAdapter.Fill(Users);
foreach (DataRow user in Users.Rows)
{
foreach (DataColumn c in Users.Columns)
{
Console.WriteLine(c.ColumnName);
if (c.DataType != typeof(DateTime))
{
// Clean up empty space around field entries
user[c.ColumnName] = user[c.ColumnName].ToString().Trim();
}
}
// user.AcceptChanges();
// Do not do an accept changes for either the table or the row before your ViewAdapter Update.
// It will appear as though you do not have changes to push.
}
// Users.AcceptChanges();
viewAdapter.Update(Users);

Categories

Resources