【问题标题】:spring-boot foreign key not found找不到spring-boot外键
【发布时间】:2014-11-03 14:30:01
【问题描述】:

我有一个使用 liquibase 和 postgresql 的 sprint-boot 1.1.4.RELEASE 应用程序。

我有两个实体:

@Entity
public class Menu {

    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    private long menuId;

    @OneToMany(cascade = CascadeType.ALL, mappedBy = "menu", fetch = FetchType.EAGER)
    private List<MenuItem> menuItems = new ArrayList<MenuItem>();

    @ManyToOne
    @JoinColumn(name = "subscriptionPackageId", nullable = false)
    private SubscriptionPackage subscriptionPackage;

    private String displayText;
    private int displayOrder;

@Entity
public class MenuItem {

    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    private long menuItemId;

    private String displayText;
    private String path;
    private String toolTip;
    private int displayOrder;

    @ManyToOne(fetch = FetchType.EAGER, cascade = CascadeType.ALL)
    @JoinColumn(name = "menuId", nullable = false)
    private Menu menu;

    @Enumerated(EnumType.STRING)
    @Column(name = "callType", nullable = false)
    private HttpType callType;

我的 db.changelog-master.xml 中有以下内容:

    <databaseChangeLog
        xmlns="http://www.liquibase.org/xml/ns/dbchangelog"
        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
        xsi:schemaLocation="http://www.liquibase.org/xml/ns/dbchangelog http://www.liquibase.org/xml/ns/dbchangelog/dbchangelog-3.0.xsd"
        objectQuotingStrategy="QUOTE_ALL_OBJECTS">

    <changeSet id="1" author="me" >
        <preConditions onFail="MARK_RAN">
            <not>
                <tableExists tableName="SubscriptionPackage"/>
                <tableExists tableName="Menu"/>
                <tableExists tableName="MenuItem"/>
            </not>
        </preConditions>

        <createSequence sequenceName="hibernate_sequence"/>

        <createTable tableName="SubscriptionPackage">
            <column name="subscriptionPackageId" type="bigint" autoIncrement="true">
                <constraints primaryKey="true"/>
            </column>
            <column name="servicePackage" type="varchar(300)"/>
            <column name="description" type="varchar(500)"/>
        </createTable>


        <createTable tableName="Menu">
            <column name="menuId" type="bigint" autoIncrement="true">
                <constraints primaryKey="true"/>
            </column>
            <column name="subscriptionPackageId" type="bigint"/>
            <column name="displayText" type="varchar(300)"/>
            <column name="displayOrder" type="int"/>
        </createTable>

        <createTable tableName="MenuItem">
            <column name="menuItemId" type="bigint" autoIncrement="true">
                <constraints primaryKey="true"/>
            </column>
            <column name="menuId" type="bigint">
                <!--<constraints foreignKeyName="fk_menu_item" references="Menu(menuId)"/>-->
            </column>
            <column name="displayText" type="varchar(100)"/>
            <column name="path" type="varchar(100)"/>
            <column name="toolTip" type="varchar(500)"/>
            <column name="displayOrder" type="int"/>
            <column name="callType" type="varchar(50)"/>
        </createTable>
    </changeSet>
</databaseChangeLog>

在启动时执行,postgresql 向我显示了表的以下 sql:

CREATE TABLE "Menu"
(
  "menuId" bigserial NOT NULL,
  "subscriptionPackageId" bigint,
  "displayText" character varying(300),
  "displayOrder" integer,
  CONSTRAINT pk_menu PRIMARY KEY ("menuId")
)

CREATE TABLE "MenuItem"
(
  "menuItemId" bigserial NOT NULL,
  "menuId" bigint,
  "displayText" character varying(100),
  path character varying(100),
  "toolTip" character varying(500),
  "displayOrder" integer,
  "callType" character varying(50),
  CONSTRAINT pk_menuitem PRIMARY KEY ("menuItemId"),
  CONSTRAINT fk_menu_item FOREIGN KEY ("menuId")
      REFERENCES "Menu" ("menuId") MATCH SIMPLE
      ON UPDATE RESTRICT ON DELETE CASCADE
)

我有一个 MenuRepository:

@Repository
public interface MenuRepository extends CrudRepository<Menu, Long> {
    List<Menu> findAll();
    List<Menu> findBySubscriptionPackage( SubscriptionPackage subscriptionPackage);
}

在启动时,以下行导致异常:

List<Menu> menus = menuRepository.findAll()

这是:

Caused by: org.postgresql.util.PSQLException: ERROR: relation "menu" does not exist
  Position: 166
    at org.postgresql.core.v3.QueryExecutorImpl.receiveErrorResponse(QueryExecutorImpl.java:2102)

正在提交的sql是:

select menu0_.menu_id as menu_id1_0_, menu0_.display_order as display_2_0_, menu0_.display_text as display_3_0_, menu0_.subscription_package_id as subscrip4_0_ from menu menu0_

我认为我的映射很好,菜单包含许多双向关系的菜单项。我有一些其他映射因相同类型的问题而失败,并且关系错误名称中有下划线而不是驼峰式大小写;这让我想知道这是否是我使用 spring.jpa.hibernate.ejb.naming_strategy=org.hibernate.cfg.EJB3NamingStrategy

的副作用

根据“a_horse_with_no_name”的优秀建议,我通过不带引号的 SQL 手动创建了 Menu 表,但又遇到了另一个错误:

Caused by: org.postgresql.util.PSQLException: ERROR: column menu0_.menu_id does not exist

这也是一个大小写问题,所以我必须错误地配置 Liquibase 来告诉 Postgresql 忽略大小写和驼峰式。

我在变更日志中尝试了以下内容:

objectQuotingStrategy="LEGACY"
objectQuotingStrategy="QUOTE_ALL_OBJECTS"
objectQuotingStrategy="QUOTE_ONLY_RESERVED_WORDS"

所有三个都用引号创建我的表和列。

【问题讨论】:

  • 您使用带引号的标识符创建了表,这意味着它们现在区分大小写。 "Menu" 是与 menu 不同的表名。我建议重新创建不带任何引号的所有表。从长远来看,这会给您带来更少的麻烦。
  • 我看不到我在哪里创建了带引号的表格。我在 XML 中为 liquibase 定义了它们。你的意思是这是一个区分大小写的问题,我应该使用 @Table(name="menu") 或其他什么这样的情况是正确的?我不确定我是否理解你的意思。
  • CREATE TABLE "MenuItem" - 也许这是你在 Liquibase 中定义它们的方式。
  • 我不知道如何告诉 Liquibase 在没有它的情况下创建数据库表。如果我理解你,我的表和实体被命名为“菜单”,而关系是“菜单”?我有另一个错误,表是 SubscriptionPackage,缺少关系是“subscription_package”,这也是区分大小写的问题吗?
  • 好的,所以我通过不带引号的 SQL 手动创建了菜单表,这让我克服了那个错误,然后出现了其他错误:错误:列 menu0_.menu_id 不存在所以这看起来像引用/案例/camelCase 问题。当我使用 Liquibase 创建和管理我的数据库时,我做错了什么?我将更新我的问题以显示整个更改文件。

标签: postgresql spring-boot liquibase


【解决方案1】:

好的,我已经解决了所有问题并发布了以防其他人遇到同样的问题。似乎 Spring-Boot 或其他东西期望列名具有下划线而不是 camelCase。我将 liquibase 变更集更改为:

 <createTable tableName="MENU">
            <column name="menu_id" type="bigint" autoIncrement="true">
                <constraints primaryKey="true"/>
            </column>
            <column name="subscription_package_id" type="bigint"/>
            <column name="display_text" type="varchar(300)"/>
            <column name="display_order" type="int"/>
        </createTable>

然后我还必须将每个实体上的表名声明为:

@Entity
@Table(name = "MENU")
public class Menu {
...
}

实体案例之间有一个“_”。我不知道是否有办法覆盖它,或者即使我应该,就像我对 EJBNamingStrategy 所做的那样。我在任何地方都找不到它的文档,但我碰巧在 spring-boot flyway 项目的集成测试中注意到了它。

这感觉不对,我不记得之前必须在实体上声明表名,但我是 Postgresql 的新手,所以我不能说它是因为它区分大小写还是问题出在哪里。如果这是正确的,或者我是否在某个地方犯了错误,我很想听听。

【讨论】:

    猜你喜欢
    • 2020-08-01
    • 2015-08-15
    • 2020-07-31
    • 2020-11-11
    • 2017-10-11
    • 2021-03-14
    • 2017-06-28
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多