Jdbi3

Hi, ich verstehe nicht, wieso das nicht häufiger eingesetzt wird… Ich zeige euch mal ein einfaches Beispiel, wobei ich aber an einer Stelle ein Problem habe, und deshalb hier nachfragen muss…

Zuallererst die Abhängigkeiten (Maven/pom):

        <dependency>
            <groupId>org.xerial</groupId>
            <artifactId>sqlite-jdbc</artifactId>
            <version>3.36.0.3</version>
        </dependency>
        <dependency>
            <groupId>org.jdbi</groupId>
            <artifactId>jdbi3-bom</artifactId>
            <type>pom</type>
            <version>3.30.0</version>
            <scope>import</scope>
        </dependency>
        <dependency>
            <groupId>org.jdbi</groupId>
            <artifactId>jdbi3-sqlite</artifactId>
            <version>3.30.0</version>
        </dependency>
        <dependency>
            <groupId>org.jdbi</groupId>
            <artifactId>jdbi3-sqlobject</artifactId>
            <version>3.30.0</version>
        </dependency>

Ich nutze SQLite. Hier ist meine Musiksammlung:

package db;

import org.jdbi.v3.sqlobject.config.RegisterConstructorMapper;
import org.jdbi.v3.sqlobject.customizer.Bind;
import org.jdbi.v3.sqlobject.customizer.BindMethods;
import org.jdbi.v3.sqlobject.statement.SqlQuery;
import org.jdbi.v3.sqlobject.statement.SqlUpdate;

import java.util.List;

public interface MyDAO {
    @SqlUpdate("CREATE TABLE IF NOT EXISTS artist (id INTEGER PRIMARY KEY, a_name TEXT, first_seen_at INTEGER)")
    void createTableArtist();

    @SqlUpdate("CREATE TABLE IF NOT EXISTS track (id INTEGER PRIMARY KEY, artist_id INTEGER, t_name TEXT, year INTEGER)")
    void createTableTrack();

    default void createTables() {
        createTableArtist();
        createTableTrack();
    }

    @SqlQuery("SELECT id FROM artist WHERE a_name = ?")
    Integer getIdFromArtist(String a_name);

    @SqlUpdate("INSERT INTO artist (a_name, first_seen_at) VALUES (:a_name, :first_seen_at)")
    void insertArtist(@BindMethods Artist artist, @Bind("first_seen_at") int first_seen_at);

    @SqlUpdate("INSERT INTO track (artist_id, t_name, year) VALUES (:artist_id, :t_name, :year)")
    void insertTrack(@BindMethods Track track, @Bind("artist_id") int artist_id);

    default void insertTracks(Artist artist, Track... tracks) {
        final int first_seen_at = (int) (System.currentTimeMillis() / 1000);
        Integer id = getIdFromArtist(artist.a_name());
        if (id == null) {
            insertArtist(artist, first_seen_at);
            id = getIdFromArtist(artist.a_name());
        }
        for (Track t : tracks) {
            insertTrack(t, id);
        }
    }

    @SqlQuery("SELECT * FROM track INNER JOIN artist ON artist.id = track.artist_id ORDER BY a_name, t_name")
    @RegisterConstructorMapper(ArtistAndTrack.class)
    List<ArtistAndTrack> listAll();
}

package db;

public record Artist(String a_name) {
}

package db;

public record Track(String t_name, int year) {
}

package db;

public record ArtistAndTrack(String a_name, String t_name, int first_seen_at, int year) {
}

package db;

import org.jdbi.v3.core.Jdbi;
import org.jdbi.v3.sqlobject.SqlObjectPlugin;

import java.util.List;

public class Test {
    public static void main(String[] args) {
        Jdbi jdbi = Jdbi.create("jdbc:sqlite:MeineMusiksammlung.db");
        jdbi.installPlugin(new SqlObjectPlugin());
        jdbi.useExtension(MyDAO.class, MyDAO::createTables);

        jdbi.useExtension(MyDAO.class, dao -> {
            Track t1 = new Track("Hit Me", 1998);
            Track t2 = new Track("Poker Face", 2008);
            Track t3 = new Track("Cardi C", 2001);
            Artist britney = new Artist("Britney Spears");
            Artist gaga = new Artist("Gaga");
            dao.insertTracks(britney, t1);
            dao.insertTracks(gaga, t2, t3);
        });

        List<ArtistAndTrack> artistAndTracks = jdbi.withExtension(MyDAO.class, MyDAO::listAll);
        artistAndTracks.forEach(System.out::println);
    }
}

Sieht schon jemand das Problem? Wie kann ich in SQL und JDBI3 formulieren, dass in der Methode insertTracks er zuerst Artist einfügen soll, wenn es Artist noch nicht gibt?

Danke. :blush:

Ich hatte mir iwie mehr Resonanz auf meine Frage erhofft… Schade. :eyes:

Also, es geht zunächst nur um die Vereinfachung dieser Methode… Das muss doch möglich sein.

Für first_seen_at den aktuellen Zeitpunkt wählen, id nur einmal abfragen, alles Tracks „auf einmal“ einfügen usw.

jdbi ist jetzt vermutlich nichts, was wirklich weit verbreitet ist. Der am weitesten verbreitete Standard ist JPA und der nimmt dir solche Dinge ab.

Soweit ich jdbi verstehe, ist das nur eine vereinfachung der JDBC Api. Um solche Dinge, was muss in welcher Reihenfolge eingefügt werden etc. muss du dich weiterhin selber kümmern.
Sprich wirklich Abfragen, gibt es den Artist schon,wenn nein dann anlegen. Ich sehe daher nicht, wie du das vereinfachen kannst.

Das Problem ist, das Ungetüm JPA ist nicht mehr zeitgemäß… und danach hatte ich auch nicht gefragt.

Also Danke für keine Hilfe von dir. :slight_smile: