0

I have the following Entities(connected to db):

@Entity
public class Campaign {
  // ...
  @OneToMany(fetch = FetchType.LAZY)
  private List<Subscriber> subscribers;
}

@Entity
public class Subscriber {
  // ...
}

I want to fetch the Campaigns but ignore Subscribers. In my controller I jsonify Campaigns but that triggers an error because it attempts to lazy load Subscribers. In this case I don't want it to lazy load Subscribers, just print out the Campaigns (In other cases I want to print out both).

I tried selecting specific fields in an hql query but that returns an array not an object.

Brayden Hancock
  • 786
  • 1
  • 6
  • 22
  • Yes so figure out how to ignore properties with whatever library is used to convert objects to json, its not a problem for Hibernate to solve. – Gimby Mar 06 '17 at 19:54
  • Which library do you use for JSON? – v.ladynev Mar 06 '17 at 20:58
  • what about creating a form object with methods for example `campaignWithSubscribers(Campaign campaign)` and `campaignWithoutSubscribers(Campaign campaign)` and you write a code to set the required values. – Pavan Kumar Jorrigala Mar 06 '17 at 21:52
  • I'm using java spring @RestController (I just return an object and it does the jsonify stuff). – Brayden Hancock Mar 07 '17 at 02:41

3 Answers3

2

As @Gimbly said I was looking at the problem incorrectly, needed to look at what was serializing the object. I got the answer from the following post:

Avoid Jackson serialization on non fetched lazy objects

Community
  • 1
  • 1
Brayden Hancock
  • 786
  • 1
  • 6
  • 22
1

The subscribers database query only is only triggered when somebody executes the method getSubscribers() (that is actually a proxy list).

So, if the subscribers field would be null, the query will never be triggered.

That said, a fast (but not so clean) solution would be create a method that set null to this field, but without alter the database, like this:

@PersistentContext
private EntityManager em;

/* ... */

private void detachCampaigns(List<Campaign> campaigns){
    for(Campaign c: campaigns){
        em.detach(c);           // Exclude from JPA context
        c.setSubscribers(null); // inhibits lazy proxy list
    }
}

The method detachCampaigns() will:

  • Detach every campaign object from JPA context (memory). From now on any modification on them won't be applied to database.
  • Set subscribers list to null overriding the proxy object, so if your code try to call to getSubscriers(), this won't access database avoiding your problem.

After this, you just need to call this method before jsonify the campaigns.

Wilfredo Pomier
  • 1,091
  • 9
  • 12
0

The main problem is that you want to serialize Entities rather than read-only projections.

In the latter case, you can easily define the fields you want to have in the result and you don't have to deal with any lazy-loading issue.

It's a good practice to use entities only when you need to change the state.

For creating projections, you can go with the Spring Data JPA way which is basically defining an interface and the framework will take care of the others.

If you are not able to use Spring Data JPA, then you can define your projection as a class, and fetch the necessary attributes through JPQL/HQL/Criteria API or even native query.

Arnold Galovics
  • 3,246
  • 3
  • 22
  • 33