0

I am using Hibernate OGM (5.2.0.Alpha1) with Mongodb (3.4)

@Entity
@Table(name = "service")
@JsonInclude(Include.NON_EMPTY)
public class Service {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    @Column(name = "SERVICE_ID", unique = true, nullable = false)
    @JsonSerialize(using = ToStringSerializer.class)
    public ObjectId id;

    private String name;

    @ManyToOne
    @JsonIgnore
    public Lab lab;

    getter....
    setter....
}

@Entity
@Table(name = "lab")
@JsonInclude(Include.NON_EMPTY)
// @JsonFilter(value=SalesUtils.MY_CUSTOM_FILTER_FOR_LAB)
public class Lab {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    @JsonSerialize(using = ToStringSerializer.class)
    @Column(name = "LAB_ID", unique = true, nullable = false)
    public ObjectId id;

    private String name;

    @OneToMany(mappedBy = "lab")
    public List<Service> listOfServices;

    getter....
    setter....
}

Dao Layer:

public <T> List<T> executeQuery(String query, Integer startPosition, Integer noOfRecords, T t) {
        List<T> listOfT = new ArrayList<>();

        if (SalesUtils.isObjectisNullOrEmpty(startPosition, noOfRecords)) {
            listOfT = entityManager.createNativeQuery(query.toString(), t.getClass()).getResultList();
        } else {
            listOfT = entityManager.createNativeQuery(query.toString(), t.getClass()).setFirstResult(startPosition)
                    .setMaxResults(noOfRecords).getResultList();
        }
        return SalesUtils.isListIsNullOrEmpty(listOfT) ? new ArrayList<>() : listOfT;
    }

Service Layer : (Issue : Lab name : null)

@Transaction
public void executeQuery(){

    String query = "db.service.find({} , {"name":1})";
    List<Service> listOfServices = myDao.executeQuery(query , null , null ,new Service());

    String anotherQuery = " { $query : { name : "CDG Service"}}";
    List<Service> listOfAnotherServices = myDao.executeQuery(query , null , null ,new Service());

    if (!SalesUtils.isListIsNullOrEmpty(listOfAnotherServices )) {
        System.out.println(listOfAnotherServices.get(0).getName());
        System.out.println(listOfAnotherServices.get(0).getLab().getName()); //null 
    }
}

Service Layer : (Temporary Solution)

 @Transaction
    public void executeQuery(){
        //Temporary solution : added lab_LAB_ID field in below 1st query
        String query = "db.service.find({} , {"name":1,"lab_LAB_ID":1})";
        List<Service> listOfServices = myDao.executeQuery(query , null , null ,new Service());

        String anotherQuery = " { $query : { name : "CDG Service"}}";
        List<Service> listOfAnotherServices = myDao.executeQuery(query , null , null ,new Service());

        if (!SalesUtils.isListIsNullOrEmpty(listOfAnotherServices )) {
            System.out.println(listOfAnotherServices.get(0).getName());
            System.out.println(listOfAnotherServices.get(0).getLab().getName()); //not null
        }
    }

Detail Explanation :

  1. Service Layer : (Issue : Lab name : null)

Here i only get 'name' field of service table using 1st query execution (variable name = query) and then executed 2nd query(variable name = anotherQuery) , but can not get lab object.

  1. Service Layer : (Temporary Solution)

so i get 'name' and 'lab_LAB_ID' both fields using 1st query execution (variable name = query) and then i executed 2nd query(variable name = anotherQuery) so not i can successfully get lab object.

I don't understand this. It seems like 2nd query result is dependent on 1st query result fields even if query is different and variable name is also different.

Is I am right?

vishvas4u
  • 41
  • 9

2 Answers2

0

EDIT: The problem is that the results of the first queries are cached (at session level) and then reused in the second query. Because the initial query you run does not return all the fields, the entity is only partially initialized. Make sure to return all the fields when you want to re-create the entity. Hibernate OGM should throw an exception when a user try to recreate an entity with only a subset of the properties. I will create a new JIRA for this.

When you specify the {name: 1}, you are asking to return only the following fields: _id and name; Because you asked for a service, Hibernate OGM will convert those values to a Service class. The problem is that the result does not contain the lab and therefore that field is null (there should be an exception instead).

When you run db.service.find({} , {"name":1,"lab_LAB_ID":1}), you are also returning the Lab identifier, with this additional information OGM will be able to also add the lab to the service.

The native query you should use, if you want the whole service, is:

    String query = "db.service.find({})";

But I would recommend a HQL query for this scenario:

    String hqlQuery = "FROM Service";
    List<Service> services = entityManager.createQuery(hqlQuery, Service.class)
                                          .getResultList();

By the way, you don't need to create a new Service() every time you run the query, you can define the parameter as Class<T> and then pass Service.class instead.

Davide D'Alto
  • 7,421
  • 2
  • 16
  • 30
0

Using native queries, if you choose to apply a projection on the root class you have to remove toEntity, because partial a entity extraction should not be allowed. It is likely that an exception throwing will be introduced in the next versions of the product to prevent this use. This is the current behaviour of Hibernate ORM (5.2 | 5.3) on H2 dialect too.

fax4ever
  • 81
  • 3