You are viewing a plain text version of this content. The canonical link for it is here.
Posted to users@openjpa.apache.org by Christian Defoy <ch...@gmail.com> on 2007/09/06 17:45:39 UTC

Join table with extra value

Hello,

I have two objects, A and B, that are involved in a many to many
relationship.  That portion works ok if class A contains:

    @ManyToMany( fetch=FetchType.EAGER, cascade=CascadeType.ALL )
    @JoinTable( name="a_b", joinColumns=@JoinColumn( name="a_id",
referencedColumnName="a_id" ),
                inverseJoinColumns=@JoinColumn( name="b_id",
referencedColumnName="b_id" ))
    private Set<B> mappedBs;

My problem is that the relationship between A and B must contain an
additional value.  The join table between A and B looks like this:

create table A_B
(
    a_id  integer not null,
    b_id  integer not null,
    value integer
);

Should I define the mapping as A (OneToMany) A_B (ManyToOne) B and
create an object for A_B?  If so, how do I do that?

Thanks in advance!

Christian

Re: Join table with extra value

Posted by Christian Defoy <ch...@gmail.com>.
Patrick,

> What goes into the value column?

The value column contains the size of the portion of A provided by B.
In other words, it is not a key of some sort but rather data that is
relevant to the association between A and B.

> You certainly could take that approach. You'd just set up a pair of
> one-to-many relations from A to A_B and B to A_B; you wouldn't need to
> do anything special to make it work.

To my understanding, every entity has to provide an ID for itself but
A_B does not have any column for that.  Instead, the primary key of
the table is (a_id, b_id).  This means that the key for A_B is really
the key of A and the key of B.  I can use the technique described in
section 5.3.2 "Entities as Identity Fields" to do that.  It works fine
in my test app.  As long as B is already in the database, I can get A
and A_B to persist correctly.

When I do the same in my real app, I get the following exceptions:

Exception in thread "main" <0.9.7-incubating fatal user error>
org.apache.openjpa.persistence.ArgumentException: Errors encountered
while resolving metadata.  See nested exceptions for details.
	at org.apache.openjpa.meta.MetaDataRepository.resolve(MetaDataRepository.java:506)
	at org.apache.openjpa.meta.MetaDataRepository.getMetaData(MetaDataRepository.java:288)
	at org.apache.openjpa.kernel.TestWithListBrokerImpl.persist(TestWithListBrokerImpl.java:2352)
	at org.apache.openjpa.kernel.TestWithListBrokerImpl.persist(TestWithListBrokerImpl.java:2204)
	at org.apache.openjpa.kernel.DelegatingBroker.persist(DelegatingBroker.java:1010)
	at org.apache.openjpa.persistence.EntityManagerImpl.persist(EntityManagerImpl.java:541)
	at ex9.Helper.testMappingSave(Helper.java:414)
	at ex9.Helper.run(Helper.java:81)
	at ex9.Helper.main(Helper.java:736)
Caused by: java.lang.NullPointerException
	at org.apache.openjpa.jdbc.meta.MappingInfo.mergeJoinColumn(MappingInfo.java:1386)
	at org.apache.openjpa.jdbc.meta.MappingInfo.createJoins(MappingInfo.java:1192)
	at org.apache.openjpa.jdbc.meta.MappingInfo.createForeignKey(MappingInfo.java:954)
	at org.apache.openjpa.jdbc.meta.ValueMappingInfo.getTypeJoin(ValueMappingInfo.java:104)
	at org.apache.openjpa.jdbc.meta.strats.RelationFieldStrategy.map(RelationFieldStrategy.java:147)
	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.resolveNonRelationMappings(ClassMapping.java:813)
	at org.apache.openjpa.jdbc.meta.MappingRepository.prepareMapping(MappingRepository.java:319)
	at org.apache.openjpa.meta.MetaDataRepository.preMapping(MetaDataRepository.java:605)
	at org.apache.openjpa.meta.MetaDataRepository.resolve(MetaDataRepository.java:492)
	... 8 more
NestedThrowables:
java.lang.NullPointerException
	at org.apache.openjpa.jdbc.meta.FieldMapping.initializeMapping(FieldMapping.java:486)
	at org.apache.openjpa.jdbc.meta.FieldMapping.resolve(FieldMapping.java:405)
	at org.apache.openjpa.jdbc.meta.ClassMapping.initializeMapping(ClassMapping.java:834)
	at org.apache.openjpa.meta.ClassMetaData.resolve(ClassMetaData.java:1590)
	at org.apache.openjpa.meta.MetaDataRepository.resolveMapping(MetaDataRepository.java:629)
	at org.apache.openjpa.meta.MetaDataRepository.resolve(MetaDataRepository.java:498)
	at org.apache.openjpa.meta.MetaDataRepository.getMetaData(MetaDataRepository.java:288)
	at org.apache.openjpa.kernel.TestWithListBrokerImpl.persist(TestWithListBrokerImpl.java:2352)
	at org.apache.openjpa.kernel.TestWithListBrokerImpl.persist(TestWithListBrokerImpl.java:2204)
	at org.apache.openjpa.kernel.DelegatingBroker.persist(DelegatingBroker.java:1010)
	at org.apache.openjpa.persistence.EntityManagerImpl.persist(EntityManagerImpl.java:541)
	at ex9.Helper.testMappingSave(Helper.java:414)
	at ex9.Helper.run(Helper.java:81)
	at ex9.Helper.main(Helper.java:736)
<0.9.7-incubating fatal user error>
org.apache.openjpa.persistence.ArgumentException: Field "..." declares
"..." as its mapped-by field, but this field is not a direct relation.
	at org.apache.openjpa.jdbc.meta.strats.RelationToManyInverseKeyFieldStrategy.map(RelationToManyInverseKeyFieldStrategy.java:126)
	at org.apache.openjpa.jdbc.meta.strats.RelationCollectionInverseKeyFieldStrategy.map(RelationCollectionInverseKeyFieldStrategy.java:95)
	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:784)
	at org.apache.openjpa.meta.ClassMetaData.resolve(ClassMetaData.java:1585)
	at org.apache.openjpa.meta.MetaDataRepository.processBuffer(MetaDataRepository.java:659)
	at org.apache.openjpa.meta.MetaDataRepository.resolveMapping(MetaDataRepository.java:620)
	at org.apache.openjpa.meta.MetaDataRepository.resolve(MetaDataRepository.java:498)
	at org.apache.openjpa.meta.MetaDataRepository.getMetaData(MetaDataRepository.java:288)
	at org.apache.openjpa.kernel.TestWithListBrokerImpl.persist(TestWithListBrokerImpl.java:2352)
	at org.apache.openjpa.kernel.TestWithListBrokerImpl.persist(TestWithListBrokerImpl.java:2204)
	at org.apache.openjpa.kernel.DelegatingBroker.persist(DelegatingBroker.java:1010)
	at org.apache.openjpa.persistence.EntityManagerImpl.persist(EntityManagerImpl.java:541)
	at ex9.Helper.testMappingSave(Helper.java:414)
	at ex9.Helper.run(Helper.java:81)
	at ex9.Helper.main(Helper.java:736)

I don't know what causes the NullPointerException but the
ArgumentException seems wrong to me.  By that, I mean that my mappings
look right:

In A:
    @OneToMany( mappedBy="a", fetch=FetchType.EAGER, cascade=CascadeType.ALL )
    private Set<AToBMapping> bMappings;

In AToBMapping:
    @Id
    @ManyToOne( fetch=FetchType.EAGER, cascade=CascadeType.ALL, optional=false )
    @Column( name="a_id" )
    @ForeignKey
    private A a;

I am still trying to find the cause for this...

Christian

On 9/6/07, Patrick Linskey <pl...@gmail.com> wrote:
> Hi,
>
> What goes into the value column?
>
> > Should I define the mapping as A (OneToMany) A_B (ManyToOne) B and
> > create an object for A_B?  If so, how do I do that?
>
> You certainly could take that approach. You'd just set up a pair of
> one-to-many relations from A to A_B and B to A_B; you wouldn't need to
> do anything special to make it work.
>
> -Patrick
>
> On 9/6/07, Christian Defoy <ch...@gmail.com> wrote:
> > Hello,
> >
> > I have two objects, A and B, that are involved in a many to many
> > relationship.  That portion works ok if class A contains:
> >
> >     @ManyToMany( fetch=FetchType.EAGER, cascade=CascadeType.ALL )
> >     @JoinTable( name="a_b", joinColumns=@JoinColumn( name="a_id",
> > referencedColumnName="a_id" ),
> >                 inverseJoinColumns=@JoinColumn( name="b_id",
> > referencedColumnName="b_id" ))
> >     private Set<B> mappedBs;
> >
> > My problem is that the relationship between A and B must contain an
> > additional value.  The join table between A and B looks like this:
> >
> > create table A_B
> > (
> >     a_id  integer not null,
> >     b_id  integer not null,
> >     value integer
> > );
> >
> > Should I define the mapping as A (OneToMany) A_B (ManyToOne) B and
> > create an object for A_B?  If so, how do I do that?
> >
> > Thanks in advance!
> >
> > Christian
> >
>
>
> --
> Patrick Linskey
> 202 669 5907
>

Re: Join table with extra value

Posted by Patrick Linskey <pl...@gmail.com>.
Hi,

What goes into the value column?

> Should I define the mapping as A (OneToMany) A_B (ManyToOne) B and
> create an object for A_B?  If so, how do I do that?

You certainly could take that approach. You'd just set up a pair of
one-to-many relations from A to A_B and B to A_B; you wouldn't need to
do anything special to make it work.

-Patrick

On 9/6/07, Christian Defoy <ch...@gmail.com> wrote:
> Hello,
>
> I have two objects, A and B, that are involved in a many to many
> relationship.  That portion works ok if class A contains:
>
>     @ManyToMany( fetch=FetchType.EAGER, cascade=CascadeType.ALL )
>     @JoinTable( name="a_b", joinColumns=@JoinColumn( name="a_id",
> referencedColumnName="a_id" ),
>                 inverseJoinColumns=@JoinColumn( name="b_id",
> referencedColumnName="b_id" ))
>     private Set<B> mappedBs;
>
> My problem is that the relationship between A and B must contain an
> additional value.  The join table between A and B looks like this:
>
> create table A_B
> (
>     a_id  integer not null,
>     b_id  integer not null,
>     value integer
> );
>
> Should I define the mapping as A (OneToMany) A_B (ManyToOne) B and
> create an object for A_B?  If so, how do I do that?
>
> Thanks in advance!
>
> Christian
>


-- 
Patrick Linskey
202 669 5907