2016-03-24 7 views
0

Javaの計算値をデータベースに格納することはできません。Ebean:プロパティを持たないゲッターの列を作成する方法

たとえば、firstNamelastNameのPersonクラスがあるとします。実際のプロパティではなく、Personの名前の長さを返すgetterが必要な場合があります。

@Entity 
public class Person extends Model { 
    @Id 
    public Long id; 

    public String firstName; 

    public String lastName; 

    public Int getNameLength() { 
     return firstName.length() + lastName.length(); 
    } 

    public Person (String firstName, String lastName) { 
     this.firstName = firstName; 
     this.lastName = lastName; 
    } 
} 

私はそうのような新しいPersonを作成するのであれば:

Person bob = new Person("Bob", "Roy"); 
bob.save(); 

その後、我々はテーブルにこれで終わる必要がありますに:これが可能であれば

| id | first_name | last_name | name_length | 
==================================================== 
| 1 | "Bob"  | "Roy" |  6  | 

誰でも知っていますか? Old Gods and the New Godsのため

答えて

1

してください、このようなものでしょう完全に台無しにしてデータベースを行うこの

をしません。あなたはになります。は遅かれ早かれ問題に遭遇します。あなたのプロフィールを見て、あなたはCSコースを取得しましたので、あなたは確実にあなたのデータベースコースを持っていました。 Second normal formThird normal formを覚えておいてください。また、他の属性に依存する属性を持っている場合は、これをどのように破ることになりますか。

実行する必要があるのは、一時フィールド(@Transientとマークされています)を持つか、ゲッターを使用してそこから情報を提供することです。 name_lengthにアクセスする必要があるたびに、このゲッターを呼び出しますが、その情報はデータベースに保存されません。

アプリケーションの外部で長さを計算する場合でも、これにはデータベース機能を使用できます(like length)。 OPで述べた要件に基づいて


編集: - フィールド上またはメソッド(ゲッター/セッター)のいずれかJPAでは

は、あなたが列を宣言することができますどのように2つの方法があります。

あなたはあなたの質問にEbeanを言及しましたが、Ebeanは参考JPA実装とはみなされませんでした。これはまだサポートされていない可能性がありますが、あなたの特定のケースで試すことができます。

動作することが証明されている別の方法があります。モデルを次のように定義します。

@Entity 
public class Person extends Model { 
    @Id 
    private Long id; 

    private String firstName; 

    private String lastName; 

    private Integer nameLength; 

    public Long getId() { 
     return id; 
    } 

    // getter for first name and last name with @Column annotation 

    @Column(name = "complex_calculation") 
    public Integer getNameLength() { 
     return firstName.length() + lastName.length(); 
    } 

    public Person (String firstName, String lastName) { 
     this.firstName = firstName; 
     this.lastName = lastName; 
     updateComplexCalculation(); 
    } 

    public void setFirstName(String firstName) { 
     this.firstName = firstName; 
     updateComplexCalculation(); 
    } 

    public void setLastName(String lastName) { 
     this.lastName = lastName; 
     updateComplexCalculation(); 
    } 

    private void updateComplexCalculation() { 
     this.nameLength = firstName.length() + lastName.length(); 
    } 
} 

重要な部分はupdateComplexCalculationメソッドです。コンストラクターが呼び出され、すべてのセッター呼び出しでこのメソッドを呼び出して複合体プロパティを更新します。もちろん、計算に必要なセッター呼び出しでのみ呼び出す必要があります。

次のコード:その後、

Person p = new Person("foo", "bar"); 
p.save(); 

Logger.debug("Complex calculation: " + p.getNameLength()); 

p.setFirstName("somethingElse"); 
p.save(); 

Logger.debug("Complex calculation: " + p.getNameLength()); 

利回り:

[debug] application - Complex calculation: 6 
[debug] application - Complex calculation: 16 
+0

私は通常のフォームをよく覚えています。私はあなたに同意します。しかし時には要件が出てくる。クライアントはデータベース内のフィールドを必要としますが、データベースによってフィールドが計算された値にならないようにします。これはパフォーマンス上の理由によるものです。 これは実際のユースケースではないため、長さは機能しません。これらのフィールドを計算するためのルールはかなり複雑で存在し、Javaコードで使用されています。 SQLを使用してレポートを生成するときにはこれらをフィールドとして必要とし、一連のSQLビューでビジネスロジックを複製しないことが望ましいでしょう。 – ncphillips

+0

私はあなたのポイントを見ます。私はまだこのアイデアが気に入らないが、私はこの作業を行うための方法で自分の答えを更新した。私の前提は、Ebeanを使用するときにプロパティを定義する必要があるということです。これはHibernateのプロパティなしで動作するはずです。 – Anton

+0

あなたのコメントを受け入れました。名前の長さのゲッターが手作業で値を計算していたという事実が私を捨てました。 – ncphillips

1

モデル内のプロパティについて間違って何?単にprivateにしてください。publicゲッターを追加しますが、セッターはなく、最後にsaveupdateのメソッドをオーバーライドします。

private Integer nameLength; 

// BTW shouldn't you also count the space between first and last name? 
public Integer getNameLength() { 
    return firstName.length() + lastName.length(); 
} 

@Override 
public void save() { 
    nameLength = firstName.length() + lastName.length(); 
    super.save(); 
} 

@Override 
public void update() { 
    nameLength = firstName.length() + lastName.length(); 
    super.update(); 
} 

それでもモデルでプロパティを避けたい場合は、(おそらくも上書きsave/updateメソッド内)カスタムSQLクエリを使用する必要があります、in other answerまたはEbean's docsを示したように、時に実行されますノート各保存または更新操作ごとに少なくとも2つのSQL照会。

0

私にいくつかのアイデアを与えてくれたAntonとbiesiorに感謝します。

むしろよりはsaveupdateメソッドをオーバーライドし、我々はそれが依存だ変数が更新されたときに再計算されるプライベート変数を選択しました。

public class Person { 
    @Id 
    public Long id; 
    private String firstName; 
    private String lastName; 
    private Integer nameLength; 

    public String getFirstName() { 
     return firstName; 
    } 

    public String getLastName() { 
     return lastName; 
    } 

    public void setFirstName() { 
     this.firstName = firstName; 
     calculateNameLength(); 
    } 

    public void setLastName(String lastName) { 
     this.lastName = lastName; 
     calculateNameLength(); 
    } 

    private void calculateNameLength() { 
     nameLength = getFirstName().length + getLastName().length; 
    } 

} 

これはsaveまたはupdate方法で値を更新する提案の方法を超えるいくつかの利点があります。

saveまたはupdateの方法で再計算すると、オブジェクトにフィールドを設定するたびにこれらのメソッドの1つを呼び出す必要があります。そうでなければ、nameLengthは同期しなくなります。たとえば、人物firstNameを変更してからnameLengthを使用して、最初にオブジェクトをデータベースに保存せずに何かを行うことはできませんでした。

さらに、save/updateメソッドを使用すると、オブジェクトの状態がEbeanに結合されます。 ORMはオブジェクトの状態を永続化するためのものであり、オブジェクトの状態を設定するものではありません。

+0

実際に私が提案したソリューションは、あなたが決めた解決策であるということを考えれば、私の答えを受け入れることができます。 – Anton

+0

AH!私はそこで一生懸命に退屈した。ごめんね。私はあなたを受け入れるでしょう! – ncphillips

+0

問題はありません、あなたの問題を解決できたことをうれしく思います!ハッピープレイ:) – Anton