2010-11-25 4 views
0


Я работаю над довольно простым CRUD-приложением с веб-интерфейсом. Я использую общий шаблон DAO в уровне сохранения. Интерфейс моего родового DAO выглядит следующим образом:Сохраняемые объекты со ссылками на другие объекты

public interface GenericDAO<T> { 

    void create(T entity) throws CannotPersistException; 
    T findById(Long id) throws NotFoundException; 
    Collection<T> findAll(); 
    void update(T entity) throws CannotPersistException, NotFoundException; 
    void delete(Long id) throws CannotPersistException, NotFoundException; 
} 

Этот интерфейс реализован с использованием JPA, но я также реализация в памяти, в основном для целей тестирования. У меня нет других классов в уровне персистентности, я просто создаю один экземпляр этого DAO для каждого класса домена.

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

Правильно знаю, я использую сервисный уровень для управления классами DAO, и я решаю проблему на , работая с несколькими DAO. я покажу пример:

public class PlayerServiceImpl implements PlayerService { 

    private GenericDAO<Player> playerDAO; 
    private GenericDAO<Club> clubDAO; 

    //constructor ommited 

    public Player addNewPlayer(Player player, Long clubId) throws NotFoundException, 
      CannotPersistException { 
     Club club = clubDAO.findById(clubId); 
     player.setClub(club); 
     playerDAO.create(player); 
     club.addPlayer(player); 
     clubDAO.update(club); 
     return player; 
    } 

    //... other methods 

} 

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

Я нашел другой недостаток при тестировании приложения - Я не могу проверить класс GenericDao в изоляции, если я хочу использовать объекты Клуба, у которых есть поля их коллекции, заполненные объектами Player.
Сначала мне нужно перенести объект Player, чтобы я мог добавить его в объект Club, чтобы я мог передать его тестируемому GenericDao.

Я искал книгу PoEAA от Fowler для решения, но я немного запутался, где O/R-фреймворк, подобный Hibernate, подходит для шаблонов, которые он описывает.

ответ

2

Используйте в памяти DataSource

Кажется, что вы бы лучше использовать DataSource в памяти, а не изобретать обходной путь для JPA каскада. Я бы предложил вам посмотреть настройку тестовой среды, чтобы вы могли выбрать другой источник данных, предназначенный для экземпляра HSQLDB в памяти. Затем вы можете аннотировать объекты своего домена для каскадирования и проверки содержимого вашего сердца. Вот контекст Spring, который демонстрирует простую конфигурацию:

<bean id="testDataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource" destroy-method="close"> 
    <property name="driverClass" value="org.hsqldb.jdbcDriver"/> 
    <property name="jdbcUrl" value="jdbc:hsqldb:mem:test"/> 
    <property name="user" value="sa"/> 
    <property name="password" value=""/> 
    </bean> 

Ваш код тест может иметь завод, который создает определенные сценарии, которые вы хотите проверить (с использованием коллекций переходных объектов домена, пока они не достигнут DAO, который будет заполнять их первичные ключевые поля). Поскольку вы можете добавить много потенциальных дубликатов в свои тестовые наборы данных, вам следует рассмотреть возможность добавления поля UUID в объекты вашего домена, чтобы они могли быть дифференцированы, когда первичный ключ равен нулю. Обычно это всего лишь лениво загруженный метод getUUID(), который сохраняется вместе с другими полями. Вы даже можете рассмотреть возможность использования его в качестве основного ключа, поскольку вероятность столкновения бесконечно мала по определению.

Кроме того, я бы приблизился к тестированию, имея как соединение JDBC, так и соединение DAO JPA. Вы просматриваете состояние базы данных для подтверждения через соединение JDBC, и вы делаете свои обновления через ваше DAO-соединение.

Анемичные объектов домена не является анти-модель

В зависимости от вашей стратегии для моделирования домена, нет ничего специфически плохого с анемией объектов предметной области. Например, у вас может быть множество мелкомасштабных бизнес-объектов, которые выполняют операции изменения состояния объектов домена в соответствии с бизнес-правилами. По сути, у вас будет подход Unit of Work/Command/DTO с вашим уровнем обслуживания, обеспечивающим транзакцию приложений.

1

in C# Я бы, вероятно, подумал о создании атрибута, который сообщает dao, если свойство должно рассматриваться как часть родительского элемента («child»). Я знаю, что в Java есть что-то подобное, но я не помню, как это называется.

К сожалению, это C#:

class Club 
{ 
    [ChildEntity] 
    List<Player> Players { get; private set; } 
} 

Он необходим, чтобы найти отражение всех детей и своих детей. Если вам не нравится это, вы могли бы просто рассмотреть, чтобы написать интерфейс, который возвращает детей:

class Club : IComplexEntity 
{ 
    List<Player> Players { get; private set; } 

    public IEnumerable<object> EntityChildren { get { return Players; } } 
} 
1

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

Вы понимаете, что JPA является стандартом Java для настойчивости, и это не фактическая реализация. Чтобы использовать JPA, вам все равно нужен PersistenceProvider (реализация), но вы можете выбирать между несколькими реализациями (Toplink, Hibernate и т. Д.).

Я думаю, вы должны использовать JPA Cascade здесь.

+0

Я знаю, что JPA имеет разные реализации. Но предположим, что я хотел бы реализовать слой persistence с помощью iBatis. – prasopes 2010-11-30 08:56:43

0

У вас есть общий тип (DOA), но поведение, которое вам нужно реализовать, не является общим. Это похоже на попытку поставить квадратную привязку в круглое отверстие: она никогда не сработает.

Некоторые возможные aproaches:

Будьте конкретны: если это был я, я бы с использованием типов, который определяет конкретные вещи: Club бы (просто думать о возможных примеров) в address, DJ бы имеют Genre/Style.

Да, у меня будет много классов классов sof, но у каждого класса будет одна работа, и это будет хорошо. Поскольку они были раздельными, они были бы изолированы от изменений, что в основе всего того, что у вас сейчас есть.

Использование наследования: если все ваши классы имеют эти основные общие черты, вы можете использовать это как базу и обрабатывать остальные отдельно?

Использование нескольких интерфейсов: немного похоже на inheretance, но отличается.Вы сохраняете существующий интерфейс, который обрабатывает основы; вы затем определяете дополнительные интерфейсы для дополнительного поведения. Когда объект приходит, он требует, чтобы некоторые действия выполнялись над ним, чтобы оценить, какие интерфейсы он реализует и обрабатывает их по очереди. Вы также сохраняете возможность изменить существующий интерфейс, чтобы лучше поддерживать этот подход - если это имеет смысл.

Возможно, вы можете смешивать и сопоставлять некоторые из этих параметров или их биты.

+0

Я не уверен, что я понимаю вашу точку зрения, но общий DAO не является необычным шаблоном и реализует его с использованием структуры ORM, такой как JPA, довольно просто: http://www.ibm.com/developerworks/java/library/j -genericdao.html – prasopes 2010-11-30 09:01:02

Смежные вопросы