I am wondering if there is a better way to update entities after they have been read from the database.
This seems like too much code to do a simple task. I have tried using em.merge() which did not persists the data to the database.
public class PodcastManager {
private EntityManagerFactory emf;
public PodcastManager(EntityManagerFactory emf) {
this.emf = emf;
}
public void updatePodcast(Podcast podcast) {
EntityManager em = emf.createEntityManager();
em.getTransaction().begin();
Podcast ptu = em.find(Podcast.class, podcast.getId());
if ( ptu != null) {
ptu.setTitle(podcast.getTitle());
ptu.setDescription(podcast.getDescription());
ptu.setUrl(podcast.getUrl());
ptu.setLang(podcast.getLang());
ptu.setCopyright(podcast.getCopyright());
ptu.setItunesSubtitle(podcast.getItunesSubtitle());
ptu.setItunesAuthor(podcast.getItunesAuthor());
ptu.setItunesSummary(podcast.getItunesSummary());
ptu.setItunesOwnerName(podcast.getItunesOwnerName());
ptu.setItunesOwnerEmail(podcast.getItunesOwnerEmail());
ptu.setItunesImageHREF(podcast.getItunesImageHREF());
ptu.setExplicit(podcast.isExplicit());
}
em.getTransaction().commit();
em.close();
}
}
I managed to get it merge to work as follows.
public void updatePodcast(Podcast podcast) {
EntityManager em = emf.createEntityManager();
try {
em.getTransaction().begin();
em.merge(podcast);
em.flush();
} finally {
em.getTransaction().commit();
em.close();
}
}
Related
I faced a problem in another topic (Empty List (not Table) at ManyToMany-Relation) and wonder if my Usage of EntityManager is correct. So what should be the best way to use EntityManager? A few years ago i read something about the DAO-Pattern (like http://www.oracle.com/technetwork/java/dataaccessobject-138824.html) which i used since that. But now when i want to join the class for WebServices i thought a "Service-Layer" would be better, so i build a class like
import java.util.List;
import javax.persistence.EntityManager;
import javax.persistence.EntityTransaction;
import javax.ws.rs.GET;
import javax.ws.rs.Path;
import javax.ws.rs.PathParam;
import javax.ws.rs.Produces;
import javax.ws.rs.QueryParam;
import javax.ws.rs.core.MediaType;
#Path("role")
public class RoleService {
#GET
#Path("ping")
#Produces(MediaType.TEXT_PLAIN)
public String helloWorld() {
return "REST-Web-Service ready for Role.class!";
}
public static void create(Role object) {
EntityManager em = PersistenceUtil.getEntityManagerFactory().createEntityManager();
EntityTransaction tx = em.getTransaction();
tx.begin();
em.persist(object);
tx.commit();
em.close();
}
public static void update(Role object) {
EntityManager em = PersistenceUtil.getEntityManagerFactory().createEntityManager();
EntityTransaction tx = em.getTransaction();
tx.begin();
em.merge(object);
tx.commit();
em.close();
}
#GET
#Produces(MediaType.APPLICATION_JSON)
#Path("id/{id}")
public static Role getRole(#PathParam("id") Integer id) {
return load(id);
}
#GET
#Produces(MediaType.APPLICATION_JSON)
#Path("name")
public static String getName(#QueryParam("id") Integer id) {
Role role = findById(id);
if (role != null) {
return "[\n {\n \"id\":"+id+",\n \"type\":\"role\",\n \"name\": \"" + role.getName() + "\",\n \"query\":\"success\"\n }\n]";
}
return "[\n {\n \"id\":"+id+",\n \"type\":\"role\",\n \"query\":\"failed\"\n }\n]";
}
public static Role findById(Integer id) {
EntityManager em = PersistenceUtil.getEntityManagerFactory().createEntityManager();
EntityTransaction tx = em.getTransaction();
tx.begin();
Role object = em.find(Role.class, id);
tx.commit();
em.close();
return object;
}
public static Role load(Integer id) {
EntityManager em = PersistenceUtil.getEntityManagerFactory().createEntityManager();
EntityTransaction tx = em.getTransaction();
tx.begin();
Role objectResult = em.find(Role.class, id);
tx.commit();
em.close();
return objectResult;
}
public static Role load(Role object) {
EntityManager em = PersistenceUtil.getEntityManagerFactory().createEntityManager();
EntityTransaction tx = em.getTransaction();
tx.begin();
Role objectResult = em.find(Role.class, object.getId());
tx.commit();
em.close();
return objectResult;
}
public static void deleteById(Integer id) {
EntityManager em = PersistenceUtil.getEntityManagerFactory().createEntityManager();
EntityTransaction tx = em.getTransaction();
tx.begin();
em.remove(em.find(Role.class, id));
tx.commit();
em.close();
}
// #DELETE
// #Path("{id}")
public static void delete(Role object) {
EntityManager em = PersistenceUtil.getEntityManagerFactory().createEntityManager();
EntityTransaction tx = em.getTransaction();
tx.begin();
em.remove(em.find(Object.class, object.getId()));
tx.commit();
em.close();
}
public static List<Role> findByName(String name) {
EntityManager em = PersistenceUtil.getEntityManagerFactory().createEntityManager();
EntityTransaction tx = em.getTransaction();
tx.begin();
List<Role> list = em.createQuery("SELECT r FROM Role r WHERE r.name LIKE :name").setParameter("name", "%" + name + "%").getResultList();
tx.commit();
em.close();
return list;
}
}
The PersistenceUtil is
import javax.persistence.EntityManagerFactory;
import javax.persistence.Persistence;
public class PersistenceUtil {
/*
* Name of persistence unit which MUST correlate to persistence-unit name in persistence.xml
*/
private static final String PERSISTENCE_UNIT_NAME = "RoleModel";
private static final EntityManagerFactory entityManagerFactory;
static {
try {
entityManagerFactory = Persistence.createEntityManagerFactory(PERSISTENCE_UNIT_NAME);
} catch (Throwable ex) {
System.err.println("EntityManagerFactory creation failed." + ex);
throw new ExceptionInInitializerError(ex);
}
}
public static EntityManagerFactory getEntityManagerFactory() {
return entityManagerFactory;
}
}
But in the article Entity manager best practices it seems different. Se where should i instantiate EntityManager? Should i use better Annotation? Better a Sigleton-Class? Is it ok when i use it in every method?
What do you think?
I think the most common way is using CDI (context and dependency injection) in first place.
Using CDI your DAO gets the EntityManager injected by the application container (Java app server, e.g. Glassfish). It could look something like this:
#Dependent
public class FooDAO {
#PersistenceContext
private EntityManager em;
public FooEntity find(final Number id) throws NoResultException {
return em.find(FooEntity.class, id);
}
public List<FooEntity> findAll() {
return em.createNamedQuery("FooEntity.findAll", FooEntity.class).getResultList();
}
// ...
}
The CDI container takes note of the #PersistenceContext annotation and the Entity Manager gets instantiated, so you don't need to worry about anything related to it. The transactions are also managed by the application server. You probably already have a persistence.xml, where you set all your DB related settings. For the server-managed persistence it needs to define transaction-type="JTA", by the way. See the tons of examples on the web.
In your service or business logic classes (depending on how many layers you want), you would use your DAO class like this:
#Stateless
public class FooManager {
#Inject
private FooDAO fooDAO;
public List<FooEntity> getFoos() {
return fooDAO.findAll();
}
// ...
}
The annotations #Dependent, #Stateless are two of many CDI offers. Depending on this the CDI manager creates one or many instances of your classes. Popular choices include #ViewScoped, #SessionScoped and #ApplicationScoped. When searching the web, don't get confused by JSF's or Seam's annotations. You do not want to use those! The only thing you want to use of JSF is the #Named annotation, and you apply that one only to the backing beans (java classes which are responsible for view). EJB annotations are okay, too. They're mostly compatible with CDI.
The code and suggestions above are about Java EE. Some frameworks are using their own annotations and patterns. Most notable ones are Spring and the Play framework. For these, please refer to the fine docs.
No matter what Pattern you are using there is one rule that is always valid.
Create the EntityManagerFactory only onces. EntityManager can be created on each transaction as it is a cheap object.
In terms of patterns, yes DAO and Repository patterns and their variations are most common.
I fully agree that the CDI method is best. The inversion of control reduces the coupling but maintains cohesion of the system. You also needn't worry about allocation/deallocating the manager.
You can also have N number of persistence-unit's in your persistence.xml and you can assign the EntityManager directly to that unit. Further you can set the Context Type which I have set here as Transaction.
#PersistenceContext(unitName = PersistenceStartupService.BJOND_STORE, type=PersistenceContextType.TRANSACTION)
private EntityManager entityManager;
I encourage folks to break-up large schemas into separate persistence units which also helps with fire-walling access to certain tables. I usually have my IdentityManager (PicketLink) as a separate persistence unit.
If you are exercising CRUD procedures do you have to do this (with transaction type: RESOURCE_LOCAL not JTA)
#PersistenceUnit(unitName="mongo")
EntityManagerFactory emf;
EntityManager em;
#Inject
private SomeObj injectableObj;
public void create()
{
em = emf.createEntityManager(); <---- here
SomeObj obj = new SomeObj();
em.persist(obj);
}
public void read()
{
em = emf.createEntityManager(); <---- here
Query query = em.createQuery("Select s from SomeObj s");
}
public void update()
{
em = emf.createEntityManager(); <---- here
SomeObj s = em.find(SomeObj.class, injectableObj.getId());
s.setSomeObj(injectableObj.getSomeObj());
}
public void delete()
{
em = emf.createEntityManager(); <---- here
SomeObj s = em.find(SomeObj.class, injectableObj.getId());
em.remove(s);
}
Question: Is there anyway to inject the EntityManager?
Maybe try to look here for exemples :
Injections EntityManager
I prefer to use : Injection via #PersistenceContext
You can use injection. I use it like this:
#PersistenceContext(unitName = "some_jndi_name")
private EntityManager em;
I am just starting to work with JPA. Based on several tutorials, I have built a simple dynamic web project that includes a GerericDAO as well as a singleton that encapsulates the EntityManagerFactory.
public class PersistenceManager {
private static final PersistenceManager instance = new PersistenceManager();
protected EntityManagerFactory emf;
public static PersistenceManager getInstance() {
return instance;
}
private PersistenceManager() {
}
public EntityManagerFactory getEntityManagerFactory() {
if (emf == null)
createEntityManagerFactory();
return emf;
}
public void closeEntityManagerFactory() {
if (emf != null) {
emf.close(); emf = null;
}
}
protected void createEntityManagerFactory() {
this.emf = Persistence.createEntityManagerFactory("Fusion");
}
}
public class GenericJPADAO<ID extends Serializable, T> implements GenericDAO<ID, T> {
private Class<T> persistentClass;
private EntityManager entityManager;
#SuppressWarnings("unchecked")
public GenericJPADAO() {
this.persistentClass = (Class<T>) ((ParameterizedType) getClass()
.getGenericSuperclass()).getActualTypeArguments()[0];
}
public void setEntityManager(EntityManager entityManager) {
this.entityManager = entityManager;
}
protected EntityManager getEntityManager() {
if (entityManager == null)
throw new IllegalStateException("EntityManager has not been set on DAO before");
return entityManager;
}
public T create(T element) throws IOException, IllegalArgumentException {
if (element == null)
throw new IllegalArgumentException();
try {
getEntityManager().persist(element);
return element;
} catch (Exception e) {
throw new IOException("create failed");
}
}
To pull this together in a Transaction method I need something like this (leaving out some of the detail):
DAOFactory factory = DAOFactory.instance(DAOFactory.JPA);
ConfigurationDAO dao = factory.getAddressDAO();
dao.setEntityManager(entityManager);
EntityTransaction ut = entityManager.getTransaction();
try {
ut.begin();
dao.create(address);
ut.commit();
} catch (Exception e) {
ut.rollback();
}
finally {
close??
}
I am very new to this, however it seems awkward to be setting the EntityManager in the DAO Class from the Transaction method. I have previously worked with Hibernate and my DAO classes have been able to retrieve a current Session from a HibernateUtil type class. I am not sure how to achieve a similar structure with JPA / EntityManager whilst maintaining a Thread safe application? Maybe my structure is poorly designed - anyway any advice / guidance much appreciated. I have not been able to find a clear complete example of this. By the way - I am not using Spring in this application.
JPA specification defines a pattern similar to Hibernate's getCurrentSession() - the current EntityManager is injected into field annotated with #PersistenceContext.
However, specification says that support for this pattern should be provided by external environment rather than by JPA providers, therefore you cannot just use it in standalone environment.
In particular, this pattern is supported by Spring Framework and Java EE application servers.
Alternatively, if you cannot use Spring Framework or Java EE application server you can emulate this pattern by storing the current EntityManager in ThreadLocal.
I'm using JPA and EJBs on WebSphere 7.
I have the following class:
#Entity
#Table(name="WIDGET")
public class Widget implements Serializable {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
private Long id;
private String name;
private String details;
/* getters and setters */
}
I have a DAO like so:
#Stateless
public class WidgetDAO implements WidgetDAOLocal {
#PersistenceUnit
private EntityManagerFactory emf;
private EntityManager em;
public EntityManager getEntityManager() {
if (emf == null) {
throw new Exception();
}
return emf.createEntityManager;
}
public Widget getWidget(Long id) {
Widget widget = null;
EntityManager em = getEntityManager();
try {
widget = (Widget)em.find(Widget.class, widgetId);
} finally {
em.close();
}
return widget;
}
public Widget createWidget(Widget widget) {
EntityManager em = getEntityManager();
try {
em.persist(widget);
em.flush();
} finally {
em.close();
}
return widget;
}
public Widget updateWidget(Widget widget) {
EntityManager em = getEntityManager();
try {
widget = getEntityManager().merge(widget);
em.flush();
} finally {
em.close();
}
return widget;
}
}
The create works fine and my widget appears in the database.
But when I try to do a merge, I get an error. The code to do the merge and the error I get follows:
public WidgetService {
#EJB
private WidgetDAO widgetDAO;
public WidgetDAO getWidgetDAO() {
return this.widgetDAO;
}
public Widget getWidget(Long id) {
return this.getWidgetDAO().getWidget(id);
}
public void updateDetails(Long widgetId, String details) {
Widget w = this.getWidget(widgetId);
w.setDetails(details);
this.widgetDAO.updateWidget(w);
}
}
The error is:
Exception caught from before_completion synchronization operation:
<openjpa-1.2.1-SNAPSHOT-r422266:686069 nonfatal user error> org.apache.openjpa.persistence.InvalidStateException:
The generated value processing detected an existing value assigned to this field: com.mydomain.domain.Widget.id.
This existing value was either provided via an initializer or by calling the setter method.
You either need to remove the #GeneratedValue annotation or modify the code to the initializer processing.
Any help on this is greatly appreciated!
Merge takes a copy of your entity, detaches it and persists the new one, which i presume attempts to set the ID from the old and causes you the conflict on your generated values. If you just want to update your object you should do so within a transaction and commit that.
Thanks for the help everybody, I figured it out, here's the cause of the problem and the solution that worked for me.
In my DAO I was doing this:
#Stateless
public class WidgetDAO implements WidgetDAOLocal {
#PersistenceUnit
private EntityManagerFactory emf;
private EntityManager em;
public EntityManager getEntityManager() {
if (emf == null) {
throw new Exception();
}
return emf.createEntityManager;
}
Because the EntityManagerFactory was being injected via the #PersistenceUnit annotation, the entities were "Application-Managed", causing some kind of conflict with WebSphere.
I changed the code to this:
#Stateless
public class WidgetDAO implements WidgetDAOLocal {
#PersistenceContext
private EntityManager em;
public EntityManager getEntityManager() {
return em;
}
public Widget updateWidget(Widget widget) throws Exception {
return getEntityManager().merge(widget);
}
The #PersistenceContext annotation causes the entities to be "Container-Managed", and everything works now.
Thanks for the all the help and suggestions here. At the end of the day, I worked out the solution after re-focusing on the "Managing Entities" section of the documentation here:
http://docs.oracle.com/javaee/5/tutorial/doc/
I want to create some sample code for JPA2 that can be run inside a Java EE container.
Running those sample normally require to have a Java EE server but i want to make things easier and to run them using an embedded container + maven.
Which one is better for this kind of "project" ?
Glassfish embedded , JBoss microcontainer or OPENEJB ?
Others ?
Thank you !
The problem to test EJB outside a container is that injections are not performed. I found this solution. In the stateless session bean you have an annotation #PersistenceContext
in a standalone Java-SE environment you need to inject the entitymanager by yourself, whcih can be done in an unittest. This is a fast alternative to an emmbeded server.
#Stateless
public class TestBean implements TestBusiness {
#PersistenceContext(unitName = "puTest")
EntityManager entityManager = null;
public List method() {
Query query = entityManager.createQuery("select t FROM Table t");
return query.getResultList();
}
}
The unittest instantiates the entitymanager and 'injects' it into the bean.
public class TestBeanJUnit {
static EntityManager em = null;
static EntityTransaction tx = null;
static TestBean tb = null;
static EntityManagerFactory emf = null;
#BeforeClass
public static void init() throws Exception {
emf = Persistence.createEntityManagerFactory("puTest");
}
#Before
public void setup() {
try {
em = emf.createEntityManager();
tx = em.getTransaction();
tx.begin();
tb = new TestBean();
Field field = TestBean.class.getDeclaredField("entityManager");
field.setAccessible(true);
field.set(tb, em);
} catch (Exception ex) {
ex.printStackTrace();
}
}
#After
public void tearDown() throws Exception {
if (em != null) {
tx.commit();
em.close();
}
}
}