Photo というテーブルと Tag というテーブルがあるとします。
写真には任意の数のタグを付けることができます。ベルリンのブランデンブルク門の写真のように、タグとして「ベルリン」、「ゲート」、...
現在、ベルリン国会議事堂の 2 番目の写真があり、タグの 1 つとして「ベルリン」も含まれています。
現時点では、これはデータベースに重複して保存されます。これは、タグテーブルに「ベルリン」が2回表示され、休止状態によって作成された結合テーブルで、各タペルが独自の「ベルリン」タグに向けられることを意味します。
この状況は好きではありません。これは、データベースに冗長なデータを保存していることを意味するからです。タグ「ベルリン」がタグテーブルに一度だけ保存され、このタグを持つ各写真がこの1つのタグオブジェクトで参照を取得する場合がもっと好きです。
要約すると:
以前(この質問を送信したときに、これが正しく表示されることを願っています)
写真
ID | 写真名
1 | ブランデンブルク門
2 | ドイツ国会議事堂 ...| ...
鬼ごっこ
ID | タグネーム 1 | ベルリン 2 | ハムスター 3 | ベルリン 4 | ベルリン 5 | 鳥 ...| ...
PHOTO_TAG (結合テーブル)
写真付き身分証明書 | タグ ID 1 | 1 2 | 3 3 | 4 ... | ...
うまくいけばその後:
写真
ID | 写真名
1 | ブランデンブルク門
2 | ドイツ国会議事堂 ...| ...
鬼ごっこ
ID | タグネーム 1 | ベルリン 2 | ハムスター 3 | 鳥 ...| ...
PHOTO_TAG (結合テーブル) 写真 ID | タグ ID 1 | 1 2 | 1 3 | 1 ... | ...
ご覧のように、Berlin はタグ テーブルに 1 回保存するだけで済みますが、結合テーブルはタペルで正しく参照されるため、情報が失われることはありません。
postgresqlデータベースで休止状態(私はプロではありません)でこれを達成しようとしました。私の Photo-Class には属性 photoTags があり、これに ManyToMany 関係を与えました (これは、すべての写真が任意の数のタグを持つことができ、すべてのタグが参照されている写真を任意の量を持つことができることを意味する可能性があると考えました)
@ManyToMany(cascade = CascadeType.ALL, fetch = FetchType.EAGER)
private Set<Tag> photoTags;
しかし、単純に、これはうまくいきませんでした。タグ テーブルに冗長なデータがたくさんあります。a さて私の質問: 私がこれを実現するのに十分な方法を知っていますか? すべての回答とコメントに感謝します(hibernate.cfg.xml などの詳細情報が必要な場合は、教えてください)。
(この質問はここで同様の問題を扱っていますが、答えは私にとって満足のいくものではありません: Hibernate - Java で繰り返し値を正規化します)
編集:私は今、休止状態のクラスを添付します:
ユーザー.java
import java.util.Date;
import java.util.Set;
import javax.persistence.CascadeType;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.FetchType;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
import javax.persistence.OneToMany;
import javax.persistence.Table;
@Entity
@Table(name = "users")
public class User {
@Id
@GeneratedValue
private Long id;
@Column(unique = true)
private String userID;
private String userName;
private String userRealName;
private int userPhotoCount;
private Date userPhotoF;
private Date userPhot_1;
private String userLocation;
private String userThumbnailURL;
private int userIsPro;
private int userIsAdmin;
private int userContact;
private int userPhotoS;
@OneToMany(cascade = CascadeType.ALL, fetch = FetchType.EAGER)
private Set<Photo> photos;
public User(String userID, String userName, String userRealName, int userPhotoCount,
Date userPhotoF, Date userPhot_1, String userLocation,
String userThumbnailURL, int userIsPro, int userIsAdmin,
int userContact, int userPhotoS, Set<Photo> photos) {
this.userID = userID;
this.userName = userName;
this.userRealName = userRealName;
this.userPhotoCount = userPhotoCount;
this.userPhotoF = userPhotoF;
this.userPhot_1 = userPhot_1;
this.userLocation = userLocation;
this.userThumbnailURL = userThumbnailURL;
this.userIsPro = userIsPro;
this.userIsAdmin = userIsAdmin;
this.userContact = userContact;
this.userPhotoS = userPhotoS;
this.photos = photos;
}
// Hibernate requirement
public User() {
}
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public String getUserID() {
return userID;
}
public void setUserID(String userID) {
this.userID = userID;
}
public String getUserRealName() {
return userRealName;
}
public void setUserRealName(String userRealName) {
this.userRealName = userRealName;
}
public int getUserPhotoCount() {
return userPhotoCount;
}
public void setUserPhotoCount(int userPhotoCount) {
this.userPhotoCount = userPhotoCount;
}
public Date getUserPhotoF() {
return userPhotoF;
}
public void setUserPhotoF(Date userPhotoF) {
this.userPhotoF = userPhotoF;
}
public Date getUserPhot_1() {
return userPhot_1;
}
public void setUserPhot_1(Date userPhot_1) {
this.userPhot_1 = userPhot_1;
}
public String getUserLocation() {
return userLocation;
}
public void setUserLocation(String userLocation) {
this.userLocation = userLocation;
}
public String getUserThumbnailURL() {
return userThumbnailURL;
}
public void setUserThumbnailURL(String userThumbnailURL) {
this.userThumbnailURL = userThumbnailURL;
}
public int getUserIsPro() {
return userIsPro;
}
public void setUserIsPro(int userIsPro) {
this.userIsPro = userIsPro;
}
public int getUserIsAdmin() {
return userIsAdmin;
}
public void setUserIsAdmin(int userIsAdmin) {
this.userIsAdmin = userIsAdmin;
}
public int getUserContact() {
return userContact;
}
public void setUserContact(int userContact) {
this.userContact = userContact;
}
public int getUserPhotoS() {
return userPhotoS;
}
public void setUserPhotoS(int userPhotoS) {
this.userPhotoS = userPhotoS;
}
public Set<Photo> getUserPhotos() {
return photos;
}
public void setUserPhotos(Set<Photo> userPhotos) {
this.photos = userPhotos;
}
public void addPhoto(Photo photo){
this.photos.add(photo);
}
public String getUserName() {
return userName;
}
public void setUserName(String userName) {
this.userName = userName;
}
}
Photo.java
import java.util.Date;
import java.util.Set;
import javax.persistence.CascadeType;
import javax.persistence.Entity;
import javax.persistence.FetchType;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
import javax.persistence.ManyToMany;
@Entity
public class Photo {
@Id
@GeneratedValue
private Long id;
private Long photoID;
private String photoTitle;
private String photoUrl;
private int photoAccur;
@ManyToMany(cascade = CascadeType.ALL, fetch = FetchType.EAGER)
private Set<Tag> photoTags;
private int photoTagsCount;
// ist das korrekt?
private int photoCommentCount;
// date objekte
private Date photoDateP;
private Date photoDateT;
private String photoDescription;
// korrekter Name?
private String photoNotes;
private int photoNot_1;
private String photoMedia;
private String photoMed_1;
private int photoLicense;
private int photoIsFam;
private int photoIsFri;
private int photoIsPri;
// x-Achse
private float photoLongitude;
// y-Achse
private float photoLatitude;
public Photo(Long photoID, String photoTitle, String photoURL,
int photoAccur, Set<Tag> photoTags, int photoTagsCount,
int photoCommentCount, Date photoDateP, Date photoDateT,
String photoDescription, String photoNotesCount, int photoNot_1,
String photoMedia, String photoMed_1, int photoLicense,
int photoIsFam, int photoIsFri, int photoIsPri, float photoLongi,
float photoLatit) {
this.photoID = photoID;
this.photoTitle = photoTitle;
this.photoUrl = photoURL;
this.photoAccur = photoAccur;
this.photoTags = photoTags;
this.photoTagsCount = photoTagsCount;
this.photoCommentCount = photoCommentCount;
this.photoDateP = photoDateP;
this.photoDateT = photoDateT;
this.photoDescription = photoDescription;
this.photoNotes = photoNotesCount;
this.photoNot_1 = photoNot_1;
this.photoMedia = photoMedia;
this.photoMed_1 = photoMed_1;
this.photoLicense = photoLicense;
this.photoIsFam = photoIsFam;
this.photoIsFri = photoIsFri;
this.photoIsPri = photoIsPri;
this.photoLongitude = photoLongi;
this.photoLatitude = photoLatit;
}
// hibernate
public Photo() {
}
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public Long getPhotoID() {
return photoID;
}
public void setPhotoID(Long photoID) {
this.photoID = photoID;
}
public String getPhotoTitle() {
return photoTitle;
}
public void setPhotoTitle(String photoTitle) {
this.photoTitle = photoTitle;
}
public String getPhotoUrl() {
return photoUrl;
}
public void setPhotoUrl(String photoUrl) {
this.photoUrl = photoUrl;
}
public int getPhotoAccur() {
return photoAccur;
}
public void setPhotoAccur(int photoAccur) {
this.photoAccur = photoAccur;
}
public Set<Tag> getPhotoTags() {
return photoTags;
}
public void setPhotoTags(Set<Tag> photoTags) {
this.photoTags = photoTags;
}
public int getPhotoTagsCount() {
return photoTagsCount;
}
public void setPhotoTagsCount(int photoTagsCount) {
this.photoTagsCount = photoTagsCount;
}
public int getPhotoCommentCount() {
return photoCommentCount;
}
public void setPhotoCommentCount(int photoCommentCount) {
this.photoCommentCount = photoCommentCount;
}
public Date getPhotoDateP() {
return photoDateP;
}
public void setPhotoDateP(Date photoDateP) {
this.photoDateP = photoDateP;
}
public Date getPhotoDateT() {
return photoDateT;
}
public void setPhotoDateT(Date photoDateT) {
this.photoDateT = photoDateT;
}
public String getPhotoDescription() {
return photoDescription;
}
public void setPhotoDescription(String photoDescription) {
this.photoDescription = photoDescription;
}
public String getPhotoNotesCount() {
return photoNotes;
}
public void setPhotoNotesCount(String photoNotesCount) {
this.photoNotes = photoNotesCount;
}
public int getPhotoNot_1() {
return photoNot_1;
}
public void setPhotoNot_1(int photoNot_1) {
this.photoNot_1 = photoNot_1;
}
public String getPhotoMedia() {
return photoMedia;
}
public void setPhotoMedia(String photoMedia) {
this.photoMedia = photoMedia;
}
public String getPhotoMed_1() {
return photoMed_1;
}
public void setPhotoMed_1(String photoMed_1) {
this.photoMed_1 = photoMed_1;
}
public int getPhotoLicense() {
return photoLicense;
}
public void setPhotoLicense(int photoLicense) {
this.photoLicense = photoLicense;
}
public int getPhotoIsFam() {
return photoIsFam;
}
public void setPhotoIsFam(int photoIsFam) {
this.photoIsFam = photoIsFam;
}
public int getPhotoIsFri() {
return photoIsFri;
}
public void setPhotoIsFri(int photoIsFri) {
this.photoIsFri = photoIsFri;
}
public int getPhotoIsPri() {
return photoIsPri;
}
public void setPhotoIsPri(int photoIsPri) {
this.photoIsPri = photoIsPri;
}
public float getPhotoLongi() {
return photoLongitude;
}
public void setPhotoLongi(float photoLongi) {
this.photoLongitude = photoLongi;
}
public float getPhotoLatit() {
return photoLatitude;
}
public void setPhotoLatit(float photoLatit) {
this.photoLatitude = photoLatit;
}
}
タグ.java
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
@Entity
public class Tag {
@Id
@GeneratedValue
private Long id;
private String tag;
public Tag(String tag) {
this.tag = tag;
}
public Tag() {
}
public String getTag() {
return tag;
}
public void setTag(String tag) {
this.tag = tag;
}
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
}
私の Hibernate.cfg.xml
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE hibernate-configuration PUBLIC
"-//Hibernate/Hibernate Configuration DTD 3.0//EN"
"http://hibernate.sourceforge.net/hibernate-configuration-3.0.dtd">
<hibernate-configuration>
<session-factory>
<property name="hibernate.connection.driver_class">org.postgresql.Driver</property>
<property name="hibernate.connection.url">jdbc:postgresql://localhost:5432/GIS</property>
<property name="hibernate.dialect">org.hibernate.dialect.PostgreSQLDialect</property>
<property name="hibernate.connection.username">postgres</property>
<property name="hibernate.connection.password">mysql15</property>
<property name="hibernate.current_session_context_class">thread</property>
<property name="hibernate.hbm2ddl.auto">create</property>
<property name="hibernate.show_sql">false</property>
<mapping class="database.User" />
<mapping class="database.Photo" />
<mapping class="database.Tag" />
</session-factory>
</hibernate-configuration>
**そして今、私のセッション管理を休止状態で扱っているいくつかのクラス。それらはおそらくそれほど重要ではありませんが、念のため。**
DAO.java
import org.hibernate.HibernateException;
import org.hibernate.Session;
import org.hibernate.stat.Statistics;
/**
* DAO provides general access methods on the database related to session
* management (opening and closing)
*
*
*
*/
public abstract class DAO {
/**
* Logs about correct behaviour of the hibernate session management
*/
public static Statistics stats = statistics();
/**
* Ensures that every client gets his correct session
*/
private static final ThreadLocal<Session> sessions = new ThreadLocal<>();
/**
* Returns the current hibernate session. Also takes care that there's
* always an open hibernate transaction when needed.
*
* @return Current hibernate session
*/
public static Session getSession() {
Session result = sessions.get();
if (result == null) {
result = HibernateUtil.getSessionFactory().openSession();
sessions.set(result);
result.beginTransaction();
}
return result;
}
/**
* Closes the current hibernate session, if there is one.
*/
public static void closeSession() {
Session sess = sessions.get();
if (sess == null || !sess.isOpen())
return;
sessions.remove();
try {
Throwable error = null;
try {
if (sess.getTransaction().isActive() == true) {
sess.getTransaction().commit();
}
} catch (Throwable e) {
sess.getTransaction().rollback();
error = e;
} finally {
try {
System.out.println("Sessions geöffnet bisher: "
+ stats.getSessionOpenCount());
sess.close();
System.out.println("Sessions geschlossen bisher: "
+ stats.getSessionCloseCount());
} catch (Throwable th) {
if (error != null) {
error.addSuppressed(th);
} else {
throw th;
}
}
}
} catch (HibernateException ex) {
ex.printStackTrace();
}
}
public static Statistics statistics() {
Statistics stats = HibernateUtil.getSessionFactory().getStatistics();
stats.setStatisticsEnabled(true);
return stats;
}
}
UserDAO.java
import java.util.List;
import org.hibernate.Session;
public class UserDAO extends DAO {
public void createUser(User user) {
if (user == null) {
throw new IllegalArgumentException("user must be not null");
}
Session session = getSession();
// speichern des test in der datenbank
session.save(user);
closeSession();
}
public void updateUser(User user) {
if (user == null) {
throw new IllegalArgumentException("User doesnt exist");
}
Session session = getSession();
// updaten des Users in der datenbank
session.saveOrUpdate(user);
closeSession();
}
public User getUser(Long userID) {
Session session = getSession();
@SuppressWarnings("unchecked")
List<User> oneUser = session.createQuery(
"FROM User WHERE id = " + userID).list();
closeSession();
return oneUser.get(0);
}
public User getUserByUserID(String userID) {
Session session = getSession();
@SuppressWarnings("unchecked")
List<User> oneUser = session.createQuery(
"FROM User WHERE userID = '" + userID + "'").list();
closeSession();
if (oneUser.size() > 0) {
return oneUser.get(0);
} else {
// user existiert nicht
return null;
}
}
public List<User> getAllUsers() {
Session session = getSession();
@SuppressWarnings("unchecked")
List<User> allUsers = session.createQuery("FROM users").list();
closeSession();
return allUsers;
}
}
HibernateUtil.java
import org.hibernate.SessionFactory;
import org.hibernate.cfg.Configuration;
/**
* HibernateUtil manages the access to the sessionFactory, which ensures that
* there's always an open database session
*
*
*
*/
@SuppressWarnings("deprecation")
public class HibernateUtil {
final private static SessionFactory sessionFactory;
static {
try {
// create the sessionfactory from standardconfig file
sessionFactory = new Configuration().configure("hibernate.cfg.xml")
.buildSessionFactory();
} catch (Throwable ex) {
// log the exception
System.err.println("Initial SessionFactory creation failed." + ex);
throw new ExceptionInInitializerError(ex);
}
}
/**
* Returns the current SessionFactory
*
* @return Current SessionFactory
*/
public static SessionFactory getSessionFactory() {
return sessionFactory;
}
}
HibernateListener.java
import javax.servlet.ServletContextEvent;
import javax.servlet.ServletContextListener;
/**
* The HibernateListener takes care that hibernate for the database connection
* management gets initialised on the server start.
*/
public class HibernateListener implements ServletContextListener {
/**
* Calls the static initializer of the HibernateUtil class
*/
public void contextInitialized(ServletContextEvent event) {
HibernateUtil.getSessionFactory(); // Just call the static initializer
// of that class
}
/**
* Frees all ressources when the server is being restarted
*/
public void contextDestroyed(ServletContextEvent event) {
HibernateUtil.getSessionFactory().close(); // Free all resources
}
}