You are viewing a plain text version of this content. The canonical link for it is here.
Posted to users@openjpa.apache.org by Uden <ud...@gmail.com> on 2008/05/08 12:17:03 UTC

Re: Question about @OneToMany

The solution quoted below but has a consequence for the Java class model: the
OneToMany relationship becomes bi-directional instead of uni-directional. 

What is the reason for creating the join-table? 

I thought (based on my database experience) that a join-table is only
required for ManyToMany relationships. 
If you look at the data in the join-table of a uni-directional relation (no
mappedBy attribute), the relation between the join-table and master table is
always OneToOne, so this relation could be handled by a FK-field in the
detail-table.

thanks for your explanation,
Uden


Andy Schlaikjer-2 wrote:
> 
> Marco Schwarz wrote:
>> 
>> How can I make only 2 tables?
> 
> Here's my guess:
> 
> First, use the "mappedBy" property of the @OneToMany annotation, like
> this:
> 
> @Entity
> class ModelObject {
>    ...
> 
>    @ManyToOne
>    ModelObject parent;
> 
>    @OneToMany(mappedBy="parent")
>    List<ModelObject> children;
> 
>    ...
> }
> 
> This way, an extra join table won't be necessary to encode the parent 
> child relationship. Only the "parent_id" column in the "ModelObject" 
> table will be used to encode the relationship.
> 

-- 
View this message in context: http://www.nabble.com/Question-about-%40OneToMany-tp16840368p17124365.html
Sent from the OpenJPA Users mailing list archive at Nabble.com.


Re: Question about @OneToMany

Posted by Andy Schlaikjer <ha...@cs.cmu.edu>.
I think I may have found OpenJPA's solution to this problem. Could 
someone comment? Thanks!

http://openjpa.apache.org/docs/latest/manual/manual.html#ref_guide_mapping_jpa_onemany

@Entity
public class Node
{
   @Id
   protected long id;

   @OneToMany
   @ElementJoinColumn(name="parent_id", target="id")
   protected Collection<Node> children;
}

Andy Schlaikjer wrote:
> I think it's not wonderful that you have to add an extra field to your 
> object model if you're really not interested in modeling the ManyToOne 
> side of a relationship like this. However, at the moment you can't 
> "reuse" a single table to map both an entity and a join table, so we're 
> stuck.
> 
> For example, this doesn't work:
> 
> @Entity
> public class Node
> {
>   @Id
>   protected long id;
> 
>   @OneToMany()
>   @JoinTable(
>     name = "Node",
>     joinColumns = @JoinColumn(name = "parent_id"), // i wish
>     inverseJoinColumns = @JoinColumn(name = "id")
>   )
>   protected Collection<Node> children;
> 
>   ...
> }
> 
> Michael Vorburger wrote:
>> Hello,
>>
>> Similar situation here, and I wonder about people's thoughts & pros/cons
>> regarding this:
>>
>>> Your solution (anotate "ModelObject parent;" with @ManyToOne instead
>> of @Transient and add mappedBy="parent" to @OneToMany) works, also for
>> my application, but turns the uni-directional relation into a
>> bi-directional relation.  And this bi-directional relation is more
>> dificult to manage and not needed in our Java application.
>>
>> Why is this "bi-directional relation is more dificult to manage and not
>> needed in our Java application" ?  If you let OpenJPA deal with this for
>> you with the Managed Inverses
>> (http://openjpa.apache.org/docs/latest/manual/ref_guide_inverses.html),
>> what's the problem with an additional field?  Hide it even - if for some
>> reason you don't want to expose the bi-directionality to the users of
>> the object model for keep that '@ManyToOne ModelObject parent' as a
>> private with no setters and getters - just to get the desired mapping!
>>
>> What's the issue with this approach?  (Portability and not wanting to
>> use Managed Inverses aside; but I don't know if that's strong enough,
>> you're using OpenJPA specific configuration elsewhere already, and
>> that's really what this is - a runtime configuration specific to one JPA
>> implementation.  Other implementations may have a similar feature?  If
>> not, worst case, when switching, manually code the logic [with loop
>> detection, if needed]).
>>
>> Regards,
>> Michael
>>
>>
>> -----Original Message-----
>> From: Uden [mailto:udenvh@gmail.com] Sent: jeudi, 8. mai 2008 21:37
>> To: users@openjpa.apache.org
>> Subject: Re: Question about @OneToMany
>>
>>
>> Hi Andy, thanks for the quick response.
>>
>> In my application i had three tables generated (a master, a detail and a
>> join table) for what i believed could be modelled by just the master and
>> a detail table (at least in traditional database modeling). So when i
>> was looking for a solution to simplify my datamodel in the database, i
>> found this posting which looked similar to my problem and added my
>> question.
>>  
>> I need to map the following Java classes (note i reuse Marco's code
>> example):
>>
>> @MappedSuperclass
>> @Inheritance(strategy=InheritanceType.TABLE_PER_CLASS)
>> class ModelObject {
>>
>>         @Id
>>         private int id
>>
>>         @Transient
>>         ModelObject parent;
>>
>>         @OneToMany(cascade={CascadeType.ALL}, fetch=FetchType.EAGER)
>>         List<ModelObject> children;
>>
>>         .....
>> }
>>
>> @Entity
>> class Company extends ModelObject {
>> }
>>
>> @Entity
>> class Employer extends ModelObject {
>> }
>>
>> to the folowing database tables:
>>
>> COMPANY (ID     (PK)
>> , ...
>> )
>>
>> and EMPLOYEE
>> (ID     (PK)
>> ,COMPANY_ID    (FK to COMPANY.ID)
>> , ...
>> )
>>
>> In Marco's original question he indicates that in his case "openjpa
>> create 4 tables (Company, Company_children, Emplpyer and
>> Employer_children).". Your solution (anotate "ModelObject parent;" 
>> with @ManyToOne instead of
>> @Transient and add mappedBy="parent" to @OneToMany) works, also for my
>> application, but turns the uni-directional relation into a
>> bi-directional relation. And this bi-directional relation is more 
>> dificult to manage and not
>> needed in our Java application. It does however results in a simpler
>> datamodel.
>> Your second solution changes the direction (or ownership) of the
>> relation in the Java model.
>>
>> So it seems we have to trade a simplified database datamodel versus a
>> simplified Java datamodel.
>>
>> Or is there an other solution?
>>
>> thanks,
>> Uden
>>
>>
>> hazen wrote:
>>> Hi Uden,
>>>
>>> If you'd rather keep the relation unidirectional just remove the 
>>> `children` field-- the `parent` field alone is enough to encode the 
>>> relation without recourse to a separate join table. Either way, I 
>>> don't see how the quoted section below results in a join table. Both 
>>> fields rely solely on a "parent_id" column within the "ModelObject" 
>>> table, not on some other join table. Am I missing something?
>>>
>>> Andy
>>>
>>> Uden wrote:
>>>> The solution quoted below but has a consequence for the Java class
>> model:
>>>> the
>>>> OneToMany relationship becomes bi-directional instead of
>> uni-directional.
>>>> What is the reason for creating the join-table?
>>>> I thought (based on my database experience) that a join-table is only
>>
>>>> required for ManyToMany relationships.
>>>> If you look at the data in the join-table of a uni-directional 
>>>> relation (no mappedBy attribute), the relation between the join-table
>>
>>>> and master table is always OneToOne, so this relation could be 
>>>> handled by a FK-field in the detail-table.
>>>>
>>>> thanks for your explanation,
>>>> Uden
>>>>
>>>>
>>>> Andy Schlaikjer-2 wrote:
>>>>> Marco Schwarz wrote:
>>>>>> How can I make only 2 tables?
>>>>> Here's my guess:
>>>>>
>>>>> First, use the "mappedBy" property of the @OneToMany annotation, like
>>>>> this:
>>>>>
>>>>> @Entity
>>>>> class ModelObject {
>>>>>    ...
>>>>>
>>>>>    @ManyToOne
>>>>>    ModelObject parent;
>>>>>
>>>>>    @OneToMany(mappedBy="parent")
>>>>>    List<ModelObject> children;
>>>>>
>>>>>    ...
>>>>> }
>>>>>
>>>>> This way, an extra join table won't be necessary to encode the 
>>>>> parent child relationship. Only the "parent_id" column in the
>> "ModelObject"
>>>>> table will be used to encode the relationship.
>>>>>
>>>
>>
>> -- 
>> View this message in context:
>> http://www.nabble.com/Question-about-%40OneToMany-tp16840368p17134828.ht
>> ml
>> Sent from the OpenJPA Users mailing list archive at Nabble.com.
>>
>>
>> ____________________________________________________________
>>
>> • This email and any files transmitted with it are CONFIDENTIAL and 
>> intended
>>   solely for the use of the individual or entity to which they are 
>> addressed.
>> • Any unauthorized copying, disclosure, or distribution of the 
>> material within
>>   this email is strictly forbidden.
>> • Any views or opinions presented within this e-mail are solely those 
>> of the
>>   author and do not necessarily represent those of Odyssey Financial
>> Technologies SA unless otherwise specifically stated.
>> • An electronic message is not binding on its sender. Any message 
>> referring to
>>   a binding engagement must be confirmed in writing and duly signed.
>> • If you have received this email in error, please notify the sender 
>> immediately
>>   and delete the original.
>>
> 

Re: Question about @OneToMany

Posted by pietia <pi...@gmail.com>.
hi there !

Is possible to define @OneToMany realtionship
without using join table ? (i saw that in book about Ejb 3.0).

i use openjpa and when i'm trying to do simple
realtionship A-B, as follows :

@Entity
public class Address implements Serializable {

	private Integer	id;
	private String	street;
	private String	city;

	@Id
	@GeneratedValue(strategy=GenerationType.AUTO)
	public Integer getId() {
		return id;
	}

...
}


@Entity
public class Customer implements Serializable {

	private Integer				id;
	private String				name;
	private String				surname;
	private Collection<Address>	address = new ArrayList<Address>();

	@Id
	@GeneratedValue(strategy = GenerationType.AUTO)
	public Integer getId() {
		return id;
	}

	@OneToMany(cascade = { CascadeType.PERSIST, CascadeType.REMOVE })
	@JoinColumn(name = "Address_id")   
	public Collection<Address> getAddress() {
		return address;
	}

...
}

Client:

public class Testuj {
	public static void main(String[] args) {
		Properties prop = new Properties();
		prop.put(
					Context.INITIAL_CONTEXT_FACTORY,
					"org.apache.openejb.client.RemoteInitialContextFactory");
		prop.put("java.naming.provider.url", "ejbd://localhost:4201");
		try {
			Context context = new InitialContext(prop);
			try {
				CustomerManagerRemote cmr = (CustomerManagerRemote) context
						.lookup("CustomerManagerRemote");

				Customer customer = new Customer();
				customer.setName("Anna");
				customer.setSurname("Maria");

				ArrayList<Address> addresses = (ArrayList<Address>)
customer.getAddress();
				
				Address address = new Address();
				address.setCity("New York");
				address.setStreet("Nieprawdopodna 12/123");
				
				addresses.add(address);
				customer.setAddress(addresses);
				cmr.addCustomer(customer);

			} catch (Exception e) {
				e.printStackTrace();
			}
		} catch (NamingException e) {
			e.printStackTrace();
		}
	}
}

.. i gets:

javax.ejb.EJBException: The bean encountered a non-application exception.;
nested exception is: 
	<openjpa-1.0.2-r420667:627158 fatal user error>
org.apache.openjpa.persistence.ArgumentException: You have supplied columns
for "org.testowa.Customer.address", but this mapping cannot have columns in
this context.
	at
org.apache.openejb.client.EJBInvocationHandler.convertException(EJBInvocationHandler.java:219)
	at
org.apache.openejb.client.EJBObjectHandler._invoke(EJBObjectHandler.java:157)
	at
org.apache.openejb.client.EJBInvocationHandler.invoke(EJBInvocationHandler.java:117)
	at
org.apache.openejb.client.proxy.Jdk13InvocationHandler.invoke(Jdk13InvocationHandler.java:52)
	at $Proxy0.addCustomer(Unknown Source)
	at org.testowa.Testuj.main(Testuj.java:44)
Caused by: <openjpa-1.0.2-r420667:627158 fatal user error>
org.apache.openjpa.persistence.ArgumentException: You have supplied columns
for "org.testowa.Customer.address", but this mapping cannot have columns in
this context.
	at
org.apache.openjpa.jdbc.meta.MappingInfo.assertNoSchemaComponents(MappingInfo.java:327)
	at
org.apache.openjpa.jdbc.meta.strats.RelationToManyTableFieldStrategy.map(RelationToManyTableFieldStrategy.java:96)
	at
org.apache.openjpa.jdbc.meta.strats.RelationCollectionTableFieldStrategy.map(RelationCollectionTableFieldStrategy.java:94)
	at
org.apache.openjpa.jdbc.meta.FieldMapping.setStrategy(FieldMapping.java:120)
	at
org.apache.openjpa.jdbc.meta.RuntimeStrategyInstaller.installStrategy(RuntimeStrategyInstaller.java:80)
	at
org.apache.openjpa.jdbc.meta.FieldMapping.resolveMapping(FieldMapping.java:438)
	at org.apache.openjpa.jdbc.meta.FieldMapping.resolve(FieldMapping.java:403)
	at
org.apache.openjpa.jdbc.meta.ClassMapping.resolveMapping(ClassMapping.java:812)
	at org.apache.openjpa.meta.ClassMetaData.resolve(ClassMetaData.java:1618)
	at
org.apache.openjpa.meta.MetaDataRepository.processBuffer(MetaDataRepository.java:675)
	at
org.apache.openjpa.meta.MetaDataRepository.resolveMapping(MetaDataRepository.java:636)
	at
org.apache.openjpa.meta.MetaDataRepository.resolve(MetaDataRepository.java:514)
	at
org.apache.openjpa.meta.MetaDataRepository.getMetaData(MetaDataRepository.java:302)
	at
org.apache.openjpa.jdbc.meta.MappingRepository.getMapping(MappingRepository.java:282)
	at
org.apache.openjpa.jdbc.meta.MappingTool.getMapping(MappingTool.java:673)
	at
org.apache.openjpa.jdbc.meta.MappingTool.buildSchema(MappingTool.java:745)
	at org.apache.openjpa.jdbc.meta.MappingTool.run(MappingTool.java:643)
	at
org.apache.openjpa.jdbc.kernel.JDBCBrokerFactory.synchronizeMappings(JDBCBrokerFactory.java:164)
	at
org.apache.openjpa.jdbc.kernel.JDBCBrokerFactory.newBrokerImpl(JDBCBrokerFactory.java:130)
	at
org.apache.openjpa.kernel.AbstractBrokerFactory.newBroker(AbstractBrokerFactory.java:188)
	at
org.apache.openjpa.kernel.DelegatingBrokerFactory.newBroker(DelegatingBrokerFactory.java:142)
	at
org.apache.openjpa.persistence.EntityManagerFactoryImpl.createEntityManager(EntityManagerFactoryImpl.java:192)
	at
org.apache.openjpa.persistence.EntityManagerFactoryImpl.createEntityManager(EntityManagerFactoryImpl.java:56)
	at
org.apache.geronimo.persistence.CMPEntityManagerTxScoped.createEntityManager(CMPEntityManagerTxScoped.java:74)
	at
org.apache.geronimo.persistence.CMPEntityManagerTxScoped.getEntityManager(CMPEntityManagerTxScoped.java:55)
	at
org.apache.geronimo.persistence.CMPEntityManagerTxScoped.persist(CMPEntityManagerTxScoped.java:81)
	at org.testowa.CustomerManagerBean.addCustomer(CustomerManagerBean.java:15)
	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:597)
	at
org.apache.openejb.core.interceptor.ReflectionInvocationContext$Invocation.invoke(ReflectionInvocationContext.java:158)
	at
org.apache.openejb.core.interceptor.ReflectionInvocationContext.proceed(ReflectionInvocationContext.java:141)
	at
org.apache.openejb.core.interceptor.InterceptorStack.invoke(InterceptorStack.java:67)
	at
org.apache.openejb.core.stateless.StatelessContainer._invoke(StatelessContainer.java:210)
	at
org.apache.openejb.core.stateless.StatelessContainer._invoke(StatelessContainer.java:188)
	at
org.apache.openejb.core.stateless.StatelessContainer.invoke(StatelessContainer.java:165)
	at
org.apache.openejb.server.ejbd.EjbRequestHandler.doEjbObject_BUSINESS_METHOD(EjbRequestHandler.java:238)
	at
org.apache.openejb.server.ejbd.EjbRequestHandler.processRequest(EjbRequestHandler.java:129)
	at
org.apache.openejb.server.ejbd.EjbDaemon.processEjbRequest(EjbDaemon.java:164)
	at org.apache.openejb.server.ejbd.EjbDaemon.service(EjbDaemon.java:122)
	at org.apache.openejb.server.ejbd.EjbDaemon.service(EjbDaemon.java:84)
	at org.apache.openejb.server.ejbd.EjbServer.service(EjbServer.java:60)
	at org.apache.openejb.server.ServicePool$2.run(ServicePool.java:78)
	at org.apache.openejb.server.ServicePool$3.run(ServicePool.java:101)
	at
java.util.concurrent.ThreadPoolExecutor$Worker.runTask(ThreadPoolExecutor.java:885)
	at
java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:907)
	at java.lang.Thread.run(Thread.java:619)

what may be wronq ? 

pietia

-- 
View this message in context: http://www.nabble.com/Question-about-%40OneToMany-tp16840368p17170612.html
Sent from the OpenJPA Users mailing list archive at Nabble.com.


Re: Question about @OneToMany

Posted by Andy Schlaikjer <ha...@cs.cmu.edu>.
I think it's not wonderful that you have to add an extra field to your 
object model if you're really not interested in modeling the ManyToOne 
side of a relationship like this. However, at the moment you can't 
"reuse" a single table to map both an entity and a join table, so we're 
stuck.

For example, this doesn't work:

@Entity
public class Node
{
   @Id
   protected long id;

   @OneToMany()
   @JoinTable(
     name = "Node",
     joinColumns = @JoinColumn(name = "parent_id"), // i wish
     inverseJoinColumns = @JoinColumn(name = "id")
   )
   protected Collection<Node> children;

   ...
}

Michael Vorburger wrote:
> Hello,
> 
> Similar situation here, and I wonder about people's thoughts & pros/cons
> regarding this:
> 
>> Your solution (anotate "ModelObject parent;" with @ManyToOne instead
> of @Transient and add mappedBy="parent" to @OneToMany) works, also for
> my application, but turns the uni-directional relation into a
> bi-directional relation.  And this bi-directional relation is more
> dificult to manage and not needed in our Java application.
> 
> Why is this "bi-directional relation is more dificult to manage and not
> needed in our Java application" ?  If you let OpenJPA deal with this for
> you with the Managed Inverses
> (http://openjpa.apache.org/docs/latest/manual/ref_guide_inverses.html),
> what's the problem with an additional field?  Hide it even - if for some
> reason you don't want to expose the bi-directionality to the users of
> the object model for keep that '@ManyToOne ModelObject parent' as a
> private with no setters and getters - just to get the desired mapping!
> 
> What's the issue with this approach?  (Portability and not wanting to
> use Managed Inverses aside; but I don't know if that's strong enough,
> you're using OpenJPA specific configuration elsewhere already, and
> that's really what this is - a runtime configuration specific to one JPA
> implementation.  Other implementations may have a similar feature?  If
> not, worst case, when switching, manually code the logic [with loop
> detection, if needed]).
> 
> Regards,
> Michael
> 
> 
> -----Original Message-----
> From: Uden [mailto:udenvh@gmail.com] 
> Sent: jeudi, 8. mai 2008 21:37
> To: users@openjpa.apache.org
> Subject: Re: Question about @OneToMany
> 
> 
> Hi Andy, thanks for the quick response.
> 
> In my application i had three tables generated (a master, a detail and a
> join table) for what i believed could be modelled by just the master and
> a detail table (at least in traditional database modeling). So when i
> was looking for a solution to simplify my datamodel in the database, i
> found this posting which looked similar to my problem and added my
> question.
>  
> I need to map the following Java classes (note i reuse Marco's code
> example):
> 
> @MappedSuperclass
> @Inheritance(strategy=InheritanceType.TABLE_PER_CLASS)
> class ModelObject {
> 
>         @Id
>         private int id
> 
>         @Transient
>         ModelObject parent;
> 
>         @OneToMany(cascade={CascadeType.ALL}, fetch=FetchType.EAGER)
>         List<ModelObject> children;
> 
>         .....
> }
> 
> @Entity
> class Company extends ModelObject {
> }
> 
> @Entity
> class Employer extends ModelObject {
> }
> 
> to the folowing database tables:
> 
> COMPANY 
> (ID     (PK)
> , ...
> )
> 
> and EMPLOYEE
> (ID     (PK)
> ,COMPANY_ID    (FK to COMPANY.ID)
> , ...
> )
> 
> In Marco's original question he indicates that in his case "openjpa
> create 4 tables (Company, Company_children, Emplpyer and
> Employer_children).". 
> Your solution (anotate "ModelObject parent;" with @ManyToOne instead of
> @Transient and add mappedBy="parent" to @OneToMany) works, also for my
> application, but turns the uni-directional relation into a
> bi-directional relation. 
> And this bi-directional relation is more dificult to manage and not
> needed in our Java application. It does however results in a simpler
> datamodel. 
> 
> Your second solution changes the direction (or ownership) of the
> relation in the Java model.
> 
> So it seems we have to trade a simplified database datamodel versus a
> simplified Java datamodel.
> 
> Or is there an other solution?
> 
> thanks,
> Uden
> 
> 
> hazen wrote:
>> Hi Uden,
>>
>> If you'd rather keep the relation unidirectional just remove the 
>> `children` field-- the `parent` field alone is enough to encode the 
>> relation without recourse to a separate join table. Either way, I 
>> don't see how the quoted section below results in a join table. Both 
>> fields rely solely on a "parent_id" column within the "ModelObject" 
>> table, not on some other join table. Am I missing something?
>>
>> Andy
>>
>> Uden wrote:
>>> The solution quoted below but has a consequence for the Java class
> model:
>>> the
>>> OneToMany relationship becomes bi-directional instead of
> uni-directional. 
>>> What is the reason for creating the join-table? 
>>>
>>> I thought (based on my database experience) that a join-table is only
> 
>>> required for ManyToMany relationships.
>>> If you look at the data in the join-table of a uni-directional 
>>> relation (no mappedBy attribute), the relation between the join-table
> 
>>> and master table is always OneToOne, so this relation could be 
>>> handled by a FK-field in the detail-table.
>>>
>>> thanks for your explanation,
>>> Uden
>>>
>>>
>>> Andy Schlaikjer-2 wrote:
>>>> Marco Schwarz wrote:
>>>>> How can I make only 2 tables?
>>>> Here's my guess:
>>>>
>>>> First, use the "mappedBy" property of the @OneToMany annotation, 
>>>> like
>>>> this:
>>>>
>>>> @Entity
>>>> class ModelObject {
>>>>    ...
>>>>
>>>>    @ManyToOne
>>>>    ModelObject parent;
>>>>
>>>>    @OneToMany(mappedBy="parent")
>>>>    List<ModelObject> children;
>>>>
>>>>    ...
>>>> }
>>>>
>>>> This way, an extra join table won't be necessary to encode the 
>>>> parent child relationship. Only the "parent_id" column in the
> "ModelObject"
>>>> table will be used to encode the relationship.
>>>>
>>
> 
> --
> View this message in context:
> http://www.nabble.com/Question-about-%40OneToMany-tp16840368p17134828.ht
> ml
> Sent from the OpenJPA Users mailing list archive at Nabble.com.
> 
> 
> ____________________________________________________________
> 
> • This email and any files transmitted with it are CONFIDENTIAL and intended
>   solely for the use of the individual or entity to which they are addressed.
> • Any unauthorized copying, disclosure, or distribution of the material within
>   this email is strictly forbidden.
> • Any views or opinions presented within this e-mail are solely those of the
>   author and do not necessarily represent those of Odyssey Financial
> Technologies SA unless otherwise specifically stated.
> • An electronic message is not binding on its sender. Any message referring to
>   a binding engagement must be confirmed in writing and duly signed.
> • If you have received this email in error, please notify the sender immediately
>   and delete the original.
> 

RE: Question about @OneToMany

Posted by Michael Vorburger <mv...@odyssey-group.com>.
Hello,

Similar situation here, and I wonder about people's thoughts & pros/cons
regarding this:

> Your solution (anotate "ModelObject parent;" with @ManyToOne instead
of @Transient and add mappedBy="parent" to @OneToMany) works, also for
my application, but turns the uni-directional relation into a
bi-directional relation.  And this bi-directional relation is more
dificult to manage and not needed in our Java application.

Why is this "bi-directional relation is more dificult to manage and not
needed in our Java application" ?  If you let OpenJPA deal with this for
you with the Managed Inverses
(http://openjpa.apache.org/docs/latest/manual/ref_guide_inverses.html),
what's the problem with an additional field?  Hide it even - if for some
reason you don't want to expose the bi-directionality to the users of
the object model for keep that '@ManyToOne ModelObject parent' as a
private with no setters and getters - just to get the desired mapping!

What's the issue with this approach?  (Portability and not wanting to
use Managed Inverses aside; but I don't know if that's strong enough,
you're using OpenJPA specific configuration elsewhere already, and
that's really what this is - a runtime configuration specific to one JPA
implementation.  Other implementations may have a similar feature?  If
not, worst case, when switching, manually code the logic [with loop
detection, if needed]).

Regards,
Michael


-----Original Message-----
From: Uden [mailto:udenvh@gmail.com] 
Sent: jeudi, 8. mai 2008 21:37
To: users@openjpa.apache.org
Subject: Re: Question about @OneToMany


Hi Andy, thanks for the quick response.

In my application i had three tables generated (a master, a detail and a
join table) for what i believed could be modelled by just the master and
a detail table (at least in traditional database modeling). So when i
was looking for a solution to simplify my datamodel in the database, i
found this posting which looked similar to my problem and added my
question.
 
I need to map the following Java classes (note i reuse Marco's code
example):

@MappedSuperclass
@Inheritance(strategy=InheritanceType.TABLE_PER_CLASS)
class ModelObject {

        @Id
        private int id

        @Transient
        ModelObject parent;

        @OneToMany(cascade={CascadeType.ALL}, fetch=FetchType.EAGER)
        List<ModelObject> children;

        .....
}

@Entity
class Company extends ModelObject {
}

@Entity
class Employer extends ModelObject {
}

to the folowing database tables:

COMPANY 
(ID     (PK)
, ...
)

and EMPLOYEE
(ID     (PK)
,COMPANY_ID    (FK to COMPANY.ID)
, ...
)

In Marco's original question he indicates that in his case "openjpa
create 4 tables (Company, Company_children, Emplpyer and
Employer_children).". 
Your solution (anotate "ModelObject parent;" with @ManyToOne instead of
@Transient and add mappedBy="parent" to @OneToMany) works, also for my
application, but turns the uni-directional relation into a
bi-directional relation. 
And this bi-directional relation is more dificult to manage and not
needed in our Java application. It does however results in a simpler
datamodel. 

Your second solution changes the direction (or ownership) of the
relation in the Java model.

So it seems we have to trade a simplified database datamodel versus a
simplified Java datamodel.

Or is there an other solution?

thanks,
Uden


hazen wrote:
> 
> Hi Uden,
> 
> If you'd rather keep the relation unidirectional just remove the 
> `children` field-- the `parent` field alone is enough to encode the 
> relation without recourse to a separate join table. Either way, I 
> don't see how the quoted section below results in a join table. Both 
> fields rely solely on a "parent_id" column within the "ModelObject" 
> table, not on some other join table. Am I missing something?
> 
> Andy
> 
> Uden wrote:
>> The solution quoted below but has a consequence for the Java class
model:
>> the
>> OneToMany relationship becomes bi-directional instead of
uni-directional. 
>> 
>> What is the reason for creating the join-table? 
>> 
>> I thought (based on my database experience) that a join-table is only

>> required for ManyToMany relationships.
>> If you look at the data in the join-table of a uni-directional 
>> relation (no mappedBy attribute), the relation between the join-table

>> and master table is always OneToOne, so this relation could be 
>> handled by a FK-field in the detail-table.
>> 
>> thanks for your explanation,
>> Uden
>> 
>> 
>> Andy Schlaikjer-2 wrote:
>>> Marco Schwarz wrote:
>>>> How can I make only 2 tables?
>>> Here's my guess:
>>>
>>> First, use the "mappedBy" property of the @OneToMany annotation, 
>>> like
>>> this:
>>>
>>> @Entity
>>> class ModelObject {
>>>    ...
>>>
>>>    @ManyToOne
>>>    ModelObject parent;
>>>
>>>    @OneToMany(mappedBy="parent")
>>>    List<ModelObject> children;
>>>
>>>    ...
>>> }
>>>
>>> This way, an extra join table won't be necessary to encode the 
>>> parent child relationship. Only the "parent_id" column in the
"ModelObject"
>>> table will be used to encode the relationship.
>>>
>> 
> 
> 

--
View this message in context:
http://www.nabble.com/Question-about-%40OneToMany-tp16840368p17134828.ht
ml
Sent from the OpenJPA Users mailing list archive at Nabble.com.


____________________________________________________________

� This email and any files transmitted with it are CONFIDENTIAL and intended
  solely for the use of the individual or entity to which they are addressed.
� Any unauthorized copying, disclosure, or distribution of the material within
  this email is strictly forbidden.
� Any views or opinions presented within this e-mail are solely those of the
  author and do not necessarily represent those of Odyssey Financial
Technologies SA unless otherwise specifically stated.
� An electronic message is not binding on its sender. Any message referring to
  a binding engagement must be confirmed in writing and duly signed.
� If you have received this email in error, please notify the sender immediately
  and delete the original.

Re: Question about @OneToMany

Posted by Uden <ud...@gmail.com>.
Hi Andy, thanks for the quick response.

In my application i had three tables generated (a master, a detail and a
join table) for what i believed could be modelled by just the master and a
detail table (at least in traditional database modeling). So when i was
looking for a solution to simplify my datamodel in the database, i found
this posting which looked similar to my problem and added my question.
 
I need to map the following Java classes (note i reuse Marco's code
example):

@MappedSuperclass
@Inheritance(strategy=InheritanceType.TABLE_PER_CLASS)
class ModelObject {

        @Id
        private int id

        @Transient
        ModelObject parent;

        @OneToMany(cascade={CascadeType.ALL}, fetch=FetchType.EAGER)
        List<ModelObject> children;

        .....
}

@Entity
class Company extends ModelObject {
}

@Entity
class Employer extends ModelObject {
}

to the folowing database tables:

COMPANY 
(ID     (PK)
, ...
)

and EMPLOYEE
(ID     (PK)
,COMPANY_ID    (FK to COMPANY.ID)
, ...
)

In Marco's original question he indicates that in his case "openjpa create 4
tables (Company,
Company_children, Emplpyer and Employer_children).". 
Your solution (anotate "ModelObject parent;" with @ManyToOne instead of
@Transient and add mappedBy="parent" to @OneToMany) works, also for my
application, but turns the uni-directional relation into a bi-directional
relation. 
And this bi-directional relation is more dificult to manage and not needed
in our Java application. It does however results in a simpler datamodel. 

Your second solution changes the direction (or ownership) of the relation in
the Java model.

So it seems we have to trade a simplified database datamodel versus a
simplified Java datamodel.

Or is there an other solution?

thanks,
Uden


hazen wrote:
> 
> Hi Uden,
> 
> If you'd rather keep the relation unidirectional just remove the 
> `children` field-- the `parent` field alone is enough to encode the 
> relation without recourse to a separate join table. Either way, I don't 
> see how the quoted section below results in a join table. Both fields 
> rely solely on a "parent_id" column within the "ModelObject" table, not 
> on some other join table. Am I missing something?
> 
> Andy
> 
> Uden wrote:
>> The solution quoted below but has a consequence for the Java class model:
>> the
>> OneToMany relationship becomes bi-directional instead of uni-directional. 
>> 
>> What is the reason for creating the join-table? 
>> 
>> I thought (based on my database experience) that a join-table is only
>> required for ManyToMany relationships. 
>> If you look at the data in the join-table of a uni-directional relation
>> (no
>> mappedBy attribute), the relation between the join-table and master table
>> is
>> always OneToOne, so this relation could be handled by a FK-field in the
>> detail-table.
>> 
>> thanks for your explanation,
>> Uden
>> 
>> 
>> Andy Schlaikjer-2 wrote:
>>> Marco Schwarz wrote:
>>>> How can I make only 2 tables?
>>> Here's my guess:
>>>
>>> First, use the "mappedBy" property of the @OneToMany annotation, like
>>> this:
>>>
>>> @Entity
>>> class ModelObject {
>>>    ...
>>>
>>>    @ManyToOne
>>>    ModelObject parent;
>>>
>>>    @OneToMany(mappedBy="parent")
>>>    List<ModelObject> children;
>>>
>>>    ...
>>> }
>>>
>>> This way, an extra join table won't be necessary to encode the parent 
>>> child relationship. Only the "parent_id" column in the "ModelObject" 
>>> table will be used to encode the relationship.
>>>
>> 
> 
> 

-- 
View this message in context: http://www.nabble.com/Question-about-%40OneToMany-tp16840368p17134828.html
Sent from the OpenJPA Users mailing list archive at Nabble.com.


Re: Question about @OneToMany

Posted by Andy Schlaikjer <ha...@cs.cmu.edu>.
Hi Uden,

If you'd rather keep the relation unidirectional just remove the 
`children` field-- the `parent` field alone is enough to encode the 
relation without recourse to a separate join table. Either way, I don't 
see how the quoted section below results in a join table. Both fields 
rely solely on a "parent_id" column within the "ModelObject" table, not 
on some other join table. Am I missing something?

Andy

Uden wrote:
> The solution quoted below but has a consequence for the Java class model: the
> OneToMany relationship becomes bi-directional instead of uni-directional. 
> 
> What is the reason for creating the join-table? 
> 
> I thought (based on my database experience) that a join-table is only
> required for ManyToMany relationships. 
> If you look at the data in the join-table of a uni-directional relation (no
> mappedBy attribute), the relation between the join-table and master table is
> always OneToOne, so this relation could be handled by a FK-field in the
> detail-table.
> 
> thanks for your explanation,
> Uden
> 
> 
> Andy Schlaikjer-2 wrote:
>> Marco Schwarz wrote:
>>> How can I make only 2 tables?
>> Here's my guess:
>>
>> First, use the "mappedBy" property of the @OneToMany annotation, like
>> this:
>>
>> @Entity
>> class ModelObject {
>>    ...
>>
>>    @ManyToOne
>>    ModelObject parent;
>>
>>    @OneToMany(mappedBy="parent")
>>    List<ModelObject> children;
>>
>>    ...
>> }
>>
>> This way, an extra join table won't be necessary to encode the parent 
>> child relationship. Only the "parent_id" column in the "ModelObject" 
>> table will be used to encode the relationship.
>>
>