2015-05-25 5 views
0

У меня есть 2 таблицы: Trip and Place (Много-To-One), и моя проблема в том, что когда я добавляю 2 поездки с разными данными, но там же, это добавляет мне 2 записи в Trip table и 2 записи в таблицу Place, в то время как она должна добавить только одну запись в Place.Резервные данные во время спящего режима для сопоставления много к одному

Например, у меня было 2 поездки с разными датами, но они были в одном месте - Италия, Рим. Таким образом, на этих местах должно быть только одна запись: Италия, Рим.

Как я могу избежать такого поведения в своем приложении?

Класс расцепления:

public class Trip implements java.io.Serializable { 
    private int idTrip; 
    private int idHotel; 
    private Date date; 
    private int cost; 
    private int profit; 
    private String organisator; 
    private int period; 
    private String food; 
    private String transport; 
    private int persons; 
    private int kidsAmount; 

    private String ownerName; 
    private String ownerLastName; 

    private Place place; 

+ Конструкторы, получаем() и установить() методы,

Место Класс:

public class Place implements java.io.Serializable { 

    private int idPlace; 
    private String country; 
    private String city; 
    private String island; 
    private String information; 
    private Set<Trip> trips; 

+ Конструкторы, получаем() и установить() методы,

Файл сопоставления визитов:

<hibernate-mapping> 
<class name="pl.th.java.biuro.hibernate.Trip" table="Trip"> 
    <id column="idTrip" name="idTrip" type="int"> 
     <generator class="native"/>  
    </id> 
    <property column="date" name="date" type="date"/> 
    <property column="cost" name="cost" type="int"/> 
    <property column="profit" name="profit" type="int"/> 
    <property column="organisator" name="organisator" type="string"/> 
    <property column="period" name="period" type="int"/> 
    <property column="food" name="food" type="string"/> 
    <property column="transport" name="transport" type="string"/> 
    <property column="persons" name="persons" type="int"/> 
    <property column="kidsAmount" name="kidsAmount" type="int"/> 
    <property column="idHotel" name="idHotel" type="int"/> 
    <many-to-one fetch="select" name="place" class="pl.th.java.biuro.hibernate.Place"> 
     <column name="idPlace" not-null="true"></column> 
    </many-to-one> 
</class> 
</hibernate-mapping> 

Место отображение файла:

<hibernate-mapping> 
<class name="pl.th.java.biuro.hibernate.Place" table="Place"> 
    <id column="idPlace" name="idPlace" type="int"> 
     <generator class="native"/>  
    </id> 
    <property column="country" name="country" type="string"/> 
    <property column="city" name="city" type="string"/> 
    <property column="island" name="island" type="string"/> 
    <property column="information" name="information" type="string"/> 
    <set name="trips" table="Trip" inverse="true" lazy="true" fetch="select"> 
     <key> 
      <column name="idPlace" not-null="true" /> 
     </key> 
     <one-to-many class="pl.th.java.biuro.hibernate.Trip" /> 
    </set> 
</class> 
</hibernate-mapping> 

Я также добавить скриншот с моей базе данных MySQL, может быть, есть какой-то вопрос, который не позволяет мне сделать это правильно: MySQL database

EDIT: Добавлено отношение «один ко многим» в файле сопоставления места и «Установить в месте», но по-прежнему имеет ту же проблему.

EDIT2: Добавление кода с сохраняющимися entites в базу данных:

Session session = DatabaseConnection.getFactory().openSession(); 
     Transaction tx = null; 
     try { 
      tx = session.beginTransaction(); 

       trip.setPlace(place); 
       session.save(place);      
       session.save(trip); 

      tx.commit(); 
     } catch (HibernateException e) { 
      if (tx != null) { 
       tx.rollback(); 
      } 
      System.out.println("Exception found while adding new trip: " + e.getMessage()); 
      e.printStackTrace(); 
     } finally { 
      session.close(); 
     } 

Но я все еще с той же проблемой ... Я добавляю одну поездки с местом А, то в следующем шаге я добавлю еще одну поездки с тем же самое, и вот что я получаю: Duplicate places

EDIT3: Создание отключений и разместить объекты:

Trip trip = null; 
    Place place = null; 

    SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd"); 
    String dateInString = tripDateField.getText(); 
    java.util.Date date = null; 
    try { 
     date = sdf.parse(dateInString); 
     place = new Place(tripCountryField.getText(), tripCityField.getText(), tripIslandField.getText(), tripPlaceInfoTextArea.getText()); 
     int period = 0, persons = 0, kidsAmount = 0; 

     //W razie braku niewymaganych liczbowych danych ustawiane są wartości -1 
     if (tripPeriodField.getText().equals("")) { 
      period = -1; 
     } 
     if (tripPersonsField.getText().equals("")) { 
      persons = -1; 
     } 
     if (tripKidsAmountField.getText().equals("")) { 
      kidsAmount = -1; 
     } 

    trip = new Trip(new Date(date.getTime()), Integer.parseInt(tripCostField.getText()), Integer.parseInt(tripProfitField.getText()), 
       tripOrganisatorField.getText(), period, tripFoodField.getText(), tripTransportField.getText(), 
       persons, kidsAmount, tripClientNameField.getText(), tripClientLastNameField.getText()); 

} catch (ParseException ex) { 
     Logger.getLogger(MainFrame.class.getName()).log(Level.SEVERE, null, ex); 
     try { 
      date = sdf.parse("0000-00-00"); 
     } catch (ParseException ex1) { 
      Logger.getLogger(MainFrame.class.getName()).log(Level.SEVERE, null, ex1); 
     } 
    } catch (NumberFormatException e) { 
     place = new Place("111", "111", "111", "111"); 
     trip = new Trip(null, WIDTH, WIDTH, dateInString, WIDTH, dateInString, dateInString, WIDTH, ABORT, dateInString, dateInString); 

     System.out.println("Exception while getting trip/place data: " + e.toString()); 
    } 

    dataEdition.addTrip(trip, place, dataEdition.validateTripData(trip, place), addRemoveSearchTripDialog); 

Я получаю данные этих объектов из textFields и анализирую их на int, если это необходимо, так что должно быть хорошо, я думаю. После этого я передаю эти 2 объекта в другой метод, где я сохраняю их в базе данных.

+1

Хм, возможно, в вашем файле сопоставления мест отсутствует ярлык «один ко многим». Итак, как ваша программа должна знать другое направление «много-к-одному»? Как '' – NwDev

+0

Хорошо, это может быть проблемой, но когда я добавляю это после последнего Я получаю эту ошибку исключения: ERROR: HHH000196: Анализ ошибок XML (2): Содержимое типа элемента «class» должно совпадать. Что я делаю не так? – Tomek

+0

Как насчет вашего файла hibernate.cfg.xml? Есть ли такая строка: «classpath: //org/hibernate/hibernate-mapping-3.0.dtd» или есть строка, подобная этой «classpath: //org/hibernate/hibernate-**configuration**-3.0. ОТД ">. И вам нужно поместить тег «один ко многим» в заданный тег. Посмотрите здесь на № 5: http://viralpatel.net/blogs/hibernate-one-to-many-xml-mapping-tutorial/ – NwDev

ответ

2

Похоже, вы создаете NEW на каждой позиции.

Place place = new Place(tripCountryField.getText(), tripCityField.getText(), tripIslandField.getText(), tripPlaceInfoTextArea.getText()); 

, а затем вы ожидаете, Hibernate, чтобы каким-то волшебным образом определить, что вы можете на самом деле хотите работать с существующей записью в базе данных.

Это не сработает.

Если предоставленное место уже существует, вам необходимо каким-то образом загрузить существующий постоянный объект и работать с ним.

Вы можете исправить это на интерфейсе, разрешив пользователю выбрать существующее место и отправить его по идентификатору или запросить подходящее место при отправке формы.

например.

Place place = myDatabaseService.findPlace(country, name ...) //does not account for misspellings 

if(place == null){ 
    place = new Place(tripCountryField.getText(), tripCityField.getText(), tripIslandField.getText(), tripPlaceInfoTextArea.getText()); 
} 
+0

Хм, я подумал, что он может указать, существует ли такое Место, возможно, не «волшебным», но каким-то приличным способом :) Поэтому перед каждым добавлением поездки я должен проверить, существует ли место, если это так, я должен загрузить это место в объект Place, сделайте trip.setPlace (место), а затем session.save (trip)? Это будет работать? – Tomek

+0

Да, звучит правильно. –

+0

Выполнено, как я сказал в предыдущем комментарии, и он работает. Спасибо за помощь, теперь я знаю, что спящий режим не так «волшебный», как я думал :) – Tomek

1

Я попытался это одно, и это не делает никаких дубликатов:

enter image description here

и создание двух классов и таблиц в БД, я создал два файла отображения в том же пакете, что и классы.

Места, отображение:

<hibernate-mapping package="pl.th.java.biuro.hibernate"> 
    <class name="Place" table="PLACE"> 
     <id name="idPlace" type="java.lang.Long" column="ID_PLACE"> 
      <generator class="native"> 
     </generator></id>   

     <set name="trips" table="Trip" inverse="true" lazy="true" fetch="select"> 
      <key> 
       <column name="idPlace" not-null="true"> 
      </column></key> 
      <one-to-many class="pl.th.java.biuro.hibernate.Trip"> 
     </one-to-many></set> 
    </class> 
</hibernate-mapping> 

И отображение поездки:

<hibernate-mapping package="pl.th.java.biuro.hibernate"> 
    <class name="Trip" table="TRIP"> 
     <id name="idTrip" type="java.lang.Long" column="ID_TRIP"> 
      <generator class="native"> 
     </generator></id> 

     <many-to-one name="place" class="pl.th.java.biuro.hibernate.Place" fetch="select"> 
      <column name="idPlace" not-null="true"> 
     </column></many-to-one> 
    </class> 
</hibernate-mapping> 

Я видел, что ваша поездка не генерируется на вашем столе? Это верно? И ваше соглашение об именах немного подвержено ошибкам. Попробуйте назвать таблицы db в верхнем регистре и заданную переменную в классе. Место, возможно, должно быть s. В ваших сопоставлениях вы сопоставили id с int. Большинство баз данных сопоставляют его с длинными, так что, возможно, есть ошибка.

+0

Я отредактировал, как вы сказали, за исключением id, чтобы долго, видели много примеров с int, которые работали, поэтому я оставил его пока. Но проблема все еще возникает ... Вы можете проверить отредактированный код здесь? – Tomek

+1

Единственное, теперь я думаю, в том, что ты настаиваешь место дважды. Добавьте код, в котором вы создадите место и поездку. BTW: на ваших экранах MySQL на месте таблицы отсутствует символ «UQ» для уникального. Но в норме это должно быть ясно, что pk уникально :-) И, возможно, вы можете попробовать заменить 'session.save (place)' на 'session.saveOrUpdate (place)' Посмотрите здесь: http://stackoverflow.com/ Вопросы/161224/what-are-the-difference-between-the-different-saving-methods-in-hibernate – NwDev

+0

Код, добавленный здесь, изменил этот первичный ключ от места в уникальный. Я также изменил метод с «save» на «saveOrUpdate», но я все равно получаю то же самое ... – Tomek

0

Я думаю, что ваши объекты должны переопределить hashcode() и equals() методы, чтобы быть в состоянии признать их уникальность.