Why isn't my Merge working? - c#

I have what I am sure is a typical situation.
I have a DB and I have an XML document of data. I'd like to combine the 2 and update the db.
I have 'fill'ed a DataSet and/or DataTable with the DB data, and if I modify the data in that structure i can call Update and all is well.
Here is what I have.
con.Open();
adapter.Fill(ds2, "BASIC");
ds.ReadXmlSchema(#"C:\asis.xsd");
ds.ReadXml("c:\\asis.xml");
// This is the XML data
DataTable loadeddt = ds.Tables["BASIC"];
// This is from the DB
DataTable dbdt = ds2.Tables["BASIC"];
// I want to put the data from xml into the dataset from the DB
dbdt.Merge(loadeddt);
// I want to them put those changes in the db
adapter.Fill(dbdt);
Here is what happens, before I loaded the XSD I got an exception saying that types didn't match.
Now I get nothing, no exception no changes. neither of the DataTable show changes and neither does the DB.
Can anyone offer any suggestions?
If I change the last line to Update I get the following:
Violation of PRIMARY KEY constraint 'PK_BASIC'. Cannot insert duplicate key in object 'dbo.BASIC'.
I have noticed that if you do a .Rows.Count pre/post the merge the record count goes from 10 to 20 so it is combining them... not merging them. argh!
FUTHER MORE if I call dbdt.GetChanges(); it returns the whole lot. if i accept changes and update it still does nothing.

You should call Update instead of Fill for this line:
// I want to them put those changes in the db
adapter.Fill(dbdt);
After question update:
You're inserting a key that already exists. Either the merge is telling the adapter that it should insert when it should update or the DB fill isn't returning all rows. Hard to tell with what's given.
This seems like somewhat of a hack but if you know what rows should be considered updates, you can call SetModified on those rows.

Right guys,
I found this article:
http://www.dotnetmonster.com/Uwe/Forum.aspx/dotnet-ado-net/14201/Merge-function-in-DataSet
Basically the XSD needs to completely describe the primary key for the merge to work.
Essentially I needed to add:
<xs:key name="ROOTKey1" msdata:PrimaryKey="true">
<xs:selector xpath=".//BASIC" />
<xs:field xpath="MEMBNO" />
</xs:key>

Related

DataGridView: cannot add row or insert to table

I have a DataGridView. It uses a BindingSource, a DataTable in a DataSet, and a TableAdapter to add/change/delete data in a table. It worked OK, but stopped working when I added a field/column, and I can't figure out what I did or how fix it.
The user can add a new row at the bottom of the DataGridView, but when he goes to save, the row disappears and is not saved. In addition, if he tries to type a second new row, the first new row disappears.
Existing Rows can be changed and saved back to the database successfully.
I've been asked for code. OK, here is code. (I've eliminated some error checking done by scanning dtDep) The point that after the third line is executed, there are no rows in dtDep even though a new row had been entered into the DataGridView. If a row had been retrieved, it would be in dtDep and the database table updated by the last statement.
this.Validate();
bsBelkDep.EndEdit();
DataTable dtDep = dsBelk.Tables["belk_elig_dep"];
int n = belk_elig_depTableAdapter.Update(this.dsBelk.belk_elig_dep);
It was a problem with the DataGridView, but I don't know what. I started deleting and re-creating the various object, and after the I recreated the DataGridView, it worked OK. Which was a pain because I have to do significant reformatting, but at least it works.
This is a very old question and I have no way of knowing if it was the OP's original problem, but I had the exact same scenario and this is how I resolved it.
For background: I have a WinForms application built using datasets and an Access database. I migrated that to use Sqlite and anything but datasets. To avoid destroying the application completely, first I copied the strongly typed data tables out, tweaked them to account for changes in the schema and then used PetaPoco to perform the data operations. That worked fine for a single test conversion.
The trouble arose when I wanted to move on and convert all data tables - I wasn't happy manually writing the logic for converting to and from typed data rows and POCOs, so I fell back to writing old school T4 templates to generate typed DataTable, DataRow classes and the necessary remapping code.
Worked a treat - for editing or removing data. But new rows disappeared on "creation", the binding navigator count didn't increment, and of course, when saving, I didn't detect any rows with the RowState of DataRowState.Added. The grid at start up was subtly different - a blank value in all columns instead of a negative number in the ID column. In hindsight, that should have been a big clue.
On reverting the behaviour back to the manually extracted typed class the grid started working again so it was clearly an error in the new code.
End of background; tldr;
The cause of the issue, in my case, was that the my Id column didn't have the AutoIncrement property set. As soon as I configured that to be true (along with setting AutoIncrementSeed and AutoIncrementStep to -1, although neither are required) new rows started being correctly added to the table.

Database not updating when using DataSet

I am doing a small project to learn how to use DataSet but i have a small problem. Consider following code:
foreach (DatabaseDataSet.ApplicationRow rowApplication in database.Application)
{
if (rowApplication.AID.ToString() == lblIDApplication.Text)
{
rowApplication.Date= tbApplicationDatum.Text;
rowApplication.Status = tbApplicationStatus.Text;
applicationAdapter.Update(rowApplication);
break;
}
}
I don't know why but the database doesn't get updated. The DataRow is being updated as when I call the data again I see the new value. But when I re-run my application it's back to it's old value again. Any help?
EDIT: I'm working with strongly typed DataSet
You need to call the Update method of your adapter to propogate the changes
AcceptChanges only updates the changes in memory for the row and does not migrate those to the database
MSDN
AcceptChanges and RejectChanges only apply to DataRow related changes
(that is, Add, Remove, Delete, and Modify). They are not applicable to
schema or structural changes.
Calling AcceptChanges will not replicate these changes back to the
data source if the DataSet was filled using a DataAdapter. In that
situation, call Update instead
See Updating Data Sources with DataAdapters for more information
Its important to remember that the DataSet is a 'local copy' of the data not a 'live link' to the DB. If your DataSet is populated by a IDataAdaptor (say a TableAdaptor) for example you need to call the DataAdaptors Update method passing in the Updated dataset to sync the results back to the underlying DB.
Also I would suspect you DONT want to be doing 'new ApplicationTableAdapter()' because typically you would want to update with the TableAdaptor you populated with, at the least you would need to ensure you had the correct connection, query etc set up.
SOLUTION: It happens that nothing was wrong with the code. I had two ConnectionString defined in App.config. I forgot to remove the first one after I removed a previous database that had errors in it. Upon removing the first ConnectionString, everything worked.

LumenWorks Csv Reader - How do I detect columns that are present in the data rows but not in the columns?

I'm using the LumenWorks CsvReader to parse a file with the following structure.
heading1,heading2,heading3
data1,data2,data3,data4,data5
The code detects that I've got three fields per row because I've got three headings. It happily allows me to parse the first row and retrieve data1, data2, and data3, but i can't access data4 or data5. At the very least, I'd like to be able to detect additional fields in the data rows. Does anyone know if this is possible?
Thanks!
It does this because it uses the first row to know how many columns your file has. If you change the first row to "heading1,heading2,heading3,," it will work as expected.
I expect that you won't be able to read the data in those fields. Rather, I expect that an error is being raised and you're not seeing it. This would at least allow you to detect that those other fields exist in the data.
Try setting the DefaultParseErrorAction enum property so that you ensure you're seeing any errors being raised. I would have expected the scenario you describe to trigger a MalformedCsvException (if you have set the DefaultParseErrorAction = ParseErrorAction.ThrowException). You could also set DefaultParseErrorAction = ParseErrorAction.RaiseEvent and then attach an event handler to the ParseError event. Finally, you should be able to just check if the ParseErrorFlag is true after each record.
HTH

Linq to SQL, Update a lot of Data before One Insert

Before insert new value to table, I need change one field in all rows of that table.
What the best way to do this? in c# code, ore use trigger? if C# can you show me the code?
UPD
*NEW VERSION of Question*
Hello. Before insert new value to table, I need change one field in all rows of that table with specific ID( It is FK to another table).
What the best way to do this? in c# code, ore use trigger? if C# can you show me the code?
You should probably consider changing your design this doesn't sound like it will scale well, i would probably do it with a trigger if it is always required, but if not, id use ExecuteCommand.
var ctx = new MyDataContext();
ctx.ExecuteCommand("UPDATE myTable SET foo = 'bar'");
Looking at your comment on Paul's answer, I feel like I should chime in here. We have a few tables where we need to keep a history of each entry in that table. We implement this by creating a separate table for each. For example, we may have a Comment table, and then a CommentArchive table with a foreign key reference to the CommentId in the Comment table.
A trigger on the Comment table ensures that each time certain fields in the Comment table are updated, the "old" version (which is accessible via the deleted table in the trigger) gets pushed to the CommentArchive table. Obviously, this means several CommentArchive entries may exist for each Comment, but if you're only looking for the "active" comments, you just look in the Comment table. And if you need information about the history of a comment, you can easily use LINQ to SQL to jump from the Comment you're interested in to the CommentArchives that reference it.
Because the triggers we use in the above example only insert a single value into the Archive table for each update, they run very quickly and we get good performance. We had issues recently where I tried making the triggers more complex and we started getting dead-locks with as few as 15 concurrent transactions. So the lesson is that you should make these triggers simple, and make them touch as few rows in as few tables as possible.

c# DataSet with 2 tables, how to delete a row from one it will delete a row from the other?

I use Visual Studio 2010
I have a DataSet with 2 tables
one (MainList) has type, name, path, parameter
the other (UpadteList) has path, hash, date
I added files to this list and it work with out problem, now I have the following
when I add file type "update"
it will be "Update","My Program", "PATH-TO-/my.setup.exe","/minimized"
if it was type "Update"
the following data goes to (UpdateList)
"PATH-TO-/my.setup.exe","asdfwefwfgg3r34t34t34t","2010-09-01"
I want when a row in the (MainList) deleted and a row with the same path in (UpdateList) exsist it will deleted too
should I use loop or (I saw) in dataSet properties use Relations
what is the best approach ?
with loops I got into some ugly bugs that delete everything in the Mainlist!
note: I use XML to store data (the data is not big)
IMO, you have two choices
Use DataTable constraints such as ForeignKeyConstraint with DeleteRule=Cascade settings.
Use RowDeleted/RowDeleting event on MainList data-table to look up and delete the corresponding row in other table.
I think that code is arguably the wrong place to deal with data consistency. I'd do it in the database, either in a stored procedure or, if you're using SQL Server, possibly with cascading deletes.

Categories