SynchroniseWithDataContext error on modified

Aug 21, 2008 at 10:34 AM
Edited Aug 21, 2008 at 1:53 PM
Hi Friend.

I've troubled when tried to sync an modified row back to Datacontext. The error is "DuplicateKeyException: Cannot add an entity with a key that is already in use"

This code in "SynchroniseWithDataContext" function made error:

                else if (entity.LINQEntityState == EntityState.Modified || entity.LINQEntityState == EntityState.Detached)
                {
                    if (entity.LINQEntityOriginalValue != null)
                        targetDataContext.GetTable(entity.GetEntityType()).Attach(entity, entity.LINQEntityOriginalValue);
                    else
                        targetDataContext.GetTable(entity.GetEntityType()).Attach(entity, true); <-- error arise here
                }


my server side code is:

Public Function dmHanghoaGetByID(ByVal hhID As Integer) As Global.TinLong.DMHangHoa

        Dim hangHoa As Global.TinLong.DMHangHoa = Nothing
        If (svData.DeferredLoadingEnabled = True) Then 'chú ý phải xét cái này kỹ khi dùng singleton, do svData một khi đã trả về kết quả truy vấn thì không thể chỉnh sửa được! (báo lỗi)
            'Dim dtOption As New DataLoadOptions() 'cái này dùng nạp các bảng, liên quan nếu cần thiết
            'svData.LoadOptions = dtOption
            svData.DeferredLoadingEnabled = False
        End If
        hangHoa = (From h In svData.DMHangHoas _
                   Where h.idHH = hhID _
                   Select h).First()
        'hangHoa.SetAsChangeTrackingRoot()
        Return hangHoa
    End Function

Public Sub dmHangHoaUpdate(ByVal editedDMHH As Global.TinLong.DMHangHoa)

        If (svData.DeferredLoadingEnabled = True) Then
            'Dim dtOption As New DataLoadOptions()
            'svData.LoadOptions = dtOption
            svData.DeferredLoadingEnabled = False
        End If

        editedDMHH.SynchroniseWithDataContext(svData, True)
        svData.SubmitChanges()
    End Sub

my client side code is:

    Private Sub btnUpdateData_Click(ByVal sender As System.Object, ByVal e As System.Windows.RoutedEventArgs) Handles btnUpdateData.Click
        ketnoi()
        Dim editedHH As New Global.TinLong.DMHangHoa()


        editedHH = svDt.dmHanghoaGetByID(CType(txtHH_ID.Text, Integer))
        editedHH.SetAsChangeTrackingRoot()

        editedHH.strTenHang = txtHH_NAME.Text  <-- i've put some new text here

        svDt.dmHangHoaUpdate(editedHH)
        svDt = Nothing
    End Sub


I've solved the problem by create new Datacontext for each call like this:

Public Sub dmHangHoaUpdate(ByVal editedDMHH As Global.TinLong.DMHangHoa)
Dim svData as ServicesDataClassesDataContext  = New ServicesDataClassesDataContext(DatabaseManager.GetKetnoiDbString())
....
End Sub

But the problem is the table in my database never updated with new value!

Coordinator
Aug 25, 2008 at 12:33 PM
Hi there,

Sorry for the late reply.

Although I can't read your comments, I did notice one word stand out... "Singleton" which may be the cause of the problem.

If you are using singleton or some other type of global value which keeps the same data context alive, this would be why it is failing with a duplicate and why creating a new data context each time works.

You must use a difference datacontext to the one you started with, otherwise you will get duplicate errors because the entity is already "attached" when you try to re-attach it when calling the SyncroniseWithDataContext() method.

Apart from this, I can't see any reason why your data is not being updated.  I'm assuming the new dmHangHoaUpdate() method looks like:

Public Sub dmHangHoaUpdate(ByVal editedDMHH As Global.TinLong.DMHangHoa)
        Dim svData as ServicesDataClassesDataContext  = New ServicesDataClassesDataContext(DatabaseManager.GetKetnoiDbString())
        
        If (svData.DeferredLoadingEnabled = True) Then
            svData.DeferredLoadingEnabled = False
        End If

        editedDMHH.SynchroniseWithDataContext(svData, True)
        svData.SubmitChanges()
End Sub

Make sure in this method that the editedDMHH value has it's EntityState set to modified when first stepping into the function.  If it isn't then re-check at the point where you make the change to strTenHang property - it should be definately set there (unless your database options make make it read only or something).  However, if the entitystate is set to "modified" correctly and it's still not updating the database, have a look at the example included with my code and add get the LOG.  This will give you more detail about what is sent to the database.

Also, are u using WCF or remoting?

Cheers

Matt.
Aug 27, 2008 at 12:53 AM
Hi Matt,

Thank for your respond. Actually, i'm using WCF and i've check that editedDMHH value has it's EntityState set to modified. I've to change my code to this for work:

    Public Sub dmHangHoaUpdate(ByVal editedDMHH As Global.TinLong.DMHangHoa)

        svData = New ServicesDataClassesDataContext(DatabaseManager.GetKetnoiDbString())
        svData.ObjectTrackingEnabled = True
        If (svData.DeferredLoadingEnabled = True) Then
            'Dim dtOption As New DataLoadOptions() 'cái này dùng nạp các bảng, liên quan nếu cần thiết
            'svData.LoadOptions = dtOption
            svData.DeferredLoadingEnabled = False
        End If
        'editedDMHH.SynchroniseWithDataContext(svData, True) <-- your EntityBase code, not affect my db
        svData.DMHangHoas.Attach(editedDMHH, True) <-- working code, database get updated!

        svData.SubmitChanges()
    End Sub

Coordinator
Aug 27, 2008 at 10:29 PM
Hi there again,

I think I know how to find the issue.  Just before you do the SyncroniseWithDataContext() call, use a editedDMHH.ToEntityTree().OfType<DMHangHoas>().  This should return all the instance known of that type.  Iterate through the list and check if there are any duplicate keys.  You should find that two objects of that type have the same key - this is what the error means. This is why SyncroniseWithDataContext() is failing because it's attempting to attach the key twice from two different objects.  The attach will work in this case because you specificially saying which object to add, whereas SyncroniseWithDataContext() will go through all objects under the root object and attempt to attach them either as unmodified or modified.

Also, make sure you have the latest source code from the Source Page

Anyway, that's what I think will be the problem - can't think of anything else.  Hope I've helped.

Cheers

Matt.