org.apache.openjpa.persistence.EntityExistsException: Attempt to persist detached object - jpa

The entity class is
package com.dunkul.entity;
import java.io.Serializable;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.EntityListeners;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.Table;
#Entity
#Table(name="employee")
public class Book implements Serializable{
private int id;
private String name;
public Book(){
}
#Id
#Column(name="Id")
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
Persisting is as follows
public void addBook(Book book) {
entityManager.persist(book);
}
Getting following exception
INFO: Using dictionary class
"org.apache.openjpa.jdbc.sql.MySQLDictionary" (MySQL 5.7.9-log ,MySQL
Connector Java mysql-connector-java-5.1.37 ( Revision:
09940f05b4c98150f352e787a2549f11a2e9d
a93 )).
Nov 16, 2015 2:08:03 PM null
INFO: Connected to MySQL version 5.5 using JDBC driver MySQL Connector Java version mysql-connector-java-5.1.37 ( Revision:
09940f05b4c98150f352e787a2549f11a2e9da93 ).
Nov 16, 2015 2:08:04 PM org.apache.openejb.core.transaction.EjbTransactionUtil
handleSystemException
SEVERE: EjbTransactionUtil.handleSystemException: Attempt to persist detached object "com.dunkul.entity.Book#1c7cf37d". If this is
a new instance, make sure any version and/or auto-generated
primary key fields are null/default when persisting.
org.apache.openjpa.persistence.EntityExistsException: Attempt to
persist detached object "com.dunkul.entity.Book#1c7cf37d". If this is
a
new instance, make sure any version and/or auto-generated primary key fields are null/default when persisting.
FailedObject: com.dunkul.entity.Book#1c7cf37d
at org.apache.openjpa.kernel.BrokerImpl.persistInternal(BrokerImpl.java:2659)
at org.apache.openjpa.kernel.BrokerImpl.persist(BrokerImpl.java:2602)
at org.apache.openjpa.kernel.BrokerImpl.persist(BrokerImpl.java:2585)
Please help. Table book has 2 columns .. Id and Name. Id is PK and NN
Name is VARCHAR(45). Default for Name is NULL.

There are a few issues here:
the entity name is "Book", but the table that it maps to is "employee"; not an error per se, but is it intended?
your #Id field needs to be generated somehow (which is what the exception tells you); you could start with adding an annotation #GeneratedValue(strategy=GenerationType.AUTO),
the attribute "name" of Book is not mapped (neither persisted, nor transient).

Related

Postgres similarity function with spring data

I tried to implement a search query in my spring-boot service which utilizes the similarity(text, text) function of postgres.
I got the similarity working in the postgres console, and managed to get it over to my #Repository interface as native query.
It seems to construct the query correctly, but every time I try to execute the query I get
ERROR: function similarity(text, character varying) does not exist
When I try to create the extension again, I get an exception, that this extension is already installed.
What am I missing? Do I need some Spring/JPA magic Object to enable this?
Example entity:
import javax.persistence.Entity;
import javax.persistence.Id;
import javax.persistence.Table;
import lombok.Data;
#Entity
#Table(name = "example")
#Data
public class ExampleEntity {
#Id
private String id;
private String textField;
}
Example repository:
import java.util.Set;
import org.springframework.data.jpa.repository.Query;
import org.springframework.data.repository.CrudRepository;
import org.springframework.stereotype.Repository;
#Repository
public interface ExampleRepository extends CrudRepository<ExampleEntity, String> {
#Query(nativeQuery = true,
value = "SELECT * FROM example ORDER BY similarity(:searchString)")
List<ExampleEntity> findBySimilarity();
#Query(nativeQuery = true, value = "CREATE EXTENSION pg_trgm")
void createSimilarityExtension();
}
Test code (excluding setup, as it is rather complex):
public void test() {
ExampleEntity r1 = dbUtils.persistNewRandomEntity();
ExampleEntity r2 = dbUtils.persistNewRandomEntity();
ExampleEntity r3 = dbUtils.persistNewRandomEntity();
try {
exampleRepository.createSimilarityExtension();
} catch (InvalidDataAccessResourceUsageException e) {
// always says that the extension is already setup
}
List<ExampleEntity> bySimilarity = exampleRepository.findBySimilarity(r2.getTextField());
for (ExampleEntity entity : bySimilarity) {
System.out.println(entity);
}
}
Turns out I created the extension in the wrong schema while trying out if the extension would work at all.
I then added the extension to my DB-migration script, but would skip it if the extension existed. Therefore my extension was registered for the public schema and did not work in the actual schema my service is using.
So if you have the same problem I had, make sure your extension is created for the correct schema by using:
SET SCHEMA <your_schema>; CREATE EXTENSION pg_trgm;

R2DBC spring postgres enum mapping

I'm new to spring r2dbc. Previously I've user hibernate. In hibernate when you need to map postgresql enum to java enum you just add com.vladmihalcea:hibernate-types-52 and use #Enumerated (as shown bellow). Related to R2DBC and enum (PostgreSQL) SO question I have to create codec for every single enum. Is it possible to achive this with some kind of tag or other general solution not just creating multiple codecs.
CREATE TYPE user_type_enum AS ENUM ('ADMIN', 'USER');
public class PostgreSQLEnumType extends org.hibernate.type.EnumType {
public void nullSafeSet(PreparedStatement st, Object value,
int index, SharedSessionContractImplementor session)
throws HibernateException, SQLException {
st.setObject(
index,
value != null ? ((Enum) value).name() : null,
Types.OTHER
);
}
}
public enum UserTypeEnum {
ADMIN,
USER
}
import javax.persistence.EnumType;
import javax.persistence.Enumerated;
import org.springframework.data.annotation.Id
import org.springframework.data.relational.core.mapping.Table;
import org.hibernate.annotations.Type;
import org.hibernate.annotations.TypeDef;
#Table;
#TypeDef(
name = "pgsql_enum",
typeClass = PostgreSQLEnumType.class
)
public class User {
#Id
private Long id;
private String usename;
#Enumerated(EnumType.STRING)
#Type(type = "pgsql_enum")
private UserEnumType userType;
// Getters and setters provided
}
You don't need to create your own codecs anymore.
See https://github.com/pgjdbc/r2dbc-postgresql#postgres-enum-types
DDL:
CREATE TYPE my_enum AS ENUM ('FIRST', 'SECOND');
Java Enum class:
enum MyEnumType {
FIRST, SECOND;
}
Your R2DBC ConnectionFactory bean:
PostgresqlConnectionConfiguration.builder()
.codecRegistrar(EnumCodec.builder()
.withEnum("my_enum",MyEnumType.class)
.build());
Note that you must use lower case letter for your "my_enum" in withEnum, otherwise won't work.
Also, you will need to provide a converter that extends EnumWriteSupport, and register it.
See: https://docs.spring.io/spring-data/r2dbc/docs/current/reference/html/#mapping.explicit.enum.converters
For example:
#Configuration
public static class R2DBCConfiguration extends AbstractR2dbcConfiguration {
#Override
#Bean
public ConnectionFactory connectionFactory() {
...
}
#Override
protected List<Object> getCustomConverters() {
return List.of(
new MyEnumTypeConverter()
);
}
}

Using GWT with Morphia/MongoDB

I was wondering if anyone has attempted and been successful at using the Morphia jar for interacting with a mongodb database inside of GWT? I've been using the below object as the base for all my POJO's, however whenever I attempt to save down the object using an UpdateOperations<DerivedPersistentEntity> or datastore.Save() I get a ConcurrentModificationException.
package com.greycells.dateone.shared;
import com.google.code.morphia.annotations.Id;
import com.google.code.morphia.annotations.Version;
public class PersistentEntity {
#Id
private String id;
#Version
private Long version = null;
public PersistentEntity() {
}
public String getId() {
return id;
}
public Long getVersion() {
return version;
}
public void setVersion(Long version) {
this.version = version;
}
}
I've also added the gwt extension jar that you have to download separately for Morphia and referenced it in my gwt.xml and this seems to be of no help. Additionally I've tried changing the id field of PersistentEntity to the ObjectId type but then I can't even get my project to bind correctly because it complains of...
[ERROR] No source code is available for type org.bson.types.ObjectId; did you forget to inherit a required module?
You can't use a String for the #Id field of the entity in Morphia it must be an ObjectId. GWT support in Morphia is completely broken as of v1.02.

JPA Warning: "No mapping is associated with the state field path 't.progress'"

I'm using JPA (EclipseLink 2.4.1) with a mapping-file containing named-queries. Eclipse shows me the following warning message in my mapping file:
No mapping is associated with the state field path 't.progress'.
The warning is of the type JPA Problem. The corresponding lines in my named-queries.xml-file look like this:
<named-query name="FinishedTasks">
<query><![CDATA[SELECT t FROM Task t WHERE t.progress = 100]]></query>
</named-query>
However, the query runs fine when executed, so no warning in run-time.
Here's what the file Task.java looks like (excerpt):
#Entity
public class Task extends Issue {
private Integer progress = 0;
public Integer getProgress() {
return progress;
}
public void setProgress(final Integer progress) {
this.progress = progress;
}
}
Issue.java looks like this (excerpt):
#Entity
#Inheritance(strategy = InheritanceType.JOINED)
public class Issue implements Serializable {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
private long id;
public long getId() {
return id;
}
public void setId(final long id) {
this.id = id;
}
}
I have no warnings about queries using Issue.
So my question is, how do I get rid of the warning? And does the warning have some implication I'm not aware of (as said, the query runs fine).
No mapping is associated with the state field path 't.progress'
I believe this is totally due to the Eclipse JPA Details View (orm.xml editor) and has nothing to do with EclipseLink nor JPA in general. The warning is reminding you that the Named Query is using a JPA query path (t.progress) that is not mapped in the mapping file. The View / xml editor is not analysing the metadata of your java classes, so is not aware whether the it is mapped via JPA annotations.
i.e. the tool is doing the best job for you it possibly can give it's technology / scope limitations.
Solution:
understand what the message is saying, manually ensure that the warning is addressed via JPA annotations (OR if you really must, insert the approprate Entity Mappings into your entity mapping XML file), and move on...
:^)
This seems to be wrong.
<named-query name="FinishedTasks">
<query><![CDATA[SELECT t FROM Task t WHERE t.progress = 100]]></query>
</named-query>
I can't find anything like that with CDATA. See examples at http://wiki.eclipse.org/EclipseLink/Examples/JPA/QueryOptimization
Try this in your named-queries.xml. Or use #NamedQuery annotation like below.
<named-query name="FinishedTasks">
<query>SELECT t FROM Task t WHERE t.progress = 100</query>
</named-query>
I just build a test project and use this
package test;
import javax.persistence.Entity;
import javax.persistence.NamedQuery;
#Entity
#NamedQuery(name = "FinishedTasks",
query = "SELECT t FROM Task t WHERE t.progress = 100")
public class Task extends Issue {
private Integer progress = 0;
public Integer getProgress() {
return progress;
}
public void setProgress(final Integer progress) {
this.progress = progress;
}
}
Using JUnit didn't resolve to any warning.
package test;
import static org.junit.Assert.assertEquals;
import java.util.List;
import javax.persistence.EntityManager;
import javax.persistence.EntityManagerFactory;
import javax.persistence.Persistence;
import javax.persistence.Query;
import org.junit.After;
import org.junit.AfterClass;
import org.junit.Before;
import org.junit.BeforeClass;
import org.junit.Test;
public class TaskTest {
private static EntityManager em;
#BeforeClass
public static void setUpBeforeClass() throws Exception {
EntityManagerFactory factory = Persistence.createEntityManagerFactory("test");
em = factory.createEntityManager();
em.getTransaction().begin();
Task t = new Task();
t.setProgress(100);
em.persist(t);
em.getTransaction().commit();
}
#AfterClass
public static void tearDownAfterClass() throws Exception {
em.close();
}
#Test
public void test() {
Query q = em.createNamedQuery("FinishedTasks");
List<?> list = q.getResultList();
int expected = 1;
int actual = list.size();
assertEquals(actual, expected);
}
}
My log
[EL Info]: 2013-05-01
21:57:55.561--ServerSession(1763596)--EclipseLink, version: Eclipse
Persistence Services - 2.4.1.v20121003-ad44345 [EL Info]: connection: 2013-05-01

new to play! Having trouble with: Please annotate your JPA model with #javax.persistence.Entity annotation

new to play and just trying to follow the video on: http://www.playframework.org/
I'm coming so far that i want to create the list of tasks after creating the Task-class. I when i reload i get this error:
"UsupportedOperationException occured : Please annotate your JPA model with #javax.persistence.Entity annotation."
I'm using Eclipse. Also note that i have changed tasks to be persons in:
My Person model/class-defination in Person.java
package models;
import play.*;
import play.db.jpa.*;
import javax.persistence.*;
import java.util.*;
public class Person extends Model{
public String title;
public boolean done;
public Person(String title){
this.title = title;
}
}
And application.java:
package controllers;
import play.*;
import play.mvc.*;
import java.util.*;
import models.*;
public class Application extends Controller {
public static void index() {
List persons = Person.find("order by id desc").fetch();
render(persons);
}
}
The error is connected with this line:
List persons = Person.find("order by id desc").fetch();
Add #Entity to the top of the model class.
And let's be clear, use the Javax Entity annotation and not Hibernate's! As suggested in the official documentation!
As mentioned before add #Entity before your Model class.
Within your example the Person class would look like that:
package models;
import play.*;
import play.db.jpa.*;
import javax.persistence.*;
import java.util.*;
#Entity
public class Person extends Model{
public String title;
public boolean done;
public Person(String title){
this.title = title;
}
}