2014-02-02 2 views
0

Позвольте мне сказать, что я не программист на Java, но я пытаюсь изучить некоторые новые (для меня) вещи.Hibernate 4.3 Spring 4 пакетная вставка с таблицей ассоциаций

Я два следующих объектов DAO: Полка

package org.sample.bookshelf.model; 

import java.util.Set; 

import javax.persistence.CascadeType; 
import javax.persistence.Entity; 
import javax.persistence.GeneratedValue; 
import javax.persistence.GenerationType; 
import javax.persistence.Id; 
import javax.persistence.JoinColumn; 
import javax.persistence.JoinTable; 
import javax.persistence.OneToMany; 
import javax.persistence.Table; 

@Entity 
@Table(name="shelves") 
public class Shelf { 
    @Id 
    @GeneratedValue(strategy=GenerationType.IDENTITY) 
    private Long id; 
    private String name; 

    @OneToMany(cascade=CascadeType.ALL) 
    @JoinTable(name="shelf_books", 
     joinColumns = {@JoinColumn(name="shelf_id", referencedColumnName="id")}, 
     inverseJoinColumns = {@JoinColumn(name="book_id", referencedColumnName="id")} 
    ) 
    private Set<Book> shelfBooks; 

    public Shelf() {} 

    public Shelf(String name) { 
     this.name = name; 
    } 

    public Long getId() { 
     return id; 
    } 
    public void setId(Long id) { 
     this.id = id; 
    } 


    public String getName() { 
     return name; 
    } 
    public void setName(String name) { 
     this.name = name; 
    } 

    public Set<Book> getShelfBooks() { 
     return shelfBooks; 
    } 
    public void setShelfBooks(Set<Book> shelfBooks) { 
     this.shelfBooks = shelfBooks; 
    } 
} 

и Книга

package org.sample.bookshelf.model; 

import javax.persistence.CascadeType; 
import javax.persistence.Entity; 
import javax.persistence.GeneratedValue; 
import javax.persistence.GenerationType; 
import javax.persistence.Id; 
import javax.persistence.JoinColumn; 
import javax.persistence.JoinTable; 
import javax.persistence.OneToOne; 
import javax.persistence.Table; 

@Entity 
@Table(name="books") 
public class Book { 
    @Id 
    @GeneratedValue(strategy=GenerationType.IDENTITY) 
    private Long id; 
    private String title; 

    @OneToOne(cascade=CascadeType.ALL) 
    @JoinTable(name="shelf_books", 
     joinColumns = {@JoinColumn(name="book_id", referencedColumnName="id")}, 
     inverseJoinColumns = {@JoinColumn(name="shelf_id", referencedColumnName="id")} 
    ) 
    private Shelf block; 

    public Book() { 
    } 

    public Book(String title) 
    { 
     this.title = title; 
    } 

    public Long getId() { 
     return id; 
    } 
    public void setId(Long id) { 
     this.id = id; 
    } 

    public String getTitle() { 
     return title; 
    } 

    public void setTitle(String title) { 
     this.title = title; 
    } 

    public Shelf getShelf() { 
     return block; 
    } 

    public void setShelf(Shelf block) { 
     this.block = block; 
    } 
} 

, как вы можете видеть, что они связаны с помощью таблицей: * shelf_books *

Сейчас в BookDaoImpl Я хотел бы иметь метод с все или ничего поведения, , что позволит мне сэкономить несколько книг, это выглядит следующим образом:

@Override 
public void saveMulti(List<Book> books) { 
    Session sess = sessionFactory.openSession(); 
    org.hibernate.Transaction tx = null; 
    try { 
     tx = sess.beginTransaction(); 
     int i = 0; 
     for (Book b : books) { 
      logger.debug(String.format("%d %s ", b.getId(), b.getTitle())); 
      sess.saveOrUpdate(b); 

      i++; 
      if (i == 20) { 
       sess.flush(); 
       sess.clear(); 
       i = 0; 
      } 
     } 
     logger.debug("saving..."); 
     tx.commit(); 
     logger.debug("done..."); 

    } catch (RuntimeException e) { 
     if (tx != null) tx.rollback(); 
     e.printStackTrace(); 

    } finally { 
     sess.close(); 
    } 
} 

По какой-то причине, данные в таблице ассоциации добавляется, чем удаляется, это видно в следующем журнале, содержащем УДАЛИТЬ org.sample.bookshelf.model.Shelf.shelfBooks коллекция:

16:08:13,857 DEBUG BookDaoImpl:58 - saving... 
16:08:13,857 DEBUG AbstractTransactionImpl:175 - committing 
16:08:13,857 DEBUG AbstractFlushingEventListener:149 - Processing flush-time cascades 
16:08:13,857 DEBUG AbstractFlushingEventListener:189 - Dirty checking collections 
16:08:13,859 DEBUG AbstractFlushingEventListener:123 - Flushed: 0 insertions, 1 updates, 0 deletions to 11 objects 
16:08:13,859 DEBUG AbstractFlushingEventListener:130 - Flushed: 0 (re)creations, 0 updates, 1 removals to 0 collections 
16:08:13,859 DEBUG EntityPrinter:114 - Listing entities: 
16:08:13,860 DEBUG EntityPrinter:121 - org.sample.bookshelf.model.Book{id=2, title=The City of the Sun, block=org.sample.bookshelf.model.Shelf#1} 
16:08:13,860 DEBUG EntityPrinter:121 - org.sample.bookshelf.model.Shelf{id=1, shelfBooks=null, name=dystopia} 
16:08:13,860 DEBUG EntityPrinter:121 - org.sample.bookshelf.model.Book{id=1, title=1984, block=org.sample.bookshelf.model.Shelf#1} 
16:08:13,860 DEBUG EntityPrinter:121 - org.sample.bookshelf.model.Book{id=6, title=Logan's Run, block=org.sample.bookshelf.model.Shelf#1} 
16:08:13,860 DEBUG EntityPrinter:121 - org.sample.bookshelf.model.Book{id=5, title=Slaughterhouse Five, block=org.sample.bookshelf.model.Shelf#1} 
16:08:13,860 DEBUG EntityPrinter:121 - org.sample.bookshelf.model.Book{id=4, title=Fahrenheit 451, block=org.sample.bookshelf.model.Shelf#1} 
16:08:13,861 DEBUG EntityPrinter:121 - org.sample.bookshelf.model.Book{id=3, title=The Honeymoon Trip of Mr. Hamilton, block=org.sample.bookshelf.model.Shelf#1} 
16:08:13,861 DEBUG EntityPrinter:121 - org.sample.bookshelf.model.Book{id=10, title=Brave New World, block=org.sample.bookshelf.model.Shelf#1} 
16:08:13,861 DEBUG EntityPrinter:121 - org.sample.bookshelf.model.Book{id=9, title=Lord of the Flies, block=org.sample.bookshelf.model.Shelf#1} 
16:08:13,861 DEBUG EntityPrinter:121 - org.sample.bookshelf.model.Book{id=8, title=Do Androids Dream of Electric Sheep?, block=org.sample.bookshelf.model.Shelf#1} 
16:08:13,861 DEBUG EntityPrinter:121 - org.sample.bookshelf.model.Book{id=7, title=The Futurological Congress, block=org.sample.bookshelf.model.Shelf#1} 
16:08:13,867 DEBUG SQL:109 - /* update org.sample.bookshelf.model.Shelf */ update shelves set name=? where id=? 
16:08:13,869 DEBUG AbstractCollectionPersister:1174 - Deleting collection: [org.sample.bookshelf.model.Shelf.shelfBooks#1] 
16:08:13,869 DEBUG SQL:109 - /* delete collection org.sample.bookshelf.model.Shelf.shelfBooks */ delete from shelf_books where shelf_id=? 
16:08:13,870 DEBUG AbstractCollectionPersister:1232 - Done deleting collection 
16:08:14,199 DEBUG JdbcTransaction:113 - committed JDBC Connection 
16:08:14,199 DEBUG JdbcTransaction:126 - re-enabling autocommit 
16:08:14,200 DEBUG BookDaoImpl:60 - done... 

Я думаю, по какой-то причине Shelf не знает о добавленных книгах, к сделать его полным, это, как я добавить данные:

 String titles[] = { 
       "1984", 
       "The City of the Sun", 
       "The Honeymoon Trip of Mr. Hamilton", 
       "Fahrenheit 451", 
       "Slaughterhouse Five", 
       "Logan's Run", 
       "The Futurological Congress", 
       "Do Androids Dream of Electric Sheep?", 
       "Lord of the Flies", 
       "Brave New World",  
     }; 
     Vector<Book> books = new Vector<Book>(titles.length); 
     for (int i=0; i<titles.length; ++i) { 
      Book book = new Book(titles[i]); 
      book.setShelf(shelf); 
      books.add(book); 
     } 
     bookDao.saveMulti(books); 

, как вы можете видеть, я не называю shelf.setShelfBooks где-нибудь, если я сделаю это, вроде бы все нормально, но то, что Спящий режим делает, плохо выглядит, взгляните на фрагмент следующего журнала:

16:20:15,015 DEBUG EntityPrinter:121 - org.sample.bookshelf.model.Book{id=8, title=Do Androids Dream of Electric Sheep?, block=org.sample.bookshelf.model.Shelf#1} 
16:20:15,015 DEBUG EntityPrinter:121 - org.sample.bookshelf.model.Book{id=7, title=Fahrenheit 451, block=org.sample.bookshelf.model.Shelf#1} 
16:20:15,021 DEBUG SQL:109 - /* update org.sample.bookshelf.model.Shelf */ update shelves set name=? where id=? 
16:20:15,023 DEBUG AbstractCollectionPersister:1174 - Deleting collection: [org.sample.bookshelf.model.Shelf.shelfBooks#1] 
16:20:15,023 DEBUG SQL:109 - /* delete collection org.sample.bookshelf.model.Shelf.shelfBooks */ delete from shelf_books where shelf_id=? 
16:20:15,026 DEBUG AbstractCollectionPersister:1232 - Done deleting collection 
16:20:15,027 DEBUG AbstractCollectionPersister:1256 - Inserting collection: [org.sample.bookshelf.model.Shelf.shelfBooks#1] 
16:20:15,028 DEBUG SQL:109 - /* insert collection row org.sample.bookshelf.model.Shelf.shelfBooks */ insert into shelf_books (shelf_id, book_id) values (?, ?) 
16:20:15,030 DEBUG SQL:109 - /* insert collection row org.sample.bookshelf.model.Shelf.shelfBooks */ insert into shelf_books (shelf_id, book_id) values (?, ?) 
16:20:15,030 DEBUG SQL:109 - /* insert collection row org.sample.bookshelf.model.Shelf.shelfBooks */ insert into shelf_books (shelf_id, book_id) values (?, ?) 

Я чувство, что я делаю это неправильно, может кто-нибудь сказать мне, что должно быть ПРАВИЛЬНОЕ способ сделать то, что я как?

ответ

1

Я не пошел дальше двух сущностей, потому что их отображение неверно, что, вероятно, является причиной ваших проблем.

Первая проблема:

Вы объявляете книги, как

@OneToMany(cascade=CascadeType.ALL) 
@JoinTable(name="shelf_books", 
    joinColumns = {@JoinColumn(name="shelf_id", referencedColumnName="id")}, 
    inverseJoinColumns = {@JoinColumn(name="book_id", referencedColumnName="id")} 
) 
private Set<Book> shelfBooks; 

Это означает, что OneToMany объединение существует, сопоставляются с помощью таблицы объединения.

Тогда вы заявляете следующее:

@OneToOne(cascade=CascadeType.ALL) 
@JoinTable(name="shelf_books", 
    joinColumns = {@JoinColumn(name="book_id", referencedColumnName="id")}, 
    inverseJoinColumns = {@JoinColumn(name="shelf_id", referencedColumnName="id")} 
) 
private Shelf block; 

Это не имеет смысла.

Возможно, вы хотите, чтобы ассоциация была двунаправленной. Так как это OneToMany с одной стороны, это должна быть ManyToOne с другой стороны. И в двунаправленной связи одна сторона ДОЛЖНА быть обратной стороной (используя атрибут mappedBy, и не объявляя, как ассоциация сопоставляется, поскольку она уже определена с другой стороны), а одна сторона ДОЛЖНА быть стороной владельца. В ассоциации OneToMany обратная сторона ДОЛЖНА быть одной стороной.Таким образом, набор книг должен быть объявлен как:

@OneToMany(cascade = CascadeType.ALL, mappedBy = "block") 
private Set<Book> shelfBooks; 

Также обратите внимание, что при использовании CascadeType.ALL на ManyToOne не имеет особого смысла. Вы не хотите, чтобы полка удалялась, как только одна из содержащейся в ней книги была удалена. Я бы посоветовал удалить все каскады, если вы действительно не поймете, что такое последствия.

+0

Это на самом деле было * ManyToOne *, не знаю, откуда это * OneToOne *. Спасибо за все советы и помощь, похоже, сейчас работает правильно. – GiM

Смежные вопросы