Column

Wij hebben het nu gehad over onze entiteit op klasseniveau, laten wij het nu hebben over onze eigenschappen (die de attributen op de tabel op de databank nabootsen).

@Id

Zoals reeds vermeld is bij een JPA-entiteit een primary key verplicht. Wij kunnen onze eigenschap die dient als PK aanduiden via de @Id annotatie.

@Entity
public class Song {
    @Id
    private Long id;
    private String title;
    private String artist;
    private String genre;
    private int year;
    private double cost;

    // noargs constructor, getters and setters

}

@GeneratedValue

Meestal wensen wij niet handmatig een id toe te wijzen aan onze nieuwe entiteiten. Wij zouden liever hebben dat deze automatisch gegenereerd wordt, net als AUTO_INCREMENT aan de kant van de databank.

JPA heeft hier ook een annotatie voor, namelijk @GeneratedValue

@Entity
public class Song {
    @Id
    @GeneratedValue
    private Long id;
    private String title;
    private String artist;
    private String genre;
    private int year;
    private double cost;

    // noargs constructor, getters and setters

}

Er bestaan meerdere strategieën die JPA kan gebruiken om een nieuwe Id te verzinnen. Als je er geen expliciet meegeeft dan zal hij de AUTO (automatische) strategie gebruiken, maar zo bestaan er nog: AUTO, IDENTITY, SEQUENCE en TABLE. Wij kunnen er zo eentje meegeven die wij liever hebben:

@Entity
public class Song {
    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    private Long id;
    // properties, noargs constructor, getters and setters

}
@Entity
public class Song {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;
    // properties, noargs constructor, getters and setters

}
@Entity
public class Song {
    @Id
    @GeneratedValue(strategy = GenerationType.SEQUENCE)
    private Long id;
    // properties, noargs constructor, getters and setters

}
@Entity
public class Song {
    @Id
    @GeneratedValue(strategy = GenerationType.TABLE)
    private Long id;
    // properties, noargs constructor, getters and setters

}

AUTO is zeker goed meestal, maar als je reeds bestaande records hebt op jouw databank, waarvan de Id kolommen automatisch zijn gegenereerd door de databank zelf (AUTO_INCREMENT), dan kan je best IDENTITY gebruiken. De geïnteresseerde lezer kan meer informatie over de verschillende strategieën lezen bij de documentatie.

@Column

Net zoals bij @Table kan je extra informatie voorzien over jouw eigenschappen/kolommen met een @Column annotatie. Deze is niet verplicht. JPA gaat ervan uit dat al jouw eigenschappen dienen overeen te komen met attributen op de tabel op de databank, dus een @Column is enkel nodig als je extra details wil voorzien.

Een zo een detail is bij voorbeeld een naam. Net zoals bij @Entity en @Table gaat JPA standaard jouw eigenschap namen zelf gebruiken en ervan uit gaan dat die overeenkomen met jouw kolomnamen. In ons geval, bij Song, is dat toevallig ook wel zo, dus moeten wij niks doen, maar stel dat wij een Actor entiteit zouden schrijven met een fullName eigenschap. In Java houden wij ons aan camelCasing, maar vaak bij databanken wordt er snake_casing gebruikt, dus die zouden niet overeenkomen (fullName vs full_name). In zo’n geval zouden wij een specifieke naam moeten meegeven:

Naast name kunnen wij ook waarden voor nullable en unique meegeven.

@Entity
public class Song {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;
    @Column(length = 45, nullable = false)
    private String title;
    private String artist;
    private String genre;
    private int year;
    private double cost;

    // noargs constructor, getters and setters

}

@Enumerated

Soms gebruiken wij voor het gemak in Java een enum. Bij voorbeeld wij willen voor een Java-klasse die een pand entiteit voorstelt het soort pand kunnen bijhouden, maar wij willen ons houden aan een reeks vaste constanten voor veiligheid (mogelijke typfouten) en gemak.

@Entity
public class Property {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;
    private String address;
    private double price;
    private PropertyType type;
    private Epc epc;
    @Column(name = "interior_area")
    private int interiorArea;
    @Column(name = "plot_area")
    private int plotArea;
    @Column(name = "nr_bedrooms")
    private int nrBedrooms;
    @Column(name = "nr_bathrooms")
    private int nrBathrooms;

    // noargs constructor, getters and setters

}
public enum PropertyType {
    HOUSE,
    APARTMENT
}

Wanneer wij eigenschappen hebben die enums zijn, kunnen wij best gebruik maken van de @Enumerated annotatie.

@Entity
public class Property {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;
    private String address;
    private double price;
    @Enumerated
    private PropertyType type;
    @Enumerated
    private Epc epc;
    @Column(name = "interior_area")
    private int interiorArea;
    @Column(name = "plot_area")
    private int plotArea;
    @Column(name = "nr_bedrooms")
    private int nrBedrooms;
    @Column(name = "nr_bathrooms")
    private int nrBathrooms;

    // noargs constructor, getters and setters

}

Wat gebeurt er dan? Hoe wordt het uiteindelijk opgeslagen op de databank?

Standaard worden zij opgeslagen als getallen die overeenkomen met de ordinal van die enum-constant. Bij voorbeeld, als je een huis zou registreren, zou op de databank, onder het kolom ‘type’ 0 staan, want dat komt overeen met de nulde constant in onze enum ‘HOUSE’. Dat zal wel blijven werken, maar wij kunnen ook kiezen om de namen van onze constanten zelf als tekst op te slaan op de databank, dan hebben wij ‘HOUSE’ op de databank staan. Dat doen wij door het in onze @Enumerated annotatie als volgt:

@Entity
public class Property {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;
    private String address;
    private double price;
    @Enumerated(EnumType.STRING)
    private PropertyType type;
    @Enumerated(EnumType.STRING)
    private Epc epc;
    @Column(name = "interior_area")
    private int interiorArea;
    @Column(name = "plot_area")
    private int plotArea;
    @Column(name = "nr_bedrooms")
    private int nrBedrooms;
    @Column(name = "nr_bathrooms")
    private int nrBathrooms;

    // noargs constructor, getters and setters

}

Als je toch liever een getal hebt (ordinal) dan kan je in plaats van ‘STRING’, ‘ORDINAL’ meegeven (of geen haakjes want standaard gebruikt hij sowieso ordinal).

Om het verschil toch nog is beter te illustreren, een voorbeeld:

Voor een entiteit ‘Person’ die een eigenschap/attribuut ‘Gender’ heeft die wij als enum bijhouden als volgt:

public enum Gender {
    MALE,
    FEMALE,
    OTHER
}

@Enumerated(EnumType.ORDINAL) (of gewoon @Enumerated)

╔════╦══════════════╦════════╗
║ ID ║    NAME      ║ GENDER ║
╠════╬══════════════╬════════╣
║  1 ║ Jeff Atwood  ║    0   ║
║  2 ║ Geoff Dalgas ║    0   ║
║  3 ║Jarrod Jesica ║    1   ║
║  4 ║ Joel Lucy    ║    1   ║
╚════╩══════════════╩════════╝

@Enumerated(EnumType.STRING)

╔════╦══════════════╦════════╗
║ ID ║    NAME      ║ GENDER ║
╠════╬══════════════╬════════╣
║  1 ║ Jeff Atwood  ║  MALE  ║
║  2 ║ Geoff Dalgas ║  MALE  ║
║  3 ║Jarrod Jesica ║ FEMALE ║
║  4 ║ Joel Lucy    ║ FEMALE ║
╚════╩══════════════╩════════╝