views:

2470

answers:

3

http://geekswithblogs.net/michelotti/archive/2007/12/17/117791.aspx

I'm using ASP.NET with C# and trying to use linq to sql to update a data context as exhibited on the blog linked above. I created the timestamp field in the table just as stated and am using the following method:

private void updateRecord(TableName updatedRecord)
{
 context db = new context();
 db.TableName.Attach(updatedRecord,true);
 db.SubmitChanges();
}

My question is, are you supposed to assign the timeStamp field to anything in your updatedRecord before trying to call the Attach method on your data context?

When I run this code I get the following exception: System.Data.Linq.ChangeConflictException: Row not found or changed. I update all of the fields, including the primary key of the record that I'm updating before passing the object to this update method. During debugging the TimeStamp attribute of the object shows as null. I'm not sure if it's supposed to be that way or not.

Every book and resource I have says that this is the way to do it, but none of them go into great detail about this TimeStamp attribute.

I know this is quick and easy, so if anybody knows, please let me know. Thanks!

Marty

+1  A: 

If you have a timestamp column, then to update a record (from a vanilla object): yes, I would expect to have to assign it. Otherwise, you lose the ability to use the timestamp for optimistic concurrency checking.

The idea is you take a copy of the timestamp when you get hold of your (disconnected) object, then when you update you can use this column to verify that nobody else has edited the row.

There are two common scenarios:

1: if you are only performing a short lived operation, get the record out of the database first - make your changes to the object, and simply SumbitChanges() [all with the same data-context]. The data-context will handle concurrency for you.

2: if you are disconnecting the object (for example passing it to a client application for a while), then use something like serialization (LINQ-to-SQL objects support DataContractSerializer (optionally; you need to enable it)). So serialize the object at the server, pass it to the client - the client makes changes to their copy and passes it back. The server deserializes it and uses Attach() and SubmitChanges(). The record in memory should still have the timestamp that it had when extracted from the database, so we can perform optimistic concurrency spanning all the time the record has been disconnected.

Marc Gravell
A: 

Since you say that you created the time stamp field in the table, I wonder if, in the case where this column was added later, the column properties may not be set correctly. You may want to check the properties on your TimeStamp column in the DBML designer. Make sure that:

AutoGenerated = true
Auto-Sync = Always
Time Stamp = True
Update Check = Never

The server data type should be rowversion NOT NULL

If it is not set to be auto generated and synced always, the row version won't be returned from the insert since you haven't changed it when the insert was done. Even though this value is generated by the database the DataContext needs to know this so that it can handle it properly.

In addition, now that you have a timestamp column, UpdateCheck should be set to Never for all of the other columns.

tvanfosson
A: 

@Marc - you were absolutely right, I just needed to grab the timeStamp from the disconnected object and store it somewhere and then send it back along w/the vanilla object. It worked! After thinking about it, I should've been able to figure that out since it makes sense, but I was thinking the wrong way about how the timeStamp was being used by LINQ. OH well, I've been set straight... thank you for the prompt and helpful/accurate response.

@tvanfosson - I went through and double-checked and all column properties and they were all already properly set as you detailed. Thanks for the response and info.

Marty