

Terjemahan disediakan oleh mesin penerjemah. Jika konten terjemahan yang diberikan bertentangan dengan versi bahasa Inggris aslinya, utamakan versi bahasa Inggris.

# Bekerja dengan hasil paginasi: pemindaian dan kueri
<a name="ddb-en-client-use-multirecord"></a>

*Metode`scan`, `query` dan `batch` metode DynamoDB Enhanced Client API mengembalikan respons dengan satu halaman atau beberapa.* Sebuah halaman berisi satu atau lebih item. Kode Anda dapat memproses respons per halaman atau dapat memproses item individual.

Respons paginasi yang dikembalikan oleh `DynamoDbEnhancedClient` klien sinkron mengembalikan [PageIterable](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/enhanced/dynamodb/model/PageIterable.html)objek, sedangkan respons yang dikembalikan oleh `DynamoDbEnhancedAsyncClient` asinkron mengembalikan objek. [PagePublisher](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/enhanced/dynamodb/model/PagePublisher.html)

Bagian ini melihat pemrosesan hasil paginasi dan memberikan contoh yang menggunakan pemindaian dan kueri APIs.

## Memindai tabel
<a name="ddb-en-client-use-multirecord-scan"></a>

[https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/enhanced/dynamodb/DynamoDbAsyncTable.html#scan(java.util.function.Consumer)](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/enhanced/dynamodb/DynamoDbAsyncTable.html#scan(java.util.function.Consumer))Metode SDK sesuai dengan operasi [DynamoDB](https://docs.aws.amazon.com/amazondynamodb/latest/APIReference/API_Scan.html) dengan nama yang sama. DynamoDB Enhanced Client API menawarkan opsi yang sama tetapi menggunakan model objek yang sudah dikenal dan menangani pagination untuk Anda.

Pertama, kita menjelajahi `PageIterable` antarmuka dengan melihat `scan` metode kelas pemetaan sinkron,. [DynamoDbTable](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/enhanced/dynamodb/DynamoDbTable.html)

### Gunakan API sinkron
<a name="ddb-en-client-use-multirecord-scan-sync"></a>

Contoh berikut menunjukkan `scan` metode yang menggunakan [ekspresi](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/enhanced/dynamodb/Expression.html) untuk memfilter item yang dikembalikan. [ProductCatalog](ddb-en-client-use.md#ddb-en-client-use-compare-cs3)Ini adalah objek model yang ditunjukkan sebelumnya.

Ekspresi pemfilteran yang ditampilkan setelah baris komentar 2 membatasi `ProductCatalog` item yang dikembalikan ke item dengan nilai harga antara 8,00 dan 80,00 secara inklusif.

Contoh ini juga mengecualikan `isbn` nilai dengan menggunakan `attributesToProject` metode yang ditampilkan setelah baris komentar 1.

Setelah komentar baris 3, `PageIterable` objek`pagedResults`,, dikembalikan oleh `scan` metode. `stream`Metode `PageIterable` mengembalikan [https://docs.oracle.com/javase/8/docs/api/java/util/stream/Stream.html](https://docs.oracle.com/javase/8/docs/api/java/util/stream/Stream.html)objek, yang dapat Anda gunakan untuk memproses halaman. Dalam contoh ini, jumlah halaman dihitung dan dicatat.

Dimulai dengan baris komentar 4, contoh menunjukkan dua variasi mengakses `ProductCatalog` item. Versi setelah baris komentar 4a mengalir melalui setiap halaman dan mengurutkan dan mencatat item di setiap halaman. Versi setelah baris komentar 4b melewatkan iterasi halaman dan mengakses item secara langsung.

`PageIterable`Antarmuka menawarkan beberapa cara untuk memproses hasil karena dua antarmuka induknya— [https://docs.oracle.com/javase/8/docs/api/java/lang/Iterable.html](https://docs.oracle.com/javase/8/docs/api/java/lang/Iterable.html)dan [https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/core/pagination/sync/SdkIterable.html](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/core/pagination/sync/SdkIterable.html). `Iterable`membawa`forEach`, `iterator` dan `spliterator` metode, dan `SdkIterable` membawa `stream` metode.

```
    public static void scanSync(DynamoDbTable<ProductCatalog> productCatalog) {

        Map<String, AttributeValue> expressionValues = Map.of(
                ":min_value", numberValue(8.00),
                ":max_value", numberValue(80.00));

        ScanEnhancedRequest request = ScanEnhancedRequest.builder()
                .consistentRead(true)
                // 1. the 'attributesToProject()' method allows you to specify which values you want returned.
                .attributesToProject("id", "title", "authors", "price")
                // 2. Filter expression limits the items returned that match the provided criteria.
                .filterExpression(Expression.builder()
                        .expression("price >= :min_value AND price <= :max_value")
                        .expressionValues(expressionValues)
                        .build())
                .build();

        // 3. A PageIterable object is returned by the scan method.
        PageIterable<ProductCatalog> pagedResults = productCatalog.scan(request);
        logger.info("page count: {}", pagedResults.stream().count());

        // 4. Log the returned ProductCatalog items using two variations.
        // 4a. This version sorts and logs the items of each page.
        pagedResults.stream().forEach(p -> p.items().stream()
                .sorted(Comparator.comparing(ProductCatalog::price))
                .forEach(
                        item -> logger.info(item.toString())
                ));
        // 4b. This version sorts and logs all items for all pages.
        pagedResults.items().stream()
                .sorted(Comparator.comparing(ProductCatalog::price))
                .forEach(
                        item -> logger.info(item.toString())
                );
    }
```

### Gunakan API asinkron
<a name="ddb-en-client-use-multirecord-scan-async"></a>

`scan`Metode asinkron mengembalikan hasil sebagai objek. `PagePublisher` `PagePublisher`Antarmuka memiliki dua `subscribe` metode yang dapat Anda gunakan untuk memproses halaman respons. Salah satu `subscribe` metode berasal dari antarmuka `org.reactivestreams.Publisher` induk. Untuk memproses halaman menggunakan opsi pertama ini, berikan `[Subscriber](https://www.reactive-streams.org/reactive-streams-1.0.0-javadoc/org/reactivestreams/Subscriber.html)` instance ke `subscribe` metode. Contoh pertama yang berikut menunjukkan penggunaan `subscribe` metode.

`subscribe`Metode kedua berasal dari [SdkPublisher](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/core/async/SdkPublisher.html)antarmuka. Versi ini `subscribe` menerima [https://docs.oracle.com/javase/8/docs/api/java/util/function/Consumer.html](https://docs.oracle.com/javase/8/docs/api/java/util/function/Consumer.html)bukan a`Subscriber`. Variasi `subscribe` metode ini ditunjukkan pada contoh kedua berikut.

Contoh berikut menunjukkan versi asinkron dari `scan` metode yang menggunakan ekspresi filter yang sama yang ditunjukkan pada contoh sebelumnya. 

Setelah baris komentar 3, `DynamoDbAsyncTable.scan` mengembalikan `PagePublisher` objek. Pada baris berikutnya, kode membuat instance `org.reactivestreams.Subscriber` antarmuka,`ProductCatalogSubscriber`, yang berlangganan baris `PagePublisher` setelah komentar 4.

`Subscriber`Objek mengumpulkan `ProductCatalog` item dari setiap halaman dalam `onNext` metode setelah baris komentar 8 dalam contoh `ProductCatalogSubscriber` kelas. Item disimpan dalam `List` variabel pribadi dan diakses dalam kode panggilan dengan `ProductCatalogSubscriber.getSubscribedItems()` metode. Ini disebut setelah baris komentar 5.

Setelah daftar diambil, kode mengurutkan semua `ProductCatalog` item berdasarkan harga dan mencatat setiap item.

[CountDownLatch](https://docs.oracle.com/javase/7/docs/api/java/util/concurrent/CountDownLatch.html)Di `ProductCatalogSubscriber` kelas memblokir thread panggilan sampai semua item telah ditambahkan ke daftar sebelum melanjutkan setelah baris komentar 5. 

```
    public static void scanAsync(DynamoDbAsyncTable productCatalog) {
        ScanEnhancedRequest request = ScanEnhancedRequest.builder()
                .consistentRead(true)
                .attributesToProject("id", "title", "authors", "price")
                .filterExpression(Expression.builder()
                        // 1. :min_value and :max_value are placeholders for the values provided by the map
                        .expression("price >= :min_value AND price <= :max_value")
                        // 2. Two values are needed for the expression and each is supplied as a map entry.
                        .expressionValues(
                                Map.of( ":min_value", numberValue(8.00),
                                        ":max_value", numberValue(400_000.00)))
                        .build())
                .build();

        // 3. A PagePublisher object is returned by the scan method.
        PagePublisher<ProductCatalog> pagePublisher = productCatalog.scan(request);
        ProductCatalogSubscriber subscriber = new ProductCatalogSubscriber();
        // 4. Subscribe the ProductCatalogSubscriber to the PagePublisher.
        pagePublisher.subscribe(subscriber);
        // 5. Retrieve all collected ProductCatalog items accumulated by the subscriber.
        subscriber.getSubscribedItems().stream()
                .sorted(Comparator.comparing(ProductCatalog::price))
                .forEach(item ->
                        logger.info(item.toString()));
        // 6. Use a Consumer to work through each page.
        pagePublisher.subscribe(page -> page
                        .items().stream()
                        .sorted(Comparator.comparing(ProductCatalog::price))
                        .forEach(item ->
                                logger.info(item.toString())))
                .join(); // If needed, blocks the subscribe() method thread until it is finished processing.
        // 7. Use a Consumer to work through each ProductCatalog item.
        pagePublisher.items()
                .subscribe(product -> logger.info(product.toString()))
                .exceptionally(failure -> {
                    logger.error("ERROR  - ", failure);
                    return null;
                })
                .join(); // If needed, blocks the subscribe() method thread until it is finished processing.
    }
```

```
    private static class ProductCatalogSubscriber implements Subscriber<Page<ProductCatalog>> {
        private CountDownLatch latch = new CountDownLatch(1);
        private Subscription subscription;
        private List<ProductCatalog> itemsFromAllPages = new ArrayList<>();

        @Override
        public void onSubscribe(Subscription sub) {
            subscription = sub;
            subscription.request(1L);
            try {
                latch.await(); // Called by main thread blocking it until latch is released.
            } catch (InterruptedException e) {
                throw new RuntimeException(e);
            }
        }

        @Override
        public void onNext(Page<ProductCatalog> productCatalogPage) {
            // 8. Collect all the ProductCatalog instances in the page, then ask the publisher for one more page.
            itemsFromAllPages.addAll(productCatalogPage.items());
            subscription.request(1L);
        }

        @Override
        public void onError(Throwable throwable) {
        }

        @Override
        public void onComplete() {
            latch.countDown(); // Call by subscription thread; latch releases.
        }

        List<ProductCatalog> getSubscribedItems() {
            return this.itemsFromAllPages;
        }
    }
```

Contoh cuplikan berikut menggunakan versi `PagePublisher.subscribe` metode yang menerima baris `Consumer` setelah komentar 6. Parameter lambda Java mengkonsumsi halaman, yang selanjutnya memproses setiap item. Dalam contoh ini, setiap halaman diproses dan item pada setiap halaman diurutkan dan kemudian dicatat.

```
        // 6. Use a Consumer to work through each page.
        pagePublisher.subscribe(page -> page
                        .items().stream()
                        .sorted(Comparator.comparing(ProductCatalog::price))
                        .forEach(item ->
                                logger.info(item.toString())))
                .join(); // If needed, blocks the subscribe() method thread until it is finished processing.
```

`items`Metode `PagePublisher` membuka bungkus contoh model sehingga kode Anda dapat memproses item secara langsung. Pendekatan ini ditunjukkan dalam cuplikan berikut.

```
        // 7. Use a Consumer to work through each ProductCatalog item.
        pagePublisher.items()
                .subscribe(product -> logger.info(product.toString()))
                .exceptionally(failure -> {
                    logger.error("ERROR  - ", failure);
                    return null;
                })
                .join(); // If needed, blocks the subscribe() method thread until it is finished processing.
```

## Mengkueri Tabel
<a name="ddb-en-client-use-multirecord-query"></a>

Anda dapat menggunakan DynamoDB Enhanced Client untuk menanyakan tabel Anda dan mengambil beberapa item yang cocok dengan kriteria tertentu. [https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/enhanced/dynamodb/DynamoDbTable.html#query(software.amazon.awssdk.enhanced.dynamodb.model.QueryEnhancedRequest)](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/enhanced/dynamodb/DynamoDbTable.html#query(software.amazon.awssdk.enhanced.dynamodb.model.QueryEnhancedRequest))Metode ini menemukan item berdasarkan nilai kunci primer menggunakan `@DynamoDbPartitionKey` dan `@DynamoDbSortKey` anotasi opsional yang ditentukan pada kelas data Anda.

`query()`Metode ini memerlukan nilai kunci partisi dan secara opsional menerima kondisi kunci pengurutan untuk lebih menyempurnakan hasil. Seperti `scan` API, kueri mengembalikan a `PageIterable` untuk panggilan sinkron dan a `PagePublisher` untuk panggilan asinkron.

### `Query`contoh metode
<a name="ddb-en-client-use-multirecord-query-example"></a>

Contoh kode `query()` metode yang mengikuti menggunakan `MovieActor` kelas. Kelas data mendefinisikan kunci primer komposit yang terdiri dari **`movie`**atribut sebagai kunci partisi dan **`actor`**atribut sebagai kunci pengurutan. 

#### `MovieActor` kelas
<a name="ddb-en-client-use-movieactor-class"></a>

```
package org.example.tests.model;

import software.amazon.awssdk.enhanced.dynamodb.mapper.annotations.DynamoDbAttribute;
import software.amazon.awssdk.enhanced.dynamodb.mapper.annotations.DynamoDbBean;
import software.amazon.awssdk.enhanced.dynamodb.mapper.annotations.DynamoDbPartitionKey;
import software.amazon.awssdk.enhanced.dynamodb.mapper.annotations.DynamoDbSecondaryPartitionKey;
import software.amazon.awssdk.enhanced.dynamodb.mapper.annotations.DynamoDbSecondarySortKey;
import software.amazon.awssdk.enhanced.dynamodb.mapper.annotations.DynamoDbSortKey;

import java.util.Objects;

@DynamoDbBean
public class MovieActor implements Comparable<MovieActor> {

    private String movieName;
    private String actorName;
    private String actingAward;
    private Integer actingYear;
    private String actingSchoolName;

    @DynamoDbPartitionKey
    @DynamoDbAttribute("movie")
    public String getMovieName() {
        return movieName;
    }

    public void setMovieName(String movieName) {
        this.movieName = movieName;
    }

    @DynamoDbSortKey
    @DynamoDbAttribute("actor")
    public String getActorName() {
        return actorName;
    }

    public void setActorName(String actorName) {
        this.actorName = actorName;
    }

    @DynamoDbSecondaryPartitionKey(indexNames = "acting_award_year")
    @DynamoDbAttribute("actingaward")
    public String getActingAward() {
        return actingAward;
    }

    public void setActingAward(String actingAward) {
        this.actingAward = actingAward;
    }

    @DynamoDbSecondarySortKey(indexNames = {"acting_award_year", "movie_year"})
    @DynamoDbAttribute("actingyear")
    public Integer getActingYear() {
        return actingYear;
    }

    public void setActingYear(Integer actingYear) {
        this.actingYear = actingYear;
    }

    @DynamoDbAttribute("actingschoolname")
    public String getActingSchoolName() {
        return actingSchoolName;
    }

    public void setActingSchoolName(String actingSchoolName) {
        this.actingSchoolName = actingSchoolName;
    }

    @Override
    public String toString() {
        final StringBuffer sb = new StringBuffer("MovieActor{");
        sb.append("movieName='").append(movieName).append('\'');
        sb.append(", actorName='").append(actorName).append('\'');
        sb.append(", actingAward='").append(actingAward).append('\'');
        sb.append(", actingYear=").append(actingYear);
        sb.append(", actingSchoolName='").append(actingSchoolName).append('\'');
        sb.append('}');
        return sb.toString();
    }

    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;
        MovieActor that = (MovieActor) o;
        return Objects.equals(movieName, that.movieName) && Objects.equals(actorName, that.actorName) && Objects.equals(actingAward, that.actingAward) && Objects.equals(actingYear, that.actingYear) && Objects.equals(actingSchoolName, that.actingSchoolName);
    }

    @Override
    public int hashCode() {
        return Objects.hash(movieName, actorName, actingAward, actingYear, actingSchoolName);
    }

    @Override
    public int compareTo(MovieActor o) {
        if (this.movieName.compareTo(o.movieName) != 0){
            return this.movieName.compareTo(o.movieName);
        } else {
            return this.actorName.compareTo(o.actorName);
        }
    }
}
```

Contoh kode yang mengikuti kueri terhadap item berikut.

#### Item dalam `MovieActor` tabel
<a name="ddb-en-client-use-movieactor-items"></a>

```
MovieActor{movieName='movie01', actorName='actor0', actingAward='actingaward0', actingYear=2001, actingSchoolName='null'}
MovieActor{movieName='movie01', actorName='actor1', actingAward='actingaward1', actingYear=2001, actingSchoolName='actingschool1'}
MovieActor{movieName='movie01', actorName='actor2', actingAward='actingaward2', actingYear=2001, actingSchoolName='actingschool2'}
MovieActor{movieName='movie01', actorName='actor3', actingAward='actingaward3', actingYear=2001, actingSchoolName='null'}
MovieActor{movieName='movie01', actorName='actor4', actingAward='actingaward4', actingYear=2001, actingSchoolName='actingschool4'}
MovieActor{movieName='movie02', actorName='actor0', actingAward='actingaward0', actingYear=2002, actingSchoolName='null'}
MovieActor{movieName='movie02', actorName='actor1', actingAward='actingaward1', actingYear=2002, actingSchoolName='actingschool1'}
MovieActor{movieName='movie02', actorName='actor2', actingAward='actingaward2', actingYear=2002, actingSchoolName='actingschool2'}
MovieActor{movieName='movie02', actorName='actor3', actingAward='actingaward3', actingYear=2002, actingSchoolName='null'}
MovieActor{movieName='movie02', actorName='actor4', actingAward='actingaward4', actingYear=2002, actingSchoolName='actingschool4'}
MovieActor{movieName='movie03', actorName='actor0', actingAward='actingaward0', actingYear=2003, actingSchoolName='null'}
MovieActor{movieName='movie03', actorName='actor1', actingAward='actingaward1', actingYear=2003, actingSchoolName='actingschool1'}
MovieActor{movieName='movie03', actorName='actor2', actingAward='actingaward2', actingYear=2003, actingSchoolName='actingschool2'}
MovieActor{movieName='movie03', actorName='actor3', actingAward='actingaward3', actingYear=2003, actingSchoolName='null'}
MovieActor{movieName='movie03', actorName='actor4', actingAward='actingaward4', actingYear=2003, actingSchoolName='actingschool4'}
```

Kode berikut mendefinisikan dua `QueryConditional` contoh: `keyEqual` (setelah baris komentar 1) dan `sortGreaterThanOrEqualTo` (setelah baris komentar 1a).

#### Item kueri dengan kunci partisi
<a name="keyEqual-query-conditional-example"></a>

`keyEqual`Instance mencocokkan item dengan nilai kunci partisi dari **`movie01`**. 

Contoh ini juga mendefinisikan ekspresi filter setelah baris komentar 2 yang menyaring item apa pun yang tidak memiliki **`actingschoolname`**nilai.

`QueryEnhancedRequest`Menggabungkan kondisi kunci dan ekspresi filter untuk kueri.

```
    public static void query(DynamoDbTable movieActorTable) {

        // 1. Define a QueryConditional instance to return items matching a partition value.
        QueryConditional keyEqual = QueryConditional.keyEqualTo(b -> b.partitionValue("movie01"));
        // 1a. Define a QueryConditional that adds a sort key criteria to the partition value criteria.
        QueryConditional sortGreaterThanOrEqualTo = QueryConditional.sortGreaterThanOrEqualTo(b -> b.partitionValue("movie01").sortValue("actor2"));
        // 2. Define a filter expression that filters out items whose attribute value is null.
        final Expression filterOutNoActingschoolname = Expression.builder().expression("attribute_exists(actingschoolname)").build();

        // 3. Build the query request.
        QueryEnhancedRequest tableQuery = QueryEnhancedRequest.builder()
                .queryConditional(keyEqual)
                .filterExpression(filterOutNoActingschoolname)
                .build();
        // 4. Perform the query using the "keyEqual" conditional and filter expression.
        PageIterable<MovieActor> pagedResults = movieActorTable.query(tableQuery);
        logger.info("page count: {}", pagedResults.stream().count()); // Log  number of pages.

        pagedResults.items().stream()
                .sorted()
                .forEach(
                        item -> logger.info(item.toString()) // Log the sorted list of items.
                );
```

**Example — Output menggunakan `keyEqual` query kondisional**  
Berikut ini adalah output dari menjalankan metode. Output menampilkan item dengan `movieName` nilai **movie01** dan tidak menampilkan item yang `actingSchoolName` sama dengan. **`null`**  

```
2023-03-05 13:11:05 [main] INFO  org.example.tests.QueryDemo:46 - page count: 1
2023-03-05 13:11:05 [main] INFO  org.example.tests.QueryDemo:51 - MovieActor{movieName='movie01', actorName='actor1', actingAward='actingaward1', actingYear=2001, actingSchoolName='actingschool1'}
2023-03-05 13:11:05 [main] INFO  org.example.tests.QueryDemo:51 - MovieActor{movieName='movie01', actorName='actor2', actingAward='actingaward2', actingYear=2001, actingSchoolName='actingschool2'}
2023-03-05 13:11:05 [main] INFO  org.example.tests.QueryDemo:51 - MovieActor{movieName='movie01', actorName='actor4', actingAward='actingaward4', actingYear=2001, actingSchoolName='actingschool4'}
```

#### Item kueri dengan kunci partisi dan kunci sortir
<a name="sort-type-query-conditional-example"></a>

`sortGreaterThanOrEqualTo``QueryConditional`**Menyempurnakan kecocokan kunci partisi (**movie01**) dengan menambahkan kondisi kunci pengurutan untuk nilai yang lebih besar dari atau sama dengan aktor2.**

[`QueryConditional`metode](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/enhanced/dynamodb/model/QueryConditional.html) yang dimulai dengan `sort` memerlukan nilai kunci partisi untuk mencocokkan dan selanjutnya menyempurnakan kueri dengan perbandingan berdasarkan nilai kunci sortir. `Sort`dalam nama metode tidak berarti hasilnya diurutkan, tetapi nilai kunci sortir akan digunakan untuk perbandingan.

Dalam cuplikan berikut, kami mengubah permintaan kueri yang ditampilkan sebelumnya setelah baris komentar 3. Cuplikan ini menggantikan kueri “KeyEqual” bersyarat dengan syarat kueri "sortGreaterThanOrEqualTo" yang ditentukan setelah baris komentar 1a. Kode berikut juga menghapus ekspresi filter.

```
        QueryEnhancedRequest tableQuery = QueryEnhancedRequest.builder()
                .queryConditional(sortGreaterThanOrEqualTo).build();
```

**Example — Output menggunakan `sortGreaterThanOrEqualTo` query kondisional**  
Output berikut menampilkan hasil dari query. **Kueri mengembalikan item yang memiliki `movieName` nilai sama dengan **movie01** dan hanya item yang memiliki `actorName` nilai yang lebih besar dari atau sama dengan actor2.** Karena kita menghapus filter, query mengembalikan item yang tidak memiliki nilai untuk `actingSchoolName` atribut.  

```
2023-03-05 13:15:00 [main] INFO  org.example.tests.QueryDemo:46 - page count: 1
2023-03-05 13:15:00 [main] INFO  org.example.tests.QueryDemo:51 - MovieActor{movieName='movie01', actorName='actor2', actingAward='actingaward2', actingYear=2001, actingSchoolName='actingschool2'}
2023-03-05 13:15:00 [main] INFO  org.example.tests.QueryDemo:51 - MovieActor{movieName='movie01', actorName='actor3', actingAward='actingaward3', actingYear=2001, actingSchoolName='null'}
2023-03-05 13:15:00 [main] INFO  org.example.tests.QueryDemo:51 - MovieActor{movieName='movie01', actorName='actor4', actingAward='actingaward4', actingYear=2001, actingSchoolName='actingschool4'}
```