0

I have an entity structure:

@Entity
@Table(name = "Book")
public class Book {

    @Id
    @Access(AccessType.PROPERTY)
    @GeneratedValue(strategy = GenerationType.AUTO)
    private Long id;

    @ManyToOne(fetch = FetchType.LAZY, optional = false)
    @JoinColumn(name = "AUT_ID")
    @Fetch(FetchMode.JOIN)
    private Author author;

    Book(){}

    public Book(Author author) {
        this.author = author;
    }

    public Long getId() {
        return this.id;
    }

    public Author getAuthor() {
        return this.author;
    }

}


@Entity
@Table(name = "Author")
public class Author {

    @Id
    @Access(AccessType.PROPERTY)
    @GeneratedValue(strategy= GenerationType.AUTO)
    private Long id;

    @OneToMany(mappedBy = "author", fetch = FetchType.LAZY)
    private List<Book> books;

    Author(){}

    public Long getId() {
        return this.id;
    }

    public List<Book> getBooks() {
        return this.books;
    }
}

I have read in other answers that having an @Id field with @Access(AccessType.PROPERTY) allows me to do something like:

// BookRepository is just a CrudRepository<Book,Long>
Book book = bookRepository.findById(1L); // Triggers a Select Query
Long authorId = book.getAuthor().getId(); // Does not trigger a query

And only a single query would be made to the DB because the Author ID is already loaded from the initial select.

When I do this and boot up my Spring Boot app I get:

org.hibernate.PropertyNotFoundException: Could not locate setter method for property [com.demo.repository.persistance.entity.Book#id]

org.hibernate.PropertyNotFoundException: Could not locate setter method for property [com.demo.repository.persistance.entity.Author#id]

This presumably means I need to have a setId method on my Entities I would rather not do this as it makes ID mutable. Is there a way I can get the benefits of Property Access (i.e that no extra query is made for a getId on a child object) and keep my IDs immutable?


If I remove the Access annotations my SQL log looks like:

DEBUG o.h.SQL:92 - select book0_.id as id1_1_, book0_.aut_id as aut_id2_1_ from book book0_ where book0_id=?
TRACE o.h.t.d.s.BasicBinder:65 - binding parameter [1] as [BIGINT] - [1]
DEBUG o.h.SQL:92 - select author0_.id as id1_0_0_ from author author0_ where author0_.id=?
TRACE o.h.t.d.s.BasicBinder:65 - binding parameter [1] as [BIGINT] - [1]
Community
  • 1
  • 1
Eduardo
  • 6,900
  • 17
  • 77
  • 121
  • Why would you need that? The `getId` wouldn't trigger a query anyway because the related entity is loaded eagerly. – M. Deinum Jan 08 '18 at 11:23
  • @M.Deinum Try removing the `@Access` annotations and running similar code, a second query to get the author/child object runs (or at least is printed in the SQL log). – Eduardo Jan 08 '18 at 11:24
  • That shouldn't happen with the annotations you have als the access mode wouldn't change that.. – M. Deinum Jan 08 '18 at 11:25
  • @M.Deinum My apologies I was experimenting with Eager to see if that fixed it, question has been changed – Eduardo Jan 08 '18 at 11:25
  • Only collection based relations are loaded lazy everything else should be loaded eagerly... Why are you loading a single entity lazy? And as stated access mode won't change that. – M. Deinum Jan 08 '18 at 11:26
  • @M.Deinum Yep correct. I've added the SQL log to prove im getting the issue when removing the `@Access` – Eduardo Jan 08 '18 at 11:41
  • @M.Deinum In fact even adding a setter doesnt solve the problem. Hibernate always makes a `SELECT .. FROM AUTHOR` query regardless – Eduardo Jan 08 '18 at 11:51
  • Because you declared it as a `LAZY` property... Don't make it lazy and it will be loaded, why would you want to make it lazy. – M. Deinum Jan 08 '18 at 11:54
  • @M.Deinum Eager loading doesnt seem to fix anything unfortunately, the SQL log remains the same with the two queries – Eduardo Jan 08 '18 at 11:56
  • @Access(AccessType.PROPERTY) means that JPA is calling getter and setter to access the field after select or before insert or update. – Simon Martinelli Jan 08 '18 at 12:51
  • Excuse me, why I can't find @Access(AccessType.PROPERTY) in my spring boot framework – moussesj94 Jun 13 '19 at 04:08

1 Answers1

0

@Access(AccessType.PROPERTY) means that JPA is calling getter and setter to access the field after select or before insert or update.

If you in some cases only need the authorId then map it read only in the Book entity:

@Column(name = "aut_id", insertable = false, updatable = false)
private Long authorId;
Eduardo
  • 6,900
  • 17
  • 77
  • 121
Simon Martinelli
  • 34,053
  • 5
  • 48
  • 82