2

I was wondering if anyone can give feedback on a pattern that I am currently playing around with? It involves having an entity implementing a DTO interface that is also used (as a projection) in a JpaRepository interface – for the same entity – to return query results with specific columns. The DTO interface also has default methods to allow any instances of the entity and the DTO proxies to have similar behaviours.

The questions I am looking to have answered are whether this pattern has any drawbacks such as performance that might prevent one from using it in production. I am also interested to hear how others are querying specific data fields using JpaRepositories. Below I have a code sample that illustrates the pattern that I am playing with.

public interface InstructorDTO {
    String getFirstName();
    String getLastName();

    default String getFullName() {
        return getFirstName() + ' ' + getLastName();
    }
}

@Entity
public class Instructor implements InstructorDTO {
    @Id
    @GeneratedValue(strategy= GenerationType.AUTO)
    private int id;

    @Column(name="first_name")
    private String firstName;

    @Column(name="last_name")
    private String lastName;

    @Column(unique = true)
    private String email;

    @Override
    public String getFirstName() {
        return this.firstName;
    }

    @Override
    public String getLastName() {
        return this.lastName;
    }

    ...remaining getters and setters
}

@Repository
public interface InstructorRepository extends JpaRepository<Instructor, Integer> {

    <S> S findById(int id, Class<S> type);

    <T> Collection<T> findByEmail(String email, Class<T> type);
}


public class SomeClass {
    @Autowired
    InstructorRepository instructorRepository;

    public void someMethod {
        int id = 1;

        // Returns proxy
        InstructorDTO instructor1 = instructorRepository.findById(id, InstructorDTO.class);

        // Returns Instructor Object
        Instructor instructor2 = instructorRepository.findOne(id);

        System.out.println(instructor1.getFullName()); // returns John Doe
        System.out.println(instructor2.getFullName()); // returns John Doe
    }
}
Andy Tang
  • 51
  • 2
  • 7

1 Answers1

1

There are no drawbacks with this solution in contrast. It's much better to use DTOs instead of Entities if you just need a few columns.

Because if you use DTOs only on SQL statement will be generated for selecting the data. Where as if you use Entities eager or lazy fetched relationships can be loaded and this may cause the n+1 select problem.

It's only questionable if you really want your Entities extend the DTO. That doesn't make sense in my opinion.

Two recommendations.

Simon Martinelli
  • 34,053
  • 5
  • 48
  • 82
  • Thanks for the swift reply! I'll make sure to keep your recommendations in mind when coding. At the moment I need both the entity and the DTO as I will be writing APIs to retrieve all information from the entity and some that only needs a few columns. Another reason is that I will be continuing someone else's work in a project and the database used is currently constructed by the entity classes. Can you refer to me some examples of using DTO? – Andy Tang Sep 18 '18 at 07:33
  • What examples do you have in mind? DTO is just a class or an interface containing some fields. – Simon Martinelli Sep 18 '18 at 07:37
  • Still not clear with what you are saying about "It's much better to use DTOs instead of Entities if you just need a few columns." I am using a DTO interface to select just the first name and last name. The reason for having the methods in the JpaRepository interface return general objects is so I can pass other DTOS that target other fields. – Andy Tang Sep 18 '18 at 07:44
  • Oh do you mean using the query paramater? e.g. @Query("select p.firstname, p.lastname from instructor p where p.firstName = ? and p.lastName=?") InstructorDTO findInfo(String firstName, String lastName); – Andy Tang Sep 18 '18 at 07:56
  • No? Can we chat? – Simon Martinelli Sep 18 '18 at 09:25
  • Sure! Thanks for your help! – Andy Tang Sep 19 '18 at 03:56
  • you have to initate the chat because you are the Asker – Simon Martinelli Sep 19 '18 at 09:22
  • I unfortunately do not have enough reputation to start a chat :( – Andy Tang Sep 19 '18 at 10:19
  • do you have a skype id? – Simon Martinelli Sep 19 '18 at 11:38