I'm creating a REST API using Spring Boot and Hibernate.
I have two tables, let's call them table Foo
and table Bar
. They have an 1-N association that is mapped through a third table, let's call it FooBarAssociation
. I created this association between them using the @JoinTable annotation.
Here is a minimum example of what I have now.
public class Foo {
@Id
@Column(name = "foo_id");
Long fooId;
}
public class Bar{
@Id
@Column(name = "bar_id");
Long barId;
@ManyToOne
@JoinTable(name = "Foo ", joinColumns = @JoinColumn(name = "bar_id"), inverseJoinColumns = @JoinColumn(name = "foo_id"))
Foo foo;
}
The thing is, the table FooBarAssociation
also has a third column that should contain the date that the relation was created. So there are three columns: foo_id
, bar_id
and date
. When hibernate tries to insert a new entry to FooBarAssociation
it generates as exception, as the column date
does not allow null values. Is there a way I can tell hibernate how to fill this extra column?
insert into FooBarAssociation (foo_id, bar_id) values (?, ?)
Cannot insert the value NULL into column 'date', table 'FooBarAssociation'; column does not allow nulls. INSERT fails.
Well since this relation is manadatory the only way I see to modify middle layer, is to obtain control over it explicitly. This will help.
@Getter
@Setter
@Entity
@NoArgsConstructor
public class Bar {
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
Long id;
@ManyToOne(cascade = CascadeType.ALL)
@JoinColumn(name = "bar_id")
FooBarRelation relation;
public void setFoo(Foo foo) {
relation = new FooBarRelation(this, foo);
}
}
@Getter
@Setter
@Entity
@NoArgsConstructor
@EntityListeners(AuditingEntityListener.class)
public class FooBarRelation {
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
Long id;
@OneToOne(cascade = CascadeType.ALL)
@JoinColumn(name = "foo_id")
Foo foo;
@OneToOne(cascade = CascadeType.ALL)
@JoinColumn(name = "bar_id")
Bar bar;
@LastModifiedDate
LocalDateTime dateTime;
public FooBarRelation(Bar bar, Foo foo) {
this.bar = bar;
this.foo = foo;
}
}
@Getter
@Setter
@Entity
@NoArgsConstructor
public class Foo {
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
Long id;
}
Test:
@Autowired
public BarRepo barRepo;
@Test
public void testBar(){
Bar bar = new Bar();
bar.setFoo(new Foo());
barRepo.save(bar);
List<Bar> all = barRepo.findAll();
FooBarRelation relation = all.get(0).getRelation();
assertNotNull(relation.getBar());
assertNotNull(relation.getFoo());
assertNotNull(relation.getDateTime());
}
Cascade types and other minor details on you ;)