0

I am using Spring data rest and EclipseLink to create a multi-tenant single table application.

But I am not able to create an Repository where I can call on custom QueryParameters.

My Kid.class

@Entity
@Table(name="kid")
@Multitenant
public class Kid {

   @Id
   private Long id;

   @Column(name = "tenant_id")
   private String tenant_id;

   @Column(name = "mother_id")
   private Long motherId;

   //more attributes, constructor, getter and setter
}

My KidRepository

@RepositoryRestResource
public interface KidRepository extends PagingAndSortingRepository<Kid, Long>, QuerydslPredicateExecutor<Kid> {}

When I call localhost/kids I get the following exception:

Exception [EclipseLink-6174] (Eclipse Persistence Services - 2.7.4.v20190115-ad5b7c6b2a): 
org.eclipse.persistence.exceptions.QueryException\r\nException Description: No value was provided for the session property [eclipselink.tenant-id]. 
This exception is possible when using additional criteria or tenant discriminator columns without specifying the associated contextual property. 
These properties must be set through EntityManager, EntityManagerFactory or persistence unit properties. 
If using native EclipseLink, these properties should be set directly on the session.

When I remove the @Multitenant annotation on my entity, everything works fine. So it has definitively something to do with EclipseLink.

When I don't extend from the QuerydslPredicateExecutor it works too. But then I have to implement all findBy* by myself. And even doing so, it breaks again. Changing my KidsRepository to:

@RepositoryRestResource
public interface KidRepository extends PagingAndSortingRepository<Kid, Long> {
    Collection<Kid> findByMotherId(@Param("motherId") Long motherId);
}

When I now call localhost/kids/search/findByMotherId?motherId=1 I get the same exception as above.

I used this tutorial to set up EcpliseLink with JPA: https://blog.marcnuri.com/spring-data-jpa-eclipselink-configuring-spring-boot-to-use-eclipselink-as-the-jpa-provider/, meaning the PlatformTransactionManager, the createJpaVendorAdapter and the getVendorProperties are overwritten. The tenant-id comes with a jwt and everything works fine as long as I don't use QuerydslPredicateExecutor, which is mandatory for the use case.

Turns out, that the wrong JpaTransactionManager is used we I rely on the QuerydslPredicateExecutor. I couldn't find out, which one is created, but having multiple breakpoints inside the EclipseLink Framework code, non of them were hit. This is true for both, using the QuerydslPredicateExecutor or using the custom findby method.

I have googled a lot and tried to override some of the basic EclipseLink methods, but non of that worked. I am running out of options.

Does anyone has any idea how to fix or work around this?

Chris
  • 5,109
  • 3
  • 19
  • 40
  • You have added an EclipseLink annotation telling it to expect tenant context information on every query or EntityManager, but don't have support for passing that in as it isn't a Spring feature. See https://www.eclipse.org/eclipselink/documentation/2.4/jpa/extensions/a_multitenant.htm as you are going to have to work in the property into the Spring classes that are creating the EntityManager from the EntityManagerFactory. There are forum posts that say they are using multi tenancy with spring you might want to look at. – Chris Feb 13 '19 at 17:39
  • Thanks for the comment. Everything is set up as in this tutorial: https://blog.marcnuri.com/spring-data-jpa-eclipselink-configuring-spring-boot-to-use-eclipselink-as-the-jpa-provider/ The tenant-id is part of a jwt. Everything works find, as long as I don't extend from QuerydslPredicateExecutor in my repository. I'll update my post. – Chris Feb 14 '19 at 08:54

1 Answers1

1

I was looking for a solution for the same issue; what finally helped was adding the Spring's @Transactional annotation to either Repository or any place from where this custom query is called. (It even works with javax.transactional.) We had the @Transactional annotation on most of our services so the issue was not obvious and its occurrence seemed rather accidental.

More detailed explanation about using @Transactional on Repository is here: How to use @Transactional with Spring Data?.

meh
  • 46
  • 1
  • 3