2016-09-27 3 views
2

Я знаю, что при использовании Wicket с фреймворками JPA нецелесообразно сериализовать объекты, которые уже были сохранены в базе данных (из-за проблем с ленивыми полями и экономии места) , В таких случаях мы должны использовать LoadableDetachableModel. Но как насчет следующего прецедента?Wicket - Сериализация сохраняемых и не сохраняемых объектов JPA

Предположим, мы хотим создать новую сущность (скажем, контракт), которая будет состоять, среди прочего, из постоянных объектов (например, Клиент, который выбран из списка клиентов, хранящихся в БД). Сущность при создании является модельным объектом некоторого компонента Wicket (скажем, Wizard). В конце (когда мы закончим наш мастер) мы сохраним новый объект в БД. Поэтому мой вопрос: каково наилучшее общее решение проблемы сериализации таких объектов модели? Мы не можем использовать LDM, потому что сущность еще не находится в БД, но мы не хотим, чтобы наши внутренние объекты (например, Клиент) тоже были сериализованы.

Моя идея состояла в том, чтобы реализовать пользовательский калибровочный сериализатор, который проверяет, является ли объект сущностью, и если он сохраняется. Если это так, сохраните только его идентификатор, иначе используйте сериализацию по умолчанию. Аналогичным образом, при десериализации использовать сохраненный идентификатор и получать объект из БД или десериализовать с использованием механизма по умолчанию. Не уверен, однако, как это сделать в общем виде. Моя следующая мысль заключалась в том, что если мы сможем это сделать, нам больше не нужен LDM, мы можем просто сохранить все наши объекты в простых моделях org.apache.wicket.model.Model, и наша логика сериализации позаботится о них, правильно ?

Вот код:

@Entity 
    Client { 
    String clientName; 

    @ManyToOne(fetch = FetchType.LAZY) 
    ClientGroup group; 
    } 

    @Entity 
    Contract { 
    Date date; 

    @ManyToOne(fetch = FetchType.LAZY) 
    Client client; 
    } 

    ContractWizard extends Wizard { 
    ContractWizard(String markupId, IModel<Contract> model) { 
     super(markupId); 
     setDefaultModel(model); 
    } 
    } 

    Contract contract = DAO.createEntity(Contract.class); 
    ContractWizard wizard = new ContractWizard("wizard", ?); 

Как передать контракт? Если мы просто скажем Model.of (контракт), весь контракт будет сериализован вместе с внутренним клиентом (и он может быть большим), более того, если мы получим доступ к contract.client.group после десериализации, мы сможем решить проблему: https://en.wikibooks.org/wiki/Java_Persistence/Relationships#Serialization.2C_and_Detaching

Так что мне интересно, как люди решают такие проблемы, я уверен, что это довольно распространенная проблема.

+0

Почти такая же проблема (с другой стороны) https://stackoverflow.com/questions/7070644/how-do-i-keep-entities-or-their-associations-attached-to-the-current-peristen - –

ответ

0

Я предполагаю, что есть 2 подхода к вашей проблеме:.

а) только сохранить материал, пользователь фактически видит в моделях. В вашем примере это может быть «contractStartDate», «contractEndDate», List of clientIds. Это основной подход, если вы не хотите, чтобы ваши DatabaseObjects были в вашем представлении.

b.) Напишите свой собственный LoadableDetachableModel и убедитесь, что вы только сериализуете переходные объекты. Например, как: (при условии, что любой отрицательный идентификатор не сохраняется в базе данных)

public class MyLoadableDetachableModel extends LoadableDetachableModel { 

private Object myObject; 

private Integer id; 

public MyLoadableDetachableModel(Object myObject) { 
    this.myObject = myObject; 
    this.id = myObject.getId(); 
} 

@Override 
protected Object load() { 
    if (id < 0) { 
     return myObject; 
    } 

    return myObjectDao.getMyObjectById(id); 
} 

@Override 
protected void onDetach() { 
    super.onDetach(); 
    id = myObject.getId(); 

    if (id >= 0) { 
     myObject = null; 
    } 
} 
} 

Крушение этого является то, что вы должны сделать свой DatabaseObjects Serializable, который не является действительно идеальным и может привести к всякого рода проблем. Вам также необходимо будет отключить ссылки на другие объекты из объекта перехода, используя ListModel.

Работая с обоими подходами, я лично предпочитаю первый. Из моей экспирации все инъекционные объекты dao в калитки могут привести к катастрофе. :) Я бы использовал это только в проектах, не слишком больших.

+0

Ну, я понимаю первый подход, но в наших объектах базы данных проекта уже широко используются, и все они тоже сериализуемы. Что касается второго подхода, я не совсем понимаю, как вы имеете дело с внутренними сохраняющимися сущностями. Сделать это по-разному? Мы получим новую реализацию LDM каждый раз, правильно? Как насчет более общего подхода, как тот, который я упоминал с помощью специального сериализатора? – koszek

+0

Вам не нужен новый LDM для каждого объекта, но вам нужно будет хранить внутренние сохраняемые объекты не в вашей сущности напрямую, а в отдельной модели (например, LoadableDetachableListModel). Но вам понадобится только это, если вам действительно нужно изменить значения внутренних постоянных полей в вашем представлении. –

0

Большинство проектов, которые я знаю, просто принимают сериализацию ссылочных объектов (например, ваших Клиентов) вместе с отредактированным объектом (Контракт).

Использование разговоров (сохранение сеанса Hibernate/JPA для нескольких запросов) является хорошей альтернативой для приложений со сложными отношениями объектов: Сеанс Hibernate и его сущности хранятся отдельно от страницы и никогда не сериализуются.Компонент просто сохраняет идентификатор для извлечения его беседы.

+1

И это то, что мы делаем. Но я начинаю сомневаться, если это хорошая идея. С этим связаны две проблемы. Во-первых, сущности JPA могут быть большими, и мы хотим, чтобы наши страницы были как можно более легкими. Во-вторых, существует известная проблема (https://en.wikibooks.org/wiki/Java_Persistence/Relationships#Serialization.2C_and_Detaching) с ленивыми полями. Так выглядит первый подход Thorsten Wendelmuth - это способ пойти? .. – koszek

+0

Предлагаемое решение IMHO Thorsten a) слишком сложно, если у вас много объектов и вы хотите отредактировать отношения между ними. Google для «калиткового диалога cdi», чтобы получить представление о моем альтернативном решении. – svenmeier

+0

Я понимаю вашу идею, но можете ли вы объяснить, как проблема с ленивыми полями рассматривается в вашем решении? Вы не хотите, чтобы ваши пользователи отображали страницу с ошибкой, если они нажимают кнопку «Назад» в браузере, а где-то в коде появляется доступ к ленивому полю, к которому не обращались, прежде чем сериализация состоялась, не так ли? – koszek