Cannot add an identity that already exists - linq-to-sql

I'm using C#4.0 in a simple expense recording app. I'm trying to save to a table with an auto incremented id field, set as the primary key. It works fine the first time I use it, but the second and subsequent time, I get the "Cannot add an identity that already exists" error.
Here's the code I'm having trouble with
public bool SaveClaim(Claim newClaim, bool blNew)
{
bool blSuccess = true;
try
{
expContext.Claims.InsertOnSubmit(newClaim);
expContext.SubmitChanges();
claim = null;
}
catch (Exception e)
{
blSuccess = false;
MessageBox.Show(e.ToString());
}
return blSuccess;
}
I've been working on this all morning, and it's driving me daft. I'd be glad for any help.

Ensure you have the following properties set in your dbml for the identity column of Claim:
Auto Generated Value = true
Auto-Sync = OnInsert
Also ensure that your new Claim object is actually a new object, and not a reuse of the one you previously added.

Maybe you should try updating your designer.
Remove the table Claim, update the server explorer, and add it again.
At least that's what I do when I get this error. It usually shows when I set the identity column on the database after compiling.

Maybe you are trying to UPDATE newClaim using the INSERT method.
If newClaim has an ID and the method expContext.Claims.InsertOnSubmit(newClaim) is trying to insert a record with that ID. That could be the issue.
if (blNew)
expContext.Claims.InsertOnSubmit(newClaim);
else
expContext.Claims.UpdateOnSubmit(newClaim); //-- Assumed method
Additional
Here is a useful thread: MSDN Forums
if (blNew)
{
expContext.Claims.InsertOnSubmit(newClaim);
}

Related

Why is persist in JPA clearing the existing data in the table row?

I am trying to update data to a mySQL database using JPA. I have no problem persisting data but flush will not work as expected. I retrieve the id for the login session, set that id (it is the primary key) along with setting the description field that I want merged to the database. I have debugged line by line through this method and all variables contain the expected values. Any ideas or suggestions to overcome this problem are appreciated.
public String update() {
factory = Persistence.createEntityManagerFactory(PERSISTENCE_UNIT_NAME);
EntityManager em = factory.createEntityManager();
if(true){
em.getTransaction().begin();
String sessionEmail=Util.getEmail();
//Create query to find user passwords matching the inputted name
Query myQuery = em.createQuery("SELECT u FROM BusinessAccount u WHERE u.email=:email");
myQuery.setParameter("email", sessionEmail);
List<BusinessAccount> accounts=myQuery.getResultList();
int intId=accounts.get(0).getId();
businessAccount.setId(intId);
String des=businessAccount.getDescription();
businessAccount.setDescription(des);
em.flush();
addMessage(new FacesMessage(FacesMessage.SEVERITY_INFO,
"User Registration Successful!", null));
return "success";
}
else {
addMessage(new FacesMessage(FacesMessage.SEVERITY_ERROR,
"User Registration Failed!", null));
return "failure";
}
}
merge() persists all the state of the entity. Not just the non-null fields. I it wasn't, you would complain that you want to set some field to null and that merge() ignores it and leaves it as is.
So get an entity from the database, and modify it, instead of only gettings its ID, creating a new entity instance from scratch and only settings some of its fields.
Note that, if you get the entity and modify it inside a single transaction, you don't even have to call merge(): the new state will be made persistent automatically.

how NamedParameterJdbcTemplate.update really works with Spring and MySQL

Ok, I've probably dug up the entire Google land and still couldn't find anything that could possibly answer my question.
I have my little foo method that does some deleting like this:
private void foo()
{
jdbcNamedParameterTemplate.update(sqlString, params); //1
jdbcNamedParameterTemplate.update(sqlString2, params2); //2
}
sqlString and sqlString2 are just delete statements like "Delete * from FooBar".
So when I get to the second call to update, do I have any guarantee that whatever operation the first one invokes in the database has already finished?
If you do that two in one session, and non multithreading, then yes the first one invokes in the database has already finished before the second update.
But if not in the same session you can check the version to check if the object already changed or not
int oldVersion = foo.getVersion();
session.load( foo, foo.getKey() ); // load the current state
if ( oldVersion != foo.getVersion()) { .... }// if true then the object has been changed

"Cannot insert explicit value for identity column..." even though I'm not

I have this function:
private static void SaveResource(StrategicPlanningDbDataContext ctx, ResourceModel resource, int impliedID)
{
var existing = ctx.Resources.FirstOrDefault(r => r.ID == resource.ID) ??
new Resource();
existing.ImpliedID = impliedID;
existing.HasAccepted = resource.HasAccepted;
existing.IsPrimary = existing.IsPrimary;
existing.UserID = resource.UserID;
if (existing.ID == default(int))
{
ctx.Resources.InsertOnSubmit(existing);
ctx.SubmitChanges();
resource.ID = existing.ID;
}
}
I'm getting a Cannot insert explicit value for identity column in table 'Resource' when IDENTITY_INSERT is set to OFF. message when I hit ctx.SubmitChanges() for a new Resource. Resource.ID is an Identity (obviously). It's 0 when we come into the function (because I just created it, and ints obviously have to have a default value.
I've tried deleting the table from my dbml and re-adding it several times, but I keep getting this error. I've checked the designer, and the designer has [global::System.Data.Linq.Mapping.ColumnAttribute(Storage="_ID", AutoSync=AutoSync.OnInsert, DbType="Int NOT NULL IDENTITY", IsPrimaryKey=true, IsDbGenerated=true)] above the ID property.
Any ideas?
Well, I closed and restarted Visual Studio and it all got better. (As an aside, it was also compiling just fine if I completely removed tables from the .dbml, which, uh, didn't make any sense).

Linq to SQL concurrency problem

Hallo,
I have web service that has multiple methods that can be called. Each time one of these methods is called I am logging the call to a statistics database so we know how many times each method is called each month and the average process time.
Each time I log statistic data I first check the database to see if that method for the current month already exists, if not the row is created and added. If it already exists I update the needed columns to the database.
My problem is that sometimes when I update a row I get the "Row not found or changed" exception and yes I know it is because the row has been modified since I read it.
To solve this I have tried using the following without success:
Use using around my datacontext.
Use using around a TransactionScope.
Use a mutex, this doesn’t work because the web service is (not sure I am calling it the right think) replicated out on different PC for performance but still using the same database.
Resolve concurrency conflict in the exception, this doesn’t work because I need to get the new database value and add a value to it.
Below I have added the code used to log the statistics data. Any help would be appreciated very much.
public class StatisticsGateway : IStatisticsGateway
{
#region member variables
private StatisticsDataContext db;
#endregion
#region Singleton
[ThreadStatic]
private static IStatisticsGateway instance;
[ThreadStatic]
private static DateTime lastEntryTime = DateTime.MinValue;
public static IStatisticsGateway Instance
{
get
{
if (!lastEntryTime.Equals(OperationState.EntryTime) || instance == null)
{
instance = new StatisticsGateway();
lastEntryTime = OperationState.EntryTime;
}
return instance;
}
}
#endregion
#region constructor / initialize
private StatisticsGateway()
{
var configurationAppSettings = new System.Configuration.AppSettingsReader();
var connectionString = ((string)(configurationAppSettings.GetValue("sqlConnection1.ConnectionString", typeof(string))));
db = new StatisticsDataContext(connectionString);
}
#endregion
#region IStatisticsGateway members
public void AddStatisticRecord(StatisticRecord record)
{
using (db)
{
var existing = db.Statistics.SingleOrDefault(p => p.MethodName == record.MethodName &&
p.CountryID == record.CountryID &&
p.TokenType == record.TokenType &&
p.Year == record.Year &&
p.Month == record.Month);
if (existing == null)
{
//Add new row
this.AddNewRecord(record);
return;
}
//Update
existing.Count += record.Count;
existing.TotalTimeValue += record.TotalTimeValue;
db.SubmitChanges();
}
}
I would suggest letting SQL Server deal with the concurrency.
Here's how:
Create a stored procedure that accepts your log values (method name, month/date, and execution statistics) as arguments.
In the stored procedure, before anything else, get an application lock as described here, and here. Now you can be sure only one instance of the stored procedure will be running at once. (Disclaimer! I have not tried sp_getapplock myself. Just saying. But it seems fairly straightforward, given all the examples out there on the interwebs.)
Next, in the stored procedure, query the log table for a current-month's entry for the method to determine whether to insert or update, and then do the insert or update.
As you may know, in VS you can drag stored procedures from the Server Explorer into the DBML designer for easy access with LINQ to SQL.
If you're trying to avoid stored procedures then this solution obviously won't be for you, but it's how I'd solve it easily and quickly. Hope it helps!
If you don't want to use the stored procedure approach, a crude way of dealing with it would simply be retrying on that specific exception. E.g:
int maxRetryCount = 5;
for (int i = 0; i < maxRetryCount; i++)
{
try
{
QueryAndUpdateDB();
break;
}
catch(RowUpdateException ex)
{
if (i == maxRetryCount) throw;
}
}
I have not used the sp_getapplock, instead I have used HOLDLOCK and ROWLOCK as seen below:
CREATE PROCEDURE [dbo].[UpdateStatistics]
#MethodName as varchar(50) = null,
#CountryID as varchar(2) = null,
#TokenType as varchar(5) = null,
#Year as int,
#Month as int,
#Count bigint,
#TotalTimeValue bigint
AS
BEGIN
SET NOCOUNT ON;
BEGIN TRAN
UPDATE dbo.[Statistics]
WITH (HOLDLOCK, ROWLOCK)
SET Count = Count + #Count
WHERE MethodName=#MethodName and CountryID=#CountryID and TokenType=#TokenType and Year=#Year and Month=#Month
IF ##ROWCOUNT=0
INSERT INTO dbo.[Statistics] (MethodName, CountryID, TokenType, TotalTimeValue, Year, Month, Count) values (#MethodName, #CountryID, #TokenType, #TotalTimeValue, #Year, #Month, #Count)
COMMIT TRAN
END
GO
I have tested it by calling my web service methods by multiple threads simultaneous and each call is logged without any problems.

"An attempt has been made to Attach or Add an entity that is not new..." after calling ObjectChangeConflict.Resolve()

I have a pair of classes which, when updated together as shown below are guaranteed to cause a ChangeConflictException because a trigger on child object table updates a value on the parent object record. I believe I am following the correct procedure for resolving the conflict and resubmitting the update, but upon calling the second db.SubmitChanges (or even if I call db.GetChangeSet()), I get the "an attempt has been made to attach or add an entity that is not new blah blah blah" error.
using (SurveyDB db = new SurveyDB())
{
Parent p = db.Parents.Single(t => t.Id == 1);
p.Children.Add(new Child {...});
p.SomeProperty = "new value";
try
{
db.SubmitChanges();
}
catch (ChangeConflictException e)
{
foreach (ObjectChangeConflict o in db.ChangeConflicts)
o.Resolve(RefreshMode.KeepChanges, true);
db.SubmitChanges(ConflictMode.FailOnFirstConflict);
}
}
Any help greatly appreciated.
The resolution for me was to set dbml "Update Check" property for the fields set by the trigger to "Never" - this works for the situation where the application never modifies those fields. Otherwise, I'd have had to call SubmitChanges twice - once after editing the parent object and then again after adding the child object (followed by retrieving the parent-object again).