cayenne-user mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From Andrus Adamchik <and...@objectstyle.org>
Subject Re: Expressions & objects state
Date Sat, 01 Mar 2008 11:27:32 GMT

On Mar 1, 2008, at 11:55 AM, Razumovsky Andrey wrote:
> First is about expressions. Suppose i have two entities, A and B. A  
> has pk 'aid' and fk (non-mandatory) 'bid'. B has pk 'bid'.
> I want to build two separate expressions for A like those (1)  
> 'aid=1' and (2) 'bid=2'. Since 'aid' and 'bid' are not properties of  
> A class, statements like this:
> Expression.fromString("aid=1") results in exception. With 'bid' the  
> sutiation is event harder, because while i write something like  
> 'b.bid=2', b relation target might event not exist.
> I know i can do this using 'db:' prefix, but this is not a solution  
> for me, because i'm using ROP and 'db:' do not work on client since  
> DBEntities are not being sent through hessian.
> So how i can create such queries (note than i prefer using  
> SelectQuery, because there might be other qualifiers in my  
> expression)??

The whole point of hiding PK/FK is to remove references to them from  
the code, and operate in object property terms. I don't see any reason  
to break this paradigm in your case. To find objects by PK, you can  
use ObjectIdQuery:

http://cayenne.apache.org/doc/objectidquery.html

to find objects by FK you can match against a relationship target  
object ObjectId:

ExpressionFactory.matchExp("relationshipName", new  
ObjectId("TargetEntity", "pk", 2);


> Other thing i discovered about expresions is they are type- 
> dependent, so that if 'count' is integer property,  
> Expression.fromString("count='1'").match(...) (note quotes here!)  
> will never work because it will search for string 'count' property.  
> This is no good because all databases i know support such automatic  
> type conversion. So SelectQuery will work ok, but simple match()  
> will not.
> Reading comments in 'ASTEqual', 'ASTLess' and other, i saw i'm not  
> the first to ask this. But i think this is quite easy to implement  
> (at least converting from String to Number), so i'd ask for this  
> feature.

I am +1 on adding type converters.  Especially if there are volunteers  
to help us with it ;-)

One may argue whether "1" equals 1, but it is worse than that. Long(1)  
is not equal to Integer(1) according to the current comparison  
algorithm, which is much more confusing. As a side note, "reflect"  
package already has a non-public type converter class. We may want to  
extend this to Expressions.


> ==========
> Second, about state of objects.
> I create new transient object 'A' and then set some EXISTING  
> relation target of B class:
>
> //b is persistent in db and fetched using SelectQuery or something  
> else
> A a = new A();
> a.setB(b);
>
> The reason i do this is somewhat like the previuos question in the  
> list. I need to persist objects only when user presses 'Save', not  
> when my data object is created.
>
> So, when i do this, several things occur. First, 'b' state is  
> changed to MODIFIED since relationship affects both sides. But note  
> that 'b' now refers to unexisting and non-'NEW' object. Second, a's  
> temp id is added to ObjectContextStateLog's dirtyIds!
> So right now these functions will definitely crash in NPE:
> -context.commitChanges()
> -context.newObjects,
> since temp id presents in dirtyIds but node is not registered in  
> GraphManager.
>
> In my local version of cayenne i managed to do some workaround by  
> changing ObjectContextStateLog and ObjectContextChangeLog so that  
> they will not mark dirty anything while working with transient  
> objects. However, probably context.registerObject(a) will not work  
> correctly, but i don't need that, instead i create 'new' object and  
> fill it with 'transient' one properties:
> A a2 = (A)context.newObject(A.class);
> a2.setB(a.getB())
> context.commitChanges().
>
> This works fine for me, but i think something must be done around  
> collapsing 'transient' and 'in-scope' (registered) objects.

That's how Cayenne works...

   context.newObject(A.class)

is always preferrable to

   A a = new A();

We are going to implement relationships between transient objects, but  
relationships between transient and persistent objects simply don't  
make sense... From the object graph maintenance perspective, the  
solution that I suggested in reply to the "State of DataObjects"  
thread is actually more cleaner than a hypothetical solution that  
would mix transient and persistent objects in a single graph.

Andrus


Mime
View raw message