So if I have an association with the previous object from the current
object, then I can manipulate that object from the current object? If
so, couldn't I do both? That is, couldn't I have the linked list but
also a position attribute? That would allow easy sorting of the list
when the items are retrieved as a group, but would still permit
navigating the list from the object for the various methods.
Could do a tree the same way.
But now if I want to have a moveToFirst method, I'll have to recurse?
What do you think the performance hit would be on that?
I'd have to also think about how a tree would work with a moveToChildOf
method. That could get complicated...
This is very cool. TWIT. (That's what I think.)
Chas.
Kris Nuttycombe wrote:
> I like the idea, but I think that the primary problem isn't really about
> maintaining the change history; it's about getting a reference to the
> related objects in the list in the first place.
>
> Suppose that Chas pulls a single element of a listable type from the
> database. In order to modify its position in the list, the moveWherever
> method must not only mutate the position field of that one object, but
> also the position of any other object that might be relocated by the
> change - which may have never even been retrieved from the persistence
> layer to begin with! ActiveRecord deals with this by just making blind
> updates to the related objects, and you could do this in a JPA setting
> as well if you are managing transactions yourself, but it wouldn't be a
> general solution.
>
> You could do it without too much difficulty if your entities implemented
> a linked list instead of an absolute position field, which isn't too bad
> using JPA, particularly if you specify that the linked objects are
> lazily fetched. I've got a few instances of this sort of construct in
> the app I'm working on. Here's what such a trait might look like in this
> case:
>
> trait ActsAsList[T] {
> def pred : T
> def succ : T
> def succ_=(t: T)
>
> def moveUp() = {
> pred.succ = succ
> this.succ = pred
> pred.pred.succ = this
> }
>
> //... and so forth
> }
>
> You'd then define an implicit conversion between your entity type and
> ActsAsList that overrides pred, succ, and succ_= with the caveat that
> succ_= must also correctly update the new successor's predecessor
> reference. The model just has (JPA, pasted from my app):
>
> @OneToOne(cascade = {CascadeType.MERGE, CascadeType.PERSIST,
> CascadeType.REFRESH}, fetch = FetchType.LAZY)
> private Segment predecessor;
>
> @OneToOne(cascade = {CascadeType.MERGE, CascadeType.PERSIST,
> CascadeType.REFRESH}, fetch = FetchType.LAZY, mappedBy = "predecessor")
> private Segment successor;
>
> so in the database you only actually end up with a single field
> (predecessor) and Hibernate is smart enough to synthetically populate
> the successor as needed.
>
> In the end, the only real boilerplate ends up in the implicit
> conversion, and it's just a few lines.
>
> WDYT?
>
> Kris
>
> On Thu, Jan 15, 2009 at 7:08 AM, David Pollak
> <[email protected] <mailto:[email protected]>>
> wrote:
>
> Okay, this is going to sound wacky (and a bit Haskell Mondadish)...
> but...
>
> What about not mutating the objects themselves... what about keeping
> a chain of mutator functions... in effect a change log. When you're
> all ready to commit the changes to the RDBMS, you open a session,
> apply the change functions, and commit the transaction?
>
>
> On Wed, Jan 14, 2009 at 11:47 PM, Charles F. Munat <[email protected]
> <mailto:[email protected]>> wrote:
>
>
> Exactly. Unfortunately, I'm not sure that this is even possible.
> Hibernate detaches objects, and, if I've understood it correctly, it
> might even be possible for an object to have multiple persistence
> contexts. So a simple link back to the context isn't going to work.
>
> But there ought to be some way to create a sort of persistence
> context
> from one entity that would allow it to access other entities. Then
> again, there may be constraints (e.g. transactional or
> otherwise) that
> make this difficult or impossible. I think the problem is with
> the way
> Hibernate is structured. ActiveRecord is more SQL based, so it's
> quite
> easy to do this sort of thing in ActiveRecord.
>
> With Mapper as a sort of ActiveRecord-like system, maybe it would be
> possible in Mapper. If I get time I'll have to think about it.
> Someone
> else could probably answer off the top of their head.
>
> Chas.
>
> Kris Nuttycombe wrote:
> >
> >
> > On Wed, Jan 14, 2009 at 6:30 PM, Charles F. Munat
> <[email protected] <mailto:[email protected]>
> > <mailto:[email protected] <mailto:[email protected]>>> wrote:
> >
> >
> > What I'm trying to do is implement list and tree-like
> behavior via a
> > trait.
> >
> > I want to create an object, say a Whatsit. And then I
> want to be able to
> > say that Whatsits have list-like behavior by mixing in an
> ActsAsList
> > trait (similar to the way Rails does it).
> >
> > so my class might be
> >
> > class Whatsit extends ActsAsList...
> >
> > And this trait would automatically add attributes and
> methods to permit
> > list-like behavior, for example:
> >
> > def moveUp
> > def moveDown
> > def moveToTop
> > def moveToBottom
> > def isFirst
> > def isLast
> >
> > and so on. So then when I created and persisted a new
> Whatsit, it would
> > automatically be added at the end of the list. Then I
> could call
> > moveToBefore(other) to position it right before "other"
> in the list.
> >
> > Same idea with trees, etc.
> >
> > I use lists and trees a lot, so I'd love to be able to
> just add a trait.
> >
> > The obvious way to do this in Java is through a DAO, but
> I've avoided
> > all that boilerplate in Scala and would like to continue
> to do so.
> >
> > This is one area, IMO, that Record/Mapper could beat the
> pants off of
> > Hibernate. Maybe someone has already done this in
> Hibernate, but I can't
> > find it.
> >
> > Chas.
> >
> >
> > Ah, I see the problem you're talking about. You need some
> reference to
> > the persistence context that you can obtain from the entity
> itself so
> > that your trait can make the necessary updates to the other
> entities in
> > the list, given that the individual entities don't have direct
> > relationships to one another.
> >
> > I've often wished that Hibernate would provide a static
> method that
> > could take a Hibernate-managed object and give you back the
> persistence
> > context to which it's bound. Seems like something that a lot of
> > applications could make use of.
> >
> > Kris
> >
> >
> > Kris Nuttycombe wrote:
> > > On Wed, Jan 14, 2009 at 5:02 PM, Charles F. Munat
> <[email protected] <mailto:[email protected]>
> > <mailto:[email protected] <mailto:[email protected]>>
> > > <mailto:[email protected] <mailto:[email protected]>
> <mailto:[email protected] <mailto:[email protected]>>>> wrote:
> > >
> > >
> > > Excellent. Your reasons for using POJOs make
> perfect sense,
> > and none of
> > > them have any relevance for me, which means that
> for my apps
> > -- which
> > > are relatively pure Scala -- I'm on the right track.
> > >
> > > Thanks again. This really helps.
> > >
> > > Now if I could just get Hibernate to permit one
> entity to
> > manipulate
> > > another without going through an EntityManager,
> I'd be in heaven.
> > >
> > >
> > > What sort of manipulation are you interested in? If
> you have your
> > > cascades set up correctly, you usually don't need to
> involve an
> > > EntityManager - the persistence layer gets updated
> correctly when the
> > > transaction associated with the request completes. The
> only bit
> > I'm not
> > > sure about with that is the behavior of removes.
> > >
> > > Kris
> > >
> > >
> > > Chas.
> > >
> > > Kris Nuttycombe wrote:
> > > > I'm not sure it's that thorough; it's just a
> copy/paste
> > from my
> > > app. :)
> > > >
> > > > The reason that the entities are POJOs is
> simple; the Lift
> > app is
> > > simply
> > > > a small internal administrative interface for a
> much
> > larger Java EE
> > > > application. I've toyed with the possibility of
> porting as
> > much
> > > of the
> > > > main app as possible to Scala, but there's just
> no time to
> > do it.
> > > Also,
> > > > I really love having good refactoring support
> in the IDE, and
> > > it's just
> > > > not there yet for scala alone, much less hybrid
> scala/java
> > projects.
> > > >
> > > > Kris
> > > >
> > > > On Wed, Jan 14, 2009 at 3:05 PM, Charles F. Munat
> > <[email protected] <mailto:[email protected]>
> <mailto:[email protected] <mailto:[email protected]>>
> > > <mailto:[email protected] <mailto:[email protected]>
> <mailto:[email protected] <mailto:[email protected]>>>
> > > > <mailto:[email protected] <mailto:[email protected]>
> <mailto:[email protected] <mailto:[email protected]>>
> > <mailto:[email protected] <mailto:[email protected]>
> <mailto:[email protected] <mailto:[email protected]>>>>> wrote:
> > > >
> > > >
> > > > Kris,
> > > >
> > > > Thank you much for this very thorough
> exegesis. I'll
> > study it
> > > and will
> > > > try to wrap my tiny brain around it. I really
> > appreciate the
> > > effort you
> > > > put into it.
> > > >
> > > > One question... why did you choose to
> implement the
> > entities
> > > as POJOs
> > > > instead of as Scala objects? I've been
> working with the
> > > latter without
> > > > too much difficulty, and I'd like to avoid
> writing Java as
> > > much as
> > > > possible. Is there some advantage to using
> POJOs?
> > > >
> > > > Chas.
> > > >
> > > > Kris Nuttycombe wrote:
> > > > > Hi, Chas,
> > > > >
> > > > > Sorry it's taken me so long to respond
> to this -
> > I've been
> > > pretty
> > > > buried
> > > > > for the past week.
> > > > >
> > > > > Here's an example of what I'm doing:
> > > > >
> > > > >
> > > > > trait Binding {
> > > > > def apply(xhtml : NodeSeq) : NodeSeq
> = xhtml
> > > > > }
> > > > >
> > > > > trait EntityBinding[+T] extends Binding {
> > > > > def entity : T
> > > > > }
> > > > >
> > > > > trait SubscriptionEventBinding extends
> > > > EntityBinding[SubscriptionEvent] {
> > > > > abstract override def apply(xhtml :
> NodeSeq) :
> > NodeSeq = {
> > > > > val transTemplate =
> chooseTemplate("event",
> > > > "transactions", xhtml)
> > > > >
> > > > > bind("event", super.apply(xhtml),
> > > > > "scheduleDate" ->
> > h(entity.getScheduleDate),
> > > > > "transactions" ->
> > > > >
> > Group(entity.getTransactions.toSeq.flatMap(_(transTemplate)))
> > > > > )
> > > > > }
> > > > > }
> > > > >
> > > > > trait BillingEventBinding extends
> > > > > EntityBinding[SubscriptionBillingEvent] with
> > > > SubscriptionEventBinding {
> > > > > abstract override def apply(xhtml :
> NodeSeq) :
> > NodeSeq = {
> > > > > bind("event", super.apply(xhtml),
> > > > > "detail" -> <span>Charges:
> > ${entity.getCharge};
> > > > Discount:
> > > > > ${entity.getDiscount}</span>,
> > > > > "type" -> h("Billing"))
> > > > > }
> > > > > }
> > > > >
> > > > > trait CancellationEventBinding extends
> > > > >
> EntityBinding[SubscriptionCancellationEvent] with
> > > > SubscriptionEventBinding {
> > > > > abstract override def apply(xhtml :
> NodeSeq) :
> > NodeSeq = {
> > > > > bind("event", super.apply(xhtml),
> > > > > "detail" -> <div>Reason:
> > > {entity.getReason}<br/>Final
> > > > > Balance: {entity.getFinalBalance}</div>,
> > > > > "type" -> h("Cancellation"))
> > > > > }
> > > > > }
> > > > >
> > > > > Then, in the appropriate scope, I import the
> > correct implicit:
> > > > >
> > > > > implicit def entityToEventBinding(e :
> > SubscriptionEvent) :
> > > > Binding = {
> > > > > e match {
> > > > > case b :
> SubscriptionBillingEvent
> > => new
> > > > > BillingEventBinding { override
> val entity = b }
> > > > > case c :
> SubscriptionCancellationEvent
> > => new
> > > > > CancellationEventBinding { override
> val entity = c }
> > > > > case _ => throw new
> > > IllegalStateException("Unbindable
> > > > event
> > > > > " + e.getClass + " (" + e + ")")
> > > > > }
> > > > > }
> > > > >
> > > > > All of the entity classes are JPA entities
> > implemented in
> > > Java. If I
> > > > > have a different set of bindings for a
> different
> > context,
> > > I simply
> > > > > create a separate trait. The nice thing
> about this
> > approach is
> > > > that the
> > > > > traits are stackable over an inheritance
> hierarchy,
> > as above.
> > > > >
> > > > > With this in place, I can just treat my
> entity as a
> > binding
> > > > context on
> > > > > its own:
> > > > >
> > > > > object Subscriptions {
> > > > > object current extends
> > > SessionVar[Box[Subscription]](Empty)
> > > > > }
> > > > >
> > > > > ... stuff that populates the SessionVar
> > > > >
> > > > > def events(xhtml : NodeSeq) : NodeSeq = {
> > > > >
> > > > >
> > > >
> > >
> >
>
> Subscriptions.current.is.map(_.events.toSeq.flatMap(_(xhtml))).openOr(h("No
> > > > > subscription to display events for."))
> > > > > }
> > > > >
> > > > >
> > > > > Kris
> > > > >
> > > > >
> > > > > On Fri, Jan 9, 2009 at 5:29 PM, Charles
> F. Munat
> > > <[email protected] <mailto:[email protected]>
> <mailto:[email protected] <mailto:[email protected]>>
> > <mailto:[email protected] <mailto:[email protected]>
> <mailto:[email protected] <mailto:[email protected]>>>
> > > > <mailto:[email protected]
> <mailto:[email protected]> <mailto:[email protected]
> <mailto:[email protected]>>
> > <mailto:[email protected] <mailto:[email protected]>
> <mailto:[email protected] <mailto:[email protected]>>>>
> > > > > <mailto:[email protected]
> <mailto:[email protected]> <mailto:[email protected]
> <mailto:[email protected]>>
> > <mailto:[email protected] <mailto:[email protected]>
> <mailto:[email protected] <mailto:[email protected]>>>
> > > <mailto:[email protected] <mailto:[email protected]>
> <mailto:[email protected] <mailto:[email protected]>>
> > <mailto:[email protected] <mailto:[email protected]>
> <mailto:[email protected] <mailto:[email protected]>>>>>> wrote:
> > > > >
> > > > >
> > > > > That sounds kinda smart. Is there
> any chance
> > you could
> > > post
> > > > some example
> > > > > code?
> > > > >
> > > > > Chas.
> > > > >
> > > > > Kris Nuttycombe wrote:
> > > > > > Oh, I'm not complaining about the
> way User is
> > > handled - my
> > > > > response was
> > > > > > more about the general hate
> towards MVC
> > upthread.
> > > Having a
> > > > sensible
> > > > > > default for a standard use case
> is great,
> > even when
> > > I'll
> > > > probably
> > > > > never
> > > > > > use the default.
> > > > > >
> > > > > > In my Lift app, my shortcut to
> different
> > renderings
> > > (well,
> > > > different
> > > > > > bindings, really) is to keep all
> the binding
> > logic
> > > for a
> > > > specific
> > > > > case
> > > > > > in a trait and have an implicit
> conversion
> > from my
> > > model
> > > > to the
> > > > > > appropriate trait in the relevant
> scope. You
> > still
> > > have to
> > > > do the
> > > > > work,
> > > > > > but it makes the bindings a lot
> easier to reuse.
> > > > > >
> > > > > > Kris
> > > > > >
> > > > > > On Fri, Jan 9, 2009 at 4:46 PM,
> Charles F. Munat
> > > > <[email protected] <mailto:[email protected]>
> <mailto:[email protected] <mailto:[email protected]>>
> > <mailto:[email protected] <mailto:[email protected]>
> <mailto:[email protected] <mailto:[email protected]>>>
> > > <mailto:[email protected] <mailto:[email protected]>
> <mailto:[email protected] <mailto:[email protected]>>
> > <mailto:[email protected] <mailto:[email protected]>
> <mailto:[email protected] <mailto:[email protected]>>>>
> > > > > <mailto:[email protected]
> <mailto:[email protected]> <mailto:[email protected]
> <mailto:[email protected]>>
> > <mailto:[email protected] <mailto:[email protected]>
> <mailto:[email protected] <mailto:[email protected]>>>
> > > <mailto:[email protected] <mailto:[email protected]>
> <mailto:[email protected] <mailto:[email protected]>>
> > <mailto:[email protected] <mailto:[email protected]>
> <mailto:[email protected] <mailto:[email protected]>>>>>
> > > > > > <mailto:[email protected]
> <mailto:[email protected]>
> > <mailto:[email protected] <mailto:[email protected]>>
> <mailto:[email protected] <mailto:[email protected]>
> <mailto:[email protected] <mailto:[email protected]>>>
> > > <mailto:[email protected] <mailto:[email protected]>
> <mailto:[email protected] <mailto:[email protected]>>
> > <mailto:[email protected] <mailto:[email protected]>
> <mailto:[email protected] <mailto:[email protected]>>>>
> > > > <mailto:[email protected]
> <mailto:[email protected]> <mailto:[email protected]
> <mailto:[email protected]>>
> > <mailto:[email protected] <mailto:[email protected]>
> <mailto:[email protected] <mailto:[email protected]>>>
> > > <mailto:[email protected] <mailto:[email protected]>
> <mailto:[email protected] <mailto:[email protected]>>
> > <mailto:[email protected] <mailto:[email protected]>
> <mailto:[email protected] <mailto:[email protected]>>>>>>> wrote:
> > > > > >
> > > > > >
> > > > > > I don't see how you're any
> worse off if the
> > > model can
> > > > render
> > > > > itself in
> > > > > > one way. And if that way is a
> common
> > > > standards-compliant way,
> > > > > such as
> > > > > > rendering to XML, and you
> include semantic
> > > > information, then
> > > > > you can
> > > > > > layer any other layers you
> want on top
> > to do the
> > > > mapping to
> > > > > the 30
> > > > > > different contexts.
> > > > > >
> > > > > > Saying that an object should
> know how to
> > render
> > > itself
> > > > to some
> > > > > > universally recognized format
> is not the
> > same as
> > > > saying that
> > > > > that solves
> > > > > > all rendering issues.
> > > > > >
> > > > > > Is there some shortcut to 30
> different
> > > renderings that I'm
> > > > > missing, or
> > > > > > do you have to do the work
> either way?
> > > > > >
> > > > > > Chas.
> > > > > >
> > > > > > Kris Nuttycombe wrote:
> > > > > > > If you want to render a
> model 30
> > different
> > > ways in 30
> > > > > different
> > > > > > > contexts, it kind of sucks
> though,
> > doesn't it?
> > > > > > >
> > > > > > > Or what if, shock horror,
> you don't
> > know how the
> > > > eventual
> > > > > system is
> > > > > > > going to want to render
> the model
> > (i.e., the
> > > person
> > > > doing the
> > > > > > rendering
> > > > > > > won't be able to change
> the model
> > code.) Not too
> > > > uncommon, I
> > > > > > don't think...
> > > > > > >
> > > > > > > Kris
> > > > > > >
> > > > > > > On Sun, Jan 4, 2009 at
> 9:58 AM, Michael
> > > <mike.sr <http://mike.sr> <http://mike.sr>
> <http://mike.sr>
> > > > <http://mike.sr>
> > > > > <http://mike.sr> <http://mike.sr>
> > > > > > > <http://mike.sr>@gmail.com
> <http://gmail.com>
> > <http://gmail.com>
> > > <http://gmail.com> <http://gmail.com>
> > > > <http://gmail.com>
> > > > > <http://gmail.com> <http://gmail.com>>
> > > > > > wrote:
> > > > > > >
> > > > > > >
> > > > > > > > Also I was looking
> at the
> > sample model
> > > > source code
> > > > > (User,
> > > > > > ProtoUser)
> > > > > > > > and saw
> presentation logic
> > mixed in it.
> > > > Shouldn't the
> > > > > > business and
> > > > > > > > model logic be kept
> separated
> > from the
> > > > presentation
> > > > > logic
> > > > > > or is there
> > > > > > > > a Lift strategy it?
> > > > > > >
> > > > > > > Hmm, a model that can
> render
> > itself ...
> > > That sounds
> > > > > like this
> > > > > > crazy
> > > > > > > paradigm called
> object-oriented
> > programming.
> > > > Some radicals
> > > > > > say it has
> > > > > > > some advantages over
> the more
> > procedural
> > > style
> > > > of MVC.
> > > > > > >
> > > > > > > -- Michael
> > > > > > >
> > > > > > >
> > > > > > >
> > > > > > >
> > > > > > > >
> > > > > >
> > > > > >
> > > > > >
> > > > > >
> > > > > > >
> > > > >
> > > > >
> > > > >
> > > > >
> > > > > >
> > > >
> > > >
> > > >
> > > >
> > > > >
> > >
> > >
> > >
> > >
> > > >
> >
> >
> >
> >
> > >
>
>
>
>
>
> --
> Lift, the simply functional web framework http://liftweb.net
> Collaborative Task Management http://much4.us
> Follow me: http://twitter.com/dpp
> Git some: http://github.com/dpp
>
>
>
>
> >
--~--~---------~--~----~------------~-------~--~----~
You received this message because you are subscribed to the Google Groups
"Lift" group.
To post to this group, send email to [email protected]
To unsubscribe from this group, send email to
[email protected]
For more options, visit this group at
http://groups.google.com/group/liftweb?hl=en
-~----------~----~----~----~------~----~------~--~---