# JPA: Objekt in Tabelle mit Composite Keys mappen (Embeddable Annotation)



## Studdi23 (25. Okt 2010)

Hallo zusammen,

ich habe 4 Tabellen mit folgendem Datenbankschema:


```
create table books
(
isbn char(13) not null, primary key(isbn),
title char(80) not null,
fname char(40) not null,
author char(40) not null,
price numeric(6,2) not null,
year_published integer not null
);

create table customers
(
cid integer not null auto_increment, primary key (cid),
cname char(40) not null,
address char(200) not null,
cardnum char(16) not null
);

create table orders
(
ordernum integer not null auto_increment, primary key(ordernum),
cid integer, foreign key(cid) references customers(cid),
order_date date not null
);

create table orderitems
(
ordernum integer not null, foreign key(ordernum) references orders(ordernum),
isbn char(13) not null, foreign key(isbn) references books(isbn),
qty integer not null,
primary key( ordernum, isbn )
);
```

Der Primärschlüssel der letzten Tabelle setzt sich aus den beiden Primärschlüsseln von books und orders zusammen. Nun möchste ich mittels JPA Testdaten in die Datenbank schreiben und hab mir von Eclipse die zugehörigen Entities generieren lassen. Bei den ersten drei Tabellen funktioniert das Auslesen und Schreiben in die DB. Wenn ich noch die Beziehung Orderitems hinzunehme erhalte ich folgende Exception:


```
[EL Warning]: 2010-10-25 17:23:07.667--UnitOfWork(25621063)--Exception [EclipseLink-4002] (Eclipse Persistence Services - 2.1.0.v20100614-r7608): org.eclipse.persistence.exceptions.DatabaseException
Internal Exception: com.mysql.jdbc.exceptions.jdbc4.MySQLSyntaxErrorException: Column 'ordernum' specified twice
Error Code: 1110
Call: INSERT INTO orderitems (QTY, ORDERNUM, ISBN, isbn, ordernum) VALUES (?, ?, ?, ?, ?)
	bind => [1, 0, null, 9-014103613-7, 44]
Query: InsertObjectQuery(de.atalay.aufgabe3.model.Orderitem@b30913)
Exception in thread "main" javax.persistence.RollbackException: Exception [EclipseLink-4002] (Eclipse Persistence Services - 2.1.0.v20100614-r7608): org.eclipse.persistence.exceptions.DatabaseException
Internal Exception: com.mysql.jdbc.exceptions.jdbc4.MySQLSyntaxErrorException: Column 'ordernum' specified twice
Error Code: 1110
Call: INSERT INTO orderitems (QTY, ORDERNUM, ISBN, isbn, ordernum) VALUES (?, ?, ?, ?, ?)
	bind => [1, 0, 9-014103613-7, 9-014103613-7, 44]
```

Die Attribute "isbn" und "ordernum" werden, aus welchem Grund auch immer, doppelt in die Tabelle gemappt, wobei die Id von ordernum beim ersten Pärchen 0 ist. Ich vermute, dass das etwas mit den für die Entity Orderitem generierten Klassen zu tun hat. Es wurden sowohl eine @Embeddable annotierte Klasse mit Gettern/Settern der Primärschlüssel, als auch eine Klasse mit einer Referenz auf diese Klasse generiert. Die Referenz ist mit @EmbeddedId annotiert. Ich weiß nicht wie ich mit diesen beiden Objekten umgehen soll, da ich noch nie Composite Keys benutzt habe. Kennt sich jemand mit dem mapping von "natürlichen" bzw. zusammengesetzten Primärschlüsseln aus und kann mir weiterhelfen? 


```
@Entity
@Table(name="orderitems")
public class Orderitem implements Serializable {
	private static final long serialVersionUID = 1L;

	@EmbeddedId
	private OrderitemPK id;

	private int qty;

    @ManyToOne
	@JoinColumn(name="isbn")
	private Book book;

    @ManyToOne
	@JoinColumn(name="ordernum")
	private Order order;

    public Orderitem() {
    }
    
	public Orderitem(OrderitemPK id, int qty, Book book, Order order) {
		super();
		this.id = id;
		this.qty = qty;
		this.book = book;
		this.order = order;
	}
//Getter und Setter Methoden
```


```
@Embeddable
public class OrderitemPK implements Serializable {
	private static final long serialVersionUID = 1L;

	private String isbn;

	private int ordernum;

    public OrderitemPK() {
    }
//Getter und Setter Methoden
```


```
private static final String PERSISTENCE_UNIT_NAME = "AmazonJPA";
	private static EntityManagerFactory factory;

	@SuppressWarnings("unchecked")
	public static void main(String[] args) {
		factory = Persistence.createEntityManagerFactory(PERSISTENCE_UNIT_NAME);
		EntityManager em = factory.createEntityManager();			
		em.getTransaction().begin();
		Book newBook = new Book("9-014103613-7", "Animal Farm", "GO-AF",
				"George Orwell", new BigDecimal(6.40), 2008, null);
		
		Customer cust = em.find(Customer.class, 1);
		Order order = new Order();
		order.setOrderDate(new Date());
		order.setCustomer(cust);
		
		Orderitem ordIt = new Orderitem();
		ordIt.setOrder(order);
		ordIt.setBook(newBook);
		ordIt.setQty(1);
		List<Orderitem> orderItems = new ArrayList<Orderitem>();
		orderItems.add(ordIt);
		
		OrderitemPK ordPK = new OrderitemPK();
		ordPK.setIsbn(ordIt.getBook().getIsbn());
		ordPK.setOrdernum(ordIt.getOrder().getOrdernum());
		ordIt.setId(ordPK);
		
		order.setOrderitems(orderItems);		
		newBook.setOrderitems(orderItems);
		
		em.persist(newBook);
		em.persist(order);
		em.persist(cust);
		em.persist(ordIt);
		
		em.getTransaction().commit();
		em.close();
```


----------



## Studdi23 (25. Okt 2010)

Hier noch die anderen beiden Klassen, die mit Orderitem in Beziehung stehen:


```
@Entity
@Table(name="books")
public class Book implements Serializable {
	private static final long serialVersionUID = 1L;

	@Id
	private String isbn;

	private String author;

	private String fname;

	private BigDecimal price;

	private String title;

	@Column(name="year_published")
	private int yearPublished;

	@OneToMany(mappedBy="book")
	private List<Orderitem> orderitems;

    public Book() {
    }
        
	public Book(String isbn, String title, String fname, String author, BigDecimal price,
		 int yearPublished, List<Orderitem> orderitems) {
		super();
		this.isbn = isbn;
		this.author = author;
		this.fname = fname;
		this.price = price;
		this.title = title;
		this.yearPublished = yearPublished;
		this.orderitems = orderitems;
	}
//Getter und Setter
```


```
@Entity
@Table(name="orders")
public class Order implements Serializable {
	private static final long serialVersionUID = 1L;

	@Id
	@GeneratedValue(strategy=GenerationType.IDENTITY)
	private int ordernum;

    @Temporal( TemporalType.TIMESTAMP)
	@Column(name="order_date")
	private Date orderDate;

	@OneToMany(mappedBy="order")
	private List<Orderitem> orderitems;

    @ManyToOne
	@JoinColumn(name="cid")
	private Customer customer;
//Getter und Setter
```


----------



## Studdi23 (25. Okt 2010)

Hat sich erledigt. Die JPA-Tools von Eclipse generieren die Entities scheinbar nicht ganz korrekt. Für alle die das gleiche Problem haben. In der Embeddable Klasse müssen die beiden Primärschlüssel zusätzlich mit folgender Annotation versehen werden:

@Column(name = "isbn", nullable = false, insertable=false, updatable=false)
@Column(name = "ordernum", nullable = false, insertable=false, updatable=false)

Danach wurden die Daten korrekt in die DB geschrieben.


----------

