2016-03-24 11 views
0

Ich könnte in der Lage sein, berechnete Werte von Java in meiner Datenbank zu speichern.Ebean: So erstellen Sie eine Spalte für einen Getter ohne eine Eigenschaft

Zum Beispiel könnte ich eine Person-Klasse haben, die mit einem firstName und einem lastName. Ich möchte vielleicht einen Getter, der die Gesamtlänge des Namens Person s zurückgibt, ohne dass es eine tatsächliche Eigenschaft ist.

@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; 
    } 
} 

Also, wenn ich ein neues Person wie so erstellen:

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

Dann sollten wir mit dieser in der Tabelle am Ende:

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

Wer weiß, ob dies möglich ist?

Antwort

1

Bitte im Interesse der Old Gods and the New Gods dies nicht tun

tun so etwas wie dies würde total mess up Ihrer Datenbank. Sie wird früher oder später in Probleme laufen. Wenn Sie auf Ihr Profil schauten, haben Sie einen CS-Abschluss gemacht, so dass Sie Ihren Datenbank-Kurs hatten. Denken Sie daran, die Second normal form und die Third normal form und wie Sie dies brechen, wenn Sie Attribute haben, die von anderen Attributen abhängen.

Was Sie tun sollten, ist entweder ein transientes Feld (markiert mit @Transient) oder Sie können den Getter verwenden und die Informationen von dort bereitstellen. Jedes Mal, wenn Sie auf die name_length zugreifen müssen, rufen Sie diesen Getter auf, aber Sie werden die Informationen nicht in der Datenbank speichern.

Auch wenn Sie die Länge außerhalb Ihrer Anwendung berechnen möchten, können Sie dafür weiterhin eine Datenbankfunktion verwenden - like length.


Bearbeiten auf der Grundlage der Anforderung durch die OP erwähnt:

In JPA gibt es zwei Möglichkeiten, wie Sie die Spalten erklären können - entweder auf den Feldern oder zu den Methoden (Getter/Setter). Es würde wie folgt aus:

@Column(name = "complex_calculation") // Due to some bad requirement 
public Integer getNameLength() { 
    return fisrtName.length() + lastName.length(); 
} 

immer Sie Ebean in Ihrer Frage und Ebean erwähnt wird, nicht als Referenz JPA-Implementierung angesehen. Es gibt eine gute Chance, dass dies noch nicht unterstützt wird, aber Sie können es in Ihrem speziellen Fall versuchen.

Es gibt einen anderen Weg, der nachweislich funktioniert. Sie definieren Ihr Modell wie folgt aus:

@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(); 
    } 
} 

Der wichtige Teil der updateComplexCalculation Methode. Wenn der Konstruktor aufgerufen wird und bei jedem Setter-Aufruf, rufen Sie diese Methode auf, um die komplexe Eigenschaft zu aktualisieren. Natürlich sollten Sie es nur bei Setter-Aufrufen aufrufen, die für die Berechnung benötigt werden.

Der folgende Code:

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()); 

Ausbeuten dann:

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

Ich erinnere mich an meine normalen Formen gut, und ich stimme dir zu. Aber manchmal kommen Anforderungen auf. Der Client möchte das Feld in der Datenbank, aber es soll nicht nur ein berechneter Wert von der Datenbank sein. Dies ist aus Leistungsgründen. Dies ist nicht der tatsächliche Anwendungsfall, also wird die Länge nicht funktionieren. Die Regeln zur Berechnung dieser Felder sind wesentlich komplizierter und existieren in unserem Java-Code. Wir benötigen diese Felder als Felder für die Erstellung von Berichten mit SQL, und es wäre besser, die Geschäftslogik nicht in einer Reihe von SQL-Ansichten zu duplizieren. – ncphillips

+0

Ich verstehe deinen Standpunkt. Obwohl ich die Idee immer noch nicht mag, habe ich meine Antwort mit einer Möglichkeit aktualisiert, diese Arbeit zu machen. Meine Annahme ist, dass Sie eine Eigenschaft definieren müssen, wenn Sie Ebean verwenden. Es sollte ohne eine Eigenschaft in Hibernate funktionieren. – Anton

+0

Akzeptiert Ihren Kommentar. Die Tatsache, dass er für die Namenslänge getwittert hat, berechnete die Werte manuell. – ncphillips

1

Was im Modell über Eigentum falsch? Machen Sie es einfach private fügen Sie die public Getter aber ohne Setter, schließlich überschreiben save und update Methoden.

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(); 
} 

Wenn Sie noch im Modell vermeiden Eigenschaft möchten, müssen Sie benutzerdefinierte SQL-Abfrage (wahrscheinlich auch innerhalb der außer Kraft gesetzt save/update Methoden) verwenden, wie in other answer oder Ebean's docs zeigte, beachten Sie, dass bei durchführen wird mindestens 2 SQL-Abfragen pro Speicher- oder Aktualisierungsvorgang

0

Danke an Anton und biesior für ein paar Ideen.

Anstatt die Methoden save oder update zu überschreiben, entschieden wir uns für eine private Variable, die neu berechnet wird, wenn die Variablen, von denen sie abhängig ist, aktualisiert werden.

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; 
    } 

} 

Dies hat mehrere Vorteile gegenüber den vorgeschlagenen Methoden den Wert in den save oder update Methoden zu aktualisieren.

Die Neuberechnung in der Methode save oder update bedeutet, dass wir jedes Mal eine dieser Methoden aufrufen müssen, wenn wir ein Feld auf das Objekt setzen. Wenn nicht, wird die nameLength nicht mehr synchron sein. Ich konnte zum Beispiel die Personen firstName nicht ändern und dann die nameLength verwenden, um etwas anderes zu tun, ohne zuerst das Objekt in der Datenbank zu halten.

Darüber hinaus verbindet die Methode save/update den Objektstatus mit der Ebean. Der ORM dient zum dauerhaften Objektstatus, nicht zum Festlegen des Objektstatus.

+0

Angesichts der Tatsache, dass die Lösung, die Sie beschlossen haben zu gehen, tatsächlich die ist, die ich vorgeschlagen habe, können Sie einfach meine Antwort akzeptieren :) – Anton

+0

AH! Ich habe mich dort sehr geärgert. Tut mir leid, Mann. Ich werde deine akzeptieren! – ncphillips

+0

Kein Problem, froh, dass Sie Ihr Problem lösen konnten! Fröhliches Spielen :) – Anton