我有一个sprint引导1.1.4.RELEASE应用程序,它使用liquibase和postgresql。
我有两个实体:
@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_
我认为我的映射很好,Menu包含许多双向关系的MenuItems。我还有一些其他映射由于相同类型的问题而失败,并且这些映射在关系错误名称中有下划线而不是驼色大小写;这让我怀疑这是否是我使用spring.jpa.hibernate.ejb.naming_strategy=org.hibernate.cfg.EJB3NamingStrategy的副作用
基于"a_hors_with_no_name"的优秀建议,我通过SQL手动创建了菜单表,但没有引号,我得到了另一个错误:
Caused by: org.postgresql.util.PSQLException: ERROR: column menu0_.menu_id does not exist
这也是一个case问题,所以我一定是错误地配置了Liquibase,告诉Postgresql忽略case和camelcase。
我在我的变更日志中尝试了以下操作:
objectQuotingStrategy="LEGACY"
objectQuotingStrategy="QUOTE_ALL_OBJECTS"
objectQuotingStrategy="QUOTE_ONLY_RESERVED_WORDS"
三者都用引号创建了我的表和列。
好吧,我已经解决了所有的问题,并正在发布,以防其他人也有同样的问题。看起来Spring Boot或其他什么东西希望列名有下划线,而不是camelCase。我把我的利口酒变更集改为:
<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的新手,所以我不能说这是因为它区分大小写还是问题所在。我很想听听这是否正确,或者我是否在哪里犯了错误。