私も PostgreSQLで同じ問題を感じていますが、Hibernateのマニュアルには、下のように説明が有って、対応できるように書いてあります。
此方では、ちょっと不注意にOSのバージョンアップをしてしまい、javaが死んでいるので、確認できていませんが、試していただければ、幸いです。
以下マニュアルの該当部分です。
URL: http://www.hibernate.org/hib_docs/annotations/reference/en/html_single/#d0e2246
2.4.3.6. Generated properties
Some properties are generated at insert or update time by your database. Hibernate can deal with such properties and triggers a subsequent select to read these properties.
@Entity
public class Antenna {
@Id public Integer id;
@Generated(GenerationTime.ALWAYS) @Column(insertable = false, updatable = false)
public String longitude;
@Generated(GenerationTime.INSERT) @Column(insertable = false)
public String latitude;
}
Annotate your property as @Generated You have to make sure your insertability or updatability does not conflict with the generation strategy you have chosen. When GenerationTime.INSERT is chosen, the property must not contains insertable columns, when GenerationTime.ALWAYS is chosen, the property must not contains insertable nor updatable columns.
@Version properties cannot be @Generated(INSERT) by design, it has to be either NEVER or ALWAYS.
_______________________________________________
Japan-jbug-seam mailing list
Japan-j...@lists.sourceforge.jp
http://lists.sourceforge.jp/mailman/listinfo/japan-jbug-seam
ご教示ありがとうございます。
Ken Yamada wrote:
> 山田です。
>
> 私も PostgreSQLで同じ問題を感じていますが、Hibernateのマニュアルには、下のように説明が有って、対応できるように書いてあります。
> 此方では、ちょっと不注意にOSのバージョンアップをしてしまい、javaが死んでいるので、確認できていませんが、試していただければ、幸いです。
>
(snip)
>
> @Generated(GenerationTime.INSERT) @Column(insertable = false)
> public String latitude;
早速試してみたのですが、色々と問題がありそうです。(使い方を間違えている
のかもしれないけど)
・@Generatedを書いても、適当な値をセットしてやらないとem.persistメソッド
を発行した時点でエラーが出る
・逆に適当な値をセットしてやってもPostgreSQL側のログで発行されたinsert文
を確認すると、@Generatedが書かれているカラムについては無視されてしまう。
・さらに、em.mergeメソッドでupdate文を発行する際にも@Generatedが書かれて
いるカラムについてはセットした値を無視されてしまう。
・つまり、デフォルト値以外の値をセットしたい場合には非常に困る
あるべき姿は
・@Geneareted(INSERT)アノテーションを書いてあるカラムについては値をセッ
トしなくても良いはず
・値を明示的にセットすれば反映される
・update文には影響しない
と思ってしまいますがそうではないようですね・・・・。
まだクラス変数自体にデフォルト値を書く方が・・・という感じです。
というか、やっぱりDDLから自動的に変換したくなりますね。
以上
試した方法
1) Usersというテーブルを作る(PostgreSQL8.2)
CREATE TABLE USERS (
ID SERIAL,
NAME TEXT NOT NULL,
ADDRESS TEXT NOT NULL,
EMAIL TEXT,
TEL TEXT,
PRIMARY KEY(ID)
);
2) seam setup/new-project/generate-entities で CRUD を作る。
3) 取り敢えず CRUDの動作を確認する。ーー> OK
4) src/model にある Users.javaのIdの所に @Generated(GenerationTime.ALWAYS)を
追加する。
============= Users.java 抜粋 ==============
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.Id;
import javax.persistence.Table;
import org.hibernate.annotations.Generated;
import org.hibernate.annotations.GenerationTime;
import org.hibernate.validator.NotNull;
/**
* Users generated by hbm2java
*/
@Entity
@Table(name = "users", schema = "public")
public class Users implements java.io.Serializable {
private int id;
private String name;
private String address;
private String email;
private String tel;
public Users() {
}
public Users(int id, String name, String address) {
this.id = id;
this.name = name;
this.address = address;
}
public Users(int id, String name, String address, String email, String tel) {
this.id = id;
this.name = name;
this.address = address;
this.email = email;
this.tel = tel;
}
@Id
@Generated(GenerationTime.ALWAYS) <--- 追加
@Column(name = "id", unique = true, nullable = false, insertable=false, updatable=false)
@NotNull
public int getId() {
return this.id;
}
public void setId(int id) {
this.id = id;
}
: : :
}
5) Compile/deploy/restartする。
Server.logに以下のように出てきて、idを処理する所でエラーとなりpersistenceが作られない
: : :
2007-07-01 18:55:24,024 INFO [org.hibernate.cfg.AnnotationBinder] Binding entity from annotated class: jp.tydfam.test1.Users
2007-07-01 18:55:24,025 INFO [org.hibernate.cfg.annotations.EntityBinder] Bind entity jp.tydfam.test1.Users on table users
2007-07-01 18:55:24,024 INFO [org.hibernate.cfg.AnnotationBinder] Binding entit
y from annotated class: jp.tydfam.test1.Users
s hbm files
2007-07-01 18:55:24,024 INFO [org.hibernate.cfg.AnnotationBinder] Binding entit
y from annotated class: jp.tydfam.test1.Users
2007-07-01 18:55:24,025 INFO [org.hibernate.cfg.annotations.EntityBinder] Bind
entity jp.tydfam.test1.Users on table users
2007-07-01 18:55:24,025 DEBUG [org.hibernate.cfg.AnnotationBinder] Processing jp
.tydfam.test1.Users property annotation
2007-07-01 18:55:24,026 DEBUG [org.jboss.mx.loading.RepositoryClassLoader] setRe
pository, repository=org.jboss.mx.loading.HeirarchicalLoaderRepository3@2aabf8,
cl=org.jboss.mx.loading.HeirarchicalLoaderRepository3$CacheClassLoader@fe7a67{ u
rl=null ,addedOrder=0}
2007-07-01 18:55:24,026 DEBUG [org.jboss.mx.loading.RepositoryClassLoader] setRe
pository, repository=org.jboss.mx.loading.HeirarchicalLoaderRepository3@2aabf8,
cl=org.jboss.mx.loading.HeirarchicalLoaderRepository3$CacheClassLoader@11633fd{
url=null ,addedOrder=0}
2007-07-01 18:55:24,027 DEBUG [org.jboss.mx.loading.RepositoryClassLoader] setRepository, repository=org.jboss.mx.loading.HeirarchicalLoaderRepository3@2aabf8, cl=org.jboss.mx.loading.HeirarchicalLoaderRepository3$CacheClassLoader@af683a{ url=null ,addedOrder=0}
2007-07-01 18:55:24,029 DEBUG [org.jboss.mx.loading.RepositoryClassLoader] setRepository, repository=org.jboss.mx.loading.HeirarchicalLoaderRepository3@2aabf8, cl=org.jboss.mx.loading.HeirarchicalLoaderRepository3$CacheClassLoader@a211cf{ url=null ,addedOrder=0}
2007-07-01 18:55:24,031 DEBUG [org.hibernate.cfg.AnnotationBinder] Processing annotations of jp.tydfam.test1.Users.id
2007-07-01 18:55:24,032 DEBUG [org.hibernate.cfg.Ejb3Column] Binding column id unique true
2007-07-01 18:55:24,032 DEBUG [org.hibernate.cfg.AnnotationBinder] id is an id
2007-07-01 18:55:24,032 DEBUG [org.hibernate.cfg.annotations.SimpleValueBinder] building SimpleValue for id
2007-07-01 18:55:24,032 DEBUG [org.hibernate.cfg.annotations.PropertyBinder] Building property id
2007-07-01 18:55:24,032 DEBUG [org.jboss.ejb3.ServiceDelegateWrapper] Starting failed persistence.units:ear=test1.ear,unitName=test1
java.lang.NullPointerException
at org.hibernate.cfg.annotations.PropertyBinder.make(PropertyBinder.java:145)
at org.hibernate.cfg.AnnotationBinder.bindId(AnnotationBinder.java:1738)
at org.hibernate.cfg.AnnotationBinder.processElementAnnotations(AnnotationBinder.java:1180)
at org.hibernate.cfg.AnnotationBinder.bindClass(AnnotationBinder.java:710)
at org.hibernate.cfg.AnnotationConfiguration.processArtifactsOfType(AnnotationConfiguration.java:452)
at org.hibernate.cfg.AnnotationConfiguration.secondPassCompile(AnnotationConfiguration.java:268)
at org.hibernate.cfg.Configuration.buildMappings(Configuration.java:1115)
at org.hibernate.ejb.Ejb3Configuration.buildMappings(Ejb3Configuration.java:1233)
at org.hibernate.ejb.EventListenerConfigurator.configure(EventListenerConfigurator.java:154)
at org.hibernate.ejb.Ejb3Configuration.configure(Ejb3Configuration.java:869)
at org.hibernate.ejb.Ejb3Configuration.configure(Ejb3Configuration.java:407)
at org.hibernate.ejb.HibernatePersistence.createContainerEntityManagerFactory(HibernatePersistence.java:126)
at org.jboss.ejb3.entity.PersistenceUnitDeployment.start(PersistenceUnitDeployment.java:246)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
at java.lang.reflect.Method.invoke(Method.java:585)
at org.jboss.ejb3.ServiceDelegateWrapper.startService(ServiceDelegateWrapper.java:103)
at org.jboss.system.ServiceMBeanSupport.jbossInternalStart(ServiceMBeanSupport.java:289)
at org.jboss.system.ServiceMBeanSupport.jbossInternalLifecycle(ServiceMBeanSupport.java:245)
at sun.reflect.GeneratedMethodAccessor3.invoke(Unknown Source)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
at java.lang.reflect.Method.invoke(Method.java:585)
at org.jboss.mx.interceptor.ReflectedDispatcher.invoke(ReflectedDispatcher.java:155)
at org.jboss.mx.server.Invocation.dispatch(Invocation.java:94)
at org.jboss.mx.server.Invocation.invoke(Invocation.java:86)
at org.jboss.mx.server.AbstractMBeanInvoker.invoke(AbstractMBeanInvoker.java:264)
at org.jboss.mx.server.MBeanServerImpl.invoke(MBeanServerImpl.java:659)
at org.jboss.system.ServiceController$ServiceProxy.invoke(ServiceController.java:978)
at $Proxy0.start(Unknown Source)
at org.jboss.system.ServiceController.start(ServiceController.java:417)
at sun.reflect.GeneratedMethodAccessor9.invoke(Unknown Source)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
at java.lang.reflect.Method.invoke(Method.java:585)
at org.jboss.mx.interceptor.ReflectedDispatcher.invoke(ReflectedDispatcher.java:155)
at org.jboss.mx.server.Invocation.dispatch(Invocation.java:94)
at org.jboss.mx.server.Invocation.invoke(Invocation.java:86)
at org.jboss.mx.server.AbstractMBeanInvoker.invoke(AbstractMBeanInvoker.java:264)
at org.jboss.mx.server.MBeanServerImpl.invoke(MBeanServerImpl.java:659)
at org.jboss.mx.util.MBeanProxyExt.invoke(MBeanProxyExt.java:210)
at $Proxy123.start(Unknown Source)
at org.jboss.ejb3.JmxKernelAbstraction.install(JmxKernelAbstraction.java:120)
at org.jboss.ejb3.Ejb3Deployment.startPersistenceUnits(Ejb3Deployment.java:551)
at org.jboss.ejb3.Ejb3Deployment.start(Ejb3Deployment.java:333)
at org.jboss.ejb3.Ejb3Module.startService(Ejb3Module.java:91)
at org.jboss.system.ServiceMBeanSupport.jbossInternalStart(ServiceMBeanSupport.java:289)
at org.jboss.system.ServiceMBeanSupport.jbossInternalLifecycle(ServiceMBeanSupport.java:245)
at sun.reflect.GeneratedMethodAccessor3.invoke(Unknown Source)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
at java.lang.reflect.Method.invoke(Method.java:585)
at org.jboss.mx.interceptor.ReflectedDispatcher.invoke(ReflectedDispatcher.java:155)
at org.jboss.mx.server.Invocation.dispatch(Invocation.java:94)
at org.jboss.mx.server.Invocation.invoke(Invocation.java:86)
at org.jboss.mx.server.AbstractMBeanInvoker.invoke(AbstractMBeanInvoker.java:264)
at org.jboss.mx.server.MBeanServerImpl.invoke(MBeanServerImpl.java:659)
at org.jboss.system.ServiceController$ServiceProxy.invoke(ServiceController.java:978)
: : :
(以下省略)
これで、
a) Unique Id はDBのsequenceで作られたものを select nextvalue('xxx')で取得して使う。
PostgreSQLのserialでは、冗長な動作となるけど、諦める。(PostgreSQL独自なので、
対応は期待できない?)
システムが振るIdなので、ここに勝手に書き込むことは出来ない、エラーになる。
seam-gen が作ったdefaultの入力画面では、0が表示されていますが、これを消してしまうと、
「Nullはダメだよ!」というエラーが出ます。また、勝手な値を入れると debug.pageへ飛ん
でしまいます。(これは入力出来ないようにしておくべきなので、これでも良しとする)。
b) triggerを利用したtimestampはDBでinsert/updateの時に付けられる。強制的に値
を入れても、システムのtriggerで作られた値で上書きされる(エラーは出ない)。
といった動作をしています。
マニュアルの読み方が十分でなかった為に、余計なご迷惑を掛けたかもしれません。失礼しました。
使用したPostgreSQLのテーブル
Table "public.users"
Column | Type | Modifiers
-----------+---------+----------------------------------------------------
id | integer | not null default nextval('users_id_seq'::regclass)
name | text | not null
address | text | not null
email | text |
tel | text |
last_user | name |
last_date | date |
Indexes:
"users_pkey" PRIMARY KEY, btree (id)
Triggers:
user_stamp BEFORE INSERT OR UPDATE ON users FOR EACH ROW EXECUTE PROCEDURE user_stamp()
使用した Users.java (Entity Bean)
package jp.tydfam.test1;
// Generated 2007/07/05 20:19:51 by Hibernate Tools 3.2.0.b9
import java.util.Date;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.SequenceGenerator;
import javax.persistence.Table;
import javax.persistence.Temporal;
import javax.persistence.TemporalType;
import org.hibernate.annotations.Generated;
import org.hibernate.annotations.GenerationTime;
import org.hibernate.validator.NotNull;
/**
* Users generated by hbm2java
*/
@Entity
@Table(name = "users", schema = "public")
public class Users implements java.io.Serializable {
private int id;
private String name;
private String address;
private String email;
private String tel;
private String lastUser;
private Date lastDate;
public Users() {
}
: : :
@Id
@GeneratedValue(strategy=GenerationType.SEQUENCE, generator="SEQ_GEN")
@SequenceGenerator(name="SEQ_GEN",sequenceName="users_id_seq", allocationSize=1)
//上の2行を seam-genで作られたコードに追加 sequenceNameはDBのsequenceの名前
// allocationSizeの意味がよくわかっていませんが、、、、
@Column(name = "id", unique = true, nullable = false, insertable=false,updatable=false)
@NotNull
public int getId() {
return this.id;
}
public void setId(int id) {
this.id = id;
}
: : :
: : : (省略)
: : :
@Column(name = "last_user")
public String getLastUser() {
return this.lastUser;
}
public void setLastUser(String lastUser) {
this.lastUser = lastUser;
}
@Temporal(TemporalType.DATE)
@Generated(GenerationTime.ALWAYS)
// 上の1行を追加
@Column(name = "last_date", length = 13, insertable=false, updatable=false)
// GenerationTime.ALWAYS/INSERT に対応して、
insertable/updatableにfalseを指定しないとエラーになる。
public Date getLastDate() {
return this.lastDate;
}
public void setLastDate(Date lastDate) {
this.lastDate = lastDate;