hibernate映射多个数据时冗余数据

时间:2015-05-25 19:58:33

标签: java mysql hibernate many-to-one redundancy

我有2个表:Trip和Place(Many-To-One),我的问题是当我添加2个不同数据但同一个地方的行程时,它会将2个记录添加到Trip表,2个记录添加到Place表中,虽然它应该只添加一条记录。

例如,我有两次不同日期的旅行,但他们在同一个地方 - 意大利,罗马。因此,这些数据应该只有一条记录:意大利,罗马。

如何在我的应用程序中避免此类行为?

旅行课程:

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;

+ constructors,get()和set()方法,

放置课程:

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;

+ constructors,get()和set()方法,

旅程映射文件:

<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

编辑:在Place map文件和Set in Place类中添加了一对多关系,但仍然遇到了同样的问题。

EDIT2:使用持久化数据库添加代码:

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();
        }

但是我仍然遇到同样的问题...我在地方A添加了一次旅行,然后在下一步中添加了另一次相同的旅行,这就是我得到的: 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,所以我猜这应该没问题。在此之后,我将这两个对象传递给另一个方法,在那里我将它们保存到数据库中。

3 个答案:

答案 0 :(得分:2)

您似乎在每次提交时都会创建一个位置。

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

然后你希望Hibernate以某种方式神奇地确定你可能真的想要使用数据库中的现有条目。

这不起作用。

如果提交的地点已经存在,那么您需要以某种方式加载现有的持久性实体并使用它。

您可以在前端修复此问题,方法是允许用户选择现有位置并通过ID发送或查询匹配位置 表格提交。

e.g。

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());
}

答案 1 :(得分:1)

我已经尝试了这个,并没有做任何重复:

enter image description here

在DB中创建了两个类和表,我在与类相同的包中创建了两个映射文件。

地点映射:

<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>

我已经看到,你的旅行ID没有在你的桌子上生成?那是对的吗?而且您的命名约定有点容易出错。尝试将db表大写和类Place中的set变量命名为trip s 。在映射中,您将id映射到int。大多数数据库将其映射为long,因此也许存在错误。

答案 2 :(得分:0)

我认为您的实体需要覆盖hashcode()equals()方法才能识别其唯一性。