2013-05-07 40 views
0

想象一下,我有一个名为Photo的表格和一个名为Tag的表格。如何在休眠状态下正常化数据库? (重复的值不会被一次又一次地保存)

照片可以有任意数量的标签。像柏林勃兰登堡门的照片一样,标签为“柏林”,“门”,...

现在柏林国会大厦还有第二张照片,并且还有“柏林”作为其标签之一。

此刻这将现在得到冗余保存在我的数据库,这意味着在我的标签表“柏林”出现两次,并在我的连接表,已休眠创建每个tupel指向自己的“柏林” - 标签。

我不喜欢这种情况,因为这意味着我将冗余数据保存在我的数据库中。我更喜欢标签“柏林”只能在我的标签表中保存一次的情况,并且每个具有此标签的照片都可以获取这一个标签对象的引用。

所以总结:

之前(我希望这个现在被正确地显示,当我发出这样的疑问)

PHOTO

ID |照片名称
1 |勃兰登堡门
2 |德国国会大厦 ... | ...

TAG

ID |标记名称 1 |柏林 2 |仓鼠 3 |柏林 4 |柏林 5 |鸟 ... | ...

PHOTO_TAG(连接表)

PHOTOID | tagID 1 | 1 2 | 3 3 | 4 ... | ...

希望算账:

PHOTO

ID |照片名称
1 |勃兰登堡门
2 |德国国会大厦 ... | ...

TAG

ID |标记名称 1 |柏林 2 |仓鼠 3 |鸟 ... | ...

PHOTO_TAG(加入表) photoID | tagID 1 | 1 2 | 1 3 | 1 ... | ...

正如你所看到的,柏林只需要在Tag表中保存一次,而仍然没有信息丢失,因为连接表在tupel上引用的是正确的。

我试图用postgresql数据库中的hibernate(我不是专业版)实现这一点。我的照片班有一个属性photoTags,我给了ManyToMany关系(我认为这可能意味着每张照片可以有任何数量的标签,而每个标签可以有任何数量的照片,他们参考)

@ManyToMany(cascade = CascadeType.ALL, fetch = FetchType.EAGER) 
private Set<Tag> photoTags; 

但简单地说,这没有奏效。我的标签表中有很多冗余数据。 a 现在我的问题:你知道有足够的方法让我意识到这一点吗?感谢您的回复和评论(如果您需要更多信息,例如我的hibernate.cfg.xml,请告诉我)。

(此问题为处理类似的问题,但答案并不让我满意: Normalize repeating values in Hibernate - Java

编辑:我现在附上我的Hibernate类:

用户.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; 
} 

} 

照片的.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; 
} 
} 

Tag.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 
    } 
} 
+0

发布你所有的hibernate类。 ManyToMany应该像你期待的那样工作....我不知道你为什么得到标签重复...你有没有重写equals和hashCode? – Thihara 2013-05-07 18:17:52

+0

感谢您的评论。我附加了所有的hibernate类和我的hibernate.cfg.xml。我没有重写equals和hashCode。 – Waylander 2013-05-07 19:29:07

回答

2

你期待它的工作方式是它是如何工作的。

我没有看到你发布的Hibernate模型类有什么问题,所以我只能假设你正在为照片设置新的Tag实例,而不是加载它们并设置它们。

当你这样做时,hibernate并不知道这些对象是否相等,因为它们没有设置ID(你只需要创建它们,记得吗?)。

加载标签对象并将它们分配给照片,或者如果您决定添加新实例,请删除cascade all选项并覆盖equals方法,以便在ID未设置(空)的情况下考虑除ID之外的其他详细信息。

+1

非常感谢您的回答!你让我走上了正确的道路,因为我一直在创造新的Tag实例,一直认为hibernate实际上会为我过滤掉它。 我现在为每个标记检查它是否已经存在于标记表中,如果这样做,我将检索它并将其分配给照片。 这对前200张照片非常有用,然后我得到了一个“org.hibernate.NonUniqueObjectException:具有相同标识符值的不同对象已经与会话关联”标记对象上的异常。 (接下来的评论,没有更多的空间......) – Waylander 2013-05-08 23:33:15

+0

我不知道为什么会发生这种情况。也许(?!),因为标签对象SOMEHOW陷入困境,因为它现在被分配到比以前更多的照片(虽然我不明白为什么这会发生在照片〜200)。任何想法?我的大脑很艰难:-) 无论如何,我解决了在UserDAO中使用session.merge()而不是session.saveOrUpdate()的情况。你认为我可能会遇到另一个使用merge()的麻烦吗? 对不起,很长的评论,谢谢你的伟大答案! – Waylander 2013-05-08 23:37:10

+0

合并方法没有错。恐怕我不能很好地告诉你为什么这个错误可能发生,而没有查看整个代码和调试:-) – Thihara 2013-05-09 03:39:02

相关问题