Шаблон Scala для доступа к свойствам объекта модели в Play 2.0

У меня простой вопрос о доступе к переменным-членам объекта модели.

У меня есть следующие объекты модели:

@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;
}

Пока все хорошо, любой заданный person может иметь один account. Объект Account скопирован из примера zentask. После аутентификации я перенаправляюсь на индексную страницу, которая отображает настоящее имя пользователя, как указано в переменной-члене Person.name. Объект Account вставляется на страницу так же, как и в примере zentasks, вот так:

Account.find.byId(Controller.request().username());

Теперь в шаблоне происходят следующие странные вещи, которые я не понимаю:

@account.person.name

приводит к вставке значения Null в шаблон при вызове:

@account.person.getName()  or   @account.person.getName

результаты, как и ожидалось, с правильным именем, вставленным из объекта человека.

@account.person

показывает .toString() объекта человека, также правильно показывая имя.

Итак, подведем итог: что не так с кодом выше? Почему я могу вызвать значение account.person без проблем, но когда я вызываю account.person.name, это больше не работает

Заранее спасибо!

Ричард


person Bjarne77    schedule 29.03.2012    source источник


Ответы (3)


Это связано с тем, что JPA использует аспекты для перехвата использования геттера и заполнения отсутствующих данных из объектов, которые загружаются отложенно. Я не знаю, что такое традиционное мышление, но по этой причине я бы никогда не использовал публичных членов с JPA, это постоянно нарушает структуру.

Если вы действительно хотите использовать общедоступные члены, вам придется пометить отношения как нетерпеливые:

@OneToMany(fetch=FetchType.EAGER)

или явно получить все дерево объектов, которое вам понадобится в вашем шаблоне (тьфу).

В вашем случае отношение OneToOne определяется на другой стороне отношения, если вы определяете его на стороне учетной записи, по умолчанию оно должно получаться с нетерпением. Я забыл, что если вы можете определить OneToOne для обоих сущностей, я думаю, что вы можете, но вам, возможно, придется немного повозиться с этим.

В целом, не используйте общедоступные члены с JPA, это сломается. А еще лучше отказаться от JPA и использовать вместо него Anorm, он гораздо успешнее отображает проблемную область, чем JPA. Проблемы, подобные этой, постоянно приводят к тому, что реализация JPA занимает в два раза больше времени, чем кто-либо может предсказать.

person PlexQ    schedule 30.03.2012
comment
Привет PlexQ! Спасибо за ответ! Такое поведение довольно странное, как и в случае с Play! framework вам рекомендуется использовать общедоступные члены в классе. Я вижу, как JPA (и в моем случае Ebean, который используется по умолчанию в Play! 2.0) использует Aspects для отложенной загрузки. Но можно было бы ожидать, что это будет работать, как указано выше. Еще раз спасибо! Я начисляю вам баллы, так как, похоже, я не получу полного ответа от сообщества по этому поводу. - person Bjarne77; 02.04.2012
comment
На ум приходит еще одна мысль: интересно, улучшит ли это статическое плетение, а не плетение во время загрузки? Я мог бы поклясться, что помню, что можно было указать доступ к полю разреза, просто реализации JPA, которые я использовал, не кажутся. Какой поставщик JPA вы используете? - person PlexQ; 03.04.2012
comment
Реализация EBean распространяется как поставщик ORM по умолчанию с Play! 2.0 фреймворк. Я не слышал об этом до Play! пришел с ним. - person Bjarne77; 03.04.2012

Я только что наткнулся на ответ, опубликованный Гийомом Бортом, который все объясняет. Читайте здесь:

https://groups.google.com/d/topic/play-framework/CNjH3w_yF6E/discussion

Надеюсь это поможет!

person Bjarne77    schedule 06.04.2012

Из-за ленивой загрузки значения в поле загружаются только при доступе к ним из самого класса (что-то, что в обычных обстоятельствах использовало бы установщик/получатель

Чтобы загрузить значения, вам нужно написать геттеры и сеттеры. Или вы можете создать метод, который проверяет каждое значение.

вы можете добавить следующий метод к вашей учетной записи:

public void checker(){

    if(email==null){}
    if(password==null){}
    if(person==null){}
}

это загрузит каждое значение, но не снизит производительность

person MrIveck    schedule 30.06.2013