I'm currently using Flextrine in a large Robotlegs based project but
I expect the principles are broadly the same for any MVC(S)
framework. For what its worth, here's how I think about it:
Service tier:
I view the EntityManager as being the (S)ervice tier.
In fact, in my application I make an EntityService which is simply
an adapter onto the methods of the EntityManager. This means that I
can theoretically swap the EntityManager out for a mock to help with
testing. When I need to use some persistence mechanism I inject
entityService into my mediators/services/models and do things like:
entityService.persist(myEntity);
entityService.flush();
In fact entityService.flush() does some other things; as well as
performing the flush() and returning the AsyncToken, it first
attaches result and fault handlers in order to send
events/notifications/signals (whatever your framework uses) to the
rest of the application. I use the changeset returned by flush() on
success to dispatch a set of entityPersisted, entityUpdated and
entityRemoved messages which other modules of my application can
respond to. Likewise on a fault I dispatch a fault message. See
https://github.com/ccapndave/flextrine/wiki/Flush-and-rollback
for an example on how to dispatch messages on a successful flush.
Command tier:
It would be totally valid to create PersistCommand, FlushCommand,
etc - in my app I haven't done this and haven't yet felt any impact
with abstraction or encapsulation, but I guess it could be argued
that this is the 'correct' MVC way to do it.
Model tier:
In my head there are two ways to use Flextine. The first is with
configuration option
configuration.entityTimeToLive = -1
This disables garbage collection and basically means that you can
treat EntityRepositories as models. Once data is loaded it goes
into the repositories and stays there for you to use, either by
directly using the entities collection, or by using the find* helper
methods. This is a nice and easy way to develop, but obviously only
useful for applications where you can be sure that you will be only
ever loading a limited subset of data.
If
entityTimeToLive is set to a positive number, as it is by
default, then entities in the repository will be garbage collected
when there are no longer a reference to them and can no longer be
regarded as models (instead they are kind of caches). In this case
you can use a normal model (however your framework implements them)
to store data that you have retrieved from Flextrine. This means
you can control garbage collection, and will eliminate the issue you
mentioned of calling loadAll() lots of times.
Take the following pseudo-code as an
public function loadUsers():void {
em.getRepository(User).loadAll().addResponder(new
AsyncResponder(onUserResult, onUserFault));
}
private function onUserResult(e:ResultEvent, token:Object =
null):void {
userModel.setUsers(e.result);
}
View tier:
The mediators in your application can have access to the models and
services. Obviously you don't want the view components themselves
to have knowledge of Flextrine, so you provide them with data via
their mediator. The only exception to this is allowing on-demand
loading of uninitialized entities and collections. This can be done
for collections using AsyncListView (Flex 4) or just using
DataGrid/List (Flex 3), and for entities just using normal data
binding. In AS3 view components the same effect can be acheived
using LazyUtil.async.
I hope that helps, and I'd be very keen to hear how other people are
using Flextrine with frameworks. This is by no means the best or
correct solution, and Flextrine is purposely vague with regards to
MVC so that people can use it however they feel it works best!
Cheers,
Dave