EntityManager persist() method does not insert record to database => SEVERE: javax.persistence.TransactionRequiredException - jpa

I have problem with using EntityManager persist() method.
I am using JSF2.0, glassfish 3, JPA and hibernate, i am not using spring.
I try to add events in an events table with the method persist, but EntityManager persist() method does not insert record to database and i have this error message =>
SEVERE: javax.persistence.TransactionRequiredException
at com.sun.enterprise.container.common.impl.EntityManagerWrapper.doTxRequiredCheck(EntityManagerWrapper.java:163)
at com.sun.enterprise.container.common.impl.EntityManagerWrapper.flush(EntityManagerWrapper.java:411)
at dao.EvenementDao.addEvenement(EvenementDao.java:128).
#ManagedBean
#Stateless
public class EvenementDao implements Serializable{
/**
*
*/
private static final long serialVersionUID = -3343483942392617877L;
/**
*
*/
private List<TEvenement> listeEvenement;
private List<SelectItem> listeSelectItemEvnt;
private TEvenement tevenement ;
public EvenementDao() {
}
#PersistenceUnit(unitName="GA2010-ejbPU-dev")
private EntityManagerFactory emf;
#PostConstruct
private void init() {
tevenement = new TEvenement();
}
public List<TEvenement> getListeEvenement() {
EntityManager em = emf.createEntityManager();
TypedQuery<TEvenement> requete = m.createNamedQuery("TEvenement.findPrivateOther",
TEvenement.class);
listeEvenement = requete.getResultList();
return listeEvenement;
}
public TEvenement getEvenement() {
return tevenement;
}
public void setEvenement(TEvenement evenement) {
this.tevenement = evenement;
}
public void addEvenement(){
EntityManager em = emf.createEntityManager();
HttpSession session = (HttpSession) FacesContext.getCurrentInstance().
getExternalContext().getSession(false);
Integer codeUser = (Integer) session.getAttribute("codeUser");
tevenement.setUtilCreation(codeUser);
System.out.println("je rentre dans addevenemnt");
try{
System.out.println("i persist "+ em);
em.persist(tevenement);
em.flush();
System.out.println(tevenement.getDetailsEvenement());
FacesMessage message = new FacesMessage("Evenement ajouté avec succès.");
FacesContext.getCurrentInstance().addMessage(null, message);
}catch(Exception e){
e.printStackTrace();
}
}
}
So, this is not working, but the progam enter in the fonction addEvenement , FacesMessage message = new FacesMessage("Evenement ajouté avec succès."); returns me the message as if it was working.
i thouht it was due to my entityMAnager but in fact an ohter function works fine with the same Entity manager so i dont understand.
**public List<TEvenement> getListeEvenement()** {
EntityManager em = emf.createEntityManager();
TypedQuery<TEvenement> requete = em.createNamedQuery("TEvenement.findPrivateOther", TEvenement.class);
listeEvenement = requete.getResultList();
return listeEvenement;
}
this one works fine, the only difference is that in this case the query is a select and in the other case it's a persist so a query that impact the database.
the code of the entity :
#Entity
#Table(name="t_evenements")
#NamedQueries({#NamedQuery(name="TEvenement.findAll", query="SELECT evnt FROM TEvenement evnt"),
#NamedQuery(name="TEvenement.findPrivateOther", query="SELECT evnt FROM TEvenement evnt WHERE evnt.typeEvenement = 6 OR evnt.typeEvenement = 7")})
public class TEvenement implements Serializable {
private static final long serialVersionUID = -1908959833491896991L;
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name="REF_EVENEMENT", unique=true, nullable=false)
private Integer refEvenement;
#Temporal(TemporalType.DATE)
#Column(name="DATE_DEBUT_EVENEMENT")
private Date dateDebutEvenement;
#Temporal(TemporalType.DATE)
#Column(name="DATE_FIN_EVENEMENT")
private Date dateFinEvenement;
#Column(name="DETAILS_EVENEMENT")
private String detailsEvenement;
#Column(name="IS_EVERYDAY")
private byte isEveryday;
#Column(name="RAPPEL_EVENEMENT")
private int rappelEvenement;
public Integer getUtilEvenement() {
return utilEvenement;
}
public void setUtilEvenement(Integer utilEvenement) {
this.utilEvenement = utilEvenement;
}
#Column(name="TITRE_EVENEMENT")
private String titreEvenement;
#Column(name="TYPE_EVENEMENT")
private String typeEvenement;
#Column(name="UTIL_COPIE_EVENEMENT")
private Integer utilCopieEvenement;
#Column(name="UTIL_EVENEMENT")
private Integer utilEvenement;
#Column(name="HEURE_EVENEMENT")
private String heureEvenement;
#Column(name="UTIL_CREATION")
private Integer utilCreation;
public String getHeureEvenement() {
return heureEvenement;
}
public void setHeureEvenement(String heureEvenement) {
this.heureEvenement = heureEvenement;
}
public TEvenement() {
}
public Integer getRefEvenement() {
return this.refEvenement;
}
public void setRefEvenement(int refEvenement) {
this.refEvenement = refEvenement;
}
public Date getDateDebutEvenement() {
return this.dateDebutEvenement;
}
public Integer getUtilCreation() {
return utilCreation;
}
public void setUtilCreation(Integer utilCreation) {
this.utilCreation = utilCreation;
}
public void setUtilCopieEvenement(Integer utilCopieEvenement) {
this.utilCopieEvenement = utilCopieEvenement;
}
public void setDateDebutEvenement(Date dateDebutEvenement) {
this.dateDebutEvenement = dateDebutEvenement;
}
public Date getDateFinEvenement() {
return this.dateFinEvenement;
}
public void setDateFinEvenement(Date dateFinEvenement) {
this.dateFinEvenement = dateFinEvenement;
}
public String getDetailsEvenement() {
return this.detailsEvenement;
}
public void setDetailsEvenement(String detailsEvenement) {
this.detailsEvenement = detailsEvenement;
}
public byte getIsEveryday() {
return this.isEveryday;
}
public void setIsEveryday(byte isEveryday) {
this.isEveryday = isEveryday;
}
public int getRappelEvenement() {
return this.rappelEvenement;
}
public void setRappelEvenement(int rappelEvenement) {
this.rappelEvenement = rappelEvenement;
}
public String getTitreEvenement() {
return this.titreEvenement;
}
public void setTitreEvenement(String titreEvenement) {
this.titreEvenement = titreEvenement;
}
public String getTypeEvenement() {
return this.typeEvenement;
}
public void setTypeEvenement(String typeEvenement) {
this.typeEvenement = typeEvenement;
}
public Integer getUtilCopieEvenement() {
return this.utilCopieEvenement;
}
public void setUtilCopieEvenement(int utilCopieEvenement) {
this.utilCopieEvenement = utilCopieEvenement;
}
}
Do anyone have a idea what am i missing?

The difference isn't that you call persist, the difference is that you call em.flush() which as the error states, requires the EntityManager be joined to a transaction. Makes sure your getListeEvenement() method is wrapped in a transaction, or start one depending on your setup.

Related

MongoRepository Save method does not insert in database

I have created a SpringBoot project with Jhipster. The database I am using is MongoDB.
In the application-dev.yml I have the following configuration:
data:
mongodb:
uri: mongodb://<user>:<pass>#<ip>:<port>
database: gateway
The user, password, ip Address, and port, in my application-dev are real values.
The DatabaseConfiguration.java is:
#Configuration
#EnableMongoRepositories("es.second.cdti.repository")
#Profile("!" + JHipsterConstants.SPRING_PROFILE_CLOUD)
#Import(value = MongoAutoConfiguration.class)
#EnableMongoAuditing(auditorAwareRef = "springSecurityAuditorAware")
public class DatabaseConfiguration {
private final Logger log = LoggerFactory.getLogger(DatabaseConfiguration.class);
#Bean
public ValidatingMongoEventListener validatingMongoEventListener() {
return new ValidatingMongoEventListener(validator());
}
#Bean
public LocalValidatorFactoryBean validator() {
return new LocalValidatorFactoryBean();
}
#Bean
public MongoCustomConversions customConversions() {
List<Converter<?, ?>> converters = new ArrayList<>();
converters.add(DateToZonedDateTimeConverter.INSTANCE);
converters.add(ZonedDateTimeToDateConverter.INSTANCE);
return new MongoCustomConversions(converters);
}
#Bean
public Mongobee mongobee(MongoClient mongoClient, MongoTemplate mongoTemplate, MongoProperties mongoProperties) {
log.debug("Configuring Mongobee");
Mongobee mongobee = new Mongobee(mongoClient);
mongobee.setDbName(mongoProperties.getMongoClientDatabase());
mongobee.setMongoTemplate(mongoTemplate);
// package to scan for migrations
mongobee.setChangeLogsScanPackage("es.second.cdti.config.dbmigrations");
mongobee.setEnabled(true);
return mongobee;
}}
The CloudDatabaseConfiguration is:
#Configuration
#EnableMongoRepositories("es.second.cdti.repository")
#Profile(JHipsterConstants.SPRING_PROFILE_CLOUD)
public class CloudDatabaseConfiguration extends AbstractCloudConfig {
private final Logger log = LoggerFactory.getLogger(CloudDatabaseConfiguration.class);
#Bean
public MongoDbFactory mongoFactory() {
return connectionFactory().mongoDbFactory();
}
#Bean
public LocalValidatorFactoryBean validator() {
return new LocalValidatorFactoryBean();
}
#Bean
public ValidatingMongoEventListener validatingMongoEventListener() {
return new ValidatingMongoEventListener(validator());
}
#Bean
public MongoCustomConversions customConversions() {
List<Converter<?, ?>> converterList = new ArrayList<>();
converterList.add(DateToZonedDateTimeConverter.INSTANCE);
converterList.add(ZonedDateTimeToDateConverter.INSTANCE);
converterList.add(DurationToLongConverter.INSTANCE);
return new MongoCustomConversions(converterList);
}
#Bean
public Mongobee mongobee(MongoDbFactory mongoDbFactory, MongoTemplate mongoTemplate, Cloud cloud) {
log.debug("Configuring Cloud Mongobee");
List<ServiceInfo> matchingServiceInfos = cloud.getServiceInfos(MongoDbFactory.class);
if (matchingServiceInfos.size() != 1) {
throw new CloudException("No unique service matching MongoDbFactory found. Expected 1, found "
+ matchingServiceInfos.size());
}
MongoServiceInfo info = (MongoServiceInfo) matchingServiceInfos.get(0);
Mongobee mongobee = new Mongobee(info.getUri());
mongobee.setDbName(mongoDbFactory.getDb().getName());
mongobee.setMongoTemplate(mongoTemplate);
// package to scan for migrations
mongobee.setChangeLogsScanPackage("es.second.cdti.config.dbmigrations");
mongobee.setEnabled(true);
return mongobee;
}
}
The cdtiApp.java is:
#SpringBootApplication
#EnableConfigurationProperties({ApplicationProperties.class})
public class CdtiApp implements InitializingBean{
private static final Logger log = LoggerFactory.getLogger(CdtiApp.class);
private final Environment env;
public CdtiApp(Environment env) {
this.env = env;
}
/**
* Initializes cdti.
* <p>
* Spring profiles can be configured with a program argument --spring.profiles.active=your-active-profile
* <p>
* You can find more information on how profiles work with JHipster on https://www.jhipster.tech/profiles/.
*/
#PostConstruct
public void initApplication() {
Collection<String> activeProfiles = Arrays.asList(env.getActiveProfiles());
if (activeProfiles.contains(JHipsterConstants.SPRING_PROFILE_DEVELOPMENT) && activeProfiles.contains(JHipsterConstants.SPRING_PROFILE_PRODUCTION)) {
log.error("You have misconfigured your application! It should not run " +
"with both the 'dev' and 'prod' profiles at the same time.");
}
if (activeProfiles.contains(JHipsterConstants.SPRING_PROFILE_DEVELOPMENT) && activeProfiles.contains(JHipsterConstants.SPRING_PROFILE_CLOUD)) {
log.error("You have misconfigured your application! It should not " +
"run with both the 'dev' and 'cloud' profiles at the same time.");
}
}
/**
* Main method, used to run the application.
*
* #param args the command line arguments.
*/
public static void main(String[] args) {
SpringApplication app = new SpringApplication(CdtiApp.class);
DefaultProfileUtil.addDefaultProfile(app);
Environment env = app.run(args).getEnvironment();
logApplicationStartup(env);
}
private static void logApplicationStartup(Environment env) {
String protocol = "http";
if (env.getProperty("server.ssl.key-store") != null) {
protocol = "https";
}
String serverPort = env.getProperty("server.port");
String contextPath = env.getProperty("server.servlet.context-path");
if (StringUtils.isBlank(contextPath)) {
contextPath = "/";
}
String hostAddress = "localhost";
try {
hostAddress = InetAddress.getLocalHost().getHostAddress();
} catch (UnknownHostException e) {
log.warn("The host name could not be determined, using `localhost` as fallback");
}
log.info("\n----------------------------------------------------------\n\t" +
"Application '{}' is running! Access URLs:\n\t" +
"Local: \t\t{}://localhost:{}{}\n\t" +
"External: \t{}://{}:{}{}\n\t" +
"Profile(s): \t{}\n----------------------------------------------------------",
env.getProperty("spring.application.name"),
protocol,
serverPort,
contextPath,
protocol,
hostAddress,
serverPort,
contextPath,
env.getActiveProfiles());
String configServerStatus = env.getProperty("configserver.status");
if (configServerStatus == null) {
configServerStatus = "Not found or not setup for this application";
}
log.info("\n----------------------------------------------------------\n\t" +
"Config Server: \t{}\n----------------------------------------------------------", configServerStatus);
}
#Override
public void afterPropertiesSet() throws Exception {
// TODO Auto-generated method stub
}
}
The Vehicle entity:
#org.springframework.data.mongodb.core.mapping.Document(collection = "vehicle")
public class Vehicle implements Serializable {
private static final long serialVersionUID = 1L;
#Id
private String id;
#NotNull
#Field("plate")
private String plate;
#NotNull
#Field("registrationDate")
private Instant registrationDate;
#NotNull
#Field("brand")
private String brand;
#NotNull
#Field("model")
private String model;
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public String getPlate() {
return plate;
}
public void setPlate(String plate) {
this.plate = plate;
}
public Instant getRegistrationDate() {
return registrationDate;
}
public void setRegistrationDate(Instant registrationDate) {
this.registrationDate = registrationDate;
}
public String getBrand() {
return brand;
}
public void setBrand(String brand) {
this.brand = brand;
}
public String getModel() {
return model;
}
public void setModel(String model) {
this.model = model;
}
}
The VehicleDTO is:
public class VehicleDTO {
private String id;
private String plate;
private Instant registrationDate;
private String brand;
private String model;
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public String getPlate() {
return plate;
}
public void setPlate(String plate) {
this.plate = plate;
}
public Instant getRegistrationDate() {
return registrationDate;
}
public void setRegistrationDate(Instant registrationDate) {
this.registrationDate = registrationDate;
}
public String getBrand() {
return brand;
}
public void setBrand(String brand) {
this.brand = brand;
}
public String getModel() {
return model;
}
public void setModel(String model) {
this.model = model;
}
}
The VehicleMapper is:
#Mapper(componentModel = "spring")
public interface VehicleMapper{
Vehicle toEntity(VehicleDTO source);
VehicleDTO toDto(Vehicle target);
}
The VehicleResource is:
#RestController
#RequestMapping("/api")
#CrossOrigin(origins = "*", methods = { RequestMethod.GET, RequestMethod.POST })
public class VehicleResource {
private final Logger log = LoggerFactory.getLogger(VehicleResource.class);
#Value("${jhipster.clientApp.name}")
private String applicationName;
#Autowired
private final VehicleService vehicleService;
public VehicleResource(VehicleService vehicleService) {
this.vehicleService = vehicleService;
}
#PostMapping("/vehicle")
#PreAuthorize("hasAuthority(\"" + AuthoritiesConstants.ADMIN + "\")")
public ResponseEntity<Vehicle> createVehicle(#Valid #RequestBody VehicleDTO vehicleDTO) throws URISyntaxException {
log.debug("REST request to save Vehicle : {}", vehicleDTO);
Vehicle newVehicle = vehicleService.createVehicle(vehicleDTO);
return ResponseEntity.created(new URI("/api/vehicle/" + newVehicle.getPlate()))
.headers(HeaderUtil.createAlert(applicationName, "vehicleManagement.created", newVehicle.getPlate()))
.body(newVehicle);
}
}
The VehicleService interface is:
public interface VehicleService {
Vehicle createVehicle(VehicleDTO vehicleDTO);
}
The VehicleServiceImpl is:
#Service
public class VehicleServiceImpl implements VehicleService{
#Autowired
private final VehicleRepository vehicleRepository;
#Autowired
private final VehicleMapper mapper;
public VehicleServiceImpl(VehicleRepository vehicleRepository, VehicleMapper mapper) {
this.vehicleRepository = vehicleRepository;
this.mapper = mapper;
}
private final Logger log = LoggerFactory.getLogger(VehicleServiceImpl.class);
#Override
public Vehicle createVehicle(VehicleDTO vehicleDTO) {
Vehicle vehicle = vehicleRepository.save(mapper.toEntity(vehicleDTO));
log.debug("Created Information for vehicle: {}", vehicle);
return vehicle;
}
}
The VehicleRepository interface is:
/**
* Spring Data MongoDB repository for the {#link Vehicle} entity.
*/
#Repository
public interface VehicleRepository extends MongoRepository<Vehicle, String> {
}
From the Swagger console I access the Vehicle-Resource:
Swagger console
Click on the button and write in the text box the json with the vehicle data:
enter JSON data
As we can see in the following image, the answer is 201. Initially the vehicle was saved with the identifier "id": "60e740935ed5a10e2c2ed19e".
Send request
I access the database to check that the vehicle has been correctly stored in the vehicle table. To my surprise ... there is no vehicle in the vehicle table:
show database
I can make sure that the data in the database application-dev is OK. I don't have any other databases.
I suspect that transactions with the database are not actually being made. This data is somehow stored in memory because if I do a findAllVehicles from Swagger it does return the vehicle.
I have a eureka server running (jhipster-registry) and two microservices that synchronize with it. The Gateway, which acts as a reverse proxy and the Vehiculos microservice. The Swagger console is the gateway, from where I make the request to insert vehicles. Everything seems to work, but as I say in bbdd does not save anything.

Drools #Watch not working with accumulate in code

I'm using Drools 7.6 and for some reason #watch doesn't stop the rule from reactivating itself or other rules when only the unwatched property is changed. Which results in an infinite loop.
Can someone figure out what am I doing wrong?
The rule:
package com.model
import com.model.*;
import java.util.List;
rule "10% for 15 High-range Items"
when
$o: Order($lines: orderLines) #watch(!discount)
Number(intValue >= 15) from accumulate(
OrderLine($item: item, $q: quantity) from $lines and
Item(category == Item.Category.HIGH_RANGE) from $item,
sum($q)
)
then
modify($o) {increaseDiscount(0.10)}
end
The model used is from the book Mastering JBoss Drools. The method increase discount has been annotated with #Modifes. The order class:
public class Order implements Serializable {
private static final long serialVersionUID = 1L;
private Long orderId;
private Date date;
private Customer customer;
private List<OrderLine> orderLines = new ArrayList<>();
private Discount discount;
public Order() {
}
public Long getOrderId() {
return orderId;
}
public void setOrderId(Long orderId) {
this.orderId = orderId;
}
public Customer getCustomer() {
return customer;
}
public void setCustomer(Customer customer) {
this.customer = customer;
}
public Date getDate() {
return date;
}
public void setDate(Date date) {
this.date = date;
}
public List<OrderLine> getOrderLines() {
return orderLines;
}
public void setItems(List<OrderLine> orderLines) {
this.orderLines = orderLines;
}
public double getTotal() {
return this.getOrderLines().stream()
.mapToDouble(item -> item.getItem().getSalePrice() * item.getQuantity())
.sum();
}
public int getTotalItems() {
return this.getOrderLines().stream()
.mapToInt(item -> item.getQuantity())
.sum();
}
#Modifies({"discount"})
public void increaseDiscount(double increase) {
if (discount == null) {
discount = new Discount(0.0);
}
discount.setPercentage(discount.getPercentage() + increase);
}
public Discount getDiscount() {
return discount;
}
public double getDiscountPercentage() {
return discount.getPercentage();
}
public void setDiscount(Discount discount) {
this.discount = discount;
}
}
I reported the problem here https://issues.jboss.org/browse/DROOLS-2427 and already pushed a fix on Drools master branch. Thanks for having reported this.
'from' is not reactive, so it cannot react to any modify changes.

multi-tenant application in spring - connecting to DB

Hi Experts,
I am working on a multi-tenant project. It's a table per tenant architecture.
We are using spring and JPA (eclipse-link) for this purpose.
Here our use case is when ever a new customer subscribes to our application a new data base would be created for the customer.
As spring configuration would be loaded only during start-up how to load this new db configuration at run time?
Could some one please give some pointers?
Thanks in advance.
BR,
kitty
For multitenan, first you need to create MultitenantConfig.java
like below file.
here tenants.get("Musa") is my tenant name, comes from application.properties file
#Configuration
#EnableConfigurationProperties(MultitenantProperties.class)
public class MultiTenantConfig extends WebMvcConfigurerAdapter {
/** The Constant log. */
private static final Logger log = LoggerFactory.getLogger(MultiTenantConfig.class);
/** The multitenant config. */
#Autowired
private MultitenantProperties multitenantConfig;
#Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(new MultiTenancyInterceptor());
}
/**
* Data source.
*
* #return the data source
*/
#Bean
public DataSource dataSource() {
Map<Object, Object> tenants = getTenants();
MultitenantDataSource multitenantDataSource = new MultitenantDataSource();
multitenantDataSource.setDefaultTargetDataSource(tenants.get("Musa"));
multitenantDataSource.setTargetDataSources(tenants);
// Call this to finalize the initialization of the data source.
multitenantDataSource.afterPropertiesSet();
return multitenantDataSource;
}
/**
* Gets the tenants.
*
* #return the tenants
*/
private Map<Object, Object> getTenants() {
Map<Object, Object> resolvedDataSources = new HashMap<>();
for (Tenant tenant : multitenantConfig.getTenants()) {
DataSourceBuilder dataSourceBuilder = new DataSourceBuilder(this.getClass().getClassLoader());
dataSourceBuilder.driverClassName(tenant.getDriverClassName()).url(tenant.getUrl())
.username(tenant.getUsername()).password(tenant.getPassword());
DataSource datasource = dataSourceBuilder.build();
for (String prop : tenant.getTomcat().keySet()) {
try {
BeanUtils.setProperty(datasource, prop, tenant.getTomcat().get(prop));
} catch (IllegalAccessException | InvocationTargetException e) {
log.error("Could not set property " + prop + " on datasource " + datasource);
}
}
log.info(datasource.toString());
resolvedDataSources.put(tenant.getName(), datasource);
}
return resolvedDataSources;
}
}
public class MultitenantDataSource extends AbstractRoutingDataSource {
#Override
protected Object determineCurrentLookupKey() {
return TenantContext.getCurrentTenant();
}
}
public class MultiTenancyInterceptor extends HandlerInterceptorAdapter {
#Override
public boolean preHandle(HttpServletRequest req, HttpServletResponse res, Object handler) {
TenantContext.setCurrentTenant("Musa");
return true;
}
}
#ConfigurationProperties(prefix = "multitenancy")
public class MultitenantProperties {
public static final String CURRENT_TENANT_IDENTIFIER = "tenantId";
public static final int CURRENT_TENANT_SCOPE = 0;
private List<Tenant> tenants;
public List<Tenant> getTenants() {
return tenants;
}
public void setTenants(List<Tenant> tenants) {
this.tenants = tenants;
}
}
public class Tenant {
private String name;
private String url;
private String driverClassName;
private String username;
private String password;
private Map<String,String> tomcat;
//setter gettter
public class TenantContext {
private static ThreadLocal<Object> currentTenant = new ThreadLocal<>();
public static void setCurrentTenant(Object tenant) {
currentTenant.set(tenant);
}
public static Object getCurrentTenant() {
return currentTenant.get();
}
}
add below properties in application.properties
multitenancy.tenants[0].name=Musa
multitenancy.tenants[0].url<url>
multitenancy.tenants[0].username=<username>
multitenancy.tenants[0].password=<password>
multitenancy.tenants[0].driver-class-name=<driverclass>

JPA Entity not stored OneToMany relationship

i trie to run the following code.
But the child is not created to the parent Entity 'Erfasser'.
If i comment out the line erfasser.getErfasst().add(neu) everything works fine.
#PostConstruct
public void init() {
Erfasser erfasser = new Erfasser();
erfasser.setEmail("benjamin.koubik#auditweb.de");
erfasser.setPasswort("counting88");
gesamtAnzahl.einfuegenErfasser(erfasser);
Erfasst neu = new Erfasst();
neu.setDatum(new Date());
neu.setJuristische(1);
neu.setNatuerliche(0);
gesamtAnzahl.einfuegen(neu);
erfasser.getErfasst().add(neu);
gesamtAnzahl.update(erfasser);
}
Only the Erfasser itself is stored correctly in the DB.
#Entity
public class Erfasser implements Serializable {
private static final long serialVersionUID = 1L;
public Erfasser() {
super();
}
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private int erfasser_id;
#Column(length = 50)
#Email(message = "Inkorrekt EMail")
private String email;
#Column(length = 30)
private String passwort;
#OneToMany(cascade = CascadeType.ALL, fetch = FetchType.EAGER)
#JoinColumn(referencedColumnName = "erfasser_id", name = "erfasst_id_referenz")
private List<Erfasst> erfasst;
public int getErfasser_id() {
return erfasser_id;
}
public void setErfasser_id(int erfasser_id) {
this.erfasser_id = erfasser_id;
}
public String getEmail() {
return email;
}
public void setEmail(String email) {
this.email = email;
}
public String getPasswort() {
return passwort;
}
public void setPasswort(String passwort) {
this.passwort = passwort;
}
public List<Erfasst> getErfasst() {
return erfasst;
}
public void setErfasst(List<Erfasst> erfasst) {
this.erfasst = erfasst;
}
}
And here my SessionBeans:
AnzahlErfasstGesamtLocal.java
#Local
public interface AnzahlErfasstGesamtLocal {
public abstract List<Integer> gesamt();
public abstract List<Erfasst> gesamtNatuerlich();
public abstract List<Erfasst> gesamtJuristisch();
public abstract void einfuegenErfasser(Erfasser e);
public abstract void einfuegen(Erfasst e);
public abstract void update(Erfasser e);
public abstract void loeschen(Erfasst e);
}
AnzahlErfasstGesamt.java
#Stateless
#LocalBean
public class AnzahlErfasstGesamt implements AnzahlErfasstGesamtLocal {
#PersistenceContext
private EntityManager em;
public AnzahlErfasstGesamt() {
}
#Override
public List<Integer> gesamt() {
return null;
}
#Override
public List<Erfasst> gesamtNatuerlich() {
try {
TypedQuery<Erfasst> q = em.createQuery(
"SELECT COUNT(e) FROM Erfasst e WHERE e.natuerliche = 1 AND e.juristische = 0; ", Erfasst.class);
List<Erfasst> liste = q.getResultList();
if (!liste.isEmpty()) {
return liste;
} else {
return null;
}
} catch (NoResultException e) {
return null;
}
}
#Override
public List<Erfasst> gesamtJuristisch() {
try {
TypedQuery<Erfasst> q = em.createQuery(
"SELECT COUNT(e) FROM Erfasst e WHERE e.juristische = 1 AND e.natuerliche = 0; ", Erfasst.class);
List<Erfasst> liste = q.getResultList();
if (!liste.isEmpty()) {
return liste;
} else {
return null;
}
} catch (NoResultException e) {
return null;
}
}
#Override
public void einfuegen(Erfasst e) {
em.persist(e);
}
#Override
public void update(Erfasser e) {
em.merge(e);
}
#Override
public void loeschen(Erfasst e) {
em.remove(em.merge(e));
}
#Override
public void einfuegenErfasser(Erfasser e) {
em.persist(e);
}
}
There is nothing wrong with JPA - something is wrong in external code (and certainly with your description of the problem). For example I don't see where the actual erfasst list is created - if nothing happens in einfuegenErfasser (whatever that means), then you will get a NullPointerException while trying to add an element to a null list. Is that what happens?
The problem is the combination of JPA entity setup and the code using it. The JPA entity Erfasser has CascadeType.ALL, therefore the gesamtAnzahl.update(erfasser); updates the child entities erfasst with it. At the same time you do not setup the erfasser reference on the neu instance. You need to do something alog the line neu.setErfasser(erfasser) before gesamtAnzahl.update(erfasser);.
On separated line of concern, using the native German naming drives my head crazy, even though I am more German then English speaker.

JPA Eclipselink JOIN FETCH LAZY relation returning null

I am always getting NULL from a JOIN FETCH clause in my JPA Query, even though I have everything configured as expected:
#XmlRootElement
#XmlAccessorType(XmlAccessType.PROPERTY)
#Entity
#Table(name = "TB_BANNER_IMAGE")
public class BannerImage extends BaseEntity<Integer> {
protected FileReference fileReference;
private String type;
private String labelTitle;
protected BannerImage() {}
#Id
#TableGenerator(name="genBannerImage", table="TB_ID_GENERATOR",
pkColumnName="ID_NAME", valueColumnName="ID_VAL",
pkColumnValue="TB_BANNER_IMAGE", allocationSize=1)
#GeneratedValue(strategy=GenerationType.TABLE, generator="genBannerImage")
#Column(name = "ID_BANNER_IMAGE", unique = true, nullable = false)
public Integer getId() {
return super.getId();
}
#Override
public void setId(Integer id) {
super.setId(id);
}
#Column(name="TYPE")
public String getType() {
return type;
}
public void setType(String type) {
this.type = type;
}
#OneToOne(fetch=FetchType.LAZY, cascade=CascadeType.ALL)
#JoinColumn(name="ID_FILE_REFERENCE", nullable=false)
public FileReference getFileReference() {
return fileReference;
}
public void setFileReference(FileReference fileReference) {
this.fileReference = fileReference;
}
#Column(name="LABEL_TITLE")
public String getLabelTitle() {
return labelTitle;
}
public void setLabelTitle(String labelTitle) {
this.labelTitle = labelTitle;
}
}
for File Reference Class:
#Entity
#Table(name = "TB_FILE_REFERENCE")
public class FileReference extends BaseNamedEntity<String> {
private String type;
public FileReference() {}
#Id
#TableGenerator(name="genFileReference", table="TB_ID_GENERATOR",
pkColumnName="ID_NAME", valueColumnName="ID_VAL",
pkColumnValue="TB_FILE_REFERENCE", allocationSize=1)
#GeneratedValue(strategy=GenerationType.TABLE, generator="genFileReference")
#Column(name = "ID_FILE_REFERENCE", unique = true, nullable = false)
public String getId() {
return super.getId();
}
#Override
public void setId(String id) {
super.setId(id);
}
#Column(name = "TYPE")
public String getType() {
return type;
}
public void setType(String type) {
this.type = type;
}
}
Service class:
#Path("/banner")
public class BannerImageService extends BaseServiceFacade<BannerImage, Integer> {
#SuppressWarnings("unchecked")
#Override
public Crud<BannerImage, Integer> lookupService() throws ServiceLocatorException {
return ServiceLocator.getInstance()
.getLocalHome(ServicesConstants.BANNER_IMAGE_SERVICE);
}
#Override
protected String getDefaultGetQuery() {
return BannerImageDAO.GET_BY_ID_FETCH_FILE_REF;
}
#Override
protected String getDefaultQuery() {
return BannerImageDAO.GET_ALL_FETCH_FILE_REF;
}
}
get REST method of BaseServiceFacade:
#Override
#GET
#Consumes(MediaType.APPLICATION_JSON)
#Produces({MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON})
#Path("/{id}")
public T get(#PathParam("id") ID id) {
try {
if (!validateID(id)) {
logMessage("Invalid Entity ID: " + id);
return null;
}
String defaultGetQuery = getDefaultGetQuery();
if (defaultGetQuery != null) {
Map<String, Object> mapParams = new HashMap<String, Object>();
mapParams.put("id", id);
List<T> entityList = getService().search(defaultGetQuery, mapParams);
if (entityList != null && entityList.size() == 1) {
T ent = entityList.get(0);
return ent;
} else {
logMessage("Invalid search by Entity ID: " + id);
}
} else {
return getService().findById(clazz, id);
}
} catch (ServiceException e) {
serviceException(e);
} catch (Exception ex) {
logException(ex);
}
return null;
}
And finally the Service Bean EJB which reads from entityManager:
public class BaseServiceBean<T extends IEntity<ID>, ID extends Serializable> implements Crud<T,ID> {
// ... generic methods to be reused by subclasses
#Override
public List<T> search(String queryOrNamedQuery) throws ServiceException {
return search(queryOrNamedQuery, null, 0, 0);
}
#SuppressWarnings("unchecked")
public List<T> search(String namedQueryOrHql, Map<String, Object> parameters, int start, int chunkSize) {
try {
Query query = createQuery(namedQueryOrHql, getQueryType(namedQueryOrHql));
if (start > 0) {
query.setFirstResult(start);
}
if (chunkSize > 0) {
query.setMaxResults(chunkSize);
}
addParameters(query, parameters);
List<T> result = query.getResultList();
afterSearch(result);
return result;
} catch (NoResultException nre) {
nre.printStackTrace();
} catch (ClassCastException cce) {
cce.printStackTrace();
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
protected void afterSearch(List<T> result) {
}
// etc...
implementation specific class for BannerImageService:
#Stateless(mappedName="ejb/BannerImageService")
public class BannerImageServiceBean extends BaseServiceBean<BannerImage, Integer> implements BannerImageServiceBeanRemote, BannerImageServiceBeanLocal {
#Override
protected void afterSearch(List<BannerImage> result) {
if (result != null && result.size() == 1) {
BannerImage bannerImage = result.get(0);
bannerImage.getFileReference();
}
super.afterSearch(result);
}
// additional code ...
When I try to fetch my BannerImage class together with it's corresponding FileReference member I always get NULL even though in my DB there is an existing foreign key present:
JPQL:
"SELECT a FROM BannerImage a join fetch a.fileReference WHERE a.id = :id";
Generated SQL:
SELECT t1.ID_BANNER_IMAGE, t1.LABEL_TEXT, t1.LABEL_TITLE, t1.TYPE,
t1.ID_FILE_REFERENCE, t0.ID_FILE_REFERENCE, t0.NAME,
t0.TYPE FROM TB_FILE_REFERENCE t0, TB_BANNER_IMAGE
t1 WHERE (t0.ID_FILE_REFERENCE = t1.ID_FILE_REFERENCE) AND t1.ID_BANNER_IMAGE = 1
in my DB the record shows a correct reference:
BANNER_IMAGE:
1;"";"main";"2bdbb063d0d0ee2939c89763945d9d9e";"banner1.png";"image/png"
If I execute :
select * from TB_FILE_REFERENCE where ID_FILE_REFERENCE = '2bdbb063d0d0ee2939c89763945d9d9e'
I can find the record in the DB, although my EclipseLink JPA Implementation always returns null:
EclipseLink Version 2.5.2-M1
This is how the Entity gets passed from Service Layer to the
Can someone help pointing why the JOIN FETCH is not properly working?
I faced a similar issue and looking closely I see that this issue was happening only to entities recently created/saved. Then I figured that it has something to do with eclipselink cache. I solved this problem by adding this line before making a join fetch JPQL query,
em.getEntityManagerFactory().getCache().evictAll();
em.createQuery("SELECT a FROM BannerImage a join fetch a.fileReference WHERE a.id = :id").getResultList();
HTH!