2013-06-07 2 views
1

Моя проблема заключается в упорствовать два класса, которые имеют 1 а: п отношения:MyBatis: Как сопоставить «обратные» отношения?

public class DayRecord { 
    private Long id; 
    private List<TimeRecord> timeRecordsToday = new ArrayList<TimeRecord>(4); 
    ... 
} 

public class TimeRecord { 
    private Long id; 
    ... 
} 

Так, в коде, DayRecord знает TimeRecord.

create table DAY_RECORDS (
    id int primary key, 
); 

create table TIME_RECORDS (
    id int primary key, 
    day_record_id int not null, 
    foreign key (day_record_id) references DAY_RECORDS (id) 
); 

В базе данных TimeRecord знает DayRecord.

Могу ли я сохранить DayRecord со всеми его TimeRecords за один шаг?

В Hibernate я могу установить обратное отображение и просто сохранить DayRecord, и все его TimeRecords также будут сохранены. С MyBatis, я пытался спасти классы независимо друг от друга:

<mapper 
    namespace="de.stevenschwenke.java.javafx.xyz.DayRecordMapper"> 
    <insert id="insertDayRecord" 
     parameterType="de.stevenschwenke.java.javafx.xyz.DayRecord"> 
     insert into DAY_RECORDS (id) values (NEXT VALUE FOR DAY_RECORDS_SEQ); 
    </insert> 
</mapper> 

<mapper 
    namespace="de.stevenschwenke.java.javafx.xyz.TimeRecordMapper"> 
    <insert id="insertTimeRecord" 
     parameterType="de.stevenschwenke.java.javafx.xyz.TimeRecord"> 
     insert into TIME_RECORDS (id) values (NEXT VALUE FOR TIME_RECORDS_SEQ); 
    </insert> 
</mapper> 

Но как я могу сохранить DayRecord-ID inTimeRecord?

Идеи:

  1. Дают TimeRecord атрибут dayRecordId. Таким образом, будет создана циклическая зависимость. Однако при сохранении картирование будет заботиться о сохранности.
  2. В одной транзакции сначала сохраните DayRecord, получите свой идентификатор, установите его в TimeRecords и сохраните этот объект.
  3. использовать вложенную Select-заявление внутри вставки, как в документации

Что такое лучший способ сохранить оба объекта? Спасибо за вашу помощь!

ответ

1

Mybatis - это просто структура отображения SQL, она позволяет абстрагировать код SQL от кода Java, и это все, более или менее. Они притворяются похожими на Hibernate с последними версиями, но это приводит к странным конструкциям в XML.

Я бы предложил хранить DayRecord и получить его от selectKey, а затем использовать этот идентификатор в последующих вызовах в mapper. Это то, что на самом деле происходит внутри mapper, но сложный XML подразумевает сложный FSM для внутренней сборки. Так что держите его простым, и вы в безопасности с myBatis или используете Hibernate.

Что еще лучше, вы можете определить пользовательские интерфейсы DAO для задач, а затем у вас может быть какой-то сервисный уровень с установленным атрибутом @Transactional. Для этого требуется mybatis-guice, но он отлично работает, и вам не нужно иметь дело с транзакциями в вашем коде (они декларативные).

+0

Спасибо за ваш быстрый ответ! Спасение DayRecord было первой идеей № 2. Однако при этом мне пришлось бы добавить dayRecordId в TimeRecord, верно? Этого я и хочу избежать. Навигация должен идти только от DayRecord до TimeRecord. – Steven

2

Как уже говорилось в jdevelop, MyBatis - это просто оболочка SQL. Поскольку SQL не предлагает способ вставки двух объектов, имеющих отношения, MyBatis тоже не может этого сделать.

Итак, вот мое обходное решение: Как я уже упоминал, я не хочу добавлять круговую зависимость, позволяя TimeRecord знать о DayRecord. Таким образом, я создал класс обертку только для вставки TimeRecords:

public class TimeRecordInsertWrapper { 
    public Long id; 
    public int hours; 
    public long dayRecordId; 
    [constructor/getter/setter omited but there with public access modifier] 
} 

Во-первых, я хранить DayRecord и получить его ID.Затем я создаю объект-оболочку и хранить TimeRecords:

public long insertDayRecord(DayRecord newRecord) { 
    SqlSession session = sqlSessionFactory.openSession(); 
    try { 

     session.insert(
       "de.stevenschwenke.java.javafx.xyz.DayRecordMapper.insertDayRecord", 
       newRecord); 

     for (TimeRecord tr : newRecord.getTimeRecordsToday()) { 
      TimeRecordInsertWrapper wrapper = new TimeRecordInsertWrapper(tr.getHours(), newRecord.getId()); 
      session.insert("de.stevenschwenke.java.javafx.xyz.TimeRecordMapper.insertTimeRecord", 
        wrapper); 
     } 
     return newRecord.getId(); 
    } finally { 
     session.commit(); 
     session.close(); 
    } 
} 

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

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