WPF DataGrid deleted rows don't get updated (deleted) in the database - sql

I have a DataGrid in my application, whose XML definition is as follows:
<DataGrid x:Name="grid"
DockPanel.Dock="Top"
Visibility="{Binding gridVisibility}"
CellStyle="{StaticResource ValidationReadyCellStyle}"
IsSynchronizedWithCurrentItem="True"
HorizontalAlignment="Stretch"
HorizontalContentAlignment="Stretch"
VerticalContentAlignment="Stretch"
ColumnWidth="*"
ItemsSource="{Binding DBtable, ValidatesOnExceptions=False,
NotifyOnSourceUpdated=True, TargetNullValue={x:Static system:String.Empty}, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"
AutoGenerateColumns="True" AutoGeneratingColumn="grid_OnAutoGeneratingColumn" CanUserAddRows="True"
BeginningEdit="grid_OnBeginningEdit" PreviewKeyDown="grid_OnPreviewKeyDown" RowEditEnding="grid_OnRowEditEnding" CellEditEnding="grid_OnCellEditEnding">
<DataGrid.RowValidationRules>
<local:RowValidationChecker ValidationStep="UpdatedValue"/>
</DataGrid.RowValidationRules>
</DataGrid>
As can be seen, the ItemsSource is bound to a table named DBtable, depending on which the rows/columns are automatically generated. Following is the code snippet used for connecting to and updating the database:
public bool SaveToDB(DataTable table, string tableName)
{
var msSqlConnectionClass = new MsSqlConnectionClass(MsSqlLogin.Default.Server,
MsSqlLogin.Default.LoremIpsumDB, MsSqlLogin.Default.UID,
MsSqlLogin.Default.Password, MsSqlLogin.Default.WinAuth);
SqlConnection msSqlConnection = msSqlConnectionClass.getMsSqlConnection();
msSqlConnection.Open();
try
{
string strSQL = "SELECT * FROM " + tableName;
SqlDataAdapter da = new SqlDataAdapter(strSQL, msSqlConnection);
SqlCommandBuilder command = new SqlCommandBuilder(da);
da.UpdateCommand = command.GetUpdateCommand();
da.DeleteCommand = command.GetDeleteCommand();
da.InsertCommand = command.GetInsertCommand();
da.Update(table);
msSqlConnection.Close();
}
catch (Exception e)
{
ServiceLog.AddLogInfo(e.ToString());
msSqlConnection.Close();
return false;
}
return true;
}
The problem is, although any addition or edit operation done in the DataGrid gets perfectly updated in the database, I am unfortunately unable to achieve the same behaviour for the deletion operation. The deletion is done in the source itself, so when I check the row count after a deletion operation (for which I use DBtable.Rows.RemoveAt()), DBtable shows me that the row is deleted, however the changes are not reflected in the database after the update attempt made using the SaveToDB() function shown above. What should I do?

I found the problem. Apparently
Dbtable.Rows.RemoveAt(selectedIndex);
does not let the data table know that a deletion command has been issued. Hence, when an update command is run over the database, no deletion is seen and executed. Instead, using
row = DBtable.Rows[selectedIndex];
row.Delete();
solved the problem.

Something similar confused me as well. Here is a solution for those who may encounter this page while searching later.
public DataTable GetMembers()
{
conn = new SqlCeConnection(#"Data Source = DataModel.sdf");
dataAdapter = new SqlCeDataAdapter("Select * from Members", conn);
commandBuilder = new SqlCeCommandBuilder(dataAdapter);
dataTable = new DataTable();
dataAdapter.Fill(dataTable);
dataTable.RowChanged += new DataRowChangeEventHandler(dataTable_RowChanged);
dataTable.RowDeleted += new DataRowChangeEventHandler(dataTable_RowDeleted);
dataTable.DefaultView.ListChanged += DefaultView_ListChanged;
return dataTable;
}
void DefaultView_ListChanged(object sender, System.ComponentModel.ListChangedEventArgs e)
{
if (e.ListChangedType == System.ComponentModel.ListChangedType.ItemDeleted)
{
try
{
dataAdapter.Update(dataTable);
}
catch (Exception ex)
{
System.Windows.MessageBox.Show(ex.Message);
}
}
}

Related

How to check whether table column of the binary type has a value?

The Download command is showing in front of all the rows, I want to show it to only those rows having PDF file attached in the database.
protected void gvupdationsummary_SelectedIndexChanged(object sender, EventArgs e)
{
SqlConnection con = new SqlConnection(st);
con.Open();
SqlCommand com = new SqlCommand("select [name],[data] from [Pragati].[dbo].[Pragati_Status_Updations] where Pragati_no=#Pragati_no", con);
com.Parameters.AddWithValue("Pragati_no", gvupdationsummary.SelectedRow.Cells[3].Text);
SqlDataReader dr = com.ExecuteReader();
if (dr.Read())
{
Response.Clear();
Response.Buffer = true;
//Response.ContentType = dr["type"].ToString();
Response.AddHeader("content-disposition", "attachment;filename=" + dr["name"].ToString());
Response.Charset = "";
Response.Cache.SetCacheability(HttpCacheability.NoCache);
Response.BinaryWrite((byte[])dr["data"]);
Response.End();
}
else
{
// ...
}
}
The code that you show seems to do the actual PDF download already. There is nothing you can do there to prevent the showing of a download button or link.
Instead you need to change the SQL query that provides data for gvupdationsummary, and add a column such as HasPDF there, like this:
SELECT /* your columns */ ,
CAST(CASE WHEN [data] IS NULL THEN 0 ELSE 1 END AS BIT) AS HasPDF
FROM ....
WHERE ....
Then in your grid rendering code you can use the boolean value of HasPDF to decide if the Download button should be shown.
Using this approach you don't needlessly transfer all PDF binary data from your database to your application, every time the grid is being rendered.
You can use SQLDataReader's IsDBNull method to see whether the column contains non-existent or missing values.
ind idx = dr.GetOrdinal("data");
if (!dr.IsDBNull(idx))
{
// set download link on to response.
}
else
{
}

How to fix this error ''reader' is a 'variable' but is used like a 'method''

I am using a C# class.Everythink working fine but i am facing this error, so please help to fix this error.
public void Filldropdownlist(DropDownList ddl, string DisplayVal, string Qstr)
{
try
{
CreateConn();
SqlCommand cmd = new SqlCommand(Qstr, constr);
SqlDataReader reader = cmd.ExecuteReader();
ddl.Items.Clear();
ddl.Items.Add(new ListItem(DisplayVal, "none"));
while (reader.Read())
{
ddl.Items.Add(new ListItem(reader(0).ToString(), reader(1).ToString()));
ddl.DataTextField = reader(0).ToString();
ddl.DataValueField = reader(1).ToString();
}
}
catch (Exception ex)
{
}
finally
{
CloseConn();
}
}
problem coming in inside the while loop.
Indexing in C# is done with the [] operator, not with the () operator as in, for example Visual Basic.
In essence
reader(0)
means "call the method reader with and argument 0" and
reader[0]
means give me value with the index 0 within the variable reader.
Aside from that, the DataTextField and the DataValueField are used only if you are data-binding the drop down, not if you are manually inserting the items, so those two lines can be omitted.
They are also incorect, because they need to be set to the name of the fields, not to their values
Change like this:
while (reader.Read())
{
ddl.Items.Add(new ListItem(reader[0].ToString(), reader(1).ToString()));
ddl.DataTextField = reader[0].ToString();
ddl.DataValueField = reader[1].ToString();
}
use [] instead of ()

C# Sql Data not saving

I have a few tables in a c# application I'm currently working on and for 4/5 of the tables everything saves perfectly fine no issues. For the 5th table everything seems good until I reload the program again (without modifying the code or working with a seperate install so that the data doesn't go away) The 4/5 tables are fine but the 5th doesn't have any records in it after it has been restarted (but it did the last time it was running). Below is some code excerpts. I have tried a few different solutions online including creating a string to run the sql commands on the database manually and creating the row directly as opposed to the below implementation which uses a generic data row.
//From main window
private void newInvoice_Click(object sender, EventArgs e)
{
PosDatabaseDataSet.InvoicesRow newInvoice = posDatabaseDataSet1.Invoices.NewInvoicesRow();
Invoices iForm = new Invoices(newInvoice, posDatabaseDataSet1, true);
}
//Invoices Table save [Works] (from Invoices.cs)
private void saveInvoice_Click(object sender, EventArgs e)
{
iRecord.Date = Convert.ToDateTime(this.dateField.Text);
iRecord.InvoiceNo = Convert.ToInt32(this.invoiceNumField.Text);
iRecord.Subtotal = (float) Convert.ToDouble(this.subtotalField.Text);
iRecord.Tax1 = (float)Convert.ToDouble(this.hstField.Text);
iRecord.Total = (float)Convert.ToDouble(this.totalField.Text);
iRecord.BillTo = this.billToField.Text;
invoicesBindingSource.EndEdit();
if (newRecord)
{
dSet.Invoices.Rows.Add(iRecord);
invoicesTableAdapter.Adapter.Update(dSet.Invoices);
}
else
{
string connString = Properties.Settings.Default.PosDatabaseConnectionString;
string queryString = "UPDATE dbo.Invoices set ";
queryString += "Date='" + iRecord.Date+"'";
queryString += ", Subtotal=" + iRecord.Subtotal;
queryString += ", Tax1=" + iRecord.Tax1.ToString("N2");
queryString += ", Total=" + iRecord.Total;
queryString += " WHERE InvoiceNo=" + iRecord.InvoiceNo;
using (SqlConnection dbConn = new SqlConnection(connString))
{
SqlCommand command = new SqlCommand(queryString, dbConn);
dbConn.Open();
SqlDataReader r = command.ExecuteReader();
dbConn.Close();
}
}
dSet.Invoices.AcceptChanges();
}
//Invoice Items save [works until restart] (also from Invoices.cs)
private void addLine_Click(object sender, EventArgs e)
{
DataRow iRow = dSet.Tables["InvoiceItems"].NewRow();
iRow["Cost"] = (float)Convert.ToDouble(this.costField.Text);
iRow["Description"] = this.descriptionField.Text;
iRow["InvoiceNo"] = Convert.ToInt32(this.invoiceNumField.Text);
iRow["JobId"] = Convert.ToInt32(this.jobIdField.Text);
iRow["Qty"] = Convert.ToInt32(this.quantityField.Text);
iRow["SalesPerson"] = Convert.ToInt32(this.salesPersonField.Text);
iRow["SKU"] = Convert.ToInt32(this.skuField.Text);
dSet.Tables["InvoiceItems"].Rows.Add(iRow);
invoiceItemsTableAdapter.Adapter.Update(dSet,"InvoiceItems");
PosDatabaseDataSet.InvoiceItemsDataTable dTable = (PosDatabaseDataSet.InvoiceItemsDataTable)dSet.InvoiceItems.Copy();
DataRow[] d = dTable.Select("InvoiceNo=" + invNo.ToString());
invoiceItemsView.DataSource = d;
}
Thanks in advance for any insight.
UPDATE: October 17, 2011. I am still unable to get this working is there any more ideas out there?
you must execute your Sql Command in order to persis the changes you made.
using (SqlConnection dbConn = new SqlConnection(connString))
{
dbConn.Open();
SqlCommand command = new SqlCommand(queryString, dbConn);
command.ExecuteNonQuery();
dbConn.Close();
}
The ExecuteReader method is intended (as the name says) to read the data from a SQL table. You need to use a different method as you can see above.
We need some more info first, you haven't shown the case where your code fails.
Common mistakes on this kind of code is calling DataSet.AcceptChanges() before actually committing the changes to the database.
Second is a conflict between databound data through the binding source vs edits to the dataset directly.
Lets see the appropriate code and we can try and help.
Set a breakpoint after teh call to invoiceItemsTableAdapter and check the InvoiceItems table for the row you have added. Release the breakpoint and then close your app. Check the database again. I would say that another table may be forcibly overwriting the invoice item table.

UPDATE Query : Incorrect Syntax (Edited)

I have a button which saves the contents edited in datagridview in my UI design. Here is the code for that Button_Save:
public void btnUpdate_Click(object sender, EventArgs e)
{
foreach (DataGridViewRow row in dataGridView1.Rows)
{
System.Data.SqlClient.SqlConnection sqlConnection1 =
new System.Data.SqlClient.SqlConnection("server=Test; Integrated Security=true; Database=Test;");
System.Data.SqlClient.SqlCommand cmd = new System.Data.SqlClient.SqlCommand();
var sql = new StringBuilder();
sql.AppendLine("UPDATE dbo.JobStatus");
sql.AppendLine("Set ShipTrackingNumber = #ShipTrackingNumber");
sql.AppendLine(", ShipMethodTransmitted = #ShipMethodTransmitted");
sql.AppendLine(", DateShipTransmitProcessed = #DateShipTransmitProcessed");
sql.AppendLine(", ShipmentProcessedBy = #ShipmentProcessedBy");
sql.AppendLine(", Critical = #Critical");
sql.AppendLine(", ShipTransmitStatus = #ShipTransmitStatus");
sql.AppendLine("Where jobtableId = #jobTableId");
cmd.Connection = sqlConnection1;
cmd.CommandText = sql.ToString();
cmd.Parameters.AddWithValue("#TrackingNumber", row.Cells[7].FormattedValue);
cmd.Parameters.AddWithValue("#ShipMethodTransmitted", row.Cells[8].FormattedValue);
cmd.Parameters.AddWithValue("#DateShipTransmitProcessed", row.Cells[9].FormattedValue);
cmd.Parameters.AddWithValue("#ShipmentProcessedBy", row.Cells[10].FormattedValue);
cmd.Parameters.AddWithValue("#Critical", row.Cells[11].FormattedValue);
cmd.Parameters.AddWithValue("#ShipTransmitStatus", row.Cells[13].FormattedValue);
cmd.Parameters.AddWithValue("#jobTableId", row.Cells[5].FormattedValue);
sqlConnection1.Open();
cmd.ExecuteNonQuery();
sqlConnection1.Close();
What I am getting error is that: "Must declare the scalar variable "#ShipTrackingNumber".
I dont want to put ShipTrackingNumber from the code. Instead I want to fetch it from the UI.
What I am doing wrong here?
Well, there's no entry in cmd.Parameters for "#ShipTrackingNumber". What do you mean by "fetch it from the UI"? You could just write a line to add an entry for this parameter:
cmd.Parameters.AddWithValue("#ShipTrackingNumber", GetShipTrackingNumberFromUI());
And then implement GetShipTrackingNumberFromUI() to get the value you want.
It looks like this line is supposed to be something along these lines, but you need to change "#TrackingNumber" to "#ShipTrackingNumber":
cmd.Parameters.AddWithValue("#TrackingNumber", row.Cells[7].FormattedValue);
To answer your direct question, add the parameter with its value taken from the UI. Let's say it's a checkbox named CheckBox1:
cmd.Parameters.AddWithValue("#ShipTrackingNumber", CheckBox1.Checked);
You need to replace this line:
cmd.Parameters.AddWithValue("#TrackingNumber", row.Cells[7].FormattedValue);
with this line:
cmd.Parameters.AddWithValue("#ShipTrackingNumber", row.Cells[7].FormattedValue);

How do you access data that has been inserted using a ADO.NET transaction?

I'm trying to get the data that has been successfully input into the database via ADO.NET transaction.
Once you've called trans.Commit() there doesn't seem to be a way of getting back the data that has been committed since all identity columns that were created during the transaction are 'virtual' since it is an offline dataset until commit
Many thanks
[EDIT]
Ahh, the problem is, I can't do a reselect as I don't have anything unique to select on other than the identity of the data inserted as part of the transaction.
I can't get the last entered item as this is a multiuser system
Code Sample from a book, not the code in question, but good enough to illustrate what I need:
using System.Data;
using System.Data.SqlClient;
namespace DataAdapterTransaction
{
class Program
{
private static string sqlConnectString = "Data Source=(local);" +
"Integrated security=SSPI;Initial Catalog=AdoDotNet35Cookbook;";
private static string sqlSelect = "SELECT * FROM DataAdapterTransaction";
static void Main(string[] args)
{
object[,] o1 = {{ "1", "field 1.1", "field 2.1" },
{ "2", "field 1.2", "field 2.2" }};
InsertRecords(o1);
object[,] o2 = {{ "3", "field 1.3", "field 2.3" },
{ null, "field 1.4", "field 2.4" }};
InsertRecords(o2);
// Retrieve and output the contents of the table
SqlDataAdapter daRead = new SqlDataAdapter(sqlSelect, sqlConnectString);
DataTable dtRead = new DataTable( );
daRead.Fill(dtRead);
Console.WriteLine("---TABLE DataAdapterTransaction---");
foreach (DataRow row in dtRead.Rows)
Console.WriteLine("Id = {0}\tField1 = {1}\tField2 = {2}",
row["Id"], row["Field1"], row["Field2"]);
Console.WriteLine("\nPress any key to continue.");
Console.ReadKey( );
}
static void InsertRecords(object[,] o)
{
DataTable dt = new DataTable( );
SqlTransaction tran;
SqlConnection connection = new SqlConnection(sqlConnectString);
// Create a DataAdapter
SqlDataAdapter da = new SqlDataAdapter(sqlSelect, connection);
// Stop updating when an error is encountered for roll back.
da.ContinueUpdateOnError = false;
// Create CommandBuilder and generate updating logic.
SqlCommandBuilder cb = new SqlCommandBuilder(da);
// Create and fill a DataTable with schema and data
da.Fill(dt);
// Open the connection
connection.Open( );
// Begin a new transaction and assign it to the DataAdapter
tran = connection.BeginTransaction( );
da.SelectCommand.Transaction = tran;
// Add two rows that will succeed update
for (int i = 0; i <= o.GetUpperBound(0); i++)
{
dt.Rows.Add(new object[] { o[i, 0], o[i, 1], o[i, 2] });
Console.WriteLine(
"=> Row with [Id = {0}] added to DataTable.", o[i, 0]);
}
Console.WriteLine("=> Updating data source using DataAdapter.");
try
{
da.Update(dt);
tran.Commit( );
Console.WriteLine("\nTRANSACTION COMMIT.\n");
}
catch (Exception ex)
{
tran.Rollback( );
Console.WriteLine("\nTRANSACTION ROLLBACK.\n{0}\n", ex.Message);
}
finally
{
connection.Close( );
}
}
}
}
Okay, so what i'm after is just after the transaction commit, I want to get the (scope) identity of the the last inserted row.
My application is successful in updating three dataadapters as part of the transaction, however I am having dificulty looking at the final committed data. I can do a select of the table and see it in there, but that really isn't good enough for production code.
SC
You may just need to reselect the data.
The Books Online says that you should call a Fill again to bring the update your Dataset:
http://msdn.microsoft.com/en-us/library/33y2221y(VS.71).aspx
I generally set my Insert and Update commands so that they they return back a valid DataRow for my DataTable and control the update of the rows in the application that way.
Right so I should do:
// update datatable
da.Update(dt);
// commit updates
tran.Commit( );
// get the updated datatable
da.Fill(dt);
I assume all the identity colums will be updated.
I'll give it a go
SC
I understand you're using identity columns, but is there any natural key in the data you can use to reselect?
(that then raises the question of 'why use identities' but that's a whole other subject...)
Unfortunately no, I cannot reselect using a natural key... I'm stuck with identities... after 8 hours of head banging I contemplated adding a guid field so I could get it to work, but decided that it is against my principles to give up!
SC
This MSDN article describes how to get back identity values when calling the Update method of a DataAdapter.