The typical way I've seen this handled is via #3 - there's an application service that generates the next primary key for the entity (either a GUID, or by getting the next auto-increment value and then setting it manually for that table so it doesn't get re-used) and then passes it to the form as a hidden field, so any related entities can use it and be saved before the parent entity is.
Here's an alternative, though:
- On the create page view, have the upload AJAX submit to a different URL
- At that URL, temporarily store the files somewhere and save their location to the session under a
pending_page_imageskey or something. - When storing a new page, have the controller/service/repository check the session for
pending_page_imagesand create and save the associated models if they exist.