DTO-based projections

While you can use DTO-based projections similarly to interface-based projections with a subset of existing domain class properties, DTO-based projections really shine when you want to add additional properties to an entity.

What if you wanted to calculate cast size and add it to the display data as a fun fact for users to know? In this lesson, you will create a DTO projection that contains the title, released, poster, and castSize properties to find out!

MovieDTO class

First, you need to create a DTO class that contains the few properties. Open the src/main/java/com/example/appspringdata folder and add a new class named MovieDTOProjection.java. Then add the properties title, released, poster, and castSize.

java
public class MovieDTOProjection {

    String title;
    String released;
    String poster;

    Long castSize;

    //getters and setters
}

Now update the MovieRepository and MovieController by adding a new method to each that returns a list of MovieDTOProjection. The repository will need a custom query that returns the movie and counts the related Person entities as a castSize variable, and the controller should use the /dtocast endpoint.

java
interface MovieRepository extends Neo4jRepository<Movie, String> {
    //other methods

    @Query("MATCH (m:Movie)<-[r:ACTED_IN]-(p:Person) " +
            "RETURN m, COUNT(p) AS castSize LIMIT 10;")
    Iterable<MovieDTOProjection> findAllDTOProjectionsWithCustomQuery();
}
@RestController
@RequestMapping("/movies")
public class MovieController {
    //other methods

    @GetMapping("/dtocast")
    Iterable<MovieDTOProjection> findAllMovieDTOProjections() { 
        return movieRepo.findAllDTOProjectionsWithCustomQuery();
    }
}

In the repository method above, the custom query calculates the castSize so that it maps to the property name in your DTO class.

Now, when you test the application and call the /movies/dtocast endpoint, you will get the four properties specified in your DTO projection, including the calculated castSize property.

shell
curl 'localhost:8080/movies/movielist'
FindMovieDTOProjections sample results
[
    {
        "title":"Toy Story",
        "released":"1995-11-22",
        "poster":"https://image.tmdb.org/t/p/w440_and_h660_face/uXDfjJbdP4ijW5hWSBrPrlKpxab.jpg",
        "castSize":4
    },
    {
        "title":"Jumanji",
        "released":"1995-12-15",
        "poster":"https://image.tmdb.org/t/p/w440_and_h660_face/vgpXmVaVyUL7GGiDeiK1mKEKzcX.jpg",
        "castSize":4
    }
    //more results
]

Cast size = 4

You might notice that nearly all of the cast sizes have a value of 4. This is because the data was only imported with a maximum of four actors per movie. If you wanted to get a more accurate cast size, you would need to alter the data import to include all actors for each movie.

Further reading

More information on projections and additional capabilities can be found in the documentation for Spring Data Neo4j Projections.

Caution! DTO-based projection

DTO projection (by nature) in Spring Data should not be used to reduce the load. SDN cannot check what will happen within the projection, and it supports capabilities (e.g. SpEL expressions) that might access fields in the domain class that are not explicitly mentioned in the projection. For this reason, SDN will fetch the whole entity, so the data transferred over the wire is not smaller.

Summary

In this lesson, you learned about and created a DTO-based projection, adding a new property to the Movie class for a calculated cast size.

Next, you will learn about some resources for continuing to learn Spring Data Neo4j.