在 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 映射时出现问题的主要内容,如果未能解决你的问题,请参考以下文章