Wrong "Duplicate entry '284093' for key 'PRIMARY'" message - c#

Preamble: This question may be useful to people who get wrong error messages when using MySQL. Proof is given that the error message is wrong.
In a MySQL database (version 5.7.18), MyISAM table "sensorhistory" has a column "id" of type "int(11)" with Extra "auto_increment". Data are inserted from an application written in C#. The INSERT query does NOT write the id column directly, of course. That's what the "auto_increment" is for. The table contains further 30 fields of float and varchar types, resp., plus a DateTime(3). The parameterized query is long.
I receive following error message:
Duplicate entry '284093' for key 'PRIMARY'
at MySql.Data.MySqlClient.MySqlStream.ReadPacket()
at MySql.Data.MySqlClient.NativeDriver.GetResult(Int32& affectedRow, Int64& insertedId)
at MySql.Data.MySqlClient.Driver.NextResult(Int32 statementId, Boolean force)
at MySql.Data.MySqlClient.MySqlDataReader.NextResult()
at MySql.Data.MySqlClient.MySqlCommand.ExecuteReader(CommandBehavior behavior)
at MySql.Data.MySqlClient.MySqlCommand.ExecuteNonQuery()
at DataStorage.SensorHistoryDatastore.StoreSensorHistory(IReadOnlyList'1 _reports, Boolean _canRetry) in C:\Users\bernhard.hiller\SVN\Product-SW\trunk\C_DataStorage\PhysicalContainers\SensorHistoryDatastore.cs:line 84
Oddly, when I execute SELECT max(id) FROM sensorhistory in MySQL Workbench, I get a maximum value of 284092, i.e. 1 less than the "duplicate entry". That is proof that the error message is wrong.
I'd like to know how such an odd error can occur, and how to fix it.
Addendum:
An "Analyze table" in MySQL Workbench showed that the table is corrupt:
Found key at page 6585344 that points to record outside datafile
It could be repaired with a simple Repair table sensorhistory
I am still interested in how that corruption of the table can have occured.
By the way: a big THANK YOU to all those DOWNVOTERS who seem to be unable to read the text: this is not a f***ing stupid question about a "duplicate key", because I showed proof that the duplicate value does not exist at all!
Addendum 208-09-12:
The error re-occured after just 1 day, same table, same error message (just with a new value).

The Windows Eventlog showed more than 7 crashes between Sep 7 and Sep 11 (id 6008: "The previous system shutdown was unexpected"). The newest entry in the table sensorhistory was shortly before such crash in both cases.
The crashes ended on Sep 11 in the morning. I do not know the reason - other people are working on that test machine too. There were no more database issues then.
I conclude that a sudden Windows crash caused some inconsistency in the database, which then lead to that error message.

Related

How do I figure out the exact cause of error in EF update?

I have read the other threads on this, and none of them have answers that resolve my current scenario, nor are they similar. My scenario is reproducible on each run of my application, though I can't seem to produce a smaller piece of code that creates this error.
I'm getting the following error:
An exception has been raised that is likely due to a transient failure. If you are connecting to a SQL Azure database consider using SqlAzureExecutionStrategy.
The inner exception says:
A transport-level error has occurred when receiving results from the server. (provider: TCP Provider, error: 0 - The semaphore timeout period has expired.)
I am not connecting to a SQL Azure database. The connection is to a remote database through VPN, hosted on premises. To give some more context, I'm importing data from an external system, and every time it gets up to a specific record, it always fails when I try to update the entity after creating it. I've tried setting debug logging on in EF and copying the statement it generates into SSMS and running it with the same credentials with no errors. The only differentiating factor between this record and the previous records are the audit fields (time created/modified) and the name, which has changed from 1USD - Holding 99 to 1USD - Holding 100. I actually tested out changing the order which the records get imported, and it always fails at 100 when editing in EF after creation, so there's probably some other underlying issue at hand here. The field itself in the database is handling strings with a higher length than this, including this same process with no errors.
This obviously doesn't seem to actually be a transient failure, nor does it seem to be a connection issue, so how do I find the exact reason why this doesn't work?
Edit: Adding some code below. Also, I've noticed that if I change the name to 1USD - Holding 99 - Test 2, it works without any error despite the name being longer. Automatic ChangeDetection is not enabled for performance reasons.
security = new Security
{
Name = securityName,
IsActive = true,
CreatedAt = DateTime.Now,
CreatedBy = ADMIN_USER,
ModifiedAt = DateTime.Now,
ModifiedBy = ADMIN_USER
};
_repository.Save(security); //Ctx.Set<T>().Add(security); Ctx.SaveChanges();
//some attributes with a foreign key referencing this entity are saved, which is why we update audit fields below, but error occurs regardless if anything additional is saved
security.ModifiedBy = ADMIN_USER;
security.ModifiedAt = DateTime.Now;
_repository.Save(security); //Ctx.Set<T>().Attach(security); Ctx.Entry(security).State = EntityState.Modified; Ctx.SaveChanges();
Edit 2: It definitely seems to be something else other than a connection issue since it's happening for anything ending in a 3 character combination, such as A10, B10, or 10A. 1, 2, or 4 characters seem to be fine. Still have no idea what the actual issue is, however.

Devart ChangeConflictException but values still written to database

I have an intermittent Devart.Data.Linq.ChangeConflictException: Row not found or changed raising it's ugly head. The funny thing is, the change is still written to the database!
The stack trace says:
Devart.Data.Linq.ChangeConflictException: Row not found or changed.
at Devart.Data.Linq.Engine.b4.a(IObjectEntry[] A_0, ConflictMode A_1, a A_2)
at Devart.Data.Linq.Engine.b4.a(ConflictMode A_0)
at Devart.Data.Linq.DataContext.SubmitChanges(ConflictMode failureMode)
at Devart.Data.Linq.DataContext.SubmitChanges()
at Billing.Eway.EwayInternal.SuccessCustomerRenewal(String username, Bill bill, EwayTransaction transaction) in c:\Users\Ian\Source\Repos\billing-class-library\Billing\Billing\Eway\EwayInternal.cs:line 552
at Billing.Eway.Eway.BillAllUsers() in c:\Users\Ian\Source\Repos\billing-class-library\Billing\Billing\Eway\Eway.cs:line 138
And my code for Billing.Eway.EwayInternal.SuccessCustomerRenewal:
internal static void SuccessCustomerRenewal(string username, Bill bill, EwayTransaction transaction)
{
// Give them their points!
ApplyBillToCustomerAccount(username, bill, true);
BillingEmail.SendRenewalSuccessEmail(username, bill, transaction);
using (MsSqlDataClassesDataContext msSqlDb = new MsSqlDataClassesDataContext())
{
// TODO: Remove this logging
msSqlDb.Log = new StreamWriter(#"logs\db\" + Common.GetCurrentTimeStamp() + "-MsSQL.txt", true) { AutoFlush = true };
EwayCustomer ewayCustomer = msSqlDb.EwayCustomers.First(c => c.Username == username);
ewayCustomer.NextBillingDate = Common.GetPlanExpiry(bill.BillPlan);
using (MySqlDataContext mySqlDb = new MySqlDataContext())
{
// TODO: Remove this logging
mySqlDb.Log = new StreamWriter(#"logs\db\" + Common.GetCurrentTimeStamp() + "-MySQL.txt", true) { AutoFlush = true };
BillingMySqlContext.Customer grasCustomer = mySqlDb.Customers.First(c => c.Username == username);
// Extend their membership date out so that the plan doesn't expire because of a failed credit card charge.
grasCustomer.MembershipDate =
ewayCustomer.NextBillingDate.AddDays(1);
mySqlDb.SubmitChanges(); // <-- This is line 552
}
msSqlDb.SubmitChanges();
}
}
I know that the issue occurs on the mySqlDb.SubmitChanges() line, since that DB context is the one using Devart (Linq solution for MySQL databases): the other context uses pure MS Linq.
Not only is the change written to the MySql DB (inner using block), but it is also written to the MsSql DB (outer using block). But that's where the magical success ends.
If I could I would write a Minimal, Complete and Verifiable example, but strangely I'm unable to generate a Devart ChangeConflictException.
So, why does the change get saved to the database after a Devart.Data.Linq.ChangeConflictException? When I previously encountered System.Data.Linq.ChangeConflictException changes weren't saved.
Edit 1:
I've also now included the .PDB file and gotten line number confirmation of the exact source of the exception.
Edit 2:
I now understand why I can't generate a ChangeConflictException, so how is it happening here?
These are the attributes for MembershipDate:_
[Column(Name = #"Membership_Date", Storage = "_MembershipDate", CanBeNull = false, DbType = "DATETIME NOT NULL", UpdateCheck = UpdateCheck.Never)]
I know I can explicitly force my changes through to override any potential conflict, but that seems undesirable (I don't know what I would be overriding!). Similarly I could wrap the submit in a try block, and retry (re-reading each time) until success, but that seems clunky. How should I deal with this intermittent issue?
Edit 3:
It's not caused by multiple calls. This function is called in one place, by a single-instance app. It creates log entries every time it is run, and they are only getting created once. I have since moved the email call to the top of the method: the email only gets sent once, the exception occurs, and database changes are still made.
I believe it has something to do with the using blocks. Whilst stepping through the debugger on an unrelated issue, I entered the using block, but stopped execution before the SubmitChanges() call. And the changes were still written to the database. My understanding was that using blocks were to ensure resources were cleaned up (connections closed, etc), but it seems that the entire block is being executed. A new avenue to research...
But it still doesn't answer how a ChangeConflictException is even possible given Devart explicitly ignores them.
Edit 4:
So I wasn't going crazy, the database change did get submitted even after I ended execution in the middle of the using block, but it only works for websites.
Edit 5:
As per #Evk's suggestion I've included some DB logging (and updated the stacktrace and code snippet above). The incidence rate of this exception seems to have dropped, as it has only just happened since I implemented the logging. Here are the additional details:
Outer (MS SQL) logfile:
SELECT TOP (1) [t0].[id], [t0].[Username], [t0].[TokenId], [t0].[PlanId], [t0].[SignupDate], [t0].[NextBillingDate], [t0].[PaymentType], [t0].[RetryCount], [t0].[AccountStatus], [t0].[CancelDate]
FROM [dbo].[EwayCustomer] AS [t0]
WHERE [t0].[Username] = #p0
-- #p0: Input NVarChar (Size = 4000; Prec = 0; Scale = 0) [dyonis]
-- Context: SqlProvider(Sql2008) Model: AttributedMetaModel Build: 4.0.30319.18408a
(It just shows the SELECT call (.First()), none of the updates show).
Inner (MySQL) logfile:
SELECT t1.Customer_ID, t1.Username, t1.Account_Group, t1.Account_Password, t1.First_Name, t1.Last_Name, t1.Account_Type, t1.Points, t1.PromoPoints, t1.Phone, t1.Cell, t1.Email, t1.Address1, t1.Address2, t1.City, t1.State, t1.Country, t1.Postcode, t1.Membership_Group, t1.Suspend_On_Zero_Points, t1.Yahoo_ID, t1.MSN_ID, t1.Skype_ID, t1.Repurchase_Thresh, t1.Active, t1.Delete_Account, t1.Last_Activity, t1.Membership_Expires_After_x_Days, t1.Membership_Date, t1.auth_name, t1.created_by, t1.created_on, t1.AccountGroup_Points_Used, t1.AccountGroup_Points_Threashold, t1.LegacyPoints, t1.Can_Make_Reservation, t1.Gallery_Access, t1.Blog_Access, t1.Private_FTP, t1.Photometrica, t1.Promo_Code, t1.Promo_Expire_DTime, t1.Gift_FirstName, t1.Gift_LastName, t1.Gift_Email, t1.Gift_Phone, t1.Gift_Active, t1.NoMarketingEmail, t1.Can_Schedule, t1.Refered_By, t1.Q1_Hear_About_Us, t1.Q2_Exp_Level, t1.Q3_Intrests, t1.GIS_DTime_UTC, t1.Membership_Expire_Notice_Sent, t1.Promo_Expire_Notice_Sent, t1.isEncrypted, t1.PlanId
FROM grasbill.customers t1
WHERE t1.Username = :p0 LIMIT 1
-- p0: Input VarChar (Size = 6; DbType = AnsiString) [dyonis]
-- Context: Devart.Data.MySql.Linq.Provider.MySqlDataProvider Mapping: AttributeMappingSource Build: 4.4.519.0
UPDATE grasbill.customers SET Membership_Date = :p1 WHERE Customer_ID = :key1
-- p1: Input DateTime (Size = 0; DbType = DateTime) [8/3/2016 4:42:53 AM]
-- key1: Input Int (Size = 0; DbType = Int32) [7731]
-- Context: Devart.Data.MySql.Linq.Provider.MySqlDataProvider Mapping: AttributeMappingSource Build: 4.4.519.0
(Shows the SELECT and UPDATE calls)
So the log files don't really give any clue as to what's happening, but again the MS SQL database has been updated! The NextBillingDate field has been set correctly, as per this line:
ewayCustomer.NextBillingDate = Common.GetPlanExpiry(bill.BillPlan);
If it hadn't been updated, the user would have been billed again on the next timer tick (5 mins later), and I can see from logging that didn't happen.
One other interesting thing to note is the log file timestamps. As you can see from the code above I grab the current (UTC) time for the log filename. Here is the information shown by Windows File Explorer:
The MS SQL logfile was created at 04:42 (UTC) and last modified at 14:42 (UTC+10, Windows local-time), but the MySQL logfile was last modified at 15:23 (UTC+10), 41 minutes after it was created. Now I assume the logfile StreamWriter is closed as soon as it leaves scope. Is this delay an expected side effect of the exception? Did it take 41 minutes for the garbage collector to realise I no longer needed a reference to the StreamWriter? Or is something else going on?
Well 6 months later I finally got to the bottom of this problem. Not sure if it will ever help anyone else, but I'll detail it anyway.
There were 2 problems in play here, and 1 of them was idiocy (as they usually are), but one was legitimately something I did not know or expect.
Problem 1
The reason the changes were magically made to the database even though there was an exception was because the very first line of code in that function ApplyBillToCustomerAccount(username, bill, true); updates the database! <facepalm>
Problem 2
The (Devart) ChangeConflictException isn't only thrown if the data has changed, but also if you're not making any changes. MS SQL stores DateTimes with great precision, but MySQL (or the one I'm running at least) only stores down to seconds. And here's where the intermittency came in. If my database calls were quick enough, or just near the second boundary, they both got rounded to the same time. Devart saw no changes to be written, and threw a ChangeConflictException.
I recently made some optimisations to the database which resulted in far greater responsiveness, and massively increased incidence of this exception. That was one of the clues.
Also I tried changing the Found Rows parameter to true as instructed in the linked Devart post but found it did not help in my case. Or perhaps I did it wrong. Either way now that I've found the source of the issue I can eliminate the duplicate database updates.

C#/SQL Error "Object not set to an instance of an object"

This may not actually be a code issue, but here goes...
My C# program reads a CSV file and builds an SQL Insert statement to insert all rows of the file into a table, so the Insert statement becomes:
Insert GHP_For_CMS (GroupId, EmployeeID, etc...) values (rec1_field1, rec1_field2, etc...), (rec2_field1, rec2_field2, etc...)
SQL runs flawlessly against a Sandbox/Dev db from a Dev Server. SQL crashes with a NullReference exception ("Object not set to an instance of an object") against the same Sandbox/Dev db from a Production server. The Dev server has Framework version 4.0.30319.18052, and the Production has Framework version 4.0.30319.18063.
I know I haven't given a lot of information here, but anyone have any ideas? Or at least ideas of something to check? I've been banging my head against this one for 3-4 days and nothing is rearing it's ugly head.
TIA!
The error happens on the 'ExecuteNonQuery' below...
string dbConnString = ConfigurationManager.ConnectionStrings[targetDatabase].ToString();
if (null != dbConnString)
{
using (SqlConnection dbConn = new SqlConnection(dbConnString))
{
if (dbConn != null)
{
SqlCommand cmd = new SqlCommand(m_sqlInserts.ToString(), dbConn);
dbConn.Open();
int rowsAdded = cmd.ExecuteNonQuery();
...
So the answer to the question (because I couldn't post more details and I really wanted to know of things to try): is that it's a simple Permissions issue with the account that is running the process not being able to insert records to the table. The comment that helped me get to that conclusion came from #cdonner (Thank you, again!) in wanting to see a stack trace. I realized that I could return a StackTrace in the console log instead of just the InnerException message and it (the SQL Error) was finally revealed.

Simple bulk delete using EntityFramework.Extended throws syntax error

I am using Entity Framework 6.1.1 with MySQL 5.6.24 and I want to bulk delete a large set of records.
I am using EntityFramework.Extended to improve performance.
However my first, very simple update query already fails:
DbContext.Tickets.Where(t => t.EventID == targetEvent.EventID).Delete();
This throws an AggregateException in mscolib, the inner Exception is a MySQLException:
[MySqlException (0x80004005): You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near '[youreal_TicketPlatform].[Tickets]
FROM [youreal_TicketPlatform].[Tickets] AS j' at line 1]
MySql.Data.MySqlClient.MySqlStream.ReadPacket() +501
MySql.Data.MySqlClient.NativeDriver.GetResult(Int32& affectedRow, Int64& insertedId) +444
MySql.Data.MySqlClient.Driver.NextResult(Int32 statementId, Boolean force) +136
MySql.Data.MySqlClient.MySqlDataReader.NextResult() +1254
MySql.Data.MySqlClient.MySqlCommand.ExecuteReader(CommandBehavior behavior) +2626
MySql.Data.MySqlClient.MySqlCommand.ExecuteNonQuery() +137
EntityFramework.Batch.<InternalDelete>d__0`1.MoveNext() +1350
Has anyone experienced this same error? What is the easiest way to see the actual query being performed? Adding a listener on DbContext.Database.Log doesn't show the query.
Basically I want to bulk remove large sets of data without having to retrieve them first.
I came across this issue and had found the solution. Just change the default BatchRunner of the Locator from SqlServerBatchRunner to MySqlBatchRunner and it will work with MySQL.
EntityFramework.Locator.Current.Register<EntityFramework.Batch.IBatchRunner>(
() => new EntityFramework.Batch.MySqlBatchRunner());
The related code in repository:
https://github.com/loresoft/EntityFramework.Extended/blob/master/Source/EntityFramework.Extended/Locator.cs
The related issue:
https://github.com/loresoft/EntityFramework.Extended/issues/163
I'm sure it's because you are using mysql. None of the Bulk tools for EF I know works with mysql. And if you look in source/Database for Extended it only contains SqlServer and SqlCompact.
You can write the Sql yourself and execute that through Entityframework.

mysql Error:13 MyISAM table file not found

I have a set of files (around 20MB each) that needs to be inserted into a table in mysql. The insert is done in a loop for all files (single threaded). This works usually fine, but from time to time I am getting the following exception: File '.table.MYD' not found (Errcode: 13) for one file in the middle of the set (the first 50 ran ok, next 2-3 will fail and then the following will run fine again). If I just re-run the queries for the failed files in mysql workbench (or re-run the failed ones), they are working fine. The table is just created, with no indexes - so problems like 'index failed', table fragmentation or any other problems should not be there.
Below is the complete stacktrace:
File '.dbtable.MYD' not found (Errcode: 13)
----------------------------------
at MySql.Data.MySqlClient.MySqlStream.ReadPacket()
at MySql.Data.MySqlClient.NativeDriver.GetResult(Int32& affectedRow, Int32& insertedId)
at MySql.Data.MySqlClient.Driver.NextResult(Int32 statementId, Boolean force)
at MySql.Data.MySqlClient.MySqlDataReader.NextResult()
at MySql.Data.MySqlClient.MySqlCommand.ExecuteReader(CommandBehavior behavior)
at MySql.Data.MySqlClient.MySqlCommand.ExecuteNonQuery()
at Utils.SqlUtils.ExecMysql(String sql, String connection)
at Utils.MySqlExecQueue.DoExec(Object data)
----------------------------------
MySql.Data
where:
+ ExecMysql - looks like
using (MySqlConnection cnn = new MySqlConnection(connection))
{
cnn.Open();
using (MySqlCommand cmd = new MySqlCommand(sql, cnn))
{
cmd.CommandType = CommandType.Text;
cmd.ExecuteNonQuery();
}
}
+DoExec is a method that pics the files from a queue, creates the sql statement and calls ExecMysql above.
+the inserting code and mysql are on the same machine (Windows 2008, x64);
+there are no antiviruses or any other tool running on that machine that may lock the table file (as found on some blogs);
+the c# (.net 4) code is using mysql connector 6.5.4, the mysql version is 5.5;
I have implemented a dummy workaround like 'try-to-insert-while-13error-exception-is-thrown' but I have a strong feeling that this is not the correct solution.
Any ideea what is going on and how to fix this issue once and for all?
UPDATE - Clearly, the 'try-to-insert-while-13error-exception-is-thrown' fix is not a good ideea: I just got the same exception while running a SELECT on the table right after succesfully inserted data.
UPDATE 2 - checked the logs and I have noticed another wierd exception: Error on rename of '.\db\table.MYD' to '.\db\#sql2-4e4-1677.MYD' (Errcode: 17) ... things are getting better ...
do you have any anti-virus? If so make sure the mysql directory and its temp folder are excluded from AV and try again.

Categories