Reputation: 636
To start off, I will say that I have seen a lot of questions with the exact same exception message, however I did not find one that corresponded to the problem I'm having personally.
I have two classes that are related to one another as follows:
Parent class
public class MapArea {
@Id
@Column(nullable = false, unique = true)
private String name;
@ManyToOne(cascade=CascadeType.PERSIST)
@OnDelete(action = OnDeleteAction.NO_ACTION)
private MapArea parent;
@OneToMany(cascade = CascadeType.ALL, orphanRemoval = true)
@JoinColumn(name = "area")
@JsonIgnore
private Set<AlternativeAreaName> alternativeNames;
@OneToMany(cascade = CascadeType.ALL, orphanRemoval = true)
@JoinColumn(name = "data")
private Set<MapAreaData> mapAreaData;
@OneToOne(targetEntity = Expenses.class,
cascade = CascadeType.ALL)
@JoinColumn(name = "name", referencedColumnName = "area")
private Expenses expenses;
@OneToOne(targetEntity = Consumption.class,
cascade = CascadeType.ALL)
@JoinColumn(name = "name", referencedColumnName = "area")
@JsonIgnore
private Consumption consumption;
@Transient
private Set<RelatedMapArea> siblings;
@Transient
private Set<RelatedMapArea> children;
...
}
Child class
public class MapAreaData {
@Id
@JsonIgnore
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
@Column(name = "num_bedrooms", nullable = false)
private Integer numBedrooms;
@Column(name = "property_type", nullable = false)
@Enumerated(EnumType.STRING)
private PropertyType propertyType;
@OneToOne(targetEntity = Property.class,
cascade = CascadeType.ALL)
@JoinColumn(name = "property_id")
private Property property;
@OneToOne(targetEntity = Rent.class,
cascade = CascadeType.ALL)
@JoinColumn(name = "rent_id")
private Rent rent;
@OneToOne(targetEntity = CalculatedStats.class,
cascade = CascadeType.ALL)
@JoinColumn(name = "calculated_stats_id")
private CalculatedStats calculatedStats;
...
}
Now the full error message that I get is this:
Caused by: org.hibernate.TransientObjectException: object references an unsaved transient instance - save the transient instance before flushing: com.topfind.search_api_common.map_area_data.MapAreaData
In similar questions, I have found that most people did not use a CascadeType
which was their issue. However, in this case I am using CascadeType.ALL
everywhere and I'd expect it to be able to save new children MapAreaData
whenever I attempt to save MapArea
.
I'd appreciate any ideas towards fixing the issue.
I'm initializing the data in one with the following code (keep in my any method starting with createMock*
creates a new object with ALL variables (including nested objects that are related) populated, however it does not persist the created object.
int top = 2;
DataQuality dataQuality = DataQuality.ROUGH;
MapArea ROUGH_mapArea = createMockArea("W5", null);
MapAreaData ROUGH_mapAreaData = ROUGH_mapArea.getMapAreaData().iterator().next();
ROUGH_mapAreaData.setCalculatedStats(createMockCalculatedStats(doubleToBigDecimal(15.43),
DataQuality.ROUGH.getMinNumAnalysed(), DataQuality.GOOD.getMinNumAnalysed()));
//ROUGH_mapAreaData = dataRepository.save(ROUGH_mapAreaData); - WORKS if this is used
ROUGH_mapArea = mapAreaRepository.save(ROUGH_mapArea);
Upvotes: 1
Views: 328
Reputation: 636
Turns out I had to specify a targetEntity
to make it all work nicely together for Set<MapAreaData>
in MapArea
class as follows:
@OneToMany(targetEntity = MapAreaData.class, cascade = CascadeType.ALL, orphanRemoval = true)
@JoinColumn(name = "data")
private Set<MapAreaData> mapAreaData;
Upvotes: 1