I have a simple question regarding accessing member variables of a model object.
I have the following model objects:
@Entity
public class Person extends Model{
@Id
public Long id;
public String name;
}
@Entity
public class Account extends Model{
@Id
public String email;
public String password;
@OneToOne
public Person person;
}
So far so good, Any given person can have a single account. The Account object is copied from the zentask example. After authentication I redirect to the index page which displays the user realname as stated in the Person.name member variable. The Account object is inserted in the page just as with the zentasks example like so:
Account.find.byId(Controller.request().username());
Now the following strange things happen in the template which i do not understand:
@account.person.name
results in a Null value inserted in the template while calling:
@account.person.getName() or @account.person.getName
results as expected with the correct name inserted from the person object.
@account.person
shows the .toString() of the person object, also correctly showing the name.
So to summarize: What is wrong with the code above? Why can I call the account.person value without any problems, but when I call account.person.name this does not work anymore
Thank you in advance!
Richard
This is because JPA uses Aspects to intercept getter usage and fill-in the missing data from objects that are lazy-loaded. I don’t know what conventional thinking is, but I would not use public members ever with JPA for this reason, it will break the framework consistently.
If you really want to use public members, you’ll have to mark relationships as eager fetching:
or explicitly fetch all of the object tree you’ll need in your template (ugh).
In your case, the relationship, a OneToOne is defined on the other side of the relationship, if you define it on the Account side, it should fetch eager by default. I forget if you can define OneToOne on both entities, I think you can, but you might have to fiddle with it a bit.
Overall, don’t use public members with JPA, it will break. Better yet, ditch JPA and use Anorm instead, it maps to the problem domain much more successfully than JPA. Issues like this consistently cause JPA implementations to take up twice as much implementation time as anyone seems able to predict.