Flazzo memiliki fokus utama untuk menambah nilai bisnis Anda.

Blog

Cara LINQ antara Java dan SQL dengan JPAStreamer

16918637-thumb.jpg
Blog

Cara LINQ antara Java dan SQL dengan JPAStreamer


Jika Anda adalah pengembang Java yang mencari cara yang lebih mudah dan lebih intuitif untuk membuat kueri basis data, mirip dengan konstruksi LINQ yang elegan di C#, Anda harus memeriksa pustaka sumber terbuka JPAStreamer. Pada artikel ini, saya akan mengeksplorasi kemampuan hebat alat Java ini yang menghadirkan pengalaman seperti LINQ ke kueri Hibernasi Anda.

Sebelum menggali lebih dalam JPAStreamerSaya akan menjelaskan beberapa sifat yang diinginkan dari LINQ. LINQ (Language Integrated Query) adalah ekspresi C# yang dapat mengubah data dari berbagai sumber data, mulai dari struktur data linear sederhana hingga database. Berikut adalah contoh dasar dari dokumentasi LINQ yang beroperasi pada larik bilangan bulat untuk menemukan skor arbitrer yang lebih besar dari 80:

int[] scores = { 97, 92, 81, 60 };

IEnumerable<int> scoreQuery =
    from score in scores
    where score > 80
    select score;

foreach (int i in scoreQuery)
{
    Console.Write(i + " "); // Output: 97 92 81
}

Seperti yang terlihat di atas, API LINQ sangat mirip dengan konstruksi SQL, namun jenisnya aman untuk digunakan dalam konteks C#. Di Java, kita dapat mengekspresikan operasi yang sama dengan lancar dan intuitif menggunakan the Aliran API diperkenalkan di Java 8:

final int[] scores = {97, 92, 81, 60}
Stream.of(scores)
    .filter(score -> score > 80)
    .foreach(System::out); 

Meskipun tidak sama dengan SQL, banyak operasi Java Stream yang memiliki saudara kandung SQL, misalnya filter (di mana), sort (urutan), dan peta (pilih).

LINQ dan Stream API menekankan gaya pemrograman deklaratif, memungkinkan pengembang untuk mengekspresikan apa yang ingin mereka capai daripada menentukan bagaimana melakukannya – sebuah pendekatan yang meningkatkan keterbacaan dan pemeliharaan kode.

Jadi, Java Streams setara dengan C# LINQ?

Tidak, tidak sesederhana itu. Katakanlah skor kami mewakili hasil historis dari aplikasi game, dan karena itu disimpan dalam database, bukan larik dalam memori. Untuk memotivasi pemain, kami ingin menyajikan daftar skor tertinggi sepanjang masa. Dengan LINQ ke SQL, larik input dapat dengan mudah diganti dengan referensi ke entitas model objek; yaitu metamodel C# dari database. Saat runtime, LINQ akan secara otomatis mengeluarkan kueri asli ke database dan dilengkapi dengan operasi gabungan dan sintaks pemahaman kueri untuk menulis kueri yang lebih kompleks.

Aliran Java, di sisi lain, tidak dapat dikonversi ke kueri SQL … atau bisakah?

Memperkenalkan JPAStreamer

JPAStreamer adalah ekstensi JPA open source yang menjembatani kesenjangan antara Java Streams dan kueri basis data. Menggunakan implementasi khusus dari antarmuka Java Stream, JPAStreamer dapat secara otomatis menerjemahkan aliran menjadi kueri basis data yang efisien dan mendukung konstruksi gabungan dan proyeksi untuk mencakup lebih banyak hal.

Tidak seperti LINQ ke SQL, JPAStreamer bukan ORM mandiri, melainkan menggunakan penyedia JPA yang ada seperti Hibernate untuk mengelola metamodel basis data yang terdiri dari entitas JPA standar. Ke depan, saya akan berasumsi bahwa aplikasi game menggunakan Hibernate untuk mengelola sesi game historis. Skor masa lalu diwakili dalam a Score tabel dalam database, dan model entitas JPA kami memiliki asosiasi Score Entity sebagai berikut:

@Entity
@Table(name = "score", schema = "game-db")
public class Score implements Serializable {
    public Score() {}
    
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
     @Column(name = "score_id", nullable = false, updatable = false, columnDefinition = "smallint(5)")
    private Integer scoreId;

    @Column(name = "value", nullable = false, columnDefinition = "varchar(255)")
    private Integer value;
    
    @Column(name = "date", nullable = false, columnDefinition = "timestamp")
    private LocalDateTime date;
    
    @ManyToOne
    @JoinColumn(name="username", nullable = false, updatable = false, insertable = false)
    private Player player;

    // Setters and getters are left out for clarity…
}

Seperti yang kita lihat di atas, skor dapat dijelaskan oleh a idA valueITU date permainan, dan rekan player.

Setelah metamodel JPA terpasang, JPAStreamer dapat diinstal dengan menambahkan Maven ketergantungan di bawah ini:

<dependency>
    <groupId>com.speedment.jpastreamer</groupId>
    <artifactId>jpastreamer-core</artifactId>
    <version>3.0.1</version>
</dependency>

(Untuk Nilai pemasangan, pelajari lebih lanjut Di Sini. Jika Anda menggunakan Quark ekosistem satu ekstensi JPAStreamer tersedia di Quarkivers.)

Selama instalasi, proyek harus dibangun kembali untuk memicu pembuatan metamodel JPAStreamer sendiri. Proses ini sepenuhnya otomatis dan hasilnya dapat ditemukan di target/generated-sources kasus. Dalam hal ini, JPAStreamer menghasilkan file a Score$ Dan Player$ kelas yang dapat kita gunakan untuk merumuskan predikat yang dapat ditafsirkan oleh pengoptimal kueri JPAStreamer.

Apakah itu tampak buram bagi Anda? Mari nyatakan dengan menulis kueri yang akan memfilter 10 skor teratas:

JPAStreamer jpaStreamer = JPAStreamer.of(“game-db”); 
jpaStreamer.stream(Score.class)
    .sorted(Score$.value.reversed())
    .limit(10)
    .foreach(System::out); 

JPAStreamer dibuat dengan satu baris kode, mereferensikan unit persistensi dengan nama imajinernya “game-db”. Baris kedua membuat aliran dari entitas Skor JPA. Skor kemudian diurutkan dari atas ke bawah dan 10 hasil teratas dipilih. Sama seperti LINQ, eksekusi kueri ditunda hingga operasi terminal dipanggil; dalam hal ini, foreach operator yang mencetak skor. Lebih penting lagi, aliran ini tidak akan mewujudkan semua skor dari database karena secara otomatis diterjemahkan ke dalam kueri SQL:

select
    score0_.score_id as score_id1_0_,
    score0_.value as value2_0_,
    score0_.date as date3_0_,
    score0_.username as username4_0_,
from
    score score0_
order by
    score0_.value dsc limit ?, ?

Untuk memberikan kredit kepada pemain di daftar skor tinggi, kami mungkin juga ingin menampilkan nama pemain yang terkait dengan setiap skor. Seperti dapat dilihat pada entitas Skor di atas, ia memiliki relasi banyak-ke-satu dengan Player kelas. Saya tidak akan menunjukkan entitas pemain JPA yang imajinatif, tetapi setiap pemain diidentifikasi secara unik dengan nama pengguna dan memiliki kolom untuk nama depan dan belakang.

Nama pemain terkait dapat diperoleh dengan mendaftarkan pemain untuk setiap skor. Menggunakan JPAStreamer berarti kita perlu memperbarui sumber aliran agar tidak hanya menyertakan Score entitas tetapi juga gabungan Player objek. Penggabungan ini ditentukan menggunakan konfigurasi aliran seperti yang ditunjukkan di bawah ini. Seperti sebelumnya, kami mengumpulkan sepuluh skor teratas dan memetakan entri tersebut ke pemain masing-masing. Terakhir, para pemain dan skor mereka dicetak ke konsol.

JPAStreamer jpaStreamer = JPAStreamer.of("game-db");

Map<Score, Player> scoreMap = jpaStreamer.stream(
  StreamConfiguration.of(Score.class).joining(Score$.player))
    .sorted(Score$.value.reversed())
    .limit(10)
    .collect(toMap(
        Function.identity(),
        Score::getPlayer
    )
);

scoreMap.forEach(
    (s, p) -> System.out.format("%s %s: %s points\n",
        p.getFirstName(),
        p.getLastName(),
        s.getValue()
    )
);

Kesimpulan

JPAStreamer menghadirkan kekuatan kueri yang lancar dan aman ke dunia pengembangan Java, memberi pengembang cara yang intuitif dan ekspresif untuk berinteraksi dengan basis data relasional. Dengan sintaks deklaratifnya, evaluasi yang malas, dan kemampuan menyusunnya, JPAStreamer memiliki kemiripan yang mencolok dengan pustaka LINQ C#. Dengan mengadopsi JPAStreamer, pengembang Java dapat memanfaatkan pendekatan ringkas dan efisien untuk menanyakan basis data, yang pada akhirnya menghasilkan kode yang lebih bersih dan lebih dapat dipelihara.

Sumber daya