Bazy danych, encje, Spring Data JPA, Hibernate, - rlip/java GitHub Wiki

W SpringBoot możemy dać do do katalogu src/main/resources pliki schema.sql i data.sql - wtedy spring boot uruchomi je. Można też wypisać nazwy plików w spring.datasource.schema. i spring.datasource.data.

spring:
   datasource:
     schema:
     - order-schema.sql
     - ingredient-schema.sql    
     data:     
     - ingredients.sql

Encje

    @Entity(name = "someThing") - nazwa nie potrzebna
    @Table(name = "someThing") - zmiana domyślnej nazwy tabeli
    
    @Id    // to i to poniżej przed wartością - spring mapuje na pola, - przed geterem - mapuje przez getery i setery
    @GeneratedValue(strategy = GenerationType.AUTO) 
    
    @Transient - nie będzie w bazie
    @Embedded - dla wygody w innej klasie, będzie w tej samej tabeli
    @Column(name = "Opis") // zmiana nazwy kolumny, można tak też inne rzeczy

    @ManyToMany(fetch = FetchType.LAZY, cascade = {CascadeType.DETACH, CascadeType.MERGE, CascadeType.PERSIST, CascadeType.REFRESH})
    @JoinTable(name = "employee_training", joinColumns = @JoinColumn(name = "id_training"), inverseJoinColumns = @JoinColumn(name="id_employee"))
    private List<Employee> employees;

Spring Data JPA

@Repository
public interface UserFbGroupRepository extends JpaRepository<UserFbGroup, Long> {

    Optional<UserFbGroup> findFirstByFbGroupAndUser(FbGroup fbGroup, User user);

    List<UserFbGroup> findByUserAndIsGroupVisibleOnHisGroupList(User user, Boolean isGroupVisibleOnHisGroupList);

    @Transactional
    void deleteByUser(User user);
}
////
public interface UserChatRepository extends JpaRepository<UserChat, Long> {

    @Query("SELECT uch1 FROM Chat ch " +
            "INNER JOIN ch.userChats uch1 INNER JOIN ch.userChats uch2 " +
            "WHERE uch1.user = :firstUser AND uch2.user = :secondUser")
    Optional<UserChat> findBetweenTwoUsers(@Param("firstUser") User firstUser, @Param("secondUser") User secondUser);


    @Query("SELECT uchat FROM UserChat uchat " +
            "INNER JOIN FETCH uchat.chat chat " +
            "WHERE uchat.user = :user " +
            "ORDER BY chat.lastMessageAt DESC")
    List<UserChat> findByUserOrderByLastMessageAtDesc(@Param("user") User user);

    @Transactional
    @Modifying
    @Query("update UserChat uchat set uchat.hasUnreadMessages = false where uchat.user = :user")
    void setAllAsReadByUser(@Param("user") User user);
}

Na początku find, read, get (te 3 są równoważne) albo count, potem:

  • Equals, Between.
  • IsAfter, After, IsBefore, Before
  • IsGreaterThan, GreaterThan, IsGreaterThanEqual, GreaterThanEqual.
  • IsLessThan, LessThan, IsLessThanEqual, LessThanEqual.
  • IsBetween, Between.
  • IsNull, Null, IsNotNull, NotNull.
  • IsIn, In, IsNotIn, NotIn.
  • IsStartingWith, StartingWith, StartsWith.
  • IsEndingWith, EndingWith, EndsWith.
  • IsContaining, Containing, Contains.
  • IsLike, Like, IsNotLike, NotLike.
  • IsTrue, True, IsFalse, False.
  • Is, Equals, IsNot, Not.
  • IgnoringCase, IgnoresCase.
  • AllIgnoringCase, AllIgnoresCase - stosuje dla wszystkich operacji porównywania ciągów tekstowych np. List<Order> findByDeliveryToAndDeliveryCityAllIgnoresCase(String deliveryTo, String deliveryCity);
  • OrderBy np. List<Order> findByDeliveryCityOrderByDeliveryTo(String city);

Inne:

    @PersistenceContext 
    private EntityManager entityManager;
    
    @Transactional - metoda jest bazodanową transakcją
    entityManager.merge(quest); // zaktualizuje quest  - jeśli quest ma id, lub utworzy jeśli nie ma, i zwraca obiekt zaktualizowany
    entityManager.persist(aga); // persist nic nie zwraca
    entityManager.detach(employee); // odłącza employee od zarządzania przez entityManager, merge może go dołączyć
    
    @Embedded // dołącza pola innej klasy do naszej encji
    private Address address;
    @Embeddable // to jeszcze można dać przed taką klasą
    
   @NamedQueries({
       @NamedQuery(name="Student.getAll", query= "Select s From Student s"),
       @NamedQuery(name="Student.byName", query= "Select s From Student s where s.name = :name"),
   }) // coś takego można przed encją, potem takie odwołanie
    entityManager.createNamedQuery("Student.byName", Student.class).setParameter("name", "Ania").getResultList().forEach(System.out::println);
Company:
    @OneToOne(cascade = {CascadeType.PERSIST, CascadeType.REMOVE})
    @JoinColumn(name="id_company_detail")
    private CompanyDetail companyDetail;

    @OneToMany(fetch = FetchType.LAZY, mappedBy = "company", cascade = {CascadeType.PERSIST, CascadeType.DETACH, CascadeType.MERGE, CascadeType.REFRESH})
    private List<Property> properties;

    @OneToMany(cascade = CascadeType.ALL, fetch = FetchType.LAZY)
    @JoinColumn(name="id_company")
    private Set<Department> departments;

    @ManyToMany(fetch = FetchType.LAZY, cascade = {CascadeType.DETACH, CascadeType.MERGE, CascadeType.PERSIST, CascadeType.REFRESH})
    @JoinTable(name = "employee_training", joinColumns = @JoinColumn(name = "id_employee"), inverseJoinColumns = @JoinColumn(name="id_training"))
    private List<Employee> employee;
--------------------------
Property
    @ManyToOne
    @JoinColumn(name="id_company")
    private Company company;
--------------------------
Traning
    @ManyToMany(fetch = FetchType.LAZY, cascade = {CascadeType.DETACH, CascadeType.MERGE, CascadeType.PERSIST, CascadeType.REFRESH})
    @JoinTable(name = "employee_training", joinColumns = @JoinColumn(name = "id_training"), inverseJoinColumns = @JoinColumn(name="id_employee"))
    private List<Employee> employees;

Hibernate

    persistence.xml w META-INF, lub hibernate.cfg.xml

    EntityManagerFactory factory = Persistence.createEntityManagerFactory("MyPersistence");
    EntityManager entityManager = factory.createEntityManager();

Fetch

Argument fetch określa sposób, w jaki powiązane obiekty są pobierane z bazy. Przyjmuje enum FetchType, który ma dwie wartości:

  • EAGER – obiekty powiązane z użyciem tego FetchType będą automatycznie wyciągane z bazy przez Hibernate, przy wczytaniu obiektu bazowego
  • LAZY – obiekty z FetchType.LAZY nie będą pobierane od razu razem z obiektem bazowym, a dopiero wtedy, gdy ich zażądamy. @OneToMany i @ManyToMany mają domyślnie FetchType.LAZY, to jednak @OneToOne i @ManyToOne mają domyślnie zdefiniowany FetchType.EAGER

Cascade

Kaskadowanie operacji na encjach oznacza, że jeśli wykonamy konkretną operację na obiekcie to obiekty powiązane relacją też zostaną poddane tej operacji. Jeśli chcemy je włączyć, podajemy do argumentu cascade enum CascadeType, który przyjmuje wartości:

  • PERSIST – kaskada przy metodzie persist(), czyli zapisywaniu nowego obiektu w bazie
  • MERGE – kaskada przy metodzie merge(), czyli modyfikowaniu obiektu już istniejącego w bazie
  • REMOVE – kaskada przy metodzie remove(), czyli usuwaniu obiektu z bazy
  • DETACH – kaskada przy metodzie detach(), która wyrzuca dany obiekt z puli obiektów oczekujących na zapisanie w bazie
  • REFRESH – kaskada przy metodzie refresh(), służącej do ponownego załadowywania obiektów z bazy
  • ALL – kaskada dla wszystkich powyższych operacji

@JsonIgnore - dla jednej strony, żeby nie było nieskończonych pętli

JDBC

    Connection connection = DriverManager.getConnection("org.h2.Driver", "", "");
    Statement statement = connection.createStatement();
    
    String insert = "INSERT INTO STUDENT VALUES(" + student.getId() + ",'" + student.getName() + "')";
    statement.execute(insert); 
    
    ResultSet resultSet = statement.executeQuery(select);
⚠️ **GitHub.com Fallback** ⚠️