views:

49

answers:

2

I am getting an error in my MVC-based website surrounding data concurrency in Linq to SQL:

"Row Not Found Or Changed"

After reading several posts on here it seems as though an accepted solution is to set all non-Primary key fields to UpdateCheck = false in the dbml designer. Before taking the plunge with this, I wanted to ask, will I be losing anything if I do this?

To be honest, it seems to me like this should always be the case, as using the primary key should be the fastest way to find a record anyway. This would be assuming that you don't have any composite PKs. I'm not terribly familiar with data concurrency scenarios, but am I missing something here?

Thanks for your time!

[EDIT]

Thanks for the feedback guys! To give some more detail, the specific scenario I have is this:

I have an Article table with a number of fields (title, content, author, etc.). One of the fields that gets updated very frequently (anytime anyone views the article), is a popularity field, which gets incremented with every click. I saw the original error mentioned above when I updated the article text in the database. Then navigated to that article on the live site (which attempted to update the popularity field).

For starters it sounds like I need to NOT be using a shared DataContext. Beyond that, maybe look into setting certain fields to UpdateCheck never. That being said, I definitely do not want the Article Popularity to not get update due to some concurrency issue. So with that being the case, is there a way for me to ensure this with optimistic concurrency?

Thanks again!!

+2  A: 

I do sometimes change UpdateCheck to Never on all but the primary key(s) on entity classes in the designer myself. What you lose is notification of interim changes to the data since you loaded it; what you end up with is a "last change wins" type of scenario. If that is OK in your situation, then... fine.

There are situations where that is definitely not a good thing to do. For instance, checking/adjusting a bank account funds balance... or any situation where an alternation to a field is going to be based on a calculation with the current value as one of the operands.

Andrew Barber
I also wanted to add; If you are frequently having concurrency errors, it's possible you may be doing something in a somewhat non-optimal way;You generally should not be caching the `DataContext` or the entity objects themselves between web page calls. The Action method that does the data changes should be loading the entity object anew from a fresh DataContext, changing the properties as needed, then saving.If a site has high-usage, you will see some concurrency things happening there, but it might not be all THAT common; so I thought I'd add that, as well.
Andrew Barber
Thanks for the great feedback! So it sounds like I'm doing several things wrong here. For one, I am in fact using a Shared (static in c#) dataContext object, through which all of my queries, inserts, and updates are performed. From what you're telling me, this is bad practice. I will look into making some adjustments here. Aside from that, I could see setting Update Check to false on certain fields as being problematic. I have added more information to my original post to detail this.
Josh Garwood
A: 

set all non-Primary key fields to UpdateCheck = false in the dbml designer. Before taking the plunge with this, I wanted to ask, will I be losing anything if I do this?

The job of concurrency mechanisms is to prevent multiple users from stomping each others changes. Pessimistic concurrency achieves this by locking out changes to a record when it is read. Then unlocking the record when changes are complete. Optimistic concurrency achieves this by remembering what the record looked like when it was read, and then not modifying the record if it has changed.

Linq to Sql uses optimistic concurrency. If you set the UpdateCheck property that way, you are disabling optimistic concurrency checking.

Consider this record:

  • Customer (Name = "Bob", Job = "Programmer", Salary = 35000.00)
  • LinqToSql DataContext#1 reads the record
  • LinqToSql DataContext#2 reads the record and commits the following change (Salary = 50000.00)
  • LinqToSql DataContext#1 attempts to commit the following change (Job = "Janitor")

With optimistic concurrency, DataContext#1 now gets a concurrency exception to resolve. Without optimistic concurrency, we now have a janitor making 50k.

David B
That makes sense; thanks for the explanation... But what about the case when you're only ever updating one field. For instance, I have a popularity field on an Article table. Every time someone views that article, I add points to the popularity column. Ideally, I never want that column to not get updated due to conflicts. So if 10 people view the article at once, I want the popularity field to be updated each time. What is the best way to ensure this happens? Is optimistic concurrency not the way to go here?
Josh Garwood
You either need concurrency, or you need a relative update SET ViewCount = ViewCount+1
David B