Graeme Hill's Dev Blog

LINQ to SQL Gotcha #2: GetChangeSet Weirdness

Star date: 2010.032

If you attach an entity with a required association that is nulled out, you will be unable to call GetChangeSet(). In my opinion, the expected behaviour is that the entity should show up in the change set as though it is valid, but an exception should be thrown when you attempt to call SubmitChanges() because a foreign key constraint has been violated. In fact, with code like this we will get exactly that result (an exception is thrown on SubmitChanges()):

Using testData As New TestDataContext
    Dim newArticle As New Article With {.title = "Foobar", _
                                        .text = "blah blah blah"}
    testData.Articles.InsertOnSubmit(newArticle)
    Dim changes = testData.GetChangeSet()
    testData.SubmitChanges()
End Using

There is a required association to the Users table that has not been set at all. Using the following snippet, with the User property explicitly set to Nothing an exception will be thrown on GetChangeSet() instead of SubmitChanges():

Using testData As New TestDataContext
    Dim newArticle As New Article With {.title = "Foobar", _
                                        .text = "blah blah blah", _
                                        .User = Nothing}
    testData.Articles.InsertOnSubmit(newArticle)
    Dim changes = testData.GetChangeSet()
    testData.SubmitChanges()
End Using

It gives this error on GetChangeSet():

An attempt was made to remove a relationship between a User and a Article. However, one of the relationship's foreign keys (Article.userID) cannot be set to null.

It appears that the internal implementation of LINQ to SQL distinguishes between an unset relationship, and one that has specifically been set to Nothing. The awkward thing here is that it is not always easy to avoid this issue since you don't even have to call InsertOnSubmit. Attaching an entity by setting an association to an already attached object gives the same result.

Using testData As New TestDataContext
    Dim existingUser = testData.Users.First
    Dim newUserGroup As New UserGroup With {.User = existingUser, .Group = Nothing}
    Dim changes = testData.GetChangeSet()
    testData.SubmitChanges()
End Using

In this snippet there are two required associations: User and Group. As soon as User is set, the UserGroup entity is attached to the DataContext. However, since Group is Nothing the ChangeSet is now corrupt.

This bug is described in this forum thread where a Microsoft employee recommended that he post it on Connect (Microsoft's bug tracking site). The bug report on Connect can be found here.