Версия для печати темы
Нажмите сюда для просмотра этой темы в оригинальном формате
Форум программистов > Java EE (J2EE) и Spring > Hibernate


Автор: Tony 1.8.2006, 01:50
Привет!
Начал учить Hibernate. Столкнулся с проблемой. Имею 2 класса (2 таблицы) и таблицу связи, состоящую из 2 колонок id first class и id second class.Пишу код
Код

        Session  session = HibernateUtil.getSessionFactory().getCurrentSession();
        session.beginTransaction();
        
        Author author=new Author();
        author.setFirstName("Боб");
        author.setSurname("Киллер");
        
        Book book=new Book();
        book.setIsbn("isbn:98439549");
        book.setTitle("Java_book");
        
        session.save(book);
        session.save(author);
        session.getTransaction().commit();

Как сделать чтобы в таблице связи были ID первого объекта, а во второй колонке ID второго объекта. Сейчас объекты сохраняются, но в таблице связи не создаётся строка.

Автор: tux 1.8.2006, 02:55
Насколько я понял у тебя здесь отношение между классами "многие-ко-многим". Тогда проще всего будет использовать соответствующие конструкции Hibernate. Предполагаем, что связующая таблица называется book_author и состоит из двух полей - book_id и author_id.

Класс Author:
Код

public class Author {
    private int authorId;
    private String authorName;
    private Set books;
    public int getAuthorId() {
        return authorId;
    }
    public void setAuthorId(int authorId) {
        this.authorId = authorId;
    }
    public String getAuthorName() {
        return authorName;
    }
    public void setAuthorName(String authorName) {
        this.authorName = authorName;
    }
    public Set getBooks() {
        return books;
    }
    public void setBooks(Set books) {
        this.books = books;
    }
}

Класс Book:
Код

public class Book {
    private int bookId;
    private String bookTitle;
    private Set authors;
    public Set getAuthors() {
        return authors;
    }
    public void setAuthors(Set authors) {
        this.authors = authors;
    }
    public int getBookId() {
        return bookId;
    }
    public void setBookId(int bookId) {
        this.bookId = bookId;
    }
    public String getBookTitle() {
        return bookTitle;
    }
    public void setBookTitle(String bookTitle) {
        this.bookTitle = bookTitle;
    }
}


Маппинг для класса Author:
Код

<?xml version="1.0" encoding="UTF-8"?>

<!DOCTYPE hibernate-mapping PUBLIC
    "-//Hibernate/Hibernate Mapping DTD 3.0//EN" 
    "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">

<hibernate-mapping>
    <class name="Author" table="author">

        <id name="authorId" column="author_id" type="int">
            <generator class="increment">
            </generator>
        </id>

        <property name="authorName" type="java.lang.String" 
            column="author_name" length="-1" not-null="true" />

        <set name="books" table="book_author" cascade="all">
            <key column="author_id"></key>
            <many-to-many column="book_id" class="Book" />
        </set>
    </class>

</hibernate-mapping>

Маппинг для класса Book:
Код

<?xml version="1.0" encoding="UTF-8"?>

<!DOCTYPE hibernate-mapping PUBLIC
    "-//Hibernate/Hibernate Mapping DTD 3.0//EN" 
    "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">

<hibernate-mapping>
    <class name="Book" table="book">

        <id name="bookId" column="book_id" type="int">
            <generator class="increment">
            </generator>
        </id>

        <property name="bookTitle" type="java.lang.String" 
            column="book_title" length="-1" not-null="true" />

        <set name="authors" table="book_author" cascade="all">
            <key column="book_id"></key>
            <many-to-many column="author_id" class="Author" />
        </set>
    </class>

</hibernate-mapping>

Ну и тестовый код:
Код

Transaction tr = session.beginTransaction();
        
Book book = new Book();
book.setBookTitle("Harry Potter");
Integer bookId = (Integer) session.save(book);
        
Author author = new Author();
author.setAuthorName("Джоан Роулинг");
Integer authorId = (Integer) session.save(author);
        
session.flush();
        
session.evict(book);
session.evict(author);
        
book = (Book) session.load(Book.class, bookId);
author = (Author) session.load(Author.class, authorId);
        
book.getAuthors().add(author);
session.save(book);
        
tr.commit();
session.close();

В результате в таблицу book_author должна добавиться одна запись. 

Небольшой комментарий. Здесь нужно отметить два момента. Первый - для работы с хранимыми множествами Hibernate использует собственные реализации интерфейсов типа Set, List и т.п. Второй - на протяжении сессии Hibernate хранит все объекты, с которыми выполнялась работа в кэше. Следовательно, для того, чтобы нормально сохранить в базу объекты, помещенные в Set нам нужно там иметь реализации Set от Hibernate. Казалось бы, можно просто сохранить объект (session.save()) и потом получить его у Hibernate (session.load()), но Hibernate в кэше сессии хранит оригинальные объекты и получим обратно тоже самое, что и сохранили, то есть объекты, в которых значения атрибутов books и authors равны null. Чтобы заставить Hibernate перегрузить объекты из базы, удаляем эти объекты из кэша выполнив session.evict(). 

В остальном думаю должно быть понятно.

Автор: batigoal 1.8.2006, 08:00

Автор: tux 1.8.2006, 08:11

Автор: Tony 1.8.2006, 21:34
Проблема была в маппинге.
Но я бе понал идею про:

Цитата

Небольшой комментарий. Здесь нужно отметить два момента. Первый - для работы с хранимыми множествами Hibernate использует собственные реализации интерфейсов типа Set, List и т.п. Второй - на протяжении сессии Hibernate хранит все объекты, с которыми выполнялась работа в кэше. Следовательно, для того, чтобы нормально сохранить в базу объекты, помещенные в Set нам нужно там иметь реализации Set от Hibernate. Казалось бы, можно просто сохранить объект (session.save()) и потом получить его у Hibernate (session.load()), но Hibernate в кэше сессии хранит оригинальные объекты и получим обратно тоже самое, что и сохранили, то есть объекты, в которых значения атрибутов books и authors равны null. Чтобы заставить Hibernate перегрузить объекты из базы, удаляем эти объекты из кэша выполнив session.evict(). 


и по4ему нельзя без
book = (Book) session.load(Book.class, bookId);
author = (Author) session.load(Author.class, authorId);
        
book.getAuthors().add(author); ?
если можно сразу при сайве session.save(); Тоесть приходится делать  save zatem load potom opat save dlja dobavlenja  book.getAuthors().add(author); ?

Автор: tux 2.8.2006, 01:46
Как я уже говорил, Hibernate реализует интерфейсы java.util.Set и другие подобные по-своему. Это в общем и понятно, ему там нужно хранить информацию о текущей сессии, об объекте, в котором есть атрибут типа Set. Чтобы получить в атрибутах объекта правильные реализации и правильно настроенные делается session.load() чтобы Hibernate сам построил объект как ему надо для корректной работы. 

В общем тот способ, который я привел - единственное что удалось придумать для такой задачи. Если у тебя получится короче и изящнее, буду только рад. Если найдешь решение, не забудь код запостить сюда. smile

Автор: Tony 3.8.2006, 09:31
Я хотел спросить по4ему ты делел так save-->load-->save когда можно сразу save.

Powered by Invision Power Board (http://www.invisionboard.com)
© Invision Power Services (http://www.invisionpower.com)