yamicha.com's Blog - Presented by yamicha.com
Blog yamicha.com's Blog - 2018/12 の記事
[1] [2] [3] [4] [5] [6] [7] [8] [9] [10] [11] [12] [13] [14] [15] [16] [17] [18] [19] [20] [21] [22] [23] [24] [25] [26] [27] [28] [29] [30] [31]

yamicha.com's Blog
 諸事情により、現在更新休止中。ご了承ください。もし今後ブログを再開することがあるとすれば、その際にはこのブログスクリプトではなく、新しく開発したものによるかもしれません。
 当ブログ管理者についてはこちらをご参照。
開発魔法(737)
社会問題(733)
お知らせ(11)
質問・バトン回答(15)
ゲスト出演(8)
経済・知的財産(150)
ゲーム開発(182)
[Ada] 勝手に補足
- Note
- 金配りの次の一手


- Endless Ultimate Diary
- 銃世界

漢字バトン
- うるる雑記帳
- 漢字接力棒

ツキアイゲノムバトン
- ブログ@うにうに画像倉庫
- あぶ内閣

縺イ縺セ縺、縺カ縺励ヰ繝医Φ
- 月夜のボヤキ
- 騎士サーラバトン
パスワードを使う
名無し (2012/02/27)


開発者解放裁判
yamicha.com (2010/03/14)
Winnyに関しては、私も「純白」とまでは考えておりませんし、使用し..

開発者解放裁判
通りすがり (2010/03/08)
winnyに関しては「ダウンロードソフト板」なんてところを拠点に開発..

新型インフルエンザの恐怖
いげ太 (2009/11/03)
> C#などの「int Some(int , int)」は、F#では「(int * int) ->..

時効に関する思考
yamicha.com (2009/08/31)
>いげ太さんコメントありがとうございます。手元にドキュメントが少..
Homepage
Blog Top
Normal View
List View
Search
Calendar
Comment List
Trackback List
Blog RSS
Send Trackback
Phone Mode
Administrator
yamicha.com
Blog
るううるる。
Source
法令データ提供システム
FindLaw
Development
Java2 Platform SE 6
Java EE 6 API
MySQL Developer Zone
PHP Reference
MSDN Library
Ada Reference Manual
Objective Caml
Python Documentation
Erlang
Prolog Documents
教育解欠く
2007/01/19(Fri)21:31:01
 何かもうドタバタ喜劇にしか見えなくなってきた教育改革。まさか世間の人々に笑いを提供し、参院選で支持してもらおうとでも考えているのでしょうか。笑いを提供するのは結構ですが、何も100年の計である教育をネタに使わなくても。
 面白いことに、最近は「いじめ禁止を校則にする」などと言い出しています。そんなものがいじめに効果があるというなら、今ごろこの世にいじめなど存在しないのです。もう少し頭を使えないのでしょうか。
 いじめといえば、いじめ加害者の出席停止などの案が議論されたこともありました。教育再生会議の連中はこうした方法を認める気なのかもしれませんが、実に愚かです。いじめ行為は犯罪行為であり、的確に出席停止を下すことは被害者を守ることにもつながるのですが、それは理想論というものです。実際に出席停止処分を下すなど、何か事件が起こった後でもない限りまず不可能です。
 仮にどこかの学校でいじめが発覚したとしましょう。加害者は出席停止になってもおかしくないのですが、このいじめは多くの人が知っていながら見て見ぬ振りをしていました。さて、「見て見ぬ振り」は無罪でしょうか。これが無罪とすれば、「シカト」と呼ばれる集団無視行為は処分対象にならないのでしょうか(以前の教育再生会議案によれば「見て見ぬ振り」もいじめだそうですが)。
 さらに、集団によるいじめの場合、加害者のうちある人は出席停止、またある人は出席停止にしないとなれば、不公平が生じることは否めません。シカト行為や見て見ぬ振りに対して処分を下す場合はそれがより顕著になります。シカトなどはほぼ全員が加害者になるわけですが、一体誰を出席停止にするのでしょう。全員を出席停止にして学級閉鎖状態にするか、罪の重さは全員ほぼ同等なのに一部のみを出席停止にするか、さもなくば加害者が多いからといって無罪にするか。
 また、いじめには流動的な側面があります。被害者が加害者になったりすることもあるのです。例えば、ここに長年いじめられ続けている被害者Aがいるとしましょう。学校に相談してものれんに腕押し、まるで効果がありません。しかし、ここへ来ていじめ加害者Bが弱い立場に立たされたのです。今までの恨みか、こちらからやらなければいじめられ続けると見たか、現在までの過酷ないじめで精神的に参っていたAはBをいじめ始めました。しかし、それからほどなくいじめが発覚したのです。AからBへの加害行為はすべて発覚しましたが、「Aは以前、執拗にBからいじめられていた」事実については「加害者の主張」ということで信用されなかったり、証拠がなかったりして証明できませんでした。
 過去には、加害者が被害者に命じて授業を混乱させるなどの妨害行為を行わせ、加害者がそれを鎮める演技をすることで、加害者を模範生、被害者をワルであると教師らに印象付けるようないじめもあったそうです。この場合、被害者が「授業妨害」などとして処分を受ける可能性はあっても、加害者は安泰です。被害者が「加害者に命令された」と告白しても、教師はそれを信用しないでしょう。こうしたケースの場合、誰が出席停止となるでしょうか。こうしたことから、出席停止処分などを盛り込むのは理想論であると分かります。
 ちなみに、教育再生会議案によれば、いじめ加害者には「いじめを人間として恥ずべき愚かな行為だと認識させる」そうです。上記のような例においては、おそらくとんちんかんなことになってしまうでしょう。現場を見ておらず、さらに現場を理解しようとしなければ、こういう案をひねり出せるのですか。
 教師免許更新制にはこれまで個人的に賛成でしたが、安倍内閣による更新制には反対しなければなりません。子どものためになる教育を行う教師は評価し、ダメ教師を排除するのであれば、免許更新制は導入されても良いでしょう。しかし、安倍内閣主導の教育を荒廃させるとしか考えられない案を見ていると、「君が代を生徒に強制しない教師にはやめていただく」であったり「内閣の政策に反発したからやめていただく」のような使い方がなされる可能性が非常に高いです。
 それでなくても政府はゆとりと学力重視をコロコロ変えて現場を大混乱させているのです。国旗国歌については答弁で「強制しない」と語られているにもかかわらず、現実はこれです。政府のこうしたバカげた案に対して「そんなものは子どものためにならない」と反論する「真の教師」がまず犠牲になるのです。
 逆に、生徒に何が何でも国歌を歌わせたり、地毛が黒でない人の髪を強引に染めたりするなど、人権侵害もいとわぬ教師が評価されることにもなりかねません。私は教師免許更新制やダメ教師の排除には賛成ですが、安倍内閣のそれには絶対反対です。
 そしてさらに許せないのが「体罰の一部解禁」です。はっきり言っておきますが、現状でも体罰はモグリで散々行われています。それでも体罰禁止の規定は「ケガを負わせて騒ぎになるほどの体罰はまずい」という意識を生み、ひどい体罰をまがりなりにも食い止めています。これのタガを外すとは、気が狂っているとしか考えられません。
 以前にはヨットスクール事件などもありました。「教育か体罰か」で争われたこの事件ですが、概要を調べてみると見れば見るほど教育の名をかたった虐待行為であることが分かります。凶器はかなり殺傷力の高いものが用いられており、また衰弱した人間をいたぶったり、十分な治療を受けさせないなど、もし「教育」などという大義名分がなければ、場合によっては未必の故意が認定されていたかもしれません。石原氏などは加害者を支持していますが、実際にこの事件を可能な限り客観的に想像してみると、かなり凄惨であると言わざるを得ません。
 とはいえ、世の中には「正当防衛的」な体罰もあります。反省のないいじめ加害者への体罰など、一方的に責められないものもあるでしょう。これを「大した理由もなく振るわれる不当体罰」と混同するから意味が分からなくなるのであって、一律に「体罰を行った教師はこの処分」とするのがおかしいのです。
 しかし、体罰を容認するような文言は絶対に含めるべきではありません。世間で問題となる体罰は氷山の一角です。世間で問題になるような大きな体罰の裏には、報道されないほど軽い処分しかなされない体罰が多数存在し、学校や教育委員会にもみ消されて葬り去られた体罰がさらに多数存在し、そもそも全く学校なり親なりが把握しない体罰が星の数ほど存在することを忘れてはいけません。そして、それらの体罰のうち少なからぬものが「正当な理由もなく振るわれる体罰」なのです。
 体罰の制限が軽くなれば、こうした教師が喜ぶだけです。出席停止にしても、世の中には絶対「お前は生意気だから出席停止にしてやろうか」などといった使い方をする教師が1人2人は現れるものなのです。
 さらには「ゆとり脱却」だそうですが、何をバカなことを。学力重視とゆとり教育を何年刻みかでコロコロ変更するなどとは、現場(特に児童・生徒)をバカにしているとしか考えられません。そもそも結果が出るのは数十年後というのに。
 私に言わせれば、これは「ずっと東に理想の教育があり、それを目指してとりあえず北へ出航。寒くなってきたので南に針路変更。今度は暑くなってきたので北へ向かおう」と言っているようなものです。永久に理想の教育に近づくことはできません。針路変更自体が単なる気まぐれであり、しかも今回の針路変更の理由はといえば、船員(国民)の一部が「暑い。ガマンできない」と言い出したからなのです。
 教育バウチャーは今後の検討課題だとか。大学9月入学化とセットの奉仕活動も同様でしょう。バウチャーと学校選択制、さらに学力テストによって学校の戦いが泥沼化し、知識・情緒育成を完全無視して「テストの点を良くするための勉強」を重ねるなどした挙句、無償奉仕活動のせいで「自己利益優先」「他人など無関係」の「堀江人間」を量産しかねない最悪の戦略です。もう安倍内閣には教育に指一本触れて欲しくありません

 しかし、「最近の学生はレベルが低い」というのはおおむね間違っていません。正直なところ、これはゆとり以前からの現象という気がしています。「自民党以外の政党を知らない」「日本が米国と戦争したのを知らない」辺りは極端な例ですが、以前に成人式の話題を書いた通り、少なからぬ学生は向上心がゼロに近いです。自分を向上させる気概もなければ手段もなく、試験勉強で得た知識は終了後に全部忘れると来ています。これではどれほど高度な教育を行っても意味がありません。
 ではどうすれば良いのか。悲しいかな、私はどうも彼らの考えが理解できないため、何とも言いようがありません。私にとっては、彼らが「向上しない自分を嫌悪」しないらしいことが不思議でならないのですから。とにかく、あれが「郵政って分からないけど、小泉さんカッコイイから自民にします」とか称する若者やら、料亭に行きたいタイゾー君やらになるのかと、妙に納得した次第です。
 で、私がそれを目の当たりにした後、絶対に自分を磨くことだけは怠るまいと誓ったのは言うまでもありません。幸い、世界にはバカと同じ数ほど目指すべき人もいるのですから。

 無賃残業合法化制度について、経団連の連中が「残業ゼロ法案と名づけられた時点でダメだった」と言い出しました。すなわち名前さえ違っていれば成立できていただろうと言っているのです。あまりに国民をバカにしています。が、「バカにするな」と言えないのが辛いところです。なぜなら少なからぬ国民は実際そうなのですから
 今回、マスコミは頻繁に「残業代ゼロ法案」の名を用いていました。これは「ホワイトカラー・エグゼンプション」では見出しにしては長すぎ、直訳の「事務職除外」「適用除外」では意味が伝わらないため、「残業代ゼロ」を通称にしていたものと考えられます。仮にもっと短い通称が存在すれば、成立した可能性は少なからず存在します。
 こうなったからには、仮に自民党が参院選で勝ちでもすれば、違う名前を用いて同じものを出してくるでしょう。そして少なからぬ国民は、これらが同じものであると見抜くことができないのです。「ゆとり教育」よりも大きな問題が日本に横たわっているのが分かるでしょう。
 しかし、マスコミが良く用いていた「残業代ゼロ法案」は少々ニュアンスが違う上に意味も弱いです。「残業代ゼロ」では意味が良く伝わりませんし、いわゆるサービス残業のようなものと混同したりと混乱を招きます。こうしたことから、当ブログでは同制度の日本語訳として「無賃残業合法化制度」を当ててきました。「残業代ゼロ法案」よりも様態を的確に表した語です。
 ついでに「敵を知り、己を知れば」ということで、この制度が断念された理由を経団連らの立場からも分析してみましょう。まず「ホワイトカラー〜」というネーミング自体は成功でした。日本では労働者の色分けなど定着しているとは言いがたく、「ホワイトカラー」という言葉から連想されるのは純白や潔白などのプラスイメージのものばかりです。
 マスコミの多くは「white-color exemption」に「ホワイトカラー・エグゼンプション」のカタカナを当てていましたが、この「エグゼンプション」にしても語感は良いです。スペルはかなり違うのに、カタカナでは「エグゼクティブ」「エグゼキューター」といった言葉にも似ています。このように、言葉のイメージは良いのですから、この時点では制度が成立に向けて有利に進むと踏んでいたのでしょう。
 しかし、問題は正式名称があまりに長すぎることです。「エアー・コンディショナー」を「エアコン」と略すようなタイプの略し方はなく、かといって直訳では「白色除外」のような意味不明な言葉になるためとても使えません。マスコミが良く用いていたのは「適用除外」でしたが、やはり意味不明です。
 新聞という旧時代的メディアにおいては、見出しの文字数が多すぎたり、意味不明になるのは致命的です。そこで、内容を簡潔に表す言葉を作る必要に迫られ、生まれたのが「残業代ゼロ法案」や「残業代不払い法案」というわけです。余談ながら、昔は「ホップ・ステップ・ジャンプ」にも適切な翻訳語がなく、各社とも珍妙な略語を使うなどして苦労していたようですが、いつしか「三段跳び」という訳が生まれ、これが適切すぎて定着したようです。いわば、これと同じ現象が発生したのです。
 ですから、もし経団連などこの制度の導入をもくろむ人間が、「日本版ホワイトカラー・エグゼンプション制度」という正式名称と同時に、制度の概要を簡潔に表す上にマイナスイメージのない短い言葉を定め、これをマスコミが多用していたら、きっとこの制度は成立してしまっていたでしょう。せめて経団連などの連中が次にこの戦略を使ってきた時には絶対だまされないようにしたいものです。
 もちろん当ブログでは、連中が今後似たような制度を「美しい」略称付きで出してきたとしても、遠慮なく「無賃残業合法化制度」と呼んで差し上げます。

 複合キー。ああ、何と美しい響きでしょう(どこがと問われると困りますが)。どういうものかといいますと、
Table : type
PRIMARY(number)
number	name
1	資産
2	負債
...

Table : category
PRIMARY KEY(type , number) 
FOREIGN KEY(type) REFERENCES type(number)
type	number	name
1	1	現金
1	2	当座預金
1	3	受取手形
2	1	当座借越
2	2	買掛金
2	3	社債
2	4	支払手形
...
 こういうものです。普通、PRIMARY KEYされたカラムは同じ値を持つことができないのですが、複合キーの場合は「複合キーに指定されたカラムすべての値が一致」する場合でなければエラーになりません。意味はおおむね見ての通りで、この場合には「負債の勘定における登録番号2番の勘定は買掛金である」と表現することができます。
 複合キーはこれで結構便利ですので、私もたびたび使用しています。その名の通り複合キーにはインデックスが作られるのですが、このインデックスは特殊であり、例えば「PRIMARY KEY(k1 , k2)」とした場合、k2単体をキーにしてデータを探すなどした場合にはインデックスは使われません。k1だけ、またはk1とk2の両方を使ってデータを探した場合のみインデックスが使われます。
 私のつたない経験上、この場合にインデックスを用いない検索が発生する可能性が存在し、k2に対しても独立したインデックスを作らなければならないような場合は、複合キーを使用すべきではありません。そうでない場合には結構便利ではないでしょうか。ただ単にデータを登録するだけであれば複合キーである必要はありませんが、例えば上記のように勘定の種類ごとに番号を当てており、「資産の勘定のみを取得したい」のようなニーズが存在する場合には、複合キーの利便性は高いです。場合によっては複合キーにせず、PRIMARY KEYは通し番号に使い、別のインデックスカラムを使ってリレーする方法も考えられるべきですが(AUTO INCREMENTを使いたい時はこちらでしょうし)。
 ちなみに今回の場合、このcategoryテーブルのデータとリレーするようなテーブルを作ると、カラムを2つ持たせなければならないデメリットがあります。しかしながら、これも時として便利な場合があり、
Table : books
PRIMARY KEY(number)
number	type	category	price	description
1	1	2	90000	サーラストラップ@900 100個を小切手で仕入れ
2	2	2	78000	イリアスストラップ@780 100個を掛け仕入れ
3	2	4	42000	シェリーの経済概論@4200 10冊を約手で仕入れ
 この場合はこのテーブル自体がtypeカラムを持っているため、これらの仕入れにおける貸方の種類が一目瞭然です。無論、複合キーを使わない場合でも種類を特定することは可能ですが、booksからcategoryにリレーし、categoryからtypeにリレーすることになります。
 Persistence APIでは複合キーも使えるようです。今回はあまり複合キーを使うべき例はありませんが、せっかく使えるなら試してみないことには。複合キーを使う場合、まずキーを保持するクラスが必要のようです。本当に絶対必要かどうかは不明ですが、複合キーのために2つも3つも変数を作るよりはこの方が楽でしょう。
 今回は「Name」クラスを複合キーとしてみます。クリエイターとキャラ番号の複合です。それにしても非効率的な構造ですが、そこは言わないお約束です。
 それから、もう1つ「@Enumerated」なる面白そうなものを見つけましたから、こちらも試してみるとしましょう。何でもenum型をマップするものだそうで。良く意味が分かりませんが、使ってみれば分かるでしょう。ということで、まずはenum型から。今回からソースは「com\yamicha\toplink\characters」に格納し、当然パッケージも「com.yamicha.toplink.characters」になっています。
// SexList.java
package com.yamicha.toplink.characters;

enum SexList{
	MALE("男性") , FEMALE("女性") , NEWTRAL("中性");

	private String label;
	private SexList(String label){
		this.label = label;
	}
	public String getLabel(){
		return label;
	}
}
 enum型はいわゆる定数リストということで、何にしようか迷いましたが、無難に「性別」にしてみました。性別であれば男性か女性しかない、という固定観念は、サーラさんが見事に打ち破ってくださるのではありますが。
 そういうわけで「中性」も用意しました。しかし、現実に性別不明の人が存在する場合には、「中性」にするよりNULLにすべきでしょう。なお、enum自体には何のアノテーションも必要ないようです。
 他のクラスも見ていきましょう。
// NameKey.java
package com.yamicha.toplink.characters;

import javax.persistence.*;

@Embeddable public class NameKey implements Cloneable{
	private int creator;
	private int number;

	public NameKey(){
	}
	public NameKey(int c , int n){
		creator = c;
		number = n;
	}

	@Id @Column(name="creator") 
		public int getCreator(){
		return creator;
	}
	@Id @Column(name="number")
		public int getNumber(){
		return number;
	}

	public void setCreator(int c){
		creator = c;
	}
	public void setNumber(int n){
		number = n;
	}

	public String toString(){
		return "[" + creator + ":" + number + "]";
	}
	public Object clone(){
		try{
			return super.clone();
		}catch(CloneNotSupportedException e){
			return null;
		}
	}
}

// Name.java
package com.yamicha.toplink.characters;

import javax.persistence.*;
import java.util.List;
import java.util.ArrayList;

@Entity @Table(name="persist_name" , schema="yamicha") 
	public class Name{
	private NameKey namekey;
	private String name;
	private Creator creator;
	private List<Element> elements;
	private Prefix prefix;
	private Sex sex;

	public Name(){
		namekey = new NameKey();
		elements = new ArrayList<Element>();
	}
	public Name(int number , Creator creator , String name){
		this();
		this.creator = creator;
		this.name = name;
		namekey.setCreator(creator.getNumber());
		namekey.setNumber(number);
	}

	@EmbeddedId public NameKey getNamekey(){
		return namekey;
	}
	@Column(name="name") public String getName(){
		return name;
	}
	@ManyToOne(fetch=FetchType.EAGER) 
		@JoinColumn(name="creator" , insertable=false , 
		updatable=false) 
		public Creator getCreator(){
		return creator;
	}
	@ManyToMany(fetch=FetchType.EAGER , mappedBy="names") 
		@OrderBy("number") 
		public List<Element> getElements(){
		return elements;
	}
	@OneToOne(cascade=CascadeType.ALL , fetch=FetchType.EAGER , 
		mappedBy="name") 
		@PrimaryKeyJoinColumn(name="number" , 
		referencedColumnName="number") 
		public Prefix getPrefix(){
		return prefix;
	}
	@OneToOne(cascade=CascadeType.ALL , fetch=FetchType.EAGER , 
		mappedBy="name") 
		@PrimaryKeyJoinColumn(name="number" , 
		referencedColumnName="number") 
		public Sex getSex(){
		return sex;
	}

	public void setNamekey(NameKey k){
		namekey = k;
	}
	public void setName(String name){
		this.name = name;
	}
	public void setCreator(Creator c){
		creator = c;
	}
	public void setElements(List<Element> e){
		elements = e;
	}
	public void setPrefix(Prefix p){
		prefix = p;
	}
	public void setSex(Sex s){
		sex = s;
	}

	public String toString(){
		return name;
	}
}
 今回は「NameKey.java」がプライマリキーを持っています。後はその型のフィールドまたはgetter/setterメソッドに「@EmbeddedId」アノテーションをつけます。これでNameKey.javaのnumber及びcreatorがPRIMARY KEYであるとみなされます。
 ポイントはgetCreatorメソッドの「@JoinColumn(name="creator" , insertable=false , updatable=false) 」アノテーションです。NameKey.javaではcreatorが@Idに登録されています。しかし、getCreatorメソッドのJoinColumnでも同じ名前のカラムにリンクしようとしています。これを違う名前にした場合、同じ値のカラムが2つ存在することになってしまいます。では一体どうしましょうか。insertable及びupdatableをfalseに設定し、こちら側からは更新を行わないことを明示する必要があるのです。今回に限らず複数の変数が同じカラムを参照している場合、insertable/updatableをtrueにできるのは1つだけです。他ではこれらを明示的にfalseに指定してやる必要があります。
 そして、今回のもう1つの目玉である@Enumeratedを使ったクラスがこちらです。
// Sex.java
package com.yamicha.toplink.characters;

import javax.persistence.*;

@Entity @Table(name="persist_sex" , schema="yamicha") 
	public class Sex{
	private NameKey namekey;
	private Name name;
	private SexList sex;
	public Sex(){
		namekey = new NameKey();
	}
	public Sex(Name name , SexList sex){
		namekey = (NameKey)name.getNamekey().clone();
		this.name = name;
		this.sex = sex;
	}

	@EmbeddedId public NameKey getNamekey(){
		return namekey;
	}
	@Column(name="sex") @Enumerated(EnumType.ORDINAL) 
		public SexList getSex(){
		return sex;
	}
	@OneToOne(fetch=FetchType.EAGER) 
		@PrimaryKeyJoinColumns({
			@PrimaryKeyJoinColumn(name="creator" , 
			referencedColumnName="creator") ,
			@PrimaryKeyJoinColumn(name="number" , 
			referencedColumnName="number")
		})
		public Name getName(){
		return name;
	}

	public void setNamekey(NameKey k){
		namekey = k;
	}
	public void setSex(SexList sl){
		sex = sl;
	}
	public void setName(Name n){
		name = n;
	}

	public String toString(){
		return sex.getLabel();
	}
}
 ここでは「@Enumerated(EnumType.ORDINAL)」アノテーションが使われています。ORDINALはデフォルト値で、使用しているenum型について0から順番に数値が割り当てられることを表します。具体的には、SexList.javaにおける記述順に数値が割り当てられます。MALEなら0、FEMALEなら1、NEWTRALなら2です。これをSTRINGにした場合、enumの定数名がそのまま文字列として("FEMALE"とか)保存されます。
 どちらにせよ地味に便利です、これ。
// Prefix.java
package com.yamicha.toplink.characters;

import javax.persistence.*;
import java.util.List;
import java.util.ArrayList;

@Entity @Table(name="persist_prefix" , schema="yamicha") 
	public class Prefix{
	private NameKey namekey;
	private String prefix;
	private Name name;

	public Prefix(){
		namekey = new NameKey();
	}
	public Prefix(Name name , String prefix){
		namekey = (NameKey)name.getNamekey().clone();
		this.prefix = prefix;
		this.name = name;
	}

	@EmbeddedId public NameKey getNamekey(){
		return namekey;
	}
	@Column(name="prefix") public String getPrefix(){
		return prefix;
	}
	@OneToOne(fetch=FetchType.EAGER) 
		@PrimaryKeyJoinColumns({
			@PrimaryKeyJoinColumn(name="creator" , 
			referencedColumnName="creator") ,
			@PrimaryKeyJoinColumn(name="number" , 
			referencedColumnName="number")
		})
		public Name getName(){
		return name;
	}

	public void setNamekey(NameKey k){
		namekey = k;
	}
	public void setPrefix(String p){
		prefix = p;
	}
	public void setName(Name n){
		name = n;
	}

	public String toString(){
		return prefix;
	}
}

// Creator.java
package com.yamicha.toplink.characters;

import javax.persistence.*;
import java.util.List;
import java.util.ArrayList;

@Entity @Table(name="persist_creator" , schema="yamicha") 
	public class Creator{
	private int number;
	private String url;
	private String creator;
	private List<Name> names;

	public Creator(){
		names = new ArrayList<Name>();
	}
	public Creator(int number , String url , String creator){
		this();
		this.number = number;
		this.url = url;
		this.creator = creator;
	}

	@Id @Column(name="number") @GeneratedValue 
		public int getNumber(){
		return number;
	}

	@Column(name="url") public String getURL(){
		return url;
	}
	@Column(name="creator") public String getCreator(){
		return creator;
	}
	@OneToMany(cascade=CascadeType.ALL , mappedBy="creator" , 
		fetch=FetchType.EAGER) 
		public List<Name> getNames(){
		return names;
	}

	public void setNumber(int n){
		number = n;
	}
	public void setURL(String u){
		url = u;
	}
	public void setCreator(String c){
		creator = c;
	}
	public void setNames(List<Name> names){
		this.names = names;
	}

	public String toString(){
		return creator;
	}
}

// Element.java
package com.yamicha.toplink.characters;

import javax.persistence.*;
import java.util.List;
import java.util.ArrayList;

@Entity @Table(name="persist_element" , schema="yamicha") 
	public class Element{
	private int number;
	private String element;
	private List<Name> names;

	public Element(){
		names = new ArrayList<Name>();
	}
	public Element(int number , String element){
		this();
		this.number = number;
		this.element = element;
	}
	public Element(List<Name> names , 
		int number , String element){
		this();
		this.number = number;
		this.element = element;
		this.names = names;
	}

	@Id @Column(name="number") 
		public int getNumber(){
		return number;
	}
	@Column(name="element") public String getElement(){
		return element;
	}
	@ManyToMany(fetch=FetchType.EAGER) 
		@JoinTable(name="persist_name_element" , 
		schema="yamicha" , 
		uniqueConstraints=@UniqueConstraint(columnNames=
			{"creator" , "number"}) , 
		joinColumns=@JoinColumn(name="element") , 
		inverseJoinColumns={
			@JoinColumn(name="creator" , 
			referencedColumnName="creator") ,
			@JoinColumn(name="name" , 
			referencedColumnName="number")
		}) 
		public List<Name> getNames(){
		return names;
	}

	public void setNumber(int n){
		number = n;
	}
	public void setElement(String e){
		element = e;
	}
	public void setNames(List<Name> n){
		names = n;
	}

	public String toString(){
		return element;
	}
}
 Prefix、Creatorについては大きな変更はありません。複合キーにするに当たって、必要な部分を修正しただけです。それに対して何かと変更点が多いのがElement.java。注意点としては「uniqueConstraints=@UniqueConstraint(columnNames={"creator" , "number"})」があります。これをしなければ、勝手にcreatorカラムのみをPRIMARY KEYとみなしてしまうため(元が複合キーだというのに)、当然ながらDuplicateエラーが発生します。
 後はデータを登録するだけです。
// Main.java
package com.yamicha.toplink.characters;

import javax.persistence.*;
import java.util.List;
import java.util.Arrays;
import java.util.ArrayList;

public class Main{
	public static void main(String args[]) throws Exception{
		EntityManagerFactory factory = 
			Persistence.createEntityManagerFactory("persist");
		EntityManager em = factory.createEntityManager();

		EntityTransaction et = em.getTransaction();
		et.begin();

		Creator creators[] = {
			new Creator(1 , "http://www.yamicha.com/" , 
				"yamicha.com") , 
			new Creator(2 , null , "hisame") , 
			new Creator(3 , "http://sousya.umu.cc/" , "ruva") , 
			new Creator(4 , null , "coolmint") , 
			new Creator(5 , null , "Shou")
		};

		for(Creator c : creators)
			em.persist(c);

		Name names[] = {
			new Name(1 , creators[0] , "イリアス") ,
			new Name(2 , creators[0] , "サーラ") ,
			new Name(3 , creators[0] , "シェイン") ,

			new Name(1 , creators[1] , "うなぎ") ,
			new Name(2 , creators[1] , "ネコ") ,
			new Name(3 , creators[1] , "クロウ") ,

			new Name(1 , creators[2] , "ルヴァ") ,
			new Name(2 , creators[2] , "リサ") ,
			new Name(3 , creators[2] , "ファルシア") ,

			new Name(1 , creators[3] , "クルード") ,
			new Name(2 , creators[3] , "フィオーナ") ,

			new Name(1 , creators[4] , "アルヤ") ,
			new Name(2 , creators[4] , "ルナン") ,
			new Name(3 , creators[4] , "レイシス")
		};

		for(Name n : names)
			em.persist(n);

		Element elements[] = {
			new Element(
				new ArrayList<Name>(
				Arrays.asList(new Name[]{
				names[0] , names[6] , names[11] , 
				names[12] , names[13]})) 
				, 1 , "火") ,
			new Element(
				new ArrayList<Name>(
				Arrays.asList(new Name[]{
				names[0] , names[3] , names[6] , names[10]})) 
				, 2 , "水") ,
			new Element(
				new ArrayList<Name>(
				Arrays.asList(new Name[]{
				names[0] , names[3] , names[6] , names[11] , 
				names[12] , names[13]})) , 3 , "雷") ,
			new Element(
				new ArrayList<Name>(
				Arrays.asList(new Name[]{
				names[0] , names[4] , names[6] , names[12] , 
				names[13]})) , 4 , "土") ,
			new Element(
				new ArrayList<Name>(
				Arrays.asList(new Name[]{
				names[0] , names[5] , names[6] , names[10] , 
				names[12] , names[13]})) , 5 , "風") ,
			new Element(
				new ArrayList<Name>(
				Arrays.asList(new Name[]{
				names[0] , names[2] , names[6] , names[8] , 
				names[11]})) , 6 , "回復") ,
			new Element(
				new ArrayList<Name>(
				Arrays.asList(new Name[]{
				names[0] , names[2] , names[6]})) 
				, 7 , "聖") ,
			new Element(
				new ArrayList<Name>(
				Arrays.asList(new Name[]{
				names[0] , names[5]})) , 8 , "暗") ,
			new Element(
				new ArrayList<Name>(
				Arrays.asList(new Name[]{
				names[0]})) , 9 , "RDBMS")
		};

		for(Element e : elements)
			em.persist(e);

		Prefix prefixes[] = {
			new Prefix(names[0] , "魔道士") ,
			new Prefix(names[1] , "騎士") ,
			new Prefix(names[2] , "聖騎士") ,

			new Prefix(names[3] , "デビル") ,
			new Prefix(names[4] , "デビル") ,
			new Prefix(names[5] , "デビル") ,

			new Prefix(names[6] , "司祭") ,
			new Prefix(names[7] , "僧侶") ,
			new Prefix(names[8] , "聖騎士") ,

			new Prefix(names[9] , "剣士") ,
			new Prefix(names[10] , "風術師") ,

			new Prefix(names[11] , null) ,
			new Prefix(names[12] , null) ,
			new Prefix(names[13] , null)
		};

		for(Prefix p : prefixes)
			em.persist(p);

		Sex sexes[] = {
			new Sex(names[0] , SexList.FEMALE) ,
			new Sex(names[1] , SexList.NEWTRAL) ,
			new Sex(names[2] , SexList.MALE) ,

			new Sex(names[3] , SexList.FEMALE) ,
			new Sex(names[4] , SexList.FEMALE) ,
			new Sex(names[5] , SexList.FEMALE) ,

			new Sex(names[6] , SexList.FEMALE) ,
			new Sex(names[7] , SexList.FEMALE) ,
			new Sex(names[8] , SexList.MALE) ,

			new Sex(names[9] , SexList.MALE) ,
			new Sex(names[10] , SexList.FEMALE) ,

			new Sex(names[11] , SexList.MALE) ,
			new Sex(names[12] , SexList.FEMALE) ,
			new Sex(names[13] , SexList.FEMALE)
		};

		for(Sex s : sexes)
			em.persist(s);

		et.commit();

		em.close();
		factory.close();
	}
}
 目を引くのが性別の登録部分。この上ないほどに一目瞭然です。@Enumeratedはなかなか便利といいましょうか、かゆいところに手が届く機能です。やはりサーラさんはニュートラル。
 ちなみにキャラクターデータはこのように登録されています。
SELECT n.creator , n.number , p.prefix , n.name , s.sex , c.creator 
FROM persist_name n 
INNER JOIN persist_creator c ON n.creator = c.number 
INNER JOIN persist_prefix p ON n.creator = p.creator AND n.number = p.number 
INNER JOIN persist_sex s ON n.creator = s.creator AND n.number = s.number 
ORDER BY n.creator , n.number;

creator	number	prefix	name	sex	creator
1	1	魔道士	イリアス	1	yamicha.com
1	2	騎士	サーラ	2	yamicha.com
1	3	聖騎士	シェイン	0	yamicha.com
2	1	デビル	うなぎ	1	hisame
2	2	デビル	ネコ	1	hisame
2	3	デビル	クロウ	1	hisame
3	1	司祭	ルヴァ	1	ruva
3	2	僧侶	リサ	1	ruva
3	3	聖騎士	ファルシア	0	ruva
4	1	剣士	クルード	0	coolmint
4	2	風術師	フィオーナ	1	coolmint
5	1	NULL	アルヤ	0	Shou
5	2	NULL	ルナン	1	Shou
5	3	NULL	レイシス	1	Shou
 creator及びnumberが複合キーですので、双方が一致しない限りエラーにはなりません。sexカラムは0が男性、1が女性、2が中性です。分かりづらい場合には、SELECT節の「s.sex」を「ELT(s.sex + 1 , '男性' , '女性' , '中性') AS 'sex'」に書き直してみると分かりやすくなるでしょう。
 それにしても、@Enumeratedは非常に便利なのですが、複合キーは失敗でした。Persistence APIで複合キーを使うのは異常に辛いです。番号の自動生成が難しくなりますし、複合キーとJoinColumnがかぶるような場合は地獄です。可能なら避けるべきでしょう。
 Persistence APIもこれで主要な機能はおおむね使ってしまいましたか。何にしても、エラーを出しては書き直す作業を行わなければならない関係上、再起動に10分かかるJava EEでは限界がありますから、SEで使えるのはありがたい限りです。
カテゴリ [開発魔法][社会問題][ゲスト出演] [トラックバック 0][コメント 0]
<- 前の記事を参照 次の記事を参照 ->

- Blog by yamicha.com -