Reputation: 18270
I am trying to create a one-to-one relationship that is optional on one side between a User table and a UserInfo table. The specifications are that a UserInfo must have exactly one User, while a User can have one or zero UserInfos. Also we require that the foreign key exist in the UserInfo table so that the columns of the User table are not modified. We would like to use the relationship in C# LINQ-to-SQL, e.g., user.UserInfo.Email = "[email protected]",
userInfo.User`, etc.
The T-SQL for the tables and the foreign key from UserInfos to Users is (roughly):
CREATE TABLE [dbo].[Users](
[UserId] [int] IDENTITY(1,1) NOT NULL,
[Username] [nvarchar](50) NOT NULL,
CONSTRAINT [PK_dbo.Users] PRIMARY KEY CLUSTERED ( [UserId] ASC ),
) ON [PRIMARY]
GO
CREATE TABLE [dbo].[UserInfos](
[UserInfoId] [int] IDENTITY(1,1) NOT NULL,
[UserId] [int] NOT NULL,
[Email] [varchar](250) NOT NULL,
CONSTRAINT [PK_UserInfo] PRIMARY KEY CLUSTERED ( [UserInfoId] ASC ),
CONSTRAINT [UQ_UserId] UNIQUE NONCLUSTERED ( [UserId] ASC )
) ON [PRIMARY]
GO
ALTER TABLE [dbo].[UserInfos] WITH CHECK
ADD CONSTRAINT [FK_UserInfos.UserID_Users.UserId] FOREIGN KEY([UserId])
REFERENCES [dbo].[Users] ([UserId])
GO
ALTER TABLE [dbo].[UserInfos] CHECK CONSTRAINT [FK_UserInfos.UserID_Users.UserId]
GO
The problem is that if I define a foreign key from Users.UserId (the primary key) to UserInfos.UserId (which is, I understand, the correct way to define a non-optional one-to-one relationship) then performing the LINQ-to-SQL code user.UserInfo = null
also sets the user.UserId
to default(int)
.
Here is the T-SQL I use to define the foreign key between Users
and UserInfos
:
ALTER TABLE [dbo].[Users] WITH CHECK
ADD CONSTRAINT [FK_Users.UserId_UserInfos.UserId] FOREIGN KEY([UserId])
REFERENCES [dbo].[UserInfos] ([UserId])
GO
ALTER TABLE [dbo].[Users] CHECK CONSTRAINT [FK_Users.UserId_UserInfos.UserId]
GO
If I do not define this foreign key, then I get no LINQ-to-SQL property on a User
allowing me to access the UserInfo
. How can I have a relationship between the table Users
and UserInfos
that is traversable with LINQ-to-SQL, while at the same time allowing this relationship to be null from the User
side? Thank you.
Upvotes: 3
Views: 2208
Reputation: 28728
You can do this but you're approaching it from the wrong side.
When you call
user.UserInfo = null;
the exception states that
An attempt was made to remove a relationship between a User and a UserInfo. However, one of the relationship's foreign keys (UserInfo.UserId) cannot be set to null.
LINQ-to-SQL thinks you are trying to remove the relationship between the two items; and in an indirect way you are. But the exception is just a reiteration of what you've stated yourself - a UserInfo
must have a User
. You're unlinking the two objects but you aren't removing the UserInfo
- you're leaving an orphaned UserInfo
in your context which cannot be persisted to the database (due to the foreign key constraint).
The answer? Delete the UserInfo
.
var user = context.Users.First();
var userinfo = user.UserInfos;
user.UserInfos = null;
context.UserInfos.DeleteOnSubmit(userinfo);
context.SubmitChanges();
// or, even simpler:
var user = context.Users.First();
context.UserInfos.DeleteOnSubmit(user.UserInfos);
context.SubmitChanges();
Upvotes: 1