views:

468

answers:

2

I am using Sql tables without rowversion or timestamp. However, I need to use Linq to update certain values in the table. Since Linq cannot know which values to update, I am using a second DataContext to retrieve the current object from database and use both the database and the actual object as Input for the Attach method like so:

Public Sub SaveCustomer(ByVal cust As Customer)
    Using dc As New AppDataContext()
        If (cust.Id > 0) Then
            Dim tempCust As Customer = Nothing

            Using dc2 As New AppDataContext()
                tempCust = dc2.Customers.Single(Function(c) c.Id = cust.Id)
            End Using

            dc.Customers.Attach(cust, tempCust)
        Else
            dc.Customers.InsertOnSubmit(cust)
        End If

        dc.SubmitChanges()
    End Using
End Sub

While this does work, I have a problem though: I am also using StoredProcedures to update some fields of Customer at certain times. Now imagine the following workflow:

  1. Get customer from database
  2. Set a customer field to a new value
  3. Use a stored procedure to update another customer field
  4. Call SaveCustomer

What happens now, is, that the SaveCustomer method retrieves the current object from the database which does not contain the value set in code, but DOES contain the value set by the stored procedure. When attaching this with the actual object and then submit, it will update the value set in code also in the database and ... tadaaaa... set the other one to NULL, since the actual object does not contain the changed made by the stored procedure.

Was that understandable?

Is there any best practice to solve this problem?

A: 

If you make changes behind the back of the ORM, and don't use concurrency checking - then you are going to have problems. You don't show what you did in step "3", but IMO you should update the object model to reflect these changes, perhaps using OUTPUT TSQL paramaters. Or; stick to object-oriented.

Of course, doing anything without concurrency checking is a good way to lose data - so my preferred option is simply "add a rowversion". Otherwise, you could perhaps read the updated object out and merge things... somehow guessing what the right data is...

Marc Gravell
That definetly sounds reasonable. However, I am working against the database and infrastructure of a customer and he won't introduce rowversionioning due to the fact, that most parts of his database is generated dynamically and he uses an own framework to access it. However, I was taking the chance working with Linq against the only tables that are static to show what Linq is all about. ;-) Now I am having the problem due to the SP's. Do you have a good source where I can learn about concurrency checking in this context?
Mephisztoe
A: 

If you're going to disconnect your object from one context and use another one for the update, you need to either retain the original object, use a row version, or implement some sort of hashing routine in your database and retain the hash as part of your object. Of these, I highly recommend the Rowversion option as well. Using the current value as the original value like you are trying to do is only asking for concurrency problems.

Jim Wooley
Problem is - as stated above - I cannot add rowversioning, since i am working against a customers database and there's simply no option to modify it. :(
Mephisztoe