jpa-streamer icon indicating copy to clipboard operation
jpa-streamer copied to clipboard

Sometimes JPA Stream doesn't load properties with relationships

Open doardin opened this issue 4 years ago • 2 comments

My Account class:

public class Account {
    @Id
    private String id;
    
    private String owner;

    @OneToOne
	@JoinColumn(name = "statusId")
    private Status status;
}

My AccountStatus class:

public class Status {   		
	@Id
	private String id = UUID.randomUUID().toString().toUpperCase();

	private String name;

	public Status(String name){
		this.name = name;
	}
}

My query with JPA

public Account findAccount(String owner){
        Account account = this.streamer.stream(Account.class).filter(
            Account$.owner.equal(owner)
        ).findFirst().orElseThrow(AccountNotFound::new);
        if (account.getStatus().getName().equalsIgnoreCase("CLOSED"))
            throw new AccountNotFound();

        return account;
}

Sometimes the AccountStatus wasn't load and returning error. I fixed this bug changing JPAStream query to JPQL

doardin avatar Sep 28 '21 15:09 doardin

Could you provide more information? For example, under which conditions the Status is not loaded. If it is not loaded, is null returned instead? Can you provide the logs of SQL. Did you also try joining the tables (e.g. using StreamConfiguration?

minborg avatar Sep 28 '21 19:09 minborg

SQL: select account0_.id as account_3_0_, account0_.status_id as account_9_0_, account0_.owner as owner6_0_ from account account0_ where account0_.owner=?

It was hard to debug because it's rare for the account's status object to return null, but sometimes it did return. I did not try joining the tables

And the account status returned null for the same account, and when I went to check the database, the status was filled.

doardin avatar Sep 30 '21 12:09 doardin

Hi, I would love to take a closer look at this issue. However, it isn't easy to reproduce without your database and code example. Are you able to provide any more information?

Generally, I recommend performing a join when in need of information from another table. In this case that would look like this:

StreamConfiguration sc = StreamConfiguration.of(Account.class).joining(Account$.status); 
Account account = this.streamer.stream(sc)
       .filter(Account$.owner.equal(owner))
       .findFirst().orElseThrow(AccountNotFound::new);

julgus avatar Jun 05 '23 14:06 julgus

I tried to reproduce the error here and was unsuccessful, but what I noticed was that even marking the property with fetch type lazy, the property was still loaded.

doardin avatar Jun 16 '23 19:06 doardin

Thanks for the update, as both of us failed to reproduce the issue I will close it for now.

Regarding the fetching, that is a question for the underlying JPA provider. JPAStreamer does not interact with the database directly (only via the JPA provider) and thus cannot control how the data is fetched.

julgus avatar Jun 26 '23 12:06 julgus