views:

125

answers:

1

Problem

I got two related tables, with a foreign key that doesn't enforce FK contraints. The "child" table should be allowed to specify a "parent" key, which is either NULL or non-existing ID.

My data access is built using Linq2Sql and it generates a one-to-many relation in the model of my tables.

The problem comes in some cleanup code, which will daily look through all the changes for the last day and fix any "errors" in the data.

Example

foreach (var user in data.Users)
{
    // Check if the user has a specified office, which does not exists.
    if (user.OfficeId != null && user.Office == null)
    {
        user.OfficeId = null; // This throws exception
    }
}

Exception: System.Data.Linq.ForeignKeyReferenceAlreadyHasValueException: Operation is not valid due to the current state of the object

This is normal behavior and somewhat expected, so I tried to set the reference object instead. But how do I define an "empty" Office?

var emptyOffice = new Office();
user.Office = emptyOffice;

The above code sets the OfficeId to NULL on the user instance, but obviously it fails during update as it tries to add a new "empty" Office to the database.

Possible solution

What I'm left with is running my own SQL which does the update, though it would be nice to actually be able to do this through Linq2Sql as there are other columns on the same row I'm updating when the related "parent" is non-existing.

Notes

There are some requirements here that is important for any comments:

  • The database cannot be changed.
  • Multiple systems is dependent on the same database schema.
  • Can potentially change to Entity Framework, if it supports such a scenario.
  • Running a custom SQL is not a problem and I'll be doing that until I find a better solution.
  • Would like to learn and know how to do this without any special code.
+1  A: 

My code has FKs enforced, so I haven't tested this, but have you tried explicitly setting

user.Office = null;

That should force the FK value OfficeId to null, too.

If that doesn't work, then it the following certainly should:

user.Office = new Office(); // or keep a cached dummy Office object to save time
user.Office = null;

That will force the FK reference to realize that its value has been changed and set to null.

Shaul
user.Office is already null, though I discovered that submitting changes after getting the object, the KontorId column is actually set to NULL. That's both troubling and positive. It's good for my current scenario, but that actually means Linq-to-Sql will update your entities foreign keys without you knowing! That has to be a design-flaw?
SondreB
Debatable if that's really a design flaw... it's just setting the relational integrity straight, just like you're trying to do... Logically, if the FK value is pointing to a non-existent value, its value is meaningless, useless, and it would be better for it to be nulled out...
Shaul
Shaul: Is there any way I can set the relational settings in the linq-to-sql model to avoid having it auto-delete FKs that doesn't exists? My problem sort of fixed itself by just running an submit changes, but for future reference I would really like to know how I could avoid such an behavior.
SondreB
None that I know of - but then I didn't know about this behavior until you pointed it out, so don't treat me as the authority on the subject... ;)
Shaul