Say I have a model with multiple has_many relationships. For example,
-module(bookstore, [Id, Name]).
-has({employees, many}).
-has({books, many}).
Now say that when I create a new bookstore, the employes and books are
inputs in the bookstore form, so that in my controller I actually have
to save instances of the 3 models. I also want to abort the whole
process if any of those fail validation.
I'm doing something like this:
- Create a new bookstore
- Create the employees, with bookstore_id undefined
- Create the books, with bookstore_id undefined
- Call validate() on all those instances; if any of them fails, abort
- Save the bookstore
- Assign the bookstore ID to each employee and book
- Save the employees and books
The code for this can become somewhat complicated as more relationships
are added (not to mention really boring to write), and it seems wasteful
too because I have to call validate() then save(), which calls
validate() itself.
So, is there a better way do this? It would be cool if there was a way
to set related objects directly, something like
B1 = bookstore:new(id, "foo"),
B2 = B1:employees(ListOfEmployees),
B3 = B2:books(ListOfBooks),
B3:save() % validates and saves each associated object too
Is it possible to add something like this to the API?
Thanks,
Andre
The trouble with this approach is that the Bookstore object is really
just a value-tuple and never includes any information about associated
books or employees; these are fetched from the database each time
employees() or books() is called. There's not a clean way that comes
to mind for keeping track of associated non-saved objects.
However, your problem might be better solved with database
transactions.... maybe the API would look like
ok = boss_db:transaction(fun() ->
Bookstore = bookstore:new(id, "foo"),
{ok, SavedBookstore} = Bookstore:save(),
lists:map(fun(Employee) ->
E1 = Employee:bookstore_id(SavedBookstore:id()),
{ok, E2} = E1:save()
end, ListOfEmployees),
lists:map(fun(Book) ->
...
end, ListOfBooks)
end)
Any run-time error would result in the transaction being rolled back.
What do you think?
Not all databases support transactions but we could probably use the
transaction semantics in Mnesia, MySQL, and Postgres at the very
least.
>
> Thanks,
> Andre
>
>
--
Evan Miller
http://www.evanmiller.org/
That would be great! It would make it much easier to write higher level
functions that handle saving an object and its associations without
having to validate them all first.
Andre
The API is
boss_db:transaction(TransactionFun::function()) -> {atomic,
ResultOfFun} | {aborted, Reason}
Hopefully adding Postgres support won't be too hard.
Evan