Versions Compared

Key

  • This line was added.
  • This line was removed.
  • Formatting was changed.

Wstęp

Mechanizm wtyczek dostarcza narzędzi, które umożliwiają wtyczkom korzystanie z bazy danych. Zalecanym sposobem jest używanie biblioteki Hibernate.

Wtyczka może uzyskać dostęp do jakiejkolwiek bazy danych, jednak w tym rozdziale opisana zostanie tylko obsługa systemowej bazy danych.

Konfiguracja obiektów

W rozdziale Konfiguracja kontekstu wtyczki opisane zostało, w jaki sposób dodawać beany do kontekstu. Obsługa bazy danych bazować będzie na integracji SpringFramework i Hibernate. Opisana zostanie konfiguracja XML.

Aby zarejestrować SessionFactory wystarczy dodać taką deklarację bean'a. Obiekt automatycznie konfiguruje używany dialect, datasource etc.

Code Block
languagehtml/xml
titleplugin-context.xml
<bean id="sessionFactory" class="com.suncode.pwfl.persistence.support.hibernate.SystemBaseSessionFactoryBean">
	<property name="packagesToScan" value="com.suncode.plugin.tutorial" />
</bean>
Info

Klasa com.suncode.pwfl.persistence.support.hibernate.SystemBaseSessionFactoryBean bazuje na klasie LocalSessionFactoryBean. Tam również znajduje się dokumentacja.

 

Prawdopodobnie chcemy także wykorzystać inne mechanizmy, które upraszczają kod transakcyjny:

Code Block
languagehtml/xml
titleplugin-context.xml
<!-- adnotacje @Transactional -->
<tx:annotation-driven/>
 
<!-- TransactionManager -->
<bean name="transactionManager" class="org.springframework.orm.hibernate4.HibernateTransactionManager">
	<property name="sessionFactory" ref="sessionFactory" />
</bean>

Przykład działania

Teraz należy stworzyć naszą encję:

Code Block
languagejava
titleNote
@Entity
@Table(name = "pm_tutorial_note")
@SequenceGenerator(name = "note", sequenceName = "pm_tutorial_note_id")
public class Note {
 
	@Id
    @GeneratedValue(strategy = GenerationType.AUTO, generator = "note")
	private Long id;
 
	@Column(length = 2000)
	private String text;
 
	// getters...
	// setters...
}
Note

Nazwy tabel, kolumn i sequencerów nie powinny przekraczać 30 znaków (limit Oracle)

 

Zapis i odczyt naszego obiektu może wyglądać tak:

Code Block
languagejava
titleNoteService
@Service
@Transactional
public class NoteService {
 
	@Autowired
	private SessionFactory sessionFactory;
 
	public void saveNote(Note note){
		sessionFactory.getCurrentSession().save(note);
	}
 
	public Note getNote(Long id){
		return (Note) sessionFactory.getCurrentSession().get(Note.class, id);
	}
}
Tip

Jakiekolwiek zmiany dokonane we wtyczce nie wymagają restartu serwera. Nawet zmiany mappingu hibernate są widoczne po aktualizacji wtyczki.

Wykorzystanie w mappingu systemowych encji

Może się zdarzyć, że w naszej encji potrzebujemy mapping np. na użytkownika systemu. W takim wypadku musimy zaimportować mapping użytkownika, żeby nasza instancja SessionFactory miała wszystkie potrzebne do zapisu w bazie danych informacje.

Import mappingów z systemu odbywa się podczas konfiguracji SessionFactory Hibernate'a:

Code Block
languagehtml/xml
titleplugin-context.xml
<bean id="sessionFactory" class="com.suncode.pwfl.persistence.support.hibernate.SystemBaseSessionFactoryBean">
	<property name="packagesToScan" value="com.suncode.plugin.tutorial" />
	
	<!-- Musimy zaimportować całe drzewo zależności -->
	<property name="importedMappings">
		<array>
			<value>com.suncode.pwfl.administration.user.User</value>
			<value>com.suncode.pwfl.administration.user.UserGroup</value>
			<value>com.suncode.pwfl.administration.structure.Position</value>
			<value>com.suncode.pwfl.administration.structure.OrganizationalUnit</value>
			<value>com.suncode.pwfl.administration.structure.Role</value>
		</array>
	</property>
</bean>
Note

Aktualnie musimy samodzielnie wypisać wszystkie zależności, nawet te przejściowe. Jeżeli chcemy zaimportować tylko użytkownika, musimy zaimportować jeszcze 4 inne mappingi jak pokazano powyżej.

Planowane jest poprawienie sposobu importu mappingów.

 

Nasza zaktualizowana encja:

Code Block
languagejava
titleNote
@Entity
@Table(name = "pm_tutorial_note")
@SequenceGenerator(name = "note", sequenceName = "pm_tutorial_note_id")
public class Note {
 
	@Id
    @GeneratedValue(strategy = GenerationType.AUTO, generator = "note")
	private Long id;
 
	@Column(length = 2000)
	private String text;
	
	@ManyToOne
    @JoinColumn(name = "user_id")
    @OnDelete(action = OnDeleteAction.CASCADE)
	private User user;
 
	// getters...
	// setters...
}
Tip

Dodanie obiektu użytkownika do naszej encji zaowocuje dodaniem klucza obcego w schemacie bazy danych. Niestety w takim wypadku nie będzie możliwe usunięcie użytkownika z systemu, dopóki nie zostaną usunięte wszystkie jego notatki.

Adnotacja:

@OnDelete(action = OnDeleteAction.CASCADE)

Dodaje kaskadowe usuwanie na poziomie schematu bazy danych (w przeciwieństwie do opcji cascade annotacji), dzięki czemu podczas usuwania użytkownika, usunięte zostaną wszystkie jego notatki.

Potrzebne jest inne rozwiązanie tego problemu, jednak aktualnie jest to jedyna opcja.