Posted at

JSF 多対多 記述方法

こんにちは! 

JavaでWEBアプリ開発を勉強している人間です。

今回、ある参考書の中で「オブジェクト関係マッピング(ORM)・@ManyToMany」が個人的に1週間くらい苦戦していたので同じ境遇の方たちに参考になればと思い記事を書かせていただきます。


実行環境

NetBeans IDE 8.0.2

cpu i5


対象

JSF 作成者(初心者)

ManyToManyの設定に苦戦している人


プログラムの説明

名前・年齢・タイトル・著者を入力しデータベースへ登録をし双方向から呼び出す。

(snp → super / super → snp)


まずはEntityから

今回用意したEntityは「Snp」・「Super」です。

Entityの記述はそんなに難しくはないです。

というか、この記事では難しいところの解説ではなくつまずきポイントの明確化なのでその点ご了承を...


Snp.java

    @Entity

public class Snp {
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
private Long snpid;
private String name;
private Integer age;
@ManyToMany(mappedBy = "snp", cascade = {CascadeType.ALL})
private List<Super> sper = new ArrayList();

public Snp(){
}

public Snp(String name, Integer age){
this.name = name;
this.age = age;
}




Super.java

   @Entity

public class Super implements Serializable{
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
private Long sperid;
private String title;
private String name_t;
@ManyToMany
private List<Snp> snp = new ArrayList();

public Super(){
}

public Super(String title, String name_t){
this.title = title;
this.name_t = name_t;
}


とりあえず、コンストラクターまでを表示します。

ここではget・setメソッドは省略していますが通常通りの宣言で問題ありません。

あと、カスケードやmappedByはお好みでw

簡単な記述ですが注意点が2個ほどあります。


1.idの名前は「クラス名 + id」

このidの名前で間違ってしまうとデータベースのほうでうまく外部キーが合わず関係マッピングができなくなってしまいます。


Snp.java

   private Long snpid;


自分はこれに気付くのにも結構な時間がかかってしまいました...


2.List宣言でArrayList()を先に代入

これに関しては絶対ここでやらなければならないわけではないのですが、自分は面倒臭いのでここで宣言しておきます。


snp.java

    @ManyToMany

private List<Snp> snp = new ArrayList();

この宣言がないと、たまに「NullPointerException」のエラーが出るので注意してください。


次にバッキングビーン

こちらも簡単なので

さらっと


Bb.java

    public String creat(){

Snp d = new Snp(name, age);

Super sd = new Super(title, name_t);

List<Super> ld = d.getSper();
ld.add(sd);

List<Snp> sld = sd.getSnp();
sld.add(d);

add1(d);

return null;
}

public void add1(Snp da){
try{
db.Snpcreat(da);
}catch(Exception e){
System.out.println("エラー1です");
}
}


変数名が適当ですいませんw

ここでは注意点はないのですが、簡単なアドバイスがあります。

それは「ListをEntityへ代入したいとき、インスタンスからではなくgetメソッドを使って代入すること!!」

です!

まあ、ArrayListにしてから入れすのもいいですがそこは好みの問題ですね。


戦慄のxhtml

自分の場合ここに問題があり一番最後にバグです(泣)

データベースから呼び出すところに注目です。


content01.xhtml

       Snpデータベース

<h:dataTable value="#{bb.all01}" var="v" class="data1">
<h:column>#{v.name}</h:column>
<h:column>#{v.age}</h:column>
<h:column>
<h:dataTable value="#{v.sper}" var="o">
<h:column>#{o.title}</h:column>
<h:column>#{o.name_t}</h:column>
</h:dataTable>
</h:column>
</h:dataTable>

Listとして宣言したsperは<h:dataTable...を使ってあげることが大切です。

このバグをどれだけ長い時間追っていたか...

ただこれだけですが気付かないと長い時間が奪われてしまうので気を付けてくださいね

ちなみに「all01」ではこんなプログラムです。


Bb.java

    public List<Snp> getAll01(){

return db.getAll01();
}

ここからEntityManagerへ


SnpDb.java

    public List<Snp> getAll01(){

List<Snp> snp = em.createQuery("SELECT c FROM Snp c").getResultList();
return snp;
}

となっています。(参考になれば...)


実行結果


終わりに

いかがだったでしょうか?

もちろん、これが絶対というわけではありません。

実務だと不足しているアノテーションやらなんやらがあるかもしれませんがとりあえず動くのでその点よろしくですwww

(ただ、どの記事よりアノテーションとかが少なくあまりない記事だったので参考になる方はいると思う)

あと、この説明で何か足りないところがあればぜひご指摘を