You are viewing a plain text version of this content. The canonical link for it is here.
Posted to users@openjpa.apache.org by Marco Schwarz <ma...@cioppino.net> on 2008/04/22 20:43:50 UTC

Question about @OneToMany

Hi,

I have a ModelObject, simple 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;

	public void addChild(ModelObject child) {
		if (children == null) {
			children = new ArrayList<ModelObject>();
		}
		children.add(child);
		child.setParent(this);
	}

	....

	public void setParent(ModelObject parent) {
		this.parent = parent;
	}

	.....

}

@Entity
class Company extends ModelObject {

}

@Entity
class Employer extends ModelObject {

}

...

public static void main(String[] args) {

	...

	Company company = new Company();

	Employer e;

	e = new Employer()
	e.setId("Person0");
	company.addChild(e);

	e = new Employer()
	e.setId("Person1");
	company.addChild(e);

	...

}

When I start my app the openjpa create 4 tables (Company, 
Company_children, Emplpyer and Employer_children).

How can I make only 2 tables?

thanks
Marco



	


Re: Question about @OneToMany

Posted by Andy Schlaikjer <ha...@cs.cmu.edu>.
Andy Schlaikjer wrote:
> Marco Schwarz wrote:
>> @Inheritance(strategy=InheritanceType.TABLE_PER_CLASS)
>> How can I make only 2 tables?
> 
> Here's my guess:
> @Inheritance(strategy=InheritanceType.SINGLE_TABLE)

Apologies. You meant to use table-per-class strategy, didn't you. Ignore 
that second bit then.

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.
>>
> 

Re: Question about @OneToMany

Posted by Uden <ud...@gmail.com>.
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 Marco Schwarz <ma...@cioppino.net>.
Thanks, so it works fine, but another question:

Why I must say @Entity on the class ModelObject? So I have a table 
ModelObject. With @MappedSuperclass I don't have the table ModelObject 
but the framework throw this error:

"net.cioppino.fita.core.model.ModelObject.children" declares a to-many 
relation strategy, but its elements are not direct, non-embedded 
relations to another mapped persistence-capable object.

Thanks
Marco

Andy Schlaikjer schrieb:
> 
> 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.
> 
> Next, you want to make sure you're using "single table" mapping to 
> encode inheritance relations. This way all classes derived from 
> ModelObject should utilize the same table. Although single table is 
> supposed to be the default inheritance strategy, it might not hurt to 
> explicitly state it:
> 
> @Entity
> @Inheritance(strategy=InheritanceType.SINGLE_TABLE)
> class ModelObject {
>   ...
> 
>   @ManyToOne
>   ModelObject parent;
> 
>   @OneToMany(mappedBy="parent")
>   List<ModelObject> children;
> 
>   ...
> }

Re: Question about @OneToMany

Posted by Andy Schlaikjer <ha...@cs.cmu.edu>.
Marco Schwarz wrote:
> @MappedSuperclass
> @Inheritance(strategy=InheritanceType.TABLE_PER_CLASS)
> class ModelObject {
>     @Transient
>     ModelObject parent;
> 
>     @OneToMany(cascade={CascadeType.ALL}, fetch=FetchType.EAGER)
>     List<ModelObject> children;
> }
> 
> When I start my app the openjpa create 4 tables (Company, 
> Company_children, Emplpyer and Employer_children).
> 
> 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.

Next, you want to make sure you're using "single table" mapping to 
encode inheritance relations. This way all classes derived from 
ModelObject should utilize the same table. Although single table is 
supposed to be the default inheritance strategy, it might not hurt to 
explicitly state it:

@Entity
@Inheritance(strategy=InheritanceType.SINGLE_TABLE)
class ModelObject {
   ...

   @ManyToOne
   ModelObject parent;

   @OneToMany(mappedBy="parent")
   List<ModelObject> children;

   ...
}