我有:
一个由一个最简单的表组成的模式" proba":
CREATE TABLE proba( id bigint NOT NULL, 值字符变化(255), CONSTRAINT proba_pkey PRIMARY KEY(id) )
一个简单的主要方法:
public static void main(String[] args) {
ServerRuntime runtime = ServerRuntimeBuilder.builder()
.addConfig("cayenne-project.xml")
.build();
ObjectContext ctx = runtime.newContext();
CayenneDataObject newObject = new CayenneDataObject();
newObject.writeProperty("value", "proba1");
ctx.registerNewObject(newObject);
ctx.commitChanges();
}
一个简单的cayenne-project.xml:
<?xml version="1.0" encoding="utf-8"?>
<domain project-version="7">
<map name="datamap"/>
<node name="datanode"
factory="org.apache.cayenne.configuration.server.XMLPoolingDataSourceFactory"
schema-update-strategy="org.apache.cayenne.access.dbsync.SkipSchemaUpdateStrategy">
<map-ref name="datamap"/>
<data-source>
....
</data-source>
</node>
</domain>
一个简单的datamap.map.xml(hand-maded):
<?xml version="1.0" encoding="utf-8"?>
<data-map xmlns="http://cayenne.apache.org/schema/7/modelMap"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://cayenne.apache.org/schema/7/modelMap http://cayenne.apache.org/schema/7/modelMap.xsd"
project-version="7">
<property name="defaultPackage" value="ru.xxx"/>
<property name="defaultSchema" value="public"/>
<db-entity name="proba" schema="public">
<db-attribute name="id" type="BIGINT" isPrimaryKey="true" isGenerated="false" length="19"/>
<db-attribute name="value" type="VARCHAR" length="255"/>
</db-entity>
<obj-entity name="Proba" dbEntityName="proba">
<obj-attribute name="value" type="java.lang.String" db-attribute-path="value"/>
</obj-entity>
</data-map>
尝试一下,我得到了以下输出:
INFO: --- transaction started.
Nov 15, 2016 5:06:26 PM org.apache.cayenne.log.CommonsJdbcEventLogger logQuery
INFO: SELECT nextval('public.pk_proba')
Exception in thread "main" org.apache.cayenne.CayenneRuntimeException: [v.4.0.M3 Feb 08 2016 16:38:05] Commit Exception
at org.apache.cayenne.access.DataContext.flushToParent(DataContext.java:776)
at org.apache.cayenne.access.DataContext.commitChanges(DataContext.java:693)
at com.echelon.proba.cayenne.Main.main(Main.java:27)
Caused by: org.postgresql.util.PSQLException: ERROR: relation "public.pk_proba" does not exist
Position: 16
at org.postgresql.core.v3.QueryExecutorImpl.receiveErrorResponse(QueryExecutorImpl.java:2458)
at org.postgresql.core.v3.QueryExecutorImpl.processResults(QueryExecutorImpl.java:2158)
所以,cayenne期待一个名为pk_proba的序列。为什么?我的意思并不是要生成它。我既没有在我的模式中也没有在Cayenne映射中提到任何postgresql序列。
所以,我有两个问题:
答案 0 :(得分:1)
TL; DR:&#34; pk_proba&#34;是用于生成PK的序列的默认名称。如果你想让Cayenne默认的PK机制起作用,你需要在PostgreSQL中提供特殊的序列。
更长的版本。您需要以这种或那种方式为每个插入的对象提供PK。 Cayenne PK生成算法大致如下:
最后一个策略要求您准备DB对象。 Cayenne根据目标DB使用不同的策略。对于PostgreSQL,它将是序列。在Modeler中转到&#34;工具&gt;生成数据库模式&#34;并取消选中除&#34;创建主键支持&#34;之外的所有复选框。然后使用生成的SQL更新数据库。
现在,如果你确实希望Cayenne在第4步失败(为什么呢?你确实希望你的插入成功),你可以使用自定义PkGenerator。以下是使用自定义DI模块通过依赖注入加载它的方法:
class CustomAdapterFactory extends DefaultDbAdapterFactory {
public CustomAdapterFactory(
@Inject("cayenne.server.adapter_detectors")
List<DbAdapterDetector> detectors) {
super(detectors);
}
@Override
public DbAdapter createAdapter(
DataNodeDescriptor nodeDescriptor,
DataSource dataSource) throws Exception {
AutoAdapter adapter =
(AutoAdapter) super.createAdapter(nodeDescriptor, dataSource);
// your PkGenerator goes here
adapter.setPkGenerator(...);
return adapter;
}
}
// add this when creating ServerRuntime
Module module = new Module() {
@Override
public void configure(Binder binder) {
binder.bind(DbAdapterFactory.class).to(CustomAdapterFactory.class);
}
};
不可否认,这可以更容易(我们计划将PkGenerator作为DI服务公开),但它应该可行。只要确保这确实是你需要的。