Ответы пользователя по тегу Hibernate
  • Как связать два отношения правильно в java?

    azerphoenix
    @azerphoenix Куратор тега Java
    Java Software Engineer
    Отвечу исходя из вашего второго вопроса, на который я уже написал ответ:

    @Entity
    @Table(name = "category")
    @Data
    public class Category {
    
        @Id
        @GeneratedValue(strategy = GenerationType.AUTO)
        private Long id;
    
        private String name;
    
        @Column(length = 1000)
        private String description;
    
        @ManyToMany(mappedBy = "categoryList")
        private List<Product> productList;
    }


    @Entity
    @Data
    @NoArgsConstructor
    @AllArgsConstructor
    public class Product {
    
    	@Id
    	@GeneratedValue(strategy = GenerationType.IDENTITY)
    	private Long id;
    	private String name;
    
    	@Column(length = 1000)
    	private String description;
    
    	private double price;
    
    
    	@ManyToMany(fetch = FetchType.LAZY, cascade = {
    			CascadeType.PERSIST,
    			CascadeType.MERGE
    	})
    	@JoinTable(name = "product_categories",
    				joinColumns = @JoinColumn(name = "product_id"),
    				inverseJoinColumns = @JoinColumn(name = "category_id"))
    	private List<Category> categoryList;
    
    }


    Полезная информация - https://vladmihalcea.com/the-best-way-to-use-the-m...
    Ответ написан
    Комментировать
  • Где создать sessionFactory в Spring проекте?

    azerphoenix
    @azerphoenix Куратор тега Java
    Java Software Engineer
    Добрый день.
    В чем именно заключается проблема?
    Судя по всему у вас есть hibernate.cfg.xml, а также есть HibernateUtil.
    Можно чуть подправить этот класс на такой вариант:
    import org.hibernate.HibernateException;
    import org.hibernate.Session;
    import org.hibernate.SessionFactory;
    import org.hibernate.boot.MetadataSources;
    import org.hibernate.boot.registry.StandardServiceRegistry;
    import org.hibernate.boot.registry.StandardServiceRegistryBuilder;
    
    public class HibernateUtil {
    
      final static StandardServiceRegistry registry = new StandardServiceRegistryBuilder()
          .configure()
          .build();
    
      private static final SessionFactory sessionFactory;
    
      static {
        try {
          sessionFactory = new MetadataSources(registry).buildMetadata()
              .buildSessionFactory();
        } catch (Throwable ex) {
          throw new ExceptionInInitializerError(ex);
        }
      }
    
      public static Session getSession()
          throws HibernateException {
        Session session = null;
        try {
          session = sessionFactory.getCurrentSession();
        } catch (org.hibernate.HibernateException he) {
          session = sessionFactory.openSession();
        }
        return session;
      }
    
    }


    Далее используя метод getSession() получаете сессию и делаете то, что нужно.
    Например,

    Session session = HibernateUtil.getSession();
          session.beginTransaction();
          note.setTitle("Example");
          session.merge(note);
          session.getTransaction().commit();
          session.close();


    как это сделать в Spring проекте где нету main`a

    Почему это в Spring проекте нет main метода?
    Вот, туториал по Spring Framework, где указан main метод - https://www.youtube.com/watch?v=nLCYk1ySY_U
    Ответ написан
    Комментировать
  • Не обогащаются таблицы при создании Entity?

    azerphoenix
    @azerphoenix Куратор тега Spring
    Java Software Engineer
    Добрый день!
    Да, конечно же сперва выполняется sql файл.
    Можно реализовать по разному:

    1) Попробуйте вынести DDL запросы в sql файл. (schema.sql)
    2) Либо наоборот содержимое data.sql инициализируйте при помощи java кода. Например, имплементируйте интерфейс CommandLineRunner
    3) Попробуйте использовать либу FlyWay для миграций

    spring.jpa.hibernate.ddl-auto=create-drop
    Это означает, что все созданные таблицы будут дропнуты и на момент старта в БД нет таблиц, куда ваши инсерты должны быть добавлены.

    Полезная информация - https://www.baeldung.com/spring-boot-data-sql-and-...
    Ответ написан
    2 комментария
  • Где нужно реализовывать HQL запросы?

    azerphoenix
    @azerphoenix Куратор тега Spring
    Java Software Engineer
    Ссылка на полезный источник: https://www.baeldung.com/hibernate-named-query

    Вот эту часть кода по логике надо писать в модели прям над названием класса?

    Да

    Теперь когда я хочу найти компании с паспортом работника, по логике я могу вызвать этот query и вызывать я его должен в классе Cервиса верно?

    Как вариант можно в сервисе. Обычно, да это делается в сервисном слое, но никто не запрещает проделывать вам это внутри контроллера или еще где-то.

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

    В Spring, используется не только HQL, но и Spring Data или Criteria API или же JPQL.
    Ответ написан
    Комментировать
  • Hibernate имеет связи, как выбрать только те записи, которые входят в диапазон дат?

    azerphoenix
    @azerphoenix
    Java Software Engineer
    Добрый день.
    Такой вариант вам не подходит?
    https://stackoverflow.com/questions/21265134/hql-t...
    Ответ написан
    Комментировать
  • Почему вылетает ошибка при ленивой инициализации при работе с БД?

    azerphoenix
    @azerphoenix Куратор тега Java
    Java Software Engineer
    Добрый день!
    Если не ошибаюсь, то вы столкнулись с этой проблемой:
    https://www.baeldung.com/spring-open-session-in-view

    Говоря проще, если у вас включен open-session-in-view, то вам не нужно использовать аннотацию Transactional, но при этом это является антипаттерном

    Because OSIV creates a Session at the beginning of the request, the transactional proxy uses the current available Session instead of creating a brand new one.
    Ответ написан
    Комментировать
  • Почему при сохранении объекта через связь OneToMany - ManyToOne получаю ошибку?

    azerphoenix
    @azerphoenix Куратор тега Java
    Java Software Engineer
    Добрый день!
    Предположу, что у вас возникла проблема с тем, что в SQL есть зарезервированные слова и при создании таблиц и колонок у вас эти столбцы не создаются.

    not-null property references a null or transient value : com.SchoolJournal.SpringHibernate.model.Pupil.name

    В данном случае это название переменной Pupil.name
    (433 строка) - Список зарезервированных слов в SQL
    И если вы глянете в БД, то в таблице pupil не найдете колонку name. Отсюда и ошибка.

    Решение: в Column укажите name, экранируйте при помощи обратной одинарной кавычки
    @Column(name = '"`name`", nullable = false)
            @Getter
            @Setter
            private String name;


    Полезный ресурс - https://vladmihalcea.com/escape-sql-reserved-keywo...

    Что касается OneToMany & ManyToOne, то рекомендую прочитать эту статью.
    https://vladmihalcea.com/the-best-way-to-map-a-one...
    Ответ написан
  • Как вынести конфиг Hibernate?

    azerphoenix
    @azerphoenix Куратор тега Java
    Java Software Engineer
    Вот, тут ответ на ваш вопрос - https://stackoverflow.com/questions/27508327/desig...
    Если вкратце, то вы можете вынести во внешнюю конфигурацию
    Ответ написан
    1 комментарий
  • Hibernate, как инициализировать вычисляемое поле в Entity?

    azerphoenix
    @azerphoenix Куратор тега Java
    Java Software Engineer
    Добрый день!
    Хочу добавить в этот класс поле, которого нет в базе

    Подозреваю, что вам нужно сделать следующее:
    1) создать поле с аннотацией @Transient
    Например,
    @Transient
    private long calc;

    https://stackoverflow.com/questions/2154622/why-do...
    Таким образом это поле не будет хранится в БД.

    ...которое вычисляется на основе других полей.

    2) К этому полю добавить аннотацию @Formula
    https://thorben-janssen.com/hibernate-tips-calcula...

    Прочитайте вот, эту статью - https://vladmihalcea.com/how-to-map-calculated-pro...

    Другой вариант выполнить пункт 1. Но вместо использования аннотации @Formula создать метод с аннотацией @PostConstruct и затем уже инициализировать ваше поле с нужным значением
    Ответ написан
    1 комментарий
  • Hibernate, как получить два объекта из одной таблицы?

    azerphoenix
    @azerphoenix Куратор тега Java
    Java Software Engineer
    Подозреваю, что вам нужно глянуть в сторону проекций
    JPA / Hibernate Projections
    https://www.baeldung.com/jpa-hibernate-projections
    Ответ написан
    1 комментарий
  • Spring Data Jpa как удалить сущность без удаления другой связной сущности?

    azerphoenix
    @azerphoenix Куратор тега Spring
    Java Software Engineer
    Добрый день.
    Можете попробовать следующее:
    CascadeType.MERGE,
    CascadeType.PERSIST

    orphanRemovel = false;
    Если orphanRemoval = true, то если у клиента будет отсутствовать lessonId, то он будет удален, так как является "сиротой". А если наоборот false, то удаляться не будет.
    Вот, разница между CascadeType.REMOVE vs orphanRemoval
    https://www.baeldung.com/jpa-cascade-remove-vs-orp...
    Ответ написан
    Комментировать
  • Как решить javax.persistence.EntityExistsException в Hibernate?

    azerphoenix
    @azerphoenix Куратор тега Java
    Java Software Engineer
    LikeKey,
    очень полезные ресурсы по каскадам
    https://www.baeldung.com/jpa-cascade-types
    https://vladmihalcea.com/a-beginners-guide-to-jpa-...
    Ответ написан
    Комментировать
  • Как в hibernate создать объект без поля optional?

    azerphoenix
    @azerphoenix Куратор тега Java
    Java Software Engineer
    Добрый день!
    Наверное будет лучше, если вы с клиента будете создавать DTO, а его уже конвертровать в Entity. Это не связано с вопросом, так небольшой совет.
    А то получается, что вы на клиенте формируете User. И возможно, что project, так как он не создается передается null.
    А при этом у вас nullabe = false
    @ManyToOne(fetch = FetchType.LAZY, optional = true)
        @JoinColumn(name = "project_id", nullable = false)
        @OnDelete(action = OnDeleteAction.CASCADE)
        @JsonIgnore
        private Project project;

    Получается нельзя создать юзера, но при этом назначить ему null project. Потому у вас и ConstraintViolationException

    В общем,
    1) используйте DTO
    2) Наверное, стоит поставить nullable = true
    Ответ написан
    Комментировать
  • Почему Hibernate разрешает удалять сущность, на которую ссылается FK?

    azerphoenix
    @azerphoenix Куратор тега Java
    Java Software Engineer
    Добрый день!
    Наверное, помимо ограничений на уровне БД можно использовать проверку средствами Java. Т.е. создать метод, который проверяет наличие курсов у юзера и выбрасывает соответствующее исключение. Соответственно, исключение будет выброшено до вызова метода delete() и будет выброшено то исключение, которе вам нужно.
    Я конечно не отвечу вам наверняка, но думаю этот ответ будет для вас полезен
    https://stackoverflow.com/questions/14875793/jpa-h...

    JPA does offer possibility to cascade operations (merge, persist, refresh, remove) to associated entities. Logic is in JPA and does not utilize database cascades.
    There is no JPA standard compliant way to do cascades with database cascades.

    Т.е. скорее всего вы каскады не указали при создании сущности ManyToMany. Проверьте ваш код

    Дополнено:
    There is no clean cut means to do this in JPA. The following will get you what you want... You can use CascadeType.DELETE, however this annotation only applies to the objects in the EntityManager, not the database. You want to be sure that ON DELETE CASCADE is added to the database constraint. To verify, you can configure JPA to generate a ddl file. Take a look at the ddl file, you'll notice that ON DELETE CASCADE is not part of the constraint. Add ON DELETE CASCADE to actual SQL in the ddl file, then update your database schema from the ddl. This will fix your problem .
    Ответ написан
  • По какому принципу Spring DataJPA обновляет записи в связанных таблицах?

    azerphoenix
    @azerphoenix Куратор тега Java
    Java Software Engineer
    Приветствую, коллега!
    Позволь, внести небольшую лепту в ваш код и отметить следующее:
    CrudCourseRepository

    Наверное, указывать Crud в названии не нужно, так как в репозиторий в будущем могут быть добавлены другие методы и соответственно, с точки зрения clean code название не будет корректным.

    Как JpaRepository производит обновление связей в таблице student_courses?

    Как говорится, лучше один раз увидеть, чем сто раз услышать. Так что лучше включить в properties
    spring.jpa.show-sql=true
    spring.jpa.properties.hibernate.format_sql=true


    Предположу, что вы увидите примерно следующее:
    Запрос на SELECT (выборку) из двух таблиц вместе с JOIN, а далее запрос на вставку новой записи (INSERT)

    Насколько я понимаю, если я попытаюсь обновить сущность Student, передав в CrudStudentRepository#save() студента с пустым списком курсов, то в таблице student_courses будут удалены все записи, в которых фигурирует обновляемый студент, но по моему опыту этого не происходит. Как мне тогда удалять/обновлять эти записи?

    Тут пожалуй, вам стоит обратить внимание на CascadeType.

    Например, если в связи OneToMany вы постараетесь сохранить список со стороны самой сущности, то элементы списка будут сохранены, но id у них будет null, так как сама сущность еще не сохранена и ей не присвоен идентификатор. Чтобы избежать этого можно как вариант, указать CascadeType.All или PERSIST & MERGE

    В случае с ManyToMany, думаю, что будет корректным указать тип каскада. Например, CascadeType.PERSIST CascadeType.MERGE

    К слову, есть хороший источник, откуда я также время от времени черпаю информацию. Вот ссылка - link
    Можешь глянуть.
    Ответ написан
    3 комментария
  • Hibernate @ManyToOne как не создавать запись, если она уже создана?

    azerphoenix
    @azerphoenix Куратор тега Java
    Java Software Engineer
    Здравствуйте!
    1) В репозиторий для City (предположительно CityRepository или CityDao) добавьте метод, который вернет вам объект City по его названию.
    Optional<City> findCityByCityName(String cityName);

    примерно так
    2) Далее
    Как сделать, чтобы hibernate не пытался добавить запись в таблицу городов, если там уже есть нужный город?

    Теперь, в сервисном уровне вы вытягиваете город по его названию и если такого нет, то добавляете, а если такой город есть, то можете в методе orElseThrow() выбросить RuntimeException исключение о том, что такой город есть. Можно создать свое исключение типа: CityExistsException

    Если не хотите использовать Optional, то можно создать метод в репозитории boolean existsByCityName(String cityName); А дальше также если true, то выбрасываете исключение
    Ответ написан
    1 комментарий
  • Что делать: ошибка в компиляции, связанная с Spring Data репозиторием (Не создаётся бин)?

    azerphoenix
    @azerphoenix Куратор тега Java
    Java Software Engineer
    IllegalArgumentException: Validation failed for query for method findByBody(String body)

    Вот, краткий лог ошибки. Ошибка валидации метода.
    Могу предположить тут 2 проблемы:

    Вот, ваш код:
    public interface ExpressionRepository extends CrudRepository<ExpressionEntity, Long> {
    
        @Query("FROM ExpressionEntity WHERE ExpressionEntity.body = body")
        public Optional<ExpressionEntity> findByBody(String body);
    
    }


    Скорее всего должно быть так:
    SELECT e FROM ExpressionEntity e WHERE e.body = ?1
    Ответ написан
  • Как подменить схему базы данных в Entity Hibernate?

    azerphoenix
    @azerphoenix Куратор тега Java
    Java Software Engineer
    Здравствуйте!
    Если я правильно понял, то у вас есть база, в которой есть 2 схемы. И в зависимости от профиля вы хотите переключать схемы?

    Я вижу тут пару вариантов:
    1) на уровне gradle || maven определить схемы.
    https://stackoverflow.com/questions/47240702/jpa-e...
    https://stackoverflow.com/questions/1149352/using-...
    <profiles>
        <profile>
          <id>production</id>
          <properties>
            <schema.name>production_schema_name</schema.name>
          </properties>
        </profile>
        <profile>
          <id>test</id>
          <properties>
            <schema.name>test_schema_name</schema.name>
          </properties>
        </profile>
    </profiles>

    2) использовать различные БД для разных профилей. Т.е. создать 2 БД по одной для каждого профиля.
    3) Создать 2 пакета (dev, prod) с сущностями, где для каждой из сущностей указывать:
    Для сущностей development
    @Table(name = "VALUES", schema = "DEV").
    Для сущностей production
    @Table(name = "VALUES", schema = "PROD").
    Ну и использовать аннотацию @Profile
    Ответ написан
    Комментировать
  • Как поменять тип столбца в postgresql через spring boot?

    azerphoenix
    @azerphoenix Куратор тега Spring
    Java Software Engineer
    Здравствуйте!
    Вы можете задавать length. Например,
    @Column (length = 2000)
    private String message;

    https://www.baeldung.com/jpa-size-length-column-di...
    или
    Использовать аннотацию @Lob
    https://www.baeldung.com/hibernate-lob
    Ответ написан
    Комментировать
  • Как исправить ошибку при формировании запроса Hibernate?

    azerphoenix
    @azerphoenix Куратор тега Java
    Java Software Engineer
    Не похоже на ошибку Hibernate.
    symbol: method getSecondName()
    Уточните пожалуйста, есть ли у вас поле secondName ?
    Есть ли у вас геттер для этого поля getSecondName() ?
    Используете ли вы библиотеку lombok ? Если да, то не забыли ли вы добавить @Data или @Getter @Setter к вашим сущностям.
    Если добавили, то включен ли annotaion processor ?
    Ответ написан
    Комментировать