coldbox-modules / quick

A ColdBox ORM Engine
https://quick.ortusbooks.com
MIT License
23 stars 19 forks source link

[Quick 7.2.0] Calling Getter Method on Relationship Throws Exception #242

Open homestar9 opened 8 months ago

homestar9 commented 8 months ago

I encountered an issue when calling a getter method on a Quick entity relationship that throws the following exception: Value must be initialized before use.

How to replicate:

  1. Create a simple entity with a relationship that joins to the same table (simple hierarchy)

    
    component
    extends="quick.models.BaseEntity"
    accessors="true"
    table="category"
    {
    
    proprety name="id";
    property name="parentId";
    
    // RELATIONSHIPS
    
    function parent() {
        return belongsTo( "Category", "parentId", "id" ).withDefault();  // Return a new entity if no match found.
    }

}


2. Now execute the following code in your handler of choice:

// Works! prc.category = getInstance( "CategoryQ@cms" ).findOrFail( rc.id ); writeDump( var=prc.category.getParent().isLoaded() );

// Works! prc.category = getInstance( "CategoryQ@cms" ) .with( "parent" ) .findOrFail( rc.id );

writeDump( var=prc.category.parent().get().isLoaded() );

// Throws Exception! prc.category = getInstance( "CategoryQ@cms" ) .with( "parent" ) .findOrFail( rc.id );

writeDump( var=prc.category.getParent().isLoaded() ); // Value must be initialized before use.



If you initialize the Quick entity and eager load the relationship using the `with()` statement.  If the relationship returns null (or a new entity because of `withDefault()` and then get the relationship using the `get[relationship]()` method, you will get an exception.  However, calling the relationship using `[relationship]().get()` still works as expected.

**Additional Info:**

I opened up FusionReactor to see if I could figure out what was going on.  What's interesting is that if the entity has a null/empty value for `parentId`, the `with( "parent" )` statement never attempts a query.  However, I suspect that it still caches the result somewhere so that the getter attempts to retrieve a null from the entity cache. 

If you call `parent().get()`, Quick executes a query and then returns a new instance of the object.

I suspect the problem has to do with the `eagerLoadRelation()` method in QuickBuilder, but I'm not sure how to fix it.  I believe it should respect the `withDefault()` property and cache the new entity.
homestar9 commented 7 months ago

Hi @elpete, I'm just checking in to see if you've been able to replicate this issue yet? Let me know if you'd like me to create a sample repo to help reproduce the error.