1

I'm using Spring data with Hibernate and MySql and I have a doubt. My entity is

@Entity
@Table(name = "car", catalog = "DEMO")
public class Car implements java.io.Serializable {

    /**
     * 
     */
    private static final long serialVersionUID = 1L;
    private Integer idCar;
    @JsonBackReference
    private CarType carType;
    @JsonBackReference
    private Fleet fleet;
    private String id;
    private int initialKm;
    private String carChassis;
    private String note;
    @JsonManagedReference
    private Set<Acquisition> acquisitions = new HashSet<Acquisition>(0);

with get and set method. Sometimes, I need external object as carType, another entity. If I use this webservice

@Override
    @RequestMapping(value = { "/cars/{idFleet}"}, method = RequestMethod.GET)
    public String getCars(@PathVariable int idFleet, Model model){  
        try{
            model.addAttribute("carsList",fleetAndCarService.findCarsByIdFleet(idFleet));
            //Modal parameter
            model.addAttribute("carTypeList",fleetAndCarService.getCarsType());
            model.addAttribute("fleetApplication",fleetAndCarService.getFleetById(idFleet));            
            model.addAttribute("carForm", new CarForm());
            model.addAttribute("error",false);
        }catch (Exception e){
            LOG.error("Threw exception in FleetAndCarControllerImpl::getCars : " + ErrorExceptionBuilder.buildErrorResponse(e));
            model.addAttribute("error",true);
        }
        return "cars";
    }

from my html page I can retrieve carType.idCarType,but if I use this

@Override
    @RequestMapping(value = { "/cars/{idFleet}"}, method = RequestMethod.GET)
    public @ResponseBody TableUI getCars(@PathVariable int idFleet) {   
        TableUI ajaxCall=new TableUI();
        try {   
            ajaxCall.setData(fleetAndCarService.findCarsByIdFleet(idFleet));
            return ajaxCall;
        } catch (QueryException e) {
            ErrorResponse errorResponse= ErrorResponseBuilder.buildErrorResponse(e);
            LOG.error("Threw exception in FleetAndCarControllerImpl::addCar :" + errorResponse.getStacktrace());
            return ajaxCall;
        }
    }

where TableUi has only a field data where I put the result to use it into datatables, I don't have carType and fleet. Why? Do I have to use Hibernate.initialize, and how so it is a list?Thansk,regards

Also this update doesn't work:

@Override
@Transactional
public List<Car> findByFleetIdFleet(int idFleet) {
    List<Car> carList= carRepository.findByFleetIdFleet(idFleet);
    for (Car car:carList)
        Hibernate.initialize(car.getCarType());
    return carList; 
}
luca
  • 3,248
  • 10
  • 66
  • 145
  • I'm a little confused by your question. Are you saying the carType and fleet are null in the second code snippet or the first code snippet? – Pace Nov 03 '15 at 18:53
  • in the second code there aren't fleet and carType – luca Nov 04 '15 at 07:50

1 Answers1

0

You could call Hibernate.initialize on each element

Collection<Car> cars = fleetAndCarService.findCarsByIdFleet(idFleet);
for(Car car : cars) {
    Hibernate.initialize(car.getCarType());
    Hibernate.initialize(car.getFleet());
}
ajaxCall.setData();
return ajaxCall;

This would be a good starting point and would allow you to move forwards. At high scales however this could become a performance bottleneck as it will perform a query with each call to initialize so you will have 2*n queries to the database.

For maximum performance you will have several other options:

  1. Iterate through the cars and build up a list of IDs and then query for the car types by ID in a single query with the list of IDs. Do the same for the fleets. Then call Hibernate.initialize. The first two queries will populate the persistence context and the call to initialize will not need to go to the database.

  2. Create a special query for this call which fetch joins the properties you will need.

  3. Setup batch fetching which will fetch the cards and fleets in batches instead of one car/fleet per query.

  4. Use a second level cache so the initialization causes Hibernate to pull from the cache instead of the database.

Describing these options in details is beyond the scope of a single question but a good place to start would be Hibernate's documentation on performance.

Pace
  • 41,875
  • 13
  • 113
  • 156
  • The first approach is been used yesterday but into carServiceImpl and it didn't work. In this case carType is an object with only one field, a lookup table for my webui so it would have to be the same, or not? For example acquisition is ever returned but I don't need it. The 2 and 4 seem me the best, I have to search how to implement them. – luca Nov 04 '15 at 11:02
  • Actually, now that I look closer, you've marked those two fields with JsonBackReference. Those fields don't will be ignored for serialization. I don't think this is necessarily an initialization issue. – Pace Nov 04 '15 at 18:39
  • that I have marked JsonManagedReference I retrieve, JsonBackReference are ignored. I had to use these annotation to resolve exception on infinite recursion. I don't know where is the problem – luca Nov 05 '15 at 07:50
  • Any field marked with @JsonBackReference will be ignored during serialization. That is why it is preventing the infinite recursion but it is also why you are not getting values in these fields. You will need to work around this somehow in your design. – Pace Nov 05 '15 at 11:24
  • this is a problem with hibernate not with my ER model. I used hibernate tools to generate my entity, but it adds fields that are not included in my model. For example car has id_fleet and id_carType, where aI generate entity it adds Acquisition. If I make query in mysql workbench all works right. I'm new in hibernate. – luca Nov 05 '15 at 11:30
  • I no longer think the issue is with Hibernate or your ER model. The issue is with serialization. If you have a circular reference then you have to work around that in some way when you serialize. By marking the entities with JsonBackReference you are telling Jackson (the JSON serializer) to set those entities to null when serializing. – Pace Nov 06 '15 at 02:02
  • So JsonBackReference is the problem in my case because I need sometimes those values. But how can I fix circular reference without JsonBackReference ? – luca Nov 06 '15 at 15:27
  • I don't know any universal answer but I can tell you my experiences. Typically for a one-to-one I don't have a circular reference in my model so I haven't dealt with that much. For a one-to-many I usually include the parent reference in the child but do not include the child reference in the parent. I then have a separate API call to return a list of children given a parent should I need that. For a many-to-many I often don't serialize either side and have separate API calls for retrieving either. – Pace Nov 06 '15 at 23:47
  • so you don't put a Set structure into parent, only one object to refer to parent into child? – luca Nov 12 '15 at 15:00
  • Usually I have the Set structure in the parent but I do not serialize it (I mark it with @JsonIgnore) – Pace Nov 12 '15 at 20:55
  • I opened one post http://stackoverflow.com/questions/33690096/mapping-hibernate-class-with-jackson-annotation – luca Nov 13 '15 at 10:02