Skip to main content

@ManyToOne when Foreign Key is also Primary Key

6 replies [Last post]
danilorocha
Offline
Joined: 2010-10-20
Points: 0

Hello!
I don't know whether I am posting my thread in the right place or no. If I am not, let me know.

I am starting with JPA but I found a problem with @ManyToOne relation when the foreign key is part of the primary key.

Here is my database:

Table Client
cli_id_client (PK)

Table Card
cli_id_card (PK)

Table ClientCard
cli_id_client (PK)
cli_id_card (PK)

Those are my entities:

public class ClientCard{
@Id
@Column(name = "car_id_card")
private int idCard;

@Id
@Column(name = "cli_id_client")
private int idClient;

@ManyToOne(fetch = FetchType.LAZY)
@PrimaryKeyJoinColumns({@PrimaryKeyJoinColumn(name = "car_id_card", referencedColumnName = "car_id_card")})
private Card card;

@ManyToOne(fetch = FetchType.LAZY)
@PrimaryKeyJoinColumns({@PrimaryKeyJoinColumn(name = "cli_id_client", referencedColumnName = "cli_id_client")})
private Client client;

}

public class Client{
..
@Id
@Column(name = "cli_id_client")
private int idClient;

@OneToMany(mappedBy="client")
private java.util.List listClientCard;
}

public class Card{
..
@Id
@Column(name = "car_id_card")
private int idCard;

@OneToMany(mappedBy = "card")
private java.util.List listClientCard;
}

Unfortunately, when I try persist the ClientCard, I receive the message:

08:21:22,711 WARN [JDBCExceptionReporter] SQL Error: 207, SQLState: S0022
08:21:22,711 ERROR [JDBCExceptionReporter] [HOST]Invalid column name 'card_car_id_card'.
08:21:22,711 WARN [JDBCExceptionReporter] SQL Error: 207, SQLState: S0022
08:21:22,711 ERROR [JDBCExceptionReporter] [HOST]Invalid column name 'client_cli_id_client'.

Am I missing any configuration?

Message was edited by: danilorocha

Reply viewing options

Select your preferred way to display the comments and click "Save settings" to activate your changes.
ldemichiel
Offline
Joined: 2003-09-25
Points: 0

It looks like there are a couple of problems here.

I don't know whether these are typos here or bugs in implementation, however the Card and ClientCard entities refer to a car_id_card column, but you show the Card and ClientCard tables as having cli_id_card columns.

The ClientCardPK class shouldn't be using @Column. It is the entity using it that does the mapping.

@PrimaryKeyJoinColumns is intended to be used where the entire primary key serves as a foreign key to the target. This is the case for one-to-one PK mappings and for secondary table mappings. You should use the JoinColumn(s) annotation(s) to override FK mappings for ManyToOne relationships.

In JPA 1.0 when using JoinColumns to handle an overlapping PK/FK mapping as would result here, you need to indicate whether the PK or the JoinColumn controls the write to the database. In JPA 1.0, the way to handle this is by mapping one of them as insertable=false, updatable=false. IIRC, the convention with Hibernate is to map the JoinColumn as insertable=false, updatable=false.

danilorocha
Offline
Joined: 2010-10-20
Points: 0

Wow!

I tried put "insertable=false, updatable=false" in the fields they are FK and PK, so it worked as magic.
Thank you very much, ldemichiel!!

To the other people who had the same problem as I did, here comes the configuration:

public class [b]ClientCard[/b]{
@Id
@Column(name = "car_id_card")
private int idCard;

@Id
@Column(name = "cli_id_client")
private int idClient;

@ManyToOne(fetch = FetchType.LAZY)
@JoinColumns({@JoinColumn(name = "car_id_card", insertable=false, updatable=false)})
private Card card;

@ManyToOne(fetch = FetchType.LAZY)
@JoinColumns({@JoinColumn(name = "cli_id_client", insertable=false, updatable=false)})
private Client client;

}

Gregory Gerard

I've done this successfully as a separate PK class with the int ids and the @Id atop the ManyToOne.

public class ClientCardPK {
private long mClient;
private long mCard;
}

@Entity
@IdClass(ClientCardPK.class)
@Table(name = "ClientCard")
public class ClientCard {
@Id
@ManyToOne
@JoinColumn(name = "Client_Id", referencedColumnName = "Client_Id")
private Client mClient;

@Id
@ManyToOne
@JoinColumn(name = "Card_Id", referencedColumnName = "Card_Id")
private Card mCard;

@Temporal(TemporalType.TIMESTAMP)
@Column(name = "ClientCard_AssociationDate", nullable = false)
private final Date mAssociationDate = new Date();
}

On Oct 20, 2010, at 08:33, glassfish@javadesktop.org wrote:

> Hello!
> I don't know whether I am posting my thread in the right place or no. If I am not, let me know.
>
> I am starting with JPA but I found a problem with @ManyToOne relation when the foreign key is part of the primary key.
>
> Here is my database:
>
> [b]Table Client[/b]
> cli_id_client (PK)
>
> [b]Table Card[/b]
> cli_id_card (PK)
>
> [b]Table ClientCard[/b]
> cli_id_client (PK)
> cli_id_card (PK)
>
>
> Those are my entities:
>
>
> public class [b]ClientCard[/b]{
> @Id
> @Column(name = "car_id_card")
> private int idCard;
>
> @Id
> @Column(name = "cli_id_client")
> private int idClient;
>
> @ManyToOne(fetch = FetchType.LAZY)
> @PrimaryKeyJoinColumns({@PrimaryKeyJoinColumn(name = "car_id_card", referencedColumnName = "car_id_card")})
> private Card card;
>
> @ManyToOne(fetch = FetchType.LAZY)
> @PrimaryKeyJoinColumns({@PrimaryKeyJoinColumn(name = "cli_id_client", referencedColumnName = "cli_id_client")})
> private Client client;
>
> }
>
> public class [b]Client[/b]{
> ..
> @Id
> @Column(name = "cli_id_client")
> private int idClient;
>
> @OneToMany(mappedBy="Client")
> private java.util.List listClientCard;
> }
>
> public class [b]Card[/b]{
> ..
> @Id
> @Column(name = "car_id_card")
> private int idCard;
>
> @OneToMany(mappedBy = "card")
> private java.util.List listClientCard;
> }
>
>
> Unfortunately, when I try persist the ClientCard, I receive the message:
>
> 08:21:22,711 WARN [JDBCExceptionReporter] SQL Error: 207, SQLState: S0022
> 08:21:22,711 ERROR [JDBCExceptionReporter] [HOST]Invalid column name 'card_car_id_card'.
> 08:21:22,711 WARN [JDBCExceptionReporter] SQL Error: 207, SQLState: S0022
> 08:21:22,711 ERROR [JDBCExceptionReporter] [HOST]Invalid column name 'client_cli_id_client'.
>
>
> Am I missing any configuration?
> [Message sent by forum member 'danilorocha']
>
> http://forums.java.net/jive/thread.jspa?messageID=485747
>
> ---------------------------------------------------------------------
> To unsubscribe, e-mail: users-unsubscribe@glassfish.dev.java.net
> For additional commands, e-mail: users-help@glassfish.dev.java.net
>

---------------------------------------------------------------------
To unsubscribe, e-mail: users-unsubscribe@glassfish.dev.java.net
For additional commands, e-mail: users-help@glassfish.dev.java.net

danilorocha
Offline
Joined: 2010-10-20
Points: 0

Hello, Gregory!
Thanks a lot for the reply.

Unfortunately, your solution didn't work to me.

I've found that configuration (using @Id annotation with @ManyToOne) you've showed me in documentation for [b]JPA 2.0[/b], but, in my enviroment, I use Java Enterprise 5 with [b]JPA 1.0[/b].

If I try configure my classes like using JPA 2.0 standard (your solution), I get the following error when I try deploy my solution:

09:36:58,753 ERROR [AbstractKernelController] Error installing to Start: name=persistence.unit:unitName=test.ear/test.dataaccess/classes#test.dataaccess state=Create
org.hibernate.AnnotationException: Unable to find properties (idCard, idClient) in entity annotated with @IdClass:test.dataaccess.to.ClientCard

Back to my initial configuration...

I forgot about mention my PK class, but I do have one.

So, here it comes again my classes:

[b]Table Client[/b]
cli_id_client (PK)

[b]Table Card[/b]
cli_id_card (PK)

[b]Table ClientCard[/b]
cli_id_client (PK)
cli_id_card (PK)

Those are my entities:

@Entity(name = "ClientCard")
@IdClass(ClientCardPK.class)
@Table(name = "ClientCard")
public class [b]ClientCard[/b]{
@Id
@Column(name = "car_id_card")
private int idCard;

@Id
@Column(name = "cli_id_client")
private int idClient;

@ManyToOne(fetch = FetchType.LAZY)
@PrimaryKeyJoinColumns({@PrimaryKeyJoinColumn(name = "car_id_card", referencedColumnName = "car_id_card")})
private Card card;

@ManyToOne(fetch = FetchType.LAZY)
@PrimaryKeyJoinColumns({@PrimaryKeyJoinColumn(name = "cli_id_client", referencedColumnName = "cli_id_client")})
private Client client;

}

public class [b]ClientCardPK[/b] {
@Column(name = "cli_id_client")
private long client;
@Column(name = "car_id_card")
private long card;
}

@Entity(name = "Client")
@Table(name = "Client")
public class [b]Client[/b]{
@Id
@Column(name = "cli_id_client")
private int idClient;

@OneToMany(mappedBy="client")
private java.util.List listClientCard;
}

@Entity(name = "Card")
@Table(name = "Card")
public class [b]Card[/b]{
@Id
@Column(name = "car_id_card")
private int idCard;

@OneToMany(mappedBy = "card")
private java.util.List listClientCard;
}

Other question: why is that @Temporal attribute for?

Gregory Gerard

D'oh! Don't know about JPA 1.0 techniques.

The attribute is just so I know when that association was made between the two records. I have other information on that relationship not shown such as who made the association as well.

Greg

On Oct 21, 2010, at 7:18, glassfish@javadesktop.org wrote:

> Hello, Gregory!
> Thanks a lot for the reply.
>
> Unfortunately, your solution didn't work to me.
>
> I've found that configuration (using @Id annotation with @ManyToOne) you've showed me in documentation for [b]JPA 2.0[/b], but, in my enviroment, I use Java Enterprise 5 with [b]JPA 1.0[/b].
>
> If I try configure my classes like using JPA 2.0 standard (your solution), I get the following error when I try deploy my solution:
>
> 09:36:58,753 ERROR [AbstractKernelController] Error installing to Start: name=persistence.unit:unitName=test.ear/test.dataaccess/classes#test.dataaccess state=Create
> org.hibernate.AnnotationException: Unable to find properties (idCard, idClient) in entity annotated with @IdClass:test.dataaccess.to.ClientCard
>
>
>
> Back to my initial configuration...
>
> I forgot about mention my PK class, but I do have one.
>
> So, here it comes again my classes:
>
> [b]Table Client[/b]
> cli_id_client (PK)
>
> [b]Table Card[/b]
> cli_id_card (PK)
>
> [b]Table ClientCard[/b]
> cli_id_client (PK)
> cli_id_card (PK)
>
>
> Those are my entities:
>
> @Entity(name = "ClientCard")
> @IdClass(ClientCardPK.class)
> @Table(name = "ClientCard")
> public class [b]ClientCard[/b]{
> @Id
> @Column(name = "car_id_card")
> private int idCard;
>
> @Id
> @Column(name = "cli_id_client")
> private int idClient;
>
> @ManyToOne(fetch = FetchType.LAZY)
> @PrimaryKeyJoinColumns({@PrimaryKeyJoinColumn(name = "car_id_card", referencedColumnName = "car_id_card")})
> private Card card;
>
> @ManyToOne(fetch = FetchType.LAZY)
> @PrimaryKeyJoinColumns({@PrimaryKeyJoinColumn(name = "cli_id_client", referencedColumnName = "cli_id_client")})
> private Client client;
>
> }
>
> public class [b]ClientCardPK[/b] {
> @Column(name = "cli_id_client")
> private long client;
> @Column(name = "car_id_card")
> private long card;
> }
>
> @Entity(name = "Client")
> @Table(name = "Client")
> public class [b]Client[/b]{
> @Id
> @Column(name = "cli_id_client")
> private int idClient;
>
> @OneToMany(mappedBy="client")
> private java.util.List listClientCard;
> }
>
> @Entity(name = "Card")
> @Table(name = "Card")
> public class [b]Card[/b]{
> @Id
> @Column(name = "car_id_card")
> private int idCard;
>
> @OneToMany(mappedBy = "card")
> private java.util.List listClientCard;
> }
>
>
>
> Other question: why is that @Temporal attribute for?
> [Message sent by forum member 'danilorocha']
>
> http://forums.java.net/jive/thread.jspa?messageID=485858
>
> ---------------------------------------------------------------------
> To unsubscribe, e-mail: users-unsubscribe@glassfish.dev.java.net
> For additional commands, e-mail: users-help@glassfish.dev.java.net
>

---------------------------------------------------------------------
To unsubscribe, e-mail: users-unsubscribe@glassfish.dev.java.net
For additional commands, e-mail: users-help@glassfish.dev.java.net

danilorocha
Offline
Joined: 2010-10-20
Points: 0

Oh, ok.
Thank you!

I am still looking for a solution.
If I get it, I'll post here for you and for the people that get in the same problem I did.