Getting inserted record from DataSet TableAdapter.Insert - c#

I'm using a DataSet with the DataSet designer on xsd file (System.Data v 4 in VS 2015). I've been searching for how to get the ID for a newly created record. I see on the designer advanced options there is an option for reading back the record for insert and updates. I also see the SELECT included in the INSERT INTO statement. However the designer generated code runs ExecuteNonQuery and returns the number of records affected. How do we get access to that record that was read back in?
Most solutions I've read involve creating your own query or sp that is set to ExecuteScalar and selects the ##ROWIDENTITY. Either that or timestamp the new record and get it back that way. But if the read-back is already being done then I should be able to get to it, right? What' the trick? What happens to that data that's been read back in?
TIA,
Mike

Related

What's causing a Concurrency Violation when using a MySQL linked Dataset via TableAdapters?

The more I read on this, the more confused I get, so hope someone can help. I have a complex database setup, which sometimes produces the error on update:
"Concurrency violation: the UpdateCommand affected 0 of the expected 1 records"
I say sometimes, because I cannot recreate conditions to trigger it consistently. I have a remote mySQL database connected to my app through the DataSource Wizard, which produces the dataset, tables and linked DataTableAdapters.
My reading suggests that this error is meant to occur when there is more than one open connection to the database trying to update the same record? This shouldn't happen in my instance, as the only updates are sequential from my app.
I am wondering whether it has something to do with running the update from a background worker? I have my table updates in one, for example, thusly:
Gi_gamethemeTableAdapter.Update(dbDS.gi_gametheme)
Gi_gameplaystyleTableAdapter.Update(dbDS.gi_gameplaystyle)
Gi_gameTableAdapter.Update(dbDS.gi_game)
These run serially in the backgroundworker, however, so unsure about this. The main thread also waits for it to finish, and there are no other db operations going on before or after this is started.
I did read about going into the dataset designer view, choosing "configure" in the datatableadapter > advanced options and setting "Use optimistic concurrency" to false. This might have worked (hard to say because of the seemingly random nature of the error), however, there are drawbacks to this that I want to avoid:
I have around 60 tables. I don't want to do this for each one.
I sometimes have to re-import the mysql schema into the dataset designer, or delete a table and re-add it. This would obviously lose this setting and I would have to remember to do it on all of them again, potentially. I also can't find a way to do this automatically in code.
I'm afraid I'm not at code level in terms of the database updates etc, relying on the Visual Studio wizards. It's a bit late to change the stack as well (e.g. can't change to Entity Framework etc).
SO my question is:
what is/how can I find what's causing the error?
What can I do about it?
thanks
When you have tableadapters that download data into datatables, they can be configured for optimistic concurrency
This means that for a table like:
Person
ID Name
1 John
They might generate an UPDATE query like:
UPDATE Person SET Name = #newName WHERE ID = #oldID AND Name = #oldName
(In reality they are more complex than this but this will suffice)
Datatables track original values and current values; you download 1/"John", and then change the name to "Jane", you(or the tableadapter) can ask the DT what the original value was and it will say "John"
The datatable can also feed this value into the UPDATE query and that's how we detect "if something else changed the row in the time we had it" i.e. a concurrency violation
Row was "John" when we downloaded it, we edited to "Jane", and went to save.. But someone else had been in and changed it to "Joe". Our update will fail because Name is no longer "John" that it was (and we still think it is) when we downloaded it. By dint of the tableadapter having an update query that said AND Name = #oldName, and setting #oldName parameter to the original value somedatarow["Name", DataRowVersion.Original].Value (i.e. "John") we cause the update to fail. This is a useful thing; mostly they will succeed so we can opportunistically hope our users can update our db without needing to get into locking rows while they have them open in some UI
Resolving the cases where it doesn't work is usually a case of coding up some strategy:
My changes win - don't use an optimistic query that features old values, just UPDATE and erase their changes
Their changes win - cancel your attempts
Re-download the latest DB state and choose what to do - auto merge it somehow (maybe the other person changed fields you didn't), or show the user so they can pick and choose what to keep etc (if both people edited the same fields)
Now you're probably sat there saying "but noone else changes my DB" - we can still get this though, if the database has changed some values upon one save and you don't have the latest ones in your dataset..
There's another option in the tableadapter wizardd - "refresh the dataset" - it's supposed to run a select after a modification to import any latest database calculated values (like auto inc primary keys or triggers/defaults/etc). Some query like INSERT INTO Person(Name) VALUES(#name) is supposed to silently have a SELECT * FROM PERSON WHERE ID = last_inserted_id() tagged on the end of it to retrieve the latest values
Except "refresh the dataset" doesn't work :/
So, while I can't tell you exactly why youre getting your CV exception, I hope that explaining why they occur and pointing out that there are sometimes bugs that cause them (insert new record, calculated ID is not retreieved, edit this recent record, update fails because data wasn't fresh) will hopefully arm you with what you need to find the problem: when you get one, keep the app stopped on the breakpoint and inspect the datarow: take a look at the query being run and what original/current values are being put as parameters - inspect the original and current values held by the row using the overload of the Item indexer that allows you to state the version you want and look in the DB
Somewhere in all of that there will be the mismatch that explains why 0 records were updated - the db has "Joe" as the name or 174354325 as the ID, your datarow has "John" as the original name or -1 as the ID (it never refreshed), and the WHERE clause is finding 0 records as a result
Some of your tables will contain a field that is marked as [ConcurrencyCheck] or [TimeStamp] concurrency token.
When you update a record, the SQL generated will include a WHERE [ConcurrencyField]='Whatever the value was when the record was retrieved'.
If that record was updated by another thread or process or something other than the current thread, then your UPDATE will return 0 records updated, rather than the 1 (or more) that was expected.
What can you do about it? Firstly, put a try/catch(DbConcurrencyException) around your code. Then you can re-read the offending record and try and update it again.

Huge oracle insert statement gets stuck

I'm trying to add data from multiple XML files into my Oracle database. I'm receiving the data in my .NET C# application and I'm using Dapper as ORM.
Currently there are 13 XML files which need to be added into the database. I deserialized all of them and turned them into an INSERT query to add to my database.
Everything seems to be working fine, except after 31 minutes of trying to insert the data in the database, I noticed the following error:
ORA-00054: resource busy and acquire with NOWAIT specified or timeout
expired
After some searching I found this solution: https://stackoverflow.com/a/11895078/2664414 but this seems way to hacky for something this "simple".
As for the details of the INSERT statement, I'm adding 3271 rows for the second INSERT. Here is a short snippet:
INSERT ALL
INTO S1589_XML_LineSection (ID, VALID_FROM_DATE, VALID_TO_DATE, LINE_ID, CHANNEL_NO, TENSION, NATURE, P70, C70, P400, C400, OPERATIONAL_IMPORTANCE, TECHNICAL_EQUIPMENT, OPERATIONALISATION, STANDARD_SPEED_DIR_1, STANDARD_SPEED_DIR_2, LAST_UPDATE_DATE) VALUES ('1','1996-06-02','2005-12-10','404','0','1','1','0','0','330','330','9','9','1','0','0','2010-06-04T04:54:51')
INTO S1589_XML_LineSection (ID, VALID_FROM_DATE, VALID_TO_DATE, LINE_ID, CHANNEL_NO, TENSION, NATURE, P70, C70, P400, C400, OPERATIONAL_IMPORTANCE, TECHNICAL_EQUIPMENT, OPERATIONALISATION, STANDARD_SPEED_DIR_1, STANDARD_SPEED_DIR_2, LAST_UPDATE_DATE) VALUES ('1','2005-12-11','2007-12-08','404','0','1','1','0','0','330','330','9','9','1','60','60','2010-06-04T04:54:51')
SELECT 1 FROM dual
I can perfectly add these lines individually, but when I try to add them all at once, it takes way too long.
So, tips on either improving the query, or making sure I don't get the error (ORA-00054)?

Resizing column size of a table in DB and effecting with the dataTableAdapter on a Dataset.xsd

I'm asking about a problem with C# and Visual Studio 2012; I'm trying to resize a column of a table in my database, effect with the dataTableAdapter on a Dataset.xsd
I'm using DataTableAdapter from a stored procedure with a SELECT statement to populate a DataGridView, reports and many more.
I created the table long time ago, but now there is an a problem with it.
I had to increase the length of a column and I changed the appropriate column length of the DataTable also. But it didn't give me the solution. still whenever I Fill or Get data through that DataTableAdapter it response with the previous (original) size of the column.
But when I create a new DataTable and redirect my code to the new DataTableAdapter, it works.
Why is this happening ?
Because redirecting code to the new DataTableAdapter is little bit difficult because I don't know all the places it use in the entire solution.
And also if can please tell me how to add new column to the table and deal with the DataTableAdapter with it also.
Thanks and waiting for your reply.
after doing small research with my friends , i got an proper way to fix this error.
not even re-sizing, but also any other change with the database Table or storedprocedure you have to reconfigure the dataTableAdaptor, unless it just work as , when it was created.
it will continue with major errors or sometimes, it will function incorrectly, even you cant figure out there is an error.
so whenever you do any change with the database Table or storedprocedure go to the dataSet.xsd , where the dataTable locate and right on the dataTable , then configure it again.
this saved me and worked.

TableAdapter Insert not persisting data

I created a service-based local db via Visual Studio 2013 Express edition.. The connection string, dataset and TableAdapter were added automatically.
On click of a button, I am trying to insert some data by calling TableAdapter.Insert
As it is I already have a dataGridView's datasource bound to the dataset, So I immediately see that the data was inserted in table properly at run time, But when I close the application, The actual DB dosn't contain the data. Therefore, The data isn't actually inserted in DB.
According to http://msdn.microsoft.com/en-us/library/ms233812%28v=vs.110%29.aspx
With insert, you have to only call insert, yet I am calling Update and AcceptChanges on table, for safety, well I tried the first way shown in link (i.e. creating a row and adding it to dataset then calling update) as well, but it seems the data isn't being inserted in DB at all.
Finally, the insert code, rds is DataSet and ta is TableAdapter
private void AddBtn_Click(object sender, EventArgs e)
{
ta.Insert("foo", "bar", 2, "zing", "tada");
ta.Fill(rds.reminders);
rds.reminders.AcceptChanges();
ta.Update(rds.reminders);
}
It turned out that, as I was using the VS compiled application each time the mdf database was being overwritten, hence the changes I made were completely erased,
The possible solution could be one of following
1)Change the connectionstring to point to database that is in Debug folder, which wont be overwritten each time you compile and run the application
2)You could simply let the connectionstring be as it is and just test it through detached compiler mode.
I was able to figure this out due to the following stackoverflow link I suddenly sumbled upon after 2 days.
Database changes do not persist after ObjectContext.SaveChanges() is called
ClearBeforeFill Property
http://msdn.microsoft.com/en-us/library/bz9tthwx.aspx
"By default, every time you execute a query to fill a TableAdapter's
data table, the data is cleared and only the results of the query are
loaded into the table."

Crystal Report multi table failure

I'm still new to C# and reports, and in order to take baby steps, I started with a Crystal Report using one table.
Eventually I figured it out and it worked brilliantly.
Then I added another table to the report. I haven't changed anything in my code. Adding a field from the second table to the report, results in a blank report.
Removing that field again (so no columns form the second table is on the report), the report produces data again.
So I get the impression that the problem is on the report side. But I have included the code anyway:
private void Load_Ord_Rep()
{
using (MySqlConnection conn = new MySqlConnection(OTW.Properties.Settings.Default.wcdbConnectionString))
{
conn.Open();
String sql = "SELECT * FROM wcdb.order_table, wcdb.mat_table WHERE order_no = '13661' and order_table.mat_code = mat_table.mat_code";
using (MySqlCommand cmdSel = new MySqlCommand(sql, conn))
{
DataSet ds = new DataSet();
MySqlDataAdapter da = new MySqlDataAdapter(cmdSel);
da.Fill(ds);
ReportDocument rpt = new ReportDocument();
rpt.Load("C:\\Visual Studio 2008\\Projects\\OTW\\OTW\\CrystalReport3.rpt");
dataView1.Table = ds.Tables[0];
rpt.SetDataSource(dataView1);
crystalReportViewer1.ReportSource = rpt;
crystalReportViewer1.Refresh();
}
conn.Close();
}
}
With further investigation I have come to the conclusion the problem is not the code or the link, but rather the loading of the second table. I did a outer join with the values being equal or greater. Only the first table's results are displayed on the report. So because the second table's values are not read, no join can be established between the two tables and thus no data on the report. Now the question: why is the second table not being read by Crystal Report!?
UPDATE
I removed the second table from the main report and added a sub-report with the data. Same result as before. The sup report shows blank. Running the sup report on its own (as the main report), it populated correctly. I'm using MySQL, could it then maybe be a database issue?
UPDATE
I created a new app, this time connected the report to the database using ODBC (instead of ADO.NET). And it worked perrrfect. Now to figure out why ADO.Net is not working....as my entire program is based on it.
You don't need to do any of the code you are doing with the dataset/dataview. I recommend you allow the report to "pull" data (you are "pushing" data to the report now).
To pull data requires only the following:
ReportDocument rpt = new ReportDocument();
rpt.Load("C:\\Visual Studio 2008\\Projects\\OTW\\OTW\\CrystalReport3.rpt");
rpt.SetDataBaseLogon("userName", "password", "servername", "database");
crystalReportViewer1.ReportSource = rpt;
This reduces the risk that you're confusing the report up by passing in a dataview that it has no idea how to map to the tables you added while designing the report. (Which I'm 99.999% sure is happening now.)
All the code above lacks is parameters if you had any that needed to be set. It looks like you may be trying to "push" data because you wanted to filter on that order number or something? If that is the case, add a 'record selection formula' inside your report, base it's 'where' aspect of that formula on a Crystal Report parameter and add a rpt.SetParameter(arguments) line to the code I provided.
No this is not a licensing constraint, I'm certain of that.
Successful troubleshooting path:
1) Used the simple code to load the report:
* No errors, but no data in the report
2) Played with join options in the report:
* Also resulted in a blank report, even with only one table
* Concerned the second table is not reading data
3) Checked for record filtering by a 'record selection formula' which might limit/prevent rows from being returned
* In this case, wasn't applicable
4) Analyzed how joins were being done:
["It's probably how you are joining. For example: if you do a right outer join to a second table and it has no data, then even the first table's rows won't come back."]
A join was done on the primary id field (mat_code) in the 'orders' table to the same field (mat_code) in the second table, 'material'. This seemed fine.
Attempted a Left Outer join with the link type being ">=". The report printed the first table (orders) with data. But still none of the second tables' (material) data.
Made a new report, this time first adding the "second" table (material) and then the first (orders). This time with an outer join, and only the material table shows data. In other words, it only appears to pull data for the first, or primary table, then stops.
5) Attempted loading the second table's data by putting it into a subreport, and linking the subreport on the same 'mat_code' field:
(Helpful tutorial: http://vb.net-informations.com/crystal-report/vb.net_crystal_report_subreport.htm)
Sub-report also shows blank. Only the main report works. Whatever table exists in the subreport is not being populated.
Still sees no data using the simple suggested code, his original code still shows the first table's data
6) Check for a mismatch between the table's connection and definition, and the actual data structure/contents being submitted to, or loaded by, the report. A specific test was suggested, go to:
i) 'Set Database Location' (where you manage tables for the report)
ii) Look to see if an XML/DataSet was used versus OLEDB was done
iii) Change the database table location to the same tables, but with an OLEDB connection type (repeat for all tables)
When attempting above, when the 'Update' button was hit, the screen just flickered for a split second, but showed no message. After testing the report again, still no change in behavior. He was using ADO.NET to connect to the data.
7) Still highly suspicious of the data table definition and connection type. Suggested the following test:
i) Make a brand new 1 page application with only simple test code.
ii) Make a new report with only the 'orders' and 'materials' tables, using OLEDB from the beginning
iii) Add only the mat_code field from the main table to the report
iv) Add a subreport for 'materials' linked on mat_code
v) Show only mat_code on the subreport
vi) Run the app
If data shows, the problem is either:
Answer 1: A mismatch between the database definition (as was read when the report was FIRST made, and connected via ADO.NET to the tables) and the actual data table/column definitions being found when loading the report later (i.e. Someone edited the 'materials' table to change a column definition, or the number of fields, etc.)
Answer 2: Possible defect in the particular combination of Crystal Reports and Windows drivers required to push ADO.NET data to the report. Using the pull-data model over OLEDB may be working around something issues. Those issues may be addressed with the latest Crystal Reports and/or Windows drivers (i.e. hotfixes or Windows updates, driver packs, etc.)
The test worked fine. Even without making a subreport. The data pulled in just like it was supposed to.
Check the link between the two tables in crystal reports. Are they as what you expect ?
Check it by
Field Explorer> DataBaseFields > (RightClick) DatabaseExpert > (See Tab) Links

Categories

Resources