如何在 SQL Server 和 LINQ-to-SQL 中定义单侧可选一对一关系?

发布于 2024-12-02 19:36:23 字数 1918 浏览 2 评论 0原文

我正在尝试在 User 表和 UserInfo 表之间创建一侧可选的一对一关系。规范是一个 UserInfo 必须恰好有一个 User,而一个 User 可以有一个或零个 UserInfo。另外,我们要求外键存在于 UserInfo 表中,以便 User 表的列不被修改。我们希望使用 C# LINQ-to-SQL 中的关系,例如 user.UserInfo.Email = "[email protected]",userInfo.User`等。

表的 T-SQL 以及从 UserInfos 到 Users 的外键是(大致):

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

问题是,如果我定义从 Users.UserId (主键)到 UserInfos.UserId (即,我了解,定义非可选一对一关系的正确方法)然后执行 LINQ-to-SQL 代码 user.UserInfo = null 还会设置 <代码>user.UserId 到default(int)

以下是我用来定义 UsersUserInfos 之间的外键的 T-SQL:

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

如果我不定义此外键,则不会得到 LINQ-to-SQL User 上的属性允许我访问 UserInfo。如何在表 UsersUserInfos 之间建立可通过 LINQ-to-SQL 遍历的关系,同时允许该关系在 <代码>用户端?谢谢。

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.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

冷弦 2024-12-09 19:36:23

你可以做到这一点,但你的做法是错误的。

当你调用

user.UserInfo = null;

异常时指出

尝试删除 User 和 UserInfo 之间的关系。但是,关系的外键之一 (UserInfo.UserId) 不能设置为 null。

LINQ-to-SQL 认为您正在尝试删除两项之间的关系;并且以一种间接的方式你是。但例外只是重申您自己所说的 - UserInfo 必须有一个 User。您取消了这两个对象的链接,但没有删除 UserInfo - 您在上下文中留下了一个孤立的 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();

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();
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文