Pergunta

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 = "test@test.com",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.

Foi útil?

Solução

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();
Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top