I have a Spring-Batch process which Reads from Bar to create a new Foo:
/* My Foo Step */
class FooStepConfig {
ItemReader<Bar> reader; // Reads records from Bar
ItemProcessor<Bar, Foo> processor; // Determines whether to create a new Foo or update an existing Foo
ItemReader<Foo> writer; // Created/Updated Foos are persisted
// ...
}
Additionally, when creating or updating a Foo, I need to also save a FooNotification that references the Foo:
// During processor step, this is saved
@Entity
public FooNotification {
@Id Long id;
@ManyToOne Foo foo; // @Entity class Foo { ... };
@Enumerated NotificationType nt; // new, updated, removed, etc...
// (removal is a soft delete with "Foo.isActive" column)
}
ItemProcessor:
class MyItemProcessor extends ItemProcessor<Foo, Bar> {
...
public Foo process(Bar bar) {
Foo foo = fromBar(bar); // some supporting method defined elsewhere.
...
// does not work as foo is still transient at this point and id is null as it is generated on persist from a Database Sequence.
fooNotificationRepository.save(new FooNotification(foo,...));
...
return Foo;
}
}
As described in the comments above, when the batch process runs through, I receive the following exception:
java.lang.IllegalStateException: org.hibernate.TransientPropertyValueException:↩
↪object references an unsaved transient instance - save the transient↩
↪instance before flushing : com.example.FooNotification.foo -> com.example.Foo
Both Foo creation/mutation and FooNotification creation should be atomic. I don't want either to exist without the other, so spliting the two into seperate steps isn't ideal. Also the FooNotification can contain information about what fields changes and previous values, so calculating that at the time of the update is much more efficient.
I know I can solve this by creating an ItemProcessor<Bar, FooNotification> and ItemWriter<FooNotification> as the saves would cascade with appropriate configuration and the Foo should always exist for each type. conceptually though, this isn't the purpose of the step and feels awkward. FooNotifications are a side product of the main Foo creation and not the main batch step's objective.
- Is there another more sensible way I can ensure the creation of the
Foobefore theFooNotification? - Do I need to 'pre-create' the
Foounfinished in order for the reference to be a valid orm managed entity?