Спящий режим, вставка или обновление без выбора

У меня есть объекты продуктов, которые принадлежат к определенным категориям, то есть к классическим отношениям «многие к одному».

@Entity
public class Product{

    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    Long id;

    String name;
    Double price;
    @ManyToOne(fetch = FetchType.LAZY)
    Category category;
...
}

@Entity
public class Category implements Identifiable {

    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    private Long id;

    private String name;
...
}

Я хочу вставлять и обновлять товары без предварительного выбора категорий. Как это:

Product product = dao.get(productId);
Category category = dao.get(categoryId);
product.setCategory(category);
dao.update(product);

or

Product product = new Product(somename);
Category category = dao.get(categoryId);
product.setCategory(category);
dao.insert(product);

Можно ли обновлять и вставлять без выбора категории? Я не хочу использовать для этого HQL или прямые запросы.


person Vladimir    schedule 30.11.2009    source источник


Ответы (3)


session.load() существует специально для таких случаев. Следующее:

Category category = session.load(categoryId);
product.setCategory(category);

не попадет в базу данных. Однако на более позднем этапе (более или менее во время сброса) будет выдано исключение, если нет доступной категории с данным идентификатором.

Использование load() быстрее, чем merge(), и не имеет побочных эффектов (каскадирование и т. д.).

person ChssPly76    schedule 30.11.2009

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

Решение состоит в том, чтобы загрузить категории при запуске, настроить поставщика кэширования, такого как ehcache для этого класса, а затем использовать этот код:

Product product = new Product(somename);
product.setCategory(session.merge(category));

Это не вызовет каких-либо обращений к базе данных, если вы настроите кеш, который экземпляры категории не могут изменить.

person Aaron Digulla    schedule 30.11.2009

Я только что попробовал следующее:

Category category = new Category(categoryId);
product.setCategory(category);

И это сработало, я имею в виду, что запись продукта в БД получила правильную ссылку на категорию и категорию с идентификатором

categoryId

не изменились.

person Vladimir    schedule 01.12.2009
comment
Проблема с этим подходом заключается в том, что вы создаете новый экземпляр постоянной сущности с тем же идентификатором. Возможно, на этот раз это сработало, потому что рассматриваемый Category не был связан с текущим сеансом; если бы это было так, Hibernate выдал бы исключение. Это также опасно с точки зрения целостности данных; если бы вы указали каскадирование для много-к-одному на category, приведенный выше код перезаписал бы исходную категорию всеми пустыми значениями (или произошел бы сбой с ошибкой нарушения ограничения) - person ChssPly76; 01.12.2009
comment
Хм, у меня было ощущение, что я делаю здесь что-то нехорошее. Спасибо за разъяснение. - person Vladimir; 02.12.2009