In a multitenant application that uses composite keys
(e.g. SiteId, $(Table)Id
)
for everything, I have the following two tables:
Owner (
SiteId bigint NOT NULL,
OwnerId bigint NOT NULL,
ThingId bigint NULL
)
Thing (
SiteId bigint NOT NULL,
ThingId bigint NOT NULL
)
and a foreign key from Owner (SiteId, ThingId)
to Thing (SiteId, ThingId)
.
If I write a method like this:
void RemoveThing(Owner owner)
{
owner.Thing = null;
db.SubmitChanges();
}
I get the exception
System.InvalidOperationException: An attempt was made to remove a relationship between a
Thing and a Owner. However, one of the relationship's foreign keys (Owner.MultiId,
Owner.ThingId) cannot be set to null.
at System.Data.Linq.ChangeTracker.StandardChangeTracker.StandardTrackedObject.SynchDependentData()
at System.Data.Linq.ChangeProcessor.ValidateAll(IEnumerable`1 list)
at System.Data.Linq.ChangeProcessor.SubmitChanges(ConflictMode failureMode)
at System.Data.Linq.DataContext.SubmitChanges(ConflictMode failureMode)
at System.Data.Linq.DataContext.SubmitChanges()
at proj.Program.RemoveThing() in C:\proj\Program.cs:line 115
To fix this, I could add a second copy of SiteId
(perhaps ThingSiteId
) to the Owner
table. But it's only ever going to be equal to the SiteId, so I'd be spending database size and schema complexity to work around my ORM.
How can I tell LINQ to SQL that it doesn't need to worry about that half of the foreign key relationship, and only set Owner.ThingId=NULL
?
Set ThingId = null
instead of Thing = null
. Don't reuse your DataContext
, otherwise you might get a "Foreign key is already set" exception.
LINQ is actively preventing this from being any easier. In ChangeTracker.SynchDependentData()
, every column is checked to see if it is part of any associations, and then an exception is thrown if the column was
set to null
the association has ANY non-nullable columns(!)
This is a bug in LINQ-to-SQL, in my opinion.