Plain Ol' Transfer Objects (Using a Transfer Object Without a Database)

0 views
Skip to first unread message

John K.

unread,
Nov 18, 2008, 11:15:15 PM11/18/08
to transfer-dev
So I've encountered this problem a few times and each time I seem to
stumble on figuring out how to best solve it. Sorry if this has been
discussed here, I looked through pages and pages and did some searches
but came up with nothing.

The site I am designing has several objects (dogs, calendar events,
ads, etc.). These all need to be created in the database, updated,
etc. Perfect opportunity to use Transfer to make these database
functions simple. I am able to set this up just fine and have
incorporated validation into the works so that the data the user
submits can be validated server side and returned to the form for
corrections if necessary.

My problem comes in when I start to work with things like a contact
form. I really want all the functionality of a Transfer object,
except I'll never have to interact with the database. I will just
validate, return the user to the form to correct errors (invalid email
address, missing info, etc.) if necessary and then once the submission
is valid I'll send an email to the proper administrator.

Has anyone used Transfer in this way? How so? Is it just as simple
as mocking up and using the object but never saving the data? Have
you come up with a better way to make this work? Maybe it's just late
and this is as simple as it sounds.

John

Jared Rypka-Hauer

unread,
Nov 19, 2008, 2:48:10 AM11/19/08
to transf...@googlegroups.com
No, this isn't something that Transfer does... it has to have the
database there to provide properties for the objects, so without a DB
table you have nothing to provide the object definition. I think it
would be sweet if Transfer's config would provide a way to configure
it with objects outside the DB model that you could simply retrieve
from the Transfer object... making it into an object factory as well
as a persistence engine.

You might try creating an object tagset that doesn't have a DB table
and then calling new() against it, but I think that would fail when
Transfer tried to create the metadata for the object.

Something to think about, anyway.

J

Mark Mandel

unread,
Nov 19, 2008, 3:42:12 AM11/19/08
to transf...@googlegroups.com
What happens if you create the objects with a table/columns that don't exist?

As long as you don't save() or get(), you shouldn't get errors.

Mark
--
E: mark....@gmail.com
W: www.compoundtheory.com

Chris Peterson

unread,
Nov 19, 2008, 5:55:42 AM11/19/08
to transf...@googlegroups.com
Sure enough, I setup a simple transfer xml for a non-existing object:

<object name="phantom" table="notReal">
    <id name="ID" type="numeric" />
    <property name="name" type="string" column="name" />
</object>

Then I used it, as such:

application.cs.getBean("transfer").new("phantom")

and it dumped out exactly what I would expect, a transfer object of type phantom, and I could use setName("foo") without any problems.  Sounds like an interesting method of using transfer for transient-persistance, kinda cool.  Maybe you could even write a save() method on there, to commit it to another data location other than the database?  Might be a cool way of wrapping up all different data locations in a standardized way.  Cool stuff, good idea =)

Chris Peterson
--
Hey! I dont tell you how to tell me what to do, so dont tell me how to do what you tell me to do! ~ Bender (Futurama)

John K.

unread,
Nov 19, 2008, 11:05:04 AM11/19/08
to transfer-dev
I didn't mean to make anyone go out and code this up for me to see if
it worked, I was really just curious how others handled this problem.
Thanks for trying it out though Chris!

I did try it out last night myself and it worked just fine. The only
trick was to dummy up a primary key, as Chris has done as well. In
this case I just used the name of the person submitting the contact
form.

Most objects in a site/application are probably persisted in some way
but there are a few that never need to be. At work we have two
different methods we use for persisted and non-persisted data, but it
seems kind of messy to me since 95% of the logic is the same. The
only difference in this case is that instead of calling .save() I am
sending an email and then throwing the data away.

The only thing that get's a little messy, in my implementation, is the
fact that I have my application set up with MG and CS and so I have
the view, controllers, services, and then gateways/dao's. Instead of
exposing Transfer to the service level and using it to replace all my
gateway/dao functionality, I expose Transfer at the gateway/dao level
as more of a wrapper. Change the ORM, change the gateways/daos
instead of the entire service layer. You might be able to imagine how
this kind of creates some goofiness as I have to have a method in the
gateway that creates the empty Transfer object for me. It works, but
I'm not entirely happy with it at the moment.

If anyone else has any comments on how they accomplish this I'd love
to hear them. And Mark, thank's for checking in to see if this worked
and for saving me plenty of time that otherwise would have been wasted
persisting data!

John
> > E: mark.man...@gmail.com

Bob Silverberg

unread,
Nov 19, 2008, 12:45:52 PM11/19/08
to transf...@googlegroups.com
I like this idea. I can see how some might see it as a misuse of the
ORM, but it seems like a very practical approach to me, and keeps
things consistent (i.e., all Business Objects are Transfer Objects).

Thanks for sharing,
Bob
--
Bob Silverberg
www.silverwareconsulting.com

Jared Rypka-Hauer

unread,
Nov 19, 2008, 1:26:42 PM11/19/08
to transf...@googlegroups.com
It depends on how you look at it, if ORM is object --> relational,
then it's no misuse at all, you're using Transfer as an object
factory to get your business objects and if they happen to have
persistence integration well that's cool.

I'm glad I was wrong, FWIW, because this is cool. Sort of puts
another nail in the coffin of the notion that Transfer requires King
Database and puts the database before the object model.

I'm going to try to write a sample application that goes thru the
process of setting up a Transfer-based app without using a service
layer at all, just real, behavior-laden domain objects... because
there's no reason that Transfer can't take the place of the service
layer and the persistence layer all at the same time. Should be
interesting.

Laterz,
J

On Nov 19, 2008, at 11:45 AM, Bob Silverberg wrote:

>
> I like this idea. I can see how some might see it as a misuse of the
> ORM, but it seems like a very practical approach to me, and keeps
> things consistent (i.e., all Business Objects are Transfer Objects).
>
> Thanks for sharing,
> Bob
>
> On Wed, Nov 19, 2008 at 11:05 AM, John K. <rayra...@gmail.com>
> wrote:
>>
>> I didn't mean to make anyone go out and code this up for me to see if
>> it worked, I was really just curious how others handled this problem.

>> Thanks for trying it out though Chris! ...

Nando

unread,
Nov 19, 2008, 1:37:55 PM11/19/08
to transf...@googlegroups.com
Why not simply expose Transfer in your service layer. If you think of your transfer objects as business objects first and foremost, which they are, then I don't see any problem. I believe it's perfectly acceptable to expose a Factory such as Transfer within your service layer when using such an architecture.




The only thing that get's a little messy, in my implementation, is the
fact that I have my application set up with MG and CS and so I have
the view, controllers, services, and then gateways/dao's.  Instead of
exposing Transfer to the service level and using it to replace all my
gateway/dao functionality, I expose Transfer at the gateway/dao level
as more of a wrapper.  Change the ORM, change the gateways/daos
instead of the entire service layer.  You might be able to imagine how
this kind of creates some goofiness as I have to have a method in the
gateway that creates the empty Transfer object for me.  It works, but
I'm not entirely happy with it at the moment.




--

Nando M. Breiter
The CarbonZero Project
CP 234
6934 Bioggio
Switzerland
+41 76 303 4477
na...@carbonzero.ch

Bob Silverberg

unread,
Nov 19, 2008, 1:39:56 PM11/19/08
to transf...@googlegroups.com
So you'd have your controller talking directly to Transfer? Is that the idea?
--
Bob Silverberg
www.silverwareconsulting.com

Jared Rypka-Hauer

unread,
Nov 19, 2008, 3:09:24 PM11/19/08
to transf...@googlegroups.com
Yeah. Exactly. The way I see this, the only function of the service
layer is to wrap calls to Transfer... which, frankly, is a bit
redundant for most applications.

Then again, I'm still giving this a lot of thought. "Real" OOP has
caught my attention lately mostly due to Joe Rinehart's ORM posts and
Hal Helms's responses... it's gotten me thinking about Hal's
objection to Transfer as a DB-centric device that's anathema to
"really good OO domain models". I also have no real training in
programming, so I tend to make a lot of this stuff up as I go. So
take this all for what it is (and what it's worth): My own (probably
uninformed) take on what I see as valuable in application
architecture. I'll be the first to admit that a lot my observations
over the last 2 years have met with some strong resistance from
friends and colleagues, so it's hard to know if I'm being less a
follower of entrenched thinking than they are or if I'm so far off
base that I should be locked in a padded cell and the key ground to
powder. ;)

So yeah, maybe I've a screw loose... it's happened before, but I am
thinking that if Transfer is acting as both the object factory for
business objects and the persistence API it sort of makes a more
traditional service/persistence mechanism, well, redundant. If the
controller is doing nothing but pulling values from the event and
dumping them into the service layer and then pulling data from the
service layer and pushing them to the view, where's the value in
having service classes and DAO and/or Gateway classes?

I guess what I'm thinking is that if you have all the behavoirs the
application needs encapsulated within the domain objects and the
those objects are all served up and persisted by Transfer, what value
is a separate service layer and CRUD layer? This has far less to do
with OOP than it does stable application architecture. I know even
Mark uses the DAO/Gw pattern and the Manager pattern (albeit referred
to as Services), but I'm starting to wonder if that's the right
direction. I have to read some more and talk about this with some folks.

Thoughts?

J

On Nov 19, 2008, at 12:39 PM, Bob Silverberg wrote:

>
> So you'd have your controller talking directly to Transfer? Is
> that the idea?
>
> On Wed, Nov 19, 2008 at 1:26 PM, Jared Rypka-Hauer
> <armcha...@gmail.com> wrote:
>>
>> It depends on how you look at it, if ORM is object --> relational,
>> then it's no misuse at all, you're using Transfer as an object
>> factory to get your business objects and if they happen to have

>> persistence integration well that's cool. ...

Elliott Sprehn

unread,
Nov 19, 2008, 4:03:28 PM11/19/08
to transfer-dev
What worries me the most about about this idea is that it utterly
breaks the insides of Transfer on a global scale. Essentially the
entire public API that it provides won't work. That is, readByProperty
() , readByPropertyMap(), TQL, saving, deleting, relationships...
won't work. And it won't just fail silently, Transfer will throw nasty
exceptions from the database.

This sounds like a nightmare for a new developer later maintaining
your project when they look at the transfer.xml, try to call save on
some object or some such, or try to understand why your code does what
it does.

What transfer does internally when you create objects is also very
very complicated for simple objects. It makes a lot of sense for
something that deals with the database (and the dynamic property/
decorator stuff), but for general objects? It's incredible overkill!

I think you're much better off rolling your own management system for
Objects, assuming you even need the kind of caching that transfer
provides for your app. It's pretty trivial to generate objects based
on an XML file, or just use plain old CFCs. Why would you even want
the massive duplication between properties and the XML if it's not
going in the database? :P

To me, using Transfer like this really makes no sense at all. You've
taken a car and used it as a gas can. Does it contain the gas for you
and tell you much there is? Sure. Are you wasting 98% of what's
provided? Yeah...

On Nov 19, 1:26 pm, Jared Rypka-Hauer <armchairde...@gmail.com> wrote:
> It depends on how you look at it, if ORM is object --> relational,  
> then it's no misuse at all, you're using Transfer as an object  
> factory to get your business objects and if they happen to have  
> persistence integration well that's cool.
>
> I'm glad I was wrong, FWIW, because this is cool. Sort of puts  
> another nail in the coffin of the notion that Transfer requires King  
> Database and puts the database before the object model.
>
> I'm going to try to write a sample application that goes thru the  
> process of setting up a Transfer-based app without using a service  
> layer at all, just real, behavior-laden domain objects... because  
> there's no reason that Transfer can't take the place of the service  
> layer and the persistence layer all at the same time. Should be  
> interesting.
>
> Laterz,
> J
>
> On Nov 19, 2008, at 11:45 AM, Bob Silverberg wrote:
>
>
>
> > I like this idea.  I can see how some might see it as a misuse of the
> > ORM, but it seems like a very practical approach to me, and keeps
> > things consistent (i.e., all Business Objects are Transfer Objects).
>
> > Thanks for sharing,
> > Bob
>
> > On Wed, Nov 19, 2008 at 11:05 AM, John K. <rayray5...@gmail.com>  

Jared Rypka-Hauer

unread,
Nov 19, 2008, 5:29:45 PM11/19/08
to transf...@googlegroups.com
Elliot, I think you're absolutely right, at least at this point.

I'm pulling from both the text and Mark's comments in these two blog
posts for a lot of what I'm about to say:

http://www.firemoss.com/post.cfm/does-coldfusion-have-no-real-orm-
frameworks
http://www.firemoss.com/post.cfm/what-makes-a-framework-an-orm

What I'm hoping will come of this is that Transfer will eventually
include an object factory as well as a persistence mechanism. Mark
has already said he's looking at several enhancements to future
versions of Transfer to include inheritance mapping and hopefully
eventually enhancements to allow things like bidi m2m joins.
Granularity needs to be on the map so you can define 2 or 3 objects
from one table, but I don't see that as insurmountable... maybe I'm
wrong but still, it doesn't seem that far fetched.

Hell, if I could make sense of the Transfer codebase (which is only
function matter of time and effort on my part) I'd be more than
willing to help add things like granularity to the framework, and
allow the addition of objects to the factory that aren't included in
the persistence scheme. Things like adding an object definition to
the Transfer config without a table="" attribute means that the
object is treated as a plain old ColdFusion object. Adding property
tags with a ref="" attribute would allow you to associate these
objects with other objects and intermingle the persistence tools with
the object factory tools. It would still allow Transfer to generate
many of the methods, even retaining the m2m, m2o and o2m terminology
to create collections of other objects... I see this working very
well and allowing Transfer to fill a need that's been around since
ColdSpring gained fame and fortune: acting as an object factory for
transient objects.

I also don't think it would be out of line to contemplate Transfer
being able to support a columns="" attribute to create a solution to
the granularity problem, or, possibly, adding subordinate objects to
the object definitions to be able to accomplish it. Doing it with
subtags would mean you'd be able to, using Joe's example from the
Granularity section of the second blog post, define a User that is
composed of simple properties and larger properties. Being able to
define things to this level means Transfer would be an "all-the-way"
sort of solution, not a partial solution for most things you need to do.

I have to admit I'm utterly, totally psyched about the idea,
especially with Transfer promising to generate DDL to create the DB
from the model and inheritance mapping. To see Transfer become
something that solves so many obvious needs, fully implemented and
roaring to go, is something that I find exciting on so many levels.

Laterz,
J

On Nov 19, 2008, at 3:03 PM, Elliott Sprehn wrote:

>
> What worries me the most about about this idea is that it utterly
> breaks the insides of Transfer on a global scale. Essentially the
> entire public API that it provides won't work. That is, readByProperty
> () , readByPropertyMap(), TQL, saving, deleting, relationships...
> won't work. And it won't just fail silently, Transfer will throw nasty

> exceptions from the database. ...

John K.

unread,
Nov 19, 2008, 6:08:53 PM11/19/08
to transfer-dev
Elliott,

I totally understand what you mean and you're right on with the car/
gas can analogy. I know I'm wasting a bunch of functionality and if
I, or another developer, were to call just about any other method on
this object other than a getter/setter/decorator method, I'd get a
nasty error.

All,

What I'm trying to get at is, how do you rectify the two different
objects. We all know now the solution I came up with but what
strategy do you use? As it stands right now my Transfer object also
has at its disposal a validate method, added in the decorator, and an
ErrorCollection that it can use to store all validation errors. I
need all this functionality but don't want to have to maintain two
very different ways of creating/using objects.

Mark,

This is really your baby. haha. Am I totally bastardizing everything
it stands for? ;-)

John

Nando

unread,
Nov 19, 2008, 6:33:55 PM11/19/08
to transf...@googlegroups.com
I used a car as a gas can only once. My father would do it all the time tho' when I was young, so I probably learned it from him.

He had this 3/4" diameter white plastic tube hanging in the garage about 2 meters long or so. He'd open the cover on the car's gas tank, feed the plastic tube down into the tank and then suck on it until his mouth started to fill with gasoline. Then he'd jam his thumb onto the end of the tube as he quickly pulled it out of his mouth, spitting the gasoline out behind him as he lowered the tube down to the lawn mower tank, and carefully opened the end to fill the lawn mower (or whatever else needed gasoline.)

Like I said, I only tried it once - BLAH! - but my father would do it all the time. Seemed to fit with his 1950's greaser personality.

Gmail

unread,
Nov 19, 2008, 6:35:14 PM11/19/08
to transfer-dev
Why not use your decorator to decorate your other, non-Transfer objects?


Sent from my iPhone
Sent from my iPhone

Elliott Sprehn

unread,
Nov 19, 2008, 9:47:43 PM11/19/08
to transfer-dev

On Nov 19, 6:08 pm, "John K." <rayray5...@gmail.com> wrote:
> ...
> All,
>
> What I'm trying to get at is, how do you rectify the two different
> objects.  We all know now the solution I came up with but what
> strategy do you use?

From your original use case, which is about forms, I create an object
for the form.

RegistrationForm extends (BaseForm extends AbstractForm).

The registration form has various steps that take a collection of user
input. It provides methods for checking if its valid, if the user
needs to complete a step because it has errors, or if the user can
move on.

I store the Form object in the session scope. I also use self posting
forms. Then when the form is submitted (http POST) I call the process
method of the form, pass in the values from the request, and ask the
form to validate. If it's valid we can process it and redirect, if
it's not we show the same view again usually so the user can fix the
form.

The form provides an error collection if it's not valid through a
getErrors() method that the view can call to show information.

If it's valid there's a method that creates the object (or objects)
the form represents, and returns them. In your use case we'd have a
createEmail() which creates and populates a brand new Email object
which we can then use for things.

// slight pseudo code:
function email( values ) {
var contactForm = session.contactForm;
var email = "";

if( cgi.request_method eq "post" ) {
contactForm.processStep1(values);
contactForm.validate();
if( not contactForm.hasAnyErrors() ) {
email = contactForm.createEmail();
getEmailService().send(email);
contactForm.clear();
renderView("contact/email-sent");
return;
}
// fall through and render the view anyway since we have
errors
}
renderView("contact/email-form");
}

Validation in Transfer objects is handled by a Validator object that
has a validate() method and validates against metadata and other
information from the database. Each object type has it's down
Validator object. The base Validator object has methods for creating
and manipulating error collections and custom validation routines.

So if we wanted an Email object to have a special Validator we could
just write one (instead of using runtime generated ones from the
database) and provide that to the Email object for validation.

Since something like a contact form is so basic, I think I'd probably
just only do the validation right in the Form object though.

Our form has a set of Required and Optional fields, and the validate()
method automatically makes sure those exist. We could then add custom
validation logic, like making sure the "email" field in the form
looked like an email.

The core platform code exists on RIAForge. The Form processing code is
very basic, but that's internal.
<http://svn.riaforge.org/saa/trunk/library/com/stellr/framework/
transfer/>

The general idea is just that your form is an Object too! Let it
validate itself and return errors to the view. If and when it's valid
you call some CreateFoo() method that returns the Foo object it has
the data to populate. We then call save(newObject);

If it's an update form them when it's valid call populateObject
(objectToUpdate) on it, and it'll add all it's values to the provided
object. We can then call save(objectToUpdate) on it.

Delete is similar, and so on.

Objects that could possible be "invalid" are honestly forms and stuff
that'd end up in Transfer (and therefore the database). Everything
beyond that "gap" is something the system would have validated already
and turned into a valid object by a Form (or similar object, ex. maybe
a CSVFileProcessor ).

(Sorry for the long post, trying to just throw out lots of concepts)

- Elliott

Jaime Metcher

unread,
Nov 19, 2008, 10:51:21 PM11/19/08
to transf...@googlegroups.com
I'm not suprised this has come up again - Transfer is so close to being a really cool object factory (and a really cool cache, and a really cool code generator - basically the persistence is just the icing on the cake).

One of the issues in using Transfer this way is in managing the object lifecycle.  If you ask Transfer for any object, it will always return one - whether it exists in the database or not.  You then use getIsPersisted(), or maybe just check if the ID is 0.  This makes sense for an ORM, but is fundamentally not how you want an object factory to behave.  You *can* create stub factories that return TransferObjects populated with some sequential ID, but you can't then mix that with persistence, and at the end of the day it's just as easy to set up a database.

Jaime
Reply all
Reply to author
Forward
0 new messages