I'm working on a legacy database which I cannot change. This database regularly synches with secondary instances, which create new entries. To make an entity's primary key unique for all instances, all entities have composite primary keys consisting of the surrogate key generated by their original database and a server ID which identifies the original instance.
Composite primary keys are no Problem for Hibernate / JPA, it looks like this:
#Embeddable
public class ID implements Serializable {
private Long autoin; // Surrogate key
private Integer serverId; // instance identifier
#Column(name = "autoin_fix")
public Long getAutoin() {
return this.autoin;
}
#Column(name = "servdat_fk")
public Integer getServerId() {
return this.serverId;
}
// ... setter, equals, hashCode ...
}
Now consider the following Entity:
#Entity
#Table(name = "LEADS")
public class Request {
private Long id;
private Article article;
private Location location;
#Id
#Column(name = "autoin_fix")
#GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "auto-increment")
#GenericGenerator(name = "auto-increment", strategy = "sequence",
parameters = #org.hibernate.annotations.Parameter(name = "sequence", value = "AUTOINCREMENT"))
public Long getId() {
return this.id;
}
#ManyToOne
#JoinColumns({
#JoinColumn(name = "artikel_fk", referencedColumnName = "autoin_fix",
insertable = false, updatable = false), // Here is the problem!
#JoinColumn(name = "servdat_fk", referencedColumnName = "servdat_fk",
insertable = false, updatable = false)
})
public Article getArticle() {
return this.article;
}
#ManyToOne
#JoinColumns({
#JoinColumn(name = "standort_fk", referencedColumnName = "autoin_fix"),
#JoinColumn(name = "servdat_fk", referencedColumnName = "servdat_fk")
})
public Location getLocation() {
return this.location;
}
// Setters omitted
}
The Request entity has references to two other entities which both use the composite primary keys to identify themselves. But since from a business logic point of view, the serverId of both of these entities (Article and Location) always have to be the same, there is only one column for the serverId in the database:
TABLE leads
-------------
autoin_fix
artikel_fk
standort_fk
servdat_fk // This only exists once, but is part of the association to both Article and Location!
To make the application start at all, I had to add insertable = false, updatable = false to the Article association, which is not what I want. If I try to persist a Request object, the field "artikel_fk" is not written, leaving a null in the database, since I told hibernate that it is read-only. And using insertable = false, updatable = false on just one of the join columns is not allowed either.
// This is illegal and the application won't start
#JoinColumns({
#JoinColumn(name = "artikel_fk", referencedColumnName = "autoin_fix"),
#JoinColumn(name = "servdat_fk", referencedColumnName = "servdat_fk", insertable = false, updatable = false)
})
Does anyone know a solution to this problem? Or is this impossible to map using Hibernate / JPA?
EDIT: The (simplified) definitions of Article and Location (really not that interesting, all that counts is that they use the composite primary key):
#Entity
#Table(name = "ARTIKEL")
public class Article {
private ID id;
private String headline;
private String description;
#EmbeddedId
public ID getId() {
return this.id;
}
#Column(name = "artbesch")
public String getDescription() {
return this.description;
}
#Column(name = "artueschr")
public String getHeadline() {
return this.headline;
}
// Setters omitted
}
#Entity
#Table(name = "STANDORT")
public class Location {
private ID id;
private GeoCoordinates geoCoordinates;
private Name name;
#EmbeddedId
public ID getId() {
return this.id;
}
#Embedded
public GeoCoordinates getGeoCoordinates() {
return this.geoCoordinates;
}
#Embedded
public Name getName() {
return this.name;
}
// Setters omitted
}
I think that if the derived identifier of a dependent entity is in the form of an embedded id class, then each attribute of that id class that represents a relationship should be referred to by a #MapsId annotation on the corresponding relationship attribute.
For instance:
#Entity
public class Request {
// ...
#Id
int id;
#MapsId
#ManyToOne
private Article article;
// ...
}
I hope that works, because I cannot try it in this moment.
Related
I am using Hibernate 4.3 and am trying to model the relationship within the entities of a legacy database that cannot be changed.
I am trying to map a many-to-one relationship between Table B and Table A. Table A has a composite primary key made up of 3 columns. One of these columns is a unique key in and of itself (and has a unique constraint on it). Table B also has a composite primary key. One field of the composite PK for Table B is the FK to Table A using that unique value. Regardless of my attempts to map this relationship I usually get an error message by Hibernate.
Here's are the entities with fields not pertaining to this question removed for brevity:
#Embeddable
class APk {
private int site;
private int client;
private int id;
#Column(name = "site", nullable = false)
public int getSite() { return this.site; }
#Column(name = "client", nullable = false)
public int getClient() { return this.client; }
#Id
#Column(name = "id", nullable = false)
public int getId() { return this.id; }
}
#Entity
#Table(name = "A", uniqueConstraints = { #UniqueConstraint(columnNames = "id") })
class A {
private APk id;
private String otherStuff;
#EmbeddedId
public APk getAPk() { return this.id; }
}
#Embeddable
class BPk {
private String value;
private int aId;
#Column(name = "VALUE", nullable = false)
public String getValue() { return this.value; }
#Column(name = "A_ID", nullable = false)
public int getAId() { return this.aId; }
}
#Entity
#Table(name = "B")
class B {
private BPk id;
private String moreFields;
private A entityA;
#EmbeddedId
public BPk getId() { return this.id; }
#ManyToOne(fetch = FetchType.LAZY)
#JoinColumn(name = "a_id", referencedColumnName = "id", insertable = false, updatable = false)
public A getEntityA() { return this.entityA; }
}
I have attempted to use #JoinColumn with that single field, but am given one of the two error messages:
In the code above the error is
referencedColumnNames(ID) of B referencing A not mapped to a single property
If I remove the referencedColumnName property and add a #MapsId("id") annotation I get the error:
org.hibernate.AnnotationException: A Foreign key refering A from B has the wrong number of column. should be 3
A few things to note:
Only B needs to be able to load A, the reverse is not required since it'll never be used. This hasn't seemed to simplify the mapping though.
I don't think I'm using the #MapsId annotation properly when removing the referencedColumnName property from the #JoinColumn annotation
Although it probably doesn't matter the underlying db is [unfortunately] Oracle 11g
I have seen other questions on SO similar to this one where we're attempting to reference a partial composite key, but none of them were able to answer this question since they either had those columns available in the database to update their model with, or the composite PK did not have a unique constraint on one of the columns.
Is there a way to handle this in Hibernate (4)? Would #JoinFormula be required for this kind of non-standard relationship?
EDIT: Some other things I have tried, but has not worked:
Replacing the #Embeddable/#EmbeddedId annotations with #IdClass annotations
Using #JoinColumnsOrFormulas annotation with formulas for the 2 "missing" fields that are not available in entity B, but are part of entity A's PK.
Imagine there is a Work table in Oracle database, the primary key of which is auto-generated sequence. There is another table called External_Reference. They are of One-to-Many relationship, i.e., one work may have many external references.
External_Reference has a foreign key Work_ID to table Work's primary key ID.
With Hibernate, wonder if possible to use saveOrUpdate(object) to save a work saveOrUpdate(aWork), which will automatically save all of its external references?
Work work = new Work("Get started with Hibernate");
Set<ExternalReference> externalRefs = new HashSet<>();
ExternalReference ref1 = new ExternalReference("isbn", "23423454");
ref1.setWork(work); // work.getId() returns null before work being saved.
externalRefs.add(ref1);
ExternalReference ref2 = new ExternalReference("doi", "d2342-345553");
ref2.setWork(work);
externalRefs.add(ref2);
work.setExternalReferences(externalRefs);
// ORA-01400: cannot insert NULL into ("External_Reference"."WORK_ID")
aHibernateSession.saveOrUpdate(work);
The challenge is, before saving the work, you won't be able to know the auto-generated work ID, which means you cannot assign it to the work's external references.
Yes you can save the work without any external references first to get the auto-generated work ID, and then assign the work ID to all of its external references and save them. But I prefer not to do a two-steps thing to save a single work, if possible.
Model classes:
#Entity
#Table(name = "Work")
public class Work implements java.io.Serializable {
#Id
#Column(name = "ID", unique = true, nullable = false, precision = 22, scale = 0)
#GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "WORK_SEQ")
#SequenceGenerator(name = "WORK_SEQ", sequenceName = "WORK_SEQ", allocationSize = 1, initialValue = 1)
public BigDecimal getId() {
return this.Id;
}
#OneToMany(fetch = FetchType.LAZY, mappedBy = "work", cascade = CascadeType.ALL, orphanRemoval=true)
public Set<ExternalReference> getExternalReferences() {
return this.externalReferences;
}
}
#Entity
#Table(name = "External_Reference")
public class ExternalReference implements java.io.Serializable {
#ManyToOne(fetch = FetchType.LAZY)
#JoinColumn(name = "WORK_ID", nullable = false, insertable = false, updatable = false)
public Work getWork() {
return this.work;
}
}
Here you need to pass just
ref1.setWorkId(work);
ref2.setWorkId(work);
also, check the hibernate mapping check mapping example
//Work Class is Parent
#Entity
#Table(name = "Work")
public class Work {
#Id
#GeneratedValue(strategy = IDENTITY)
#Column(name = "ID", unique = true, nullable = false)
private Long id;
#Column(name = "TITTLE", nullable = false)
private String title;
#OneToMany(fetch = FetchType.LAZY, mappedBy = "work")
private Set<ExternalReference> externalReference;
public Work() {
}
public Work(String title) {
this.title = title;
}
//setter and getter
}
//ExternalReference Class is Child
#Entity
#Table(name = "External_Reference")
public class ExternalReference {
#Id
#GeneratedValue(strategy = IDENTITY)
#Column(name = "ID", unique = true, nullable = false)
private Long id;
#Column(name = "Ref_Source", nullable = false)
private String ref_source;
#Column(name = "Ref_Id", nullable = false)
private String ref_id;
#ManyToOne(cascade = CascadeType.ALL, fetch = FetchType.LAZY)
#JoinColumn(name ="Work_ID")
private Work work;
public ExternalReference() {
}
public ExternalReference(String ref_source, String ref_id) {
this.ref_source = ref_source;
this.ref_id = ref_id;
}
//setter and getter
}
The workaround I thought of and tested is a manual way (for your reference):
For a new work, manually get the next sequence from the database first, and assign it to the work and all of its external references. Then you can persist the work with all of its external references by just using aHibernateSession.saveOrUpdate(work);
For an existing work, just use its existing ID, and assign it to its new external references if any.
Getting sequences from the database will guarantee that the sequence is unique. It is thread safe.
public BigDecimal getNextSeq() {
Session session = null;
try {
session = sessionFactory.openSession(); // sessionFactory should have been initialised.
Query query = session.createSQLQuery("select WORK_SEQ.nextval as num from dual")
.addScalar("num", StandardBasicTypes.BIG_DECIMAL);
BigDecimal nextSeq = (BigDecimal) query.uniqueResult();
return nextSeq;
} finally {
if (session != null){
session.close();
}
}
}
For this workaround to work, you need to comment out the Work's key generator, as below:
#Entity
#Table(name = "Work")
public class Work implements java.io.Serializable {
#Id
#Column(name = "ID", unique = true, nullable = false, precision = 22, scale = 0)
// #GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "WORK_SEQ")
// #SequenceGenerator(name = "WORK_SEQ", sequenceName = "WORK_SEQ", allocationSize = 1, initialValue = 1)
public BigDecimal getId() {
return this.Id;
}
#OneToMany(fetch = FetchType.LAZY, mappedBy = "work", cascade = CascadeType.ALL, orphanRemoval=true)
public Set<ExternalReference> getExternalReferences() {
return this.externalReferences;
}
}
This workaround is a manual way, not elegant, but works. Still hoping to find the elegant approach, it must exist somewhere, as this is a quite common use case.
I have the following two classes (and their pk classes) with these annotations. I removed setters/getters/hashcode/equals to compress the example
I am ultimately getting this error
org.hibernate.MappingException: Repeated column in mapping for collection: com.stackOverflow.Features.thingCategory column: YEAR
My guess is that because "year" is shared in the join table, I have messed up some syntax for associating my entities. Note these are views which have an implicit relationship between their entities, that I am trying to model in my annotations. I have tried some JPA modelling tools which are giving me the same errors after modelling. I have tried setting the join columns to insertable and updatable to false as well.
I can of course just write a SQL query, but I really surprised at how hard this seems to me in Hibernate.
Feature Entity
#Entity
#Table(name = "myTableOfFeatures")
public class Feature {
private static final long serialVersionUID = 1L;
#EmbeddedId
private FeatureKey id;
#Column(name="displayText")
private String description;
//bi-directional many-to-many association
#ManyToMany
#JoinTable(
name="joinTableToThingCategories"
, joinColumns={
#JoinColumn(name="name", referencedColumnName="name", insertable = false, updatable = false),
#JoinColumn(name="year", referencedColumnName="year", insertable = false, updatable = false)
}
, inverseJoinColumns={
#JoinColumn(name="year", referencedColumnName="year", insertable = false, updatable = false),
#JoinColumn(name="title", referencedColumnName="title", insertable = false, updatable = false)
}
)
private List<ThingCategory> thingCategory;
public Feature() {
}
// ... gets and sets
}
#Embeddable
public class FeatureKey implements Serializable {
//default serial version id, required for serializable classes.
private static final long serialVersionUID = 1L;
#Column(name="name")
private String myName;
private String year;
public FeatureKey() {
}
// ... gets and sets and equals and hashes
}
ThingCategory Entity
#Entity
#Table(name = "CategoriesOfThings")
public class ThingCategory implements Serializable {
private static final long serialVersionUID = 1L;
#EmbeddedId
private ThingCategoryKey id;
private String comment;
//bi-directional many-to-many association to categories
#ManyToMany(mappedBy="thingCategory")
private List<Feature> features;
public ThingCategory() {
}
// ... gets and sets
}
#Embeddable
public class ThingCategoryKey implements Serializable {
//default serial version id, required for serializable classes.
private static final long serialVersionUID = 1L;
private String year;
#Column(name="categoryName")
private String title;
public ThingCategoryKey() {
}
// ... gets and sets and equals and hashes
}
This is an example from JPA 2.1 specification.
I hope it helps.
#Entity
public class Employee {
#Id int id;
#Embedded ContactInfo contactInfo;
...
}
#Embeddable
public class ContactInfo {
#ManyToOne Address address; // Unidirectional
#ManyToMany List<PhoneNumber> phoneNumbers; // Bidirectional
}
#Entity
public class PhoneNumber {
#Id int phNumber;
#ManyToMany(mappedBy="contactInfo.phoneNumbers")
Collection<Employee> employees;
}
I highly recommend you this specification. JPA 2.1
This might work, but I haven't tried myself; so I wanted to write this as a comment but it is cumbersome to write code as a comment. So you might want to try it if it works (sorry no time to try it out). If it doesn't work leave me a comment and I'll delete it.
#JoinTable(
name="joinTableToThingCategories",
joinColumns={
#JoinColumn(name="feature_name", referencedColumnName="name", insertable = false, updatable = false),
#JoinColumn(name="feature_year", referencedColumnName="year", insertable = false, updatable = false)
},
inverseJoinColumns={
#JoinColumn(name="tcat_year", referencedColumnName="year", insertable = false, updatable = false),
#JoinColumn(name="tcat_title", referencedColumnName="title", insertable = false, updatable = false)
}
)
private List<ThingCategory> thingCategory;
I have an entity for storing Workshops where I am using a composite primary key.
I do not like the concept of auto-generated keys and until now have mostly used business derived keys, such as email id etc for entities. However over here, the workshop entity did not appear to have a natural candidate for primary key, so I went for a composite key.I created a WorkshopIdType which is an enum containing the three possible workshops that will be organised
public enum WorkshopIdType implements Serializable {
FOUNDATION("FND"), INTERMEIDATE("IMT"), ADVANCED("ADV");
private final String name;
private WorkshopIdType(String name) {
this.name = name;
}
#Override
public String toString() {
return this.name;
}
public boolean equals(String otherName) {
return (otherName == null) ? false : name.equals(otherName);
}
}
And then I have an Embeddable class for primary key; the combination of workshop type and date appears to me as the best fit for primary key in this scenario
#Embeddable
#Access(AccessType.FIELD)
public class WorkshopId implements Serializable {
private static final long serialVersionUID = -7287847106009163526L;
private String workshopIdType;
private Date date;
#Column(name = "id", nullable = false)
public String getWorkshopIdType() {
return workshopIdType;
}
public void setWorkshopIdType(WorkshopIdType workshopIdType) {
this.workshopIdType = workshopIdType.toString();
}
#Temporal(TemporalType.DATE)
#Column(name = "date", nullable = false)
public Date getDate() {
return date;
}
public void setDate(Date date) {
this.date = date;
}
}
The entity also has a ManyToOne relationship with Venue, here again, the Venues are actually 5 of the pre-designated centres across three cities
#Entity
public class Workshop implements Serializable {
private static final long serialVersionUID = -5516160437873476233L;
private WorkshopId id;
private Venue venue;
private Integer seatsAvailable;
#EmbeddedId
public WorkshopId getId() {
return id;
}
public void setId(WorkshopId id) {
this.id = id;
}
#ManyToOne
#JoinTable(name = "workshop_venue", joinColumns = { #JoinColumn(name = "workshop_id", referencedColumnName = "id") }, inverseJoinColumns = { #JoinColumn(name = "venue_name", referencedColumnName = "name") })
public Venue getVenue() {
return venue;
}
public void setVenue(Venue venue) {
this.venue = venue;
}
#Column(name = "seats_available", nullable = false)
public Integer getSeatsAvailable() {
return seatsAvailable;
}
public void setSeatsAvailable(Integer seatsAvailable) {
this.seatsAvailable = seatsAvailable;
}
}
Problem is mapping this ManyToOne with a JoinTable in case of a composite key
#ManyToOne
#JoinTable(name = "workshop_venue", joinColumns = { #JoinColumn(name = "workshop_id", referencedColumnName = "id") }, inverseJoinColumns = { #JoinColumn(name = "venue_name", referencedColumnName = "name") })
public Venue getVenue() {
return venue;
}
This won't work as I had suspected, it cannot find a column with logical name "id". I am going with ManyToOne with JoinTable because there can be a scenario where users should get to know is there a training scheduled for the given Venue. How do I specify the referencedColumnName in this case?
Either that or I got it all wrong in the way I am modelling this?
You have a composite Primary Key represented by the embeddable WorkshopId
embedded in Workshop. Both fields of the Primary Key need to be joined to the target entity in the link table – therefore you need 2 joincolumns and one inversejoin. You just need to add the missing join;
#ManyToOne
#JoinTable(name = "workshop_venue",
joinColumns =
{ #JoinColumn(name = "workshop_id", referencedColumnName = "id"),
/* Add this joincolumn */
#JoinColumn(name = "date_id", referencedColumnName = "date") },
inverseJoinColumns =
{ #JoinColumn(name = "venue_name", referencedColumnName = "name") })
public Venue getVenue() {
return venue;
Of course you need to ensure that you link table has these three fields. I guess you are missing the date_id column.
Ok so today I have spent all day trying to figure out how to map a relationship between Orders, Products, and OrderLine with hibernate using annotations all java config.
I want OrderLine to be a junction table with extra fields, that joins Products and Orders.
Orders has a OneToMany relationsbhip with OrderLine - One order has many order lines.
Each Order has one or more OrderLines, Each OrderLine has one Order, Each OrderLine has one Product, Each Product can have 0 or more OrderLines.
From what I have been following along with tutorials, there are two ways to do it. One being with #Embeddable, #EmbeddedId annotations and the other being #IdClass annotations, I have tried both with no success I will post my code for my shot at #IdClass method.
My orders class
#Entity
#Table(name="orders")
public class Order {
#Id
#Column(name = "order_id")
#OneToMany(fetch = FetchType.EAGER, mappedBy = "order")
private Set<OrderLine> orderLines = new HashSet<>();
...some extra properties relevant to all orders
public Order(){}
...setters/getters
}
My Products class
#Entity
#Table(name="products")
public class Product implements Serializable {
private static final long serialVersionUID = 1L;
#Id
#Column(name = "product_id")
public Integer product_id; // primary key
#OneToMany(fetch = FetchType.EAGER, mappedBy = "product")
private Set<OrderLine> orderLines = new HashSet<>();
...other properties
public Product() {
}
...setters/getters
}
Here is my OrderLine Class
#Entity
#IdClass(OrderLineId.class)
#Table(name="order_line")
public class OrderLine implements Serializable {
private static final long serialVersionUID = 1L;
#Id
#Column(name = "product_id", insertable= false, updatable= false)
public Integer product_id;
#Id
#Column(name = "order_id", insertable= false, updatable= false)
public Integer order_id;
#ManyToOne
#JoinColumn(name = "product_id", insertable = false, updatable = false)
private Product product;
#ManyToOne
#JoinColumn(name = "order_id", insertable = false, updatable = false)
private Order order;
#Column(name = "product_quantity", unique = false, nullable = false)
private int productQuantity;
...additional fields associated with each OrderLine
And finally my OrderLineId implementation
public class OrderLineId implements Serializable {
private static final long serialVersionUID = 1L;
private Integer order_id;
private Integer product_id;
public OrderLineId(){}
public OrderLineId(Integer order_id, Integer product_id) {
this.order_id = order_id;
this.product_id = product_id;
}
#Column(name = "order_id")
public Integer getOrder() {
return this.order_id;
}
public void setOrder(Integer order_id) {
this.order_id = order_id;
}
#Column(name = "product_id")
public Integer getProduct() {
return this.product_id;
}
public void setProduct(Integer product_id) {
this.product_id = product_id;
}
#Override
public int hashCode() {
return order_id + product_id;
}
#Override
public boolean equals(Object obj) {
if(obj instanceof OrderLineId){
OrderLineId orderLineId = (OrderLineId) obj;
return orderLineId.order_id == order_id && orderLineId.product_id == product_id;
}
return false;
}
}
Here is the exception I am getting
MySQLSyntaxErrorException: Unknown column 'orderlines0_.order' in 'field list'
when I visit the end point below
#RequestMapping(value = "/testorder", method = RequestMethod.GET)
public ModelAndView testOrder(){
Order order = orderService.findOrderById(23);
Product product = productService.findProduct(2);
OrderLine ol = new OrderLine(product, order);
ol.setSize("large");
ol.setProductQuantity(30);
orderService.saveOrderLine(ol);
return null;
}
Please can somebody help me, this is driving me crazy....
Thank you
After going through your question and code, I think you have got your design wrong.
You say
want OrderLine to be a junction table with extra fields, that joins Products and Orders.
However you have only two variables, Order and Product in your OrderLine Class.
If I am not wrong, What you really need is a many-to-many table.
Your table order_line would contain two columns order_id and product_id, having foreign key to table orders and products respectively.
Your Order class would be:
#Entity
#Table(name="orders")
public class Order {
#Id
//id of table Order
#ManyToMany(
targetEntity = Product.class,
cascade = CascadeType.DETACH, fetch = FetchType.LAZY)
#JoinTable(name = "order_line",
joinColumns =
#JoinColumn(name = "order_id", nullable = false, updatable = false),
inverseJoinColumns =
#JoinColumn(name = "product_id", nullable = false, updatable = false))
public Set<Product> products= new HashSet(0);
...some extra properties relevant to all orders
public Order(){}
...setters/getters
}
Your Product Class would look like:
#Entity
#Table(name="products")
public class Product implements Serializable {
#Id
#Column(name = "product_id")
public Integer product_id; // primary key
#ManyToMany(cascade = CascadeType.ALL, fetch = FetchType.LAZY, mappedBy = "products", targetEntity = Order.class) private Set<Order> order = new HashSet<>();
...other properties
public Product() {
}
...setters/getters
}
As you can see, from Order entity you can get 'products' and from Product entity you can get 'orders'. This should server your purpose. No need to use 'OrderLine' class.
Other major errors in code:
- #Id is used to represent Primary key. You have used #Id multiple times for single class.
- In 'Order' class #Id given to Set, and #Id is used along with #OneToMany, which won't work.
Code provided would help you if, indeed what you need is many-to-many table.
I got it to work on my last try last night by doing this change
in OrderLine I removed the product_id and order_id fields and placed the #Id annotation over both ManyToOne relationships like so
#Entity
#IdClass(OrderLineId.class)
#Table(name="order_line")
public class OrderLine implements Serializable {
private static final long serialVersionUID = 1L;
#Id
#ManyToOne
#JoinColumn(name = "product_id", insertable = false, updatable = false)
private Product product;
#Id
#ManyToOne
#JoinColumn(name = "order_id", insertable = false, updatable = false)
private Order order;
#Column(name = "product_quantity", unique = false, nullable = false)
private int productQuantity;
...additional fields associated with each OrderLine
I did not think this woudl work but correct table with correct values was updated, is this valid?
Thank you
Ok I figured it out - I ended up using embeddable method instead based on this guys excellent tutorial here
He goes through 3 major ways to implement many to many assosiations - a simple junction only table, a junction table (with additional fields) which is the method I needed to implement, and finally a less popular method where the class is mapped as a component.