在 SQL Server 中的非主键上添加 @ManyToOne 映射时出现问题

Posted

技术标签:

【中文标题】在 SQL Server 中的非主键上添加 @ManyToOne 映射时出现问题【英文标题】:Problem adding @ManyToOne mapping on Non primary-key in SQL Server 【发布时间】:2011-04-01 14:50:12 【问题描述】:

我在将 spring/hibernate 应用程序从 mysql 更改为 SQL Server 时遇到问题。

当 Hibernate 通过启动他想要创建的服务器来更新数据库时(由 hibernate.hbm2ddl.auto 设置在 update 上)数据库但外键因以下错误而失败:

Unsuccessful: alter table table2 add constraint FKDC2DC97ECEB31922 foreign key (login) references table1
Column 'table1.id' is not the same data type as referencing column 'table2.table1_login' in foreign key 'FKDC2DC97ECEB31922'.

映射如下:

table1:

@Id
public String getLogin() 
    return login;

public void setLogin(String login) 
    this.login = login;

table2:

@ManyToOne
@JoinColumn (name = "table1_login", referencedColumnName = "login", insertable=false, updatable=false)
public Table1 getTable1() 
    return table1;

public void setTable1(Table1 table1) 
    this.table1= table1;

++编辑: SQL 看起来像这样:

table1 中的键:

表 table1 也被其他应用程序使用,因此该表需要列 'id' 作为主键。所以 table1.id 是 table1 的主键。但是hibernate不使用这个table1.id,因为hibernate使用table1.login作为id(见上面的注释)。但是为什么 SQL Server 试图将外键设置为 table1.id 而不是 table1.login ?

谢谢

【问题讨论】:

【参考方案1】:

以下是 JPA 规范中关于 Id 注释的内容:

9.1.8 Id注解

Id 注释指定 主键属性或字段 实体。 Id 注释可能是 应用于实体或映射 超类。

默认情况下, 假定实体的主键 成为primary的主键 桌子。如果没有 Column 注释是 指定,主键列名 假定为 主键属性或字段。

所以我很想说事情的行为符合规范(login 属性实际上映射到id 列上)。尝试指定Column 注解:

@Id @Column(name = "login")
public String getLogin() 
    return login;

public void setLogin(String login) 
    this.login = login;


我无法重新创建 table1,因为这是一个现有的表。我必须使用 DLL 中的 alter table 选项:“alter table table2 add constraint FK1751F2B3CEB31922 foreign key (table1_login) references table1”,我更想要参照完整性。

为了澄清,这里是***关于外键的说法:外键标识一个(引用)表中的一个列或一组列,它引用另一个(引用)表中的一组列。引用表中的列必须是被引用表中的主键或其他候选键

所以,虽然你不能应用上面的alter语句(table1_login不能引用table1的id,你可以在table1中使login唯一并创建一个FK将引用 login 的约束。类似的东西:

ALTER TABLE table2
ADD CONSTRAINT FK_table2_table1
FOREIGN KEY (table1_login)
REFERENCES table1(login)

这假设您在 table1 中的登录上添加了 UNIQUE 约束。

另见

FOREIGN KEY Constraints

【讨论】:

感谢您的建议,但这种可能的解决方案不起作用。仍然收到错误:列 'table1.id' 与引用外键 'FK1751F2B3CEB31922' 中的列 'table2.table1_login' 的数据类型不同立即开始赏金 我无法重新创建 table1,因为这是一个现有的表。我必须使用 DLL 中的 alter table 选项:“alter table table2 add constraint FK1751F2B3CEB31922 foreign key (table1_login) references table1”,我更想要参照完整性。但是,如果您说这是不可能的,那么我必须寻找其他解决方案。奇怪的是这个问题并没有出现在Mysql btw 不,你是对的,那么存在 FK 约束没有任何意义我不知道在 MSSql 中,FK 总是必须约束另一个表的主键。因为这似乎不在 MySQL InnoDB 中。再次感谢您的解释 @michel 我部分错了,外键可以也引用UNIQUE列,而不仅仅是PK。我已经相应地更新了我的答案,并提供了在 PK 之外的另一列上创建 FK 约束的语法(但你需要使 login 唯一,这无论如何都是有意义的)。 登录始终是唯一的密钥...这很奇怪。当它不是时,我已经注意到错误。然后您会收到参考列不是候选键或主键的消息【参考方案2】:

编辑:

仔细阅读消息后,我发现了这个......

“table1.id”与引用列“table2.table1_login”的数据类型不同

Table1.ID -> table2.table1_login

ID 和登录名不是相同的数据类型。所以周围有一个错误的PK-FK关系......


这听起来像是您使用了错误的collation。两列都需要相同的排序规则。否则你不能加入他们。

http://msdn.microsoft.com/en-us/library/aa174903(SQL.80).aspx

确保删除数据库创建脚本上所有明确设置的排序规则。

【讨论】:

我已经想到了,但这不是问题。但是列具有代表“Latin1_General”的属性“数据库默认值”,我在列属性上检查了这一点。 评论您的编辑:我注意到了这一点。但是为什么要尝试休眠来引用 table.id 而不是 table1.login 如注释配置 'referencedColumnName = "login"' 中所述?如果我将 table1 的主键从“id”更改为“login”,那么问题就不存在了。但不幸的是,这是不可能的,因为 table1.id 必须是 table1 的主键,并且我的应用程序中的 manyToOne 映射需要从 table2.table1_login 的 table1.login 上设置 那么你需要让 table1.login 成为你的主键或一个唯一的列,至少我会说...... 正如我所说:“但不幸的是,这是不可能的,因为 table1.id 必须是 table1 的主键,并且我的应用程序中的 manyToOne 映射需要在 table2.table1_login 的 table1.login 上设置" 并且 table1.login 已经有一个唯一的键约束。但这无济于事。但无论如何感谢您的帮助!

以上是关于在 SQL Server 中的非主键上添加 @ManyToOne 映射时出现问题的主要内容,如果未能解决你的问题,请参考以下文章

如何使用 JPA 和 Hibernate 在非主键上连接表

SQL Server 使用没有主键的聚集索引创建表

如何在辅助表中的非主键列上连接表?

数据库常见面试问题

数据库常见面试题总结

数据库知识点总结