-->
These old forums are deprecated now and set to read-only. We are waiting for you on our new forums!
More modern, Discourse-based and with GitHub/Google/Twitter authentication built-in.

All times are UTC - 5 hours [ DST ]



Forum locked This topic is locked, you cannot edit posts or make further replies.  [ 6 posts ] 
Author Message
 Post subject: @ManyToMany or two @OneToMany's?
PostPosted: Wed Jun 18, 2008 1:41 pm 
Senior
Senior

Joined: Sun Jun 11, 2006 10:41 am
Posts: 164
Hibernate version:
3.2.6
Name and version of the database you are using:
MySQL5

Hi,
Could someone pls suggest how to annotate the following? This is my case:
I have a Domain entity, and an Identity entity. Each Identity may be associated to one or more domains via an ALIAS, which is unique within a domain. For example, if I have 2 identities: Alice and Bob, and 2 domains: CarAgency and DrugStore, I would like to be able to "map" Bob and Alice to both domains, using different aliases. Let's say that Bob has the alias "b1" in the CarAgency domain, and the alias "b2" in the DrugStore domain. Alice has the alias "a1" in CarAgency, and "a2" in DrugStore.

This effectively creates a map such that:
map(CarAgency, a1) --> Alice
map(CarAgency, b1) --> Bob
map(DrugStore, a2) --> Alice
map(DrugStore, b2) --> Bob

In order to represent this map in native SQL, I would have probably created a table that looks like this:
(domain_id, alias, identity_id)
where domain_id, alias make a composite PK.

How do I do this in JPA? At first, I was thinking about @ManyToMany between Domain and Identity (which would somehow accomodate the Alias), or to define a 3rd entity, e.g. DomainIdentity such that:
Domain --> 1:N --> DomainIdentity <-- N:1 <-- Identity

any ideas on what's best and how to do it?
thanks.


Top
 Profile  
 
 Post subject:
PostPosted: Mon Jun 23, 2008 9:43 am 
Hibernate Team
Hibernate Team

Joined: Thu Apr 05, 2007 5:52 am
Posts: 1689
Location: Sweden
Hi,

there are basically two ways to add columns to your join tables (that's pretty much what you are doing here). Which solution you are choosing depends really on your use case. In one scenario your DomainIdentity is mapped to a real intermediate entity and the other you are mapping to a collection of components. The former is a little bit more complex, but allows bidirectional navigation whereas the latter is simpler without bidirectional navigation.

Have a look at this thread:http://forum.hibernate.org/viewtopic.php?t=986506. There is an example for how to use an intermediate entity (BusinessAddress). Otherwise I recommend you have a look at section 7.2.3 of Java Persistence with Hibernate.

--hardy


Top
 Profile  
 
 Post subject: First attempt
PostPosted: Tue Jun 24, 2008 2:52 am 
Senior
Senior

Joined: Sun Jun 11, 2006 10:41 am
Posts: 164
Hi,
I've tried your suggestion, and created a 3rd entity, DomainIdentity. It has a compound key: (domain_id, alias) and another column: identity_id.

To take care of the compound key, I looked at the Order application (LineItem entity) from the JEE tutorial, and I found some inconsistencies that I would like to ask about. First, I'll present the FINAL WORKING code. I've skipped the straightforward property accessors, and highlighted the "inconsistent" parts with comments. I would appreciate any insights on those inconsistencies.. I'm attempting to use pure JPA, so the same code should run with any entity manager, however it's not the case as you'll see below.

Code:
// the identity class
@Entity
public class SecurityIdentity implements Serializable {
   
    public SecurityIdentity() {}
   
    @Id
    @Column(name="IDENTITY_ID")
    @GeneratedValue
    public Long getId() ...

    @Column(name="IDENTITY_NAME")
    public String getName() ...
   
    @Override public boolean equals(Object o) ...
    @Override public int hashCode() ...
}


// the domain class
@Entity
public class SecurityDomain implements Serializable {
   
    public SecurityDomain() {}
   
    @Id
    @Column(name="DOMAIN_ID")
    @GeneratedValue
    public Long getId() ...

    @Column(name="DOMAIN_NAME")
    public String getName() ...
   
    @Override public boolean equals(Object o) ...
    @Override public int hashCode() ...
}



// the domain-identity mapping class
@Entity
@IdClass(pu1.DomainIdentityPK.class)
public class DomainIdentity implements Serializable {
   
    public DomainIdentity() {}

    @Id
    public Long getDomainId() ...

    @Id
    public String getUserAlias() ...   

    @ManyToOne
    @JoinColumn(name="IDENTITY_ID")
    public SecurityIdentity getSecurityIdentity() ...

    @ManyToOne
    /******************* @JoinColumn inconsistency, see remark #2 below *****/
    @JoinColumn(name="DOMAIN_ID", insertable=false, updatable=false)
    public SecurityDomain getSecurityDomain() { return securityDomain; }
    public void setSecurityDomain(SecurityDomain securityDomain) {
        this.securityDomain = securityDomain;
        this.domainId = (securityDomain != null ? securityDomain.getId() : null);
    }
    private SecurityDomain securityDomain;
}


// the map key class
public class DomainIdentityPK implements Serializable {
   
    public DomainIdentityPK() {
    }
   
    /********* @Column inconsistency, see remark #1 below *******/
    @Column(name="DOMAIN_ID")
    public Long getDomainId() ...

    [b]@Column(name="ALIAS")[/b]
    public String getUserAlias() ...

    public boolean equals(Object o) ...
    public int hashCode() ...
}




1. In the Order application (LineItem entity), the @Column annotation, which defines the column name is placed in the ENTITY class - not in the PK class. The order application is using the TopLink entity manager. However, in my app, I HAVE to place the @Column annotation in the PK class, otherwise, Hibernate simply ignores it.

2. In the Order application (LineItem entity), the "insertable=false, updateable=false" declaration is placed on the orderId property - not on the corresponding order property. In my case, if I try to place the declaration on the domainId property instead of on the securityDomain property, I get an exception during em.persist(domainIdentity):
Code:
DomainIdentity di = new DomainIdentity();
di.setSecurityDomain(d);
di.setSecurityIdentity(i);
di.setUserAlias("xx");
em.persist(di);


Exception (full stack trace below):
could not bind value 'xx' to parameter: 4; Parameter index out of range (4 > number of parameters, which is 3).

To resolve this, I HAVE to place the inseratble/updatable declaration on the securityDomain property and NOT on the domainId property.

Needless to say, the Order application works using TopLink. I have not yet had the time to test it under Hibernate, or alternatively, test my app under TopLink (will never happen due to other limitations).


full stack trace:
could not bind value 'xx' to parameter: 4; Parameter index out of range (4 > number of parameters, which is 3).
SQL Error: 0, SQLState: S1009
Parameter index out of range (4 > number of parameters, which is 3).
Could not synchronize database state with session
org.hibernate.exception.GenericJDBCException: could not insert: [pu1.DomainIdentity]
at org.hibernate.exception.SQLStateConverter.handledNonSpecificException(SQLStateConverter.java:103)
at org.hibernate.exception.SQLStateConverter.convert(SQLStateConverter.java:91)
at org.hibernate.exception.JDBCExceptionHelper.convert(JDBCExceptionHelper.java:43)
at org.hibernate.persister.entity.AbstractEntityPersister.insert(AbstractEntityPersister.java:2272)
at org.hibernate.persister.entity.AbstractEntityPersister.insert(AbstractEntityPersister.java:2665)
at org.hibernate.action.EntityInsertAction.execute(EntityInsertAction.java:60)
at org.hibernate.engine.ActionQueue.execute(ActionQueue.java:279)
at org.hibernate.engine.ActionQueue.executeActions(ActionQueue.java:263)
at org.hibernate.engine.ActionQueue.executeActions(ActionQueue.java:167)
at org.hibernate.event.def.AbstractFlushingEventListener.performExecutions(AbstractFlushingEventListener.java:298)
at org.hibernate.event.def.DefaultFlushEventListener.onFlush(DefaultFlushEventListener.java:27)
at org.hibernate.impl.SessionImpl.flush(SessionImpl.java:1000)
at org.hibernate.impl.SessionImpl.managedFlush(SessionImpl.java:338)
at org.hibernate.ejb.AbstractEntityManagerImpl$1.beforeCompletion(AbstractEntityManagerImpl.java:523)
at com.sun.enterprise.distributedtx.J2EETransaction.commit(J2EETransaction.java:419)
at com.sun.enterprise.distributedtx.J2EETransactionManagerOpt.commit(J2EETransactionManagerOpt.java:371)
at com.sun.ejb.containers.BaseContainer.completeNewTx(BaseContainer.java:3792)
at com.sun.ejb.containers.BaseContainer.postInvokeTx(BaseContainer.java:3571)
at com.sun.ejb.containers.BaseContainer.postInvoke(BaseContainer.java:1354)
at com.sun.ejb.containers.BaseContainer.postInvoke(BaseContainer.java:1316)
at com.sun.ejb.containers.EJBObjectInvocationHandler.invoke(EJBObjectInvocationHandler.java:210)
at com.sun.ejb.containers.EJBObjectInvocationHandlerDelegate.invoke(EJBObjectInvocationHandlerDelegate.java:117)
at $Proxy158.testDomain(Unknown Source)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
at java.lang.reflect.Method.invoke(Method.java:585)
at com.sun.corba.ee.impl.presentation.rmi.ReflectiveTie._invoke(ReflectiveTie.java:154)
at com.sun.corba.ee.impl.protocol.CorbaServerRequestDispatcherImpl.dispatchToServant(CorbaServerRequestDispatcherImpl.java:687)
at com.sun.corba.ee.impl.protocol.CorbaServerRequestDispatcherImpl.dispatch(CorbaServerRequestDispatcherImpl.java:227)
at com.sun.corba.ee.impl.protocol.CorbaMessageMediatorImpl.handleRequestRequest(CorbaMessageMediatorImpl.java:1846)
at com.sun.corba.ee.impl.protocol.CorbaMessageMediatorImpl.handleRequest(CorbaMessageMediatorImpl.java:1706)
at com.sun.corba.ee.impl.protocol.CorbaMessageMediatorImpl.handleInput(CorbaMessageMediatorImpl.java:1088)
at com.sun.corba.ee.impl.protocol.giopmsgheaders.RequestMessage_1_2.callback(RequestMessage_1_2.java:223)
at com.sun.corba.ee.impl.protocol.CorbaMessageMediatorImpl.handleRequest(CorbaMessageMediatorImpl.java:806)
at com.sun.corba.ee.impl.protocol.CorbaMessageMediatorImpl.dispatch(CorbaMessageMediatorImpl.java:563)
at com.sun.corba.ee.impl.protocol.CorbaMessageMediatorImpl.doWork(CorbaMessageMediatorImpl.java:2567)
at com.sun.corba.ee.impl.orbutil.threadpool.ThreadPoolImpl$WorkerThread.run(ThreadPoolImpl.java:555)
Caused by: java.sql.SQLException: Parameter index out of range (4 > number of parameters, which is 3).
at com.mysql.jdbc.SQLError.createSQLException(SQLError.java:1055)
at com.mysql.jdbc.SQLError.createSQLException(SQLError.java:956)
at com.mysql.jdbc.SQLError.createSQLException(SQLError.java:926)
at com.mysql.jdbc.PreparedStatement.checkBounds(PreparedStatement.java:3288)
at com.mysql.jdbc.PreparedStatement.setInternal(PreparedStatement.java:3272)
at com.mysql.jdbc.PreparedStatement.setString(PreparedStatement.java:4108)
at org.hibernate.type.StringType.set(StringType.java:26)
at org.hibernate.type.NullableType.nullSafeSet(NullableType.java:136)
at org.hibernate.type.NullableType.nullSafeSet(NullableType.java:116)
at org.hibernate.type.ComponentType.nullSafeSet(ComponentType.java:284)
at org.hibernate.persister.entity.AbstractEntityPersister.dehydrate(AbstractEntityPersister.java:2013)
at org.hibernate.persister.entity.AbstractEntityPersister.insert(AbstractEntityPersister.java:2248)
... 34 more
EJB5018: An exception was thrown during an ejb invocation on [TestBean]
javax.ejb.EJBException: Transaction aborted; nested exception is: javax.transaction.RollbackException: Transaction marked for rollback.
javax.transaction.RollbackException: Transaction marked for rollback.
at com.sun.enterprise.distributedtx.J2EETransaction.commit(J2EETransaction.java:440)
at com.sun.enterprise.distributedtx.J2EETransactionManagerOpt.commit(J2EETransactionManagerOpt.java:371)
at com.sun.ejb.containers.BaseContainer.completeNewTx(BaseContainer.java:3792)
at com.sun.ejb.containers.BaseContainer.postInvokeTx(BaseContainer.java:3571)
at com.sun.ejb.containers.BaseContainer.postInvoke(BaseContainer.java:1354)
at com.sun.ejb.containers.BaseContainer.postInvoke(BaseContainer.java:1316)
at com.sun.ejb.containers.EJBObjectInvocationHandler.invoke(EJBObjectInvocationHandler.java:210)
at com.sun.ejb.containers.EJBObjectInvocationHandlerDelegate.invoke(EJBObjectInvocationHandlerDelegate.java:117)
at $Proxy158.testDomain(Unknown Source)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
at java.lang.reflect.Method.invoke(Method.java:585)
at com.sun.corba.ee.impl.presentation.rmi.ReflectiveTie._invoke(ReflectiveTie.java:154)
at com.sun.corba.ee.impl.protocol.CorbaServerRequestDispatcherImpl.dispatchToServant(CorbaServerRequestDispatcherImpl.java:687)
at com.sun.corba.ee.impl.protocol.CorbaServerRequestDispatcherImpl.dispatch(CorbaServerRequestDispatcherImpl.java:227)
at com.sun.corba.ee.impl.protocol.CorbaMessageMediatorImpl.handleRequestRequest(CorbaMessageMediatorImpl.java:1846)
at com.sun.corba.ee.impl.protocol.CorbaMessageMediatorImpl.handleRequest(CorbaMessageMediatorImpl.java:1706)
at com.sun.corba.ee.impl.protocol.CorbaMessageMediatorImpl.handleInput(CorbaMessageMediatorImpl.java:1088)
at com.sun.corba.ee.impl.protocol.giopmsgheaders.RequestMessage_1_2.callback(RequestMessage_1_2.java:223)
at com.sun.corba.ee.impl.protocol.CorbaMessageMediatorImpl.handleRequest(CorbaMessageMediatorImpl.java:806)
at com.sun.corba.ee.impl.protocol.CorbaMessageMediatorImpl.dispatch(CorbaMessageMediatorImpl.java:563)
at com.sun.corba.ee.impl.protocol.CorbaMessageMediatorImpl.doWork(CorbaMessageMediatorImpl.java:2567)
at com.sun.corba.ee.impl.orbutil.threadpool.ThreadPoolImpl$WorkerThread.run(ThreadPoolImpl.java:555)
javax.ejb.EJBException: Transaction aborted; nested exception is: javax.transaction.RollbackException: Transaction marked for rollback.
at com.sun.ejb.containers.BaseContainer.completeNewTx(BaseContainer.java:3798)
at com.sun.ejb.containers.BaseContainer.postInvokeTx(BaseContainer.java:3571)
at com.sun.ejb.containers.BaseContainer.postInvoke(BaseContainer.java:1354)
at com.sun.ejb.containers.BaseContainer.postInvoke(BaseContainer.java:1316)
at com.sun.ejb.containers.EJBObjectInvocationHandler.invoke(EJBObjectInvocationHandler.java:210)
at com.sun.ejb.containers.EJBObjectInvocationHandlerDelegate.invoke(EJBObjectInvocationHandlerDelegate.java:117)
at $Proxy158.testDomain(Unknown Source)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
at java.lang.reflect.Method.invoke(Method.java:585)
at com.sun.corba.ee.impl.presentation.rmi.ReflectiveTie._invoke(ReflectiveTie.java:154)
at com.sun.corba.ee.impl.protocol.CorbaServerRequestDispatcherImpl.dispatchToServant(CorbaServerRequestDispatcherImpl.java:687)
at com.sun.corba.ee.impl.protocol.CorbaServerRequestDispatcherImpl.dispatch(CorbaServerRequestDispatcherImpl.java:227)
at com.sun.corba.ee.impl.protocol.CorbaMessageMediatorImpl.handleRequestRequest(CorbaMessageMediatorImpl.java:1846)
at com.sun.corba.ee.impl.protocol.CorbaMessageMediatorImpl.handleRequest(CorbaMessageMediatorImpl.java:1706)
at com.sun.corba.ee.impl.protocol.CorbaMessageMediatorImpl.handleInput(CorbaMessageMediatorImpl.java:1088)
at com.sun.corba.ee.impl.protocol.giopmsgheaders.RequestMessage_1_2.callback(RequestMessage_1_2.java:223)
at com.sun.corba.ee.impl.protocol.CorbaMessageMediatorImpl.handleRequest(CorbaMessageMediatorImpl.java:806)
at com.sun.corba.ee.impl.protocol.CorbaMessageMediatorImpl.dispatch(CorbaMessageMediatorImpl.java:563)
at com.sun.corba.ee.impl.protocol.CorbaMessageMediatorImpl.doWork(CorbaMessageMediatorImpl.java:2567)
at com.sun.corba.ee.impl.orbutil.threadpool.ThreadPoolImpl$WorkerThread.run(ThreadPoolImpl.java:555)


Top
 Profile  
 
 Post subject: Re: First attempt
PostPosted: Wed Jun 25, 2008 3:55 am 
Hibernate Team
Hibernate Team

Joined: Thu Apr 05, 2007 5:52 am
Posts: 1689
Location: Sweden
sagimann wrote:
Hi,
1. In the Order application (LineItem entity), the @Column annotation, which defines the column name is placed in the ENTITY class - not in the PK class. The order application is using the TopLink entity manager. However, in my app, I HAVE to place the @Column annotation in the PK class, otherwise, Hibernate simply ignores it.

2. In the Order application (LineItem entity), the "insertable=false, updateable=false" declaration is placed on the orderId property - not on the corresponding order property. In my case, if I try to place the declaration on the domainId property instead of on the securityDomain property, I get an exception during em.persist(domainIdentity):


1. I would also expect that you could place the @Column annotation on the entity class. In fact the PK class should not need any annotations. This looks like a bug.

2. The mapping makes sense to me as is. I don't think that the specs enforce a certain way.


Top
 Profile  
 
 Post subject: @Column annotation
PostPosted: Wed Jun 25, 2008 5:36 am 
Senior
Senior

Joined: Sun Jun 11, 2006 10:41 am
Posts: 164
The hibernate docs claim that placing annotations in the PK class is a hibernate-specific optional feature. However, they don't say that they MUST be placed in the PK or else they are ignored :-) I'll open a JIRA issue and see what comes up.

thanks.


Top
 Profile  
 
 Post subject:
PostPosted: Mon Aug 25, 2008 6:48 am 
Newbie

Joined: Mon Aug 25, 2008 6:44 am
Posts: 1
Hi,

I'm just curious if a JIRA issue was created for this problem. I have the exact same problem, but now it is a non-issue thanks to this thread.


Top
 Profile  
 
Display posts from previous:  Sort by  
Forum locked This topic is locked, you cannot edit posts or make further replies.  [ 6 posts ] 

All times are UTC - 5 hours [ DST ]


You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum

Search for:
© Copyright 2014, Red Hat Inc. All rights reserved. JBoss and Hibernate are registered trademarks and servicemarks of Red Hat, Inc.