2013-06-07 5 views
1

Mon problème est de persister deux classes qui ont une 1: relation n:MyBatis: Comment mapper une relation "inverse"?

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

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

Ainsi, dans le code, DayRecord SAIT 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) 
); 

Dans la base de données, TimeRecord connaît DayRecord. Puis-je sauvegarder un DayRecord avec tous ses TimeRecords en une seule fois? En mode Hibernate, je peux définir un mappage inverse et enregistrer simplement un enregistrement de jour et tous ses enregistrements TimeRecord seront également enregistrés. Avec mybatis, j'ai essayé de sauver les classes indépendamment les uns des autres:

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

Mais comment puis-je enregistrer le DayRecord-ID inTimeRecord?

Idées:

  1. TimeRecord un attribut Donne dayRecordId. De cette façon, une dépendance cyclique serait créée. Cependant, la cartographie prendrait soin de la dpenedency tout en économisant.
  2. Dans une transaction, enregistrez d'abord le DayRecord, obtenez son ID, le définissez dans TimeRecords et enregistrez cet objet.
  3. utiliser un instruction_select imbriqué dans insertion comme dans la documentation

Quelle est la meilleure façon de sauver les deux objets? Merci de votre aide!

Répondre

1

Mybatis est juste un framework de mapping SQL, il vous permet d'abstraire le code SQL du code Java et c'est tout, plus ou moins. Ils font semblant de ressembler à Hibernate avec des versions récentes, mais cela conduit à des constructions bizarres en XML.

Je suggère de stocker le DayRecord et l'obtenir à partir de selectKey, puis utiliser cet ID dans les appels ultérieurs au mappeur. C'est ce qui se passe réellement à l'intérieur du mappeur, mais le XML complexe implique un FSM complexe à construire à l'intérieur. Alors gardez les choses simples et vous êtes en sécurité avec myBatis, ou utilisez Hibernate. Ce qui est encore mieux, vous pouvez définir des interfaces DAO personnalisées pour les tâches, et vous pouvez ensuite avoir une sorte de couche Service avec l'ensemble d'attributs @Transactional. Cela nécessite mybatis-guice, mais cela fonctionne vraiment bien et vous n'avez pas besoin de traiter les transactions dans votre code (ils sont déclaratifs).

+0

Merci pour votre réponse rapide! Sauvegarder DayRecord d'abord était mon idée # 2. Cependant, en faisant cela, je devrais ajouter un dayRecordId à TimeRecord, non? C'est ce que je veux éviter. La navigation devrait seulement aller de DayRecord à TimeRecord. – Steven

2

Comme jdevelop déjà mentionné, MyBatis est juste un wrapper SQL. Parce que SQL n'offre pas un moyen d'insérer deux objets qui ont une relation, MyBatis ne peut pas faire cela non plus. Donc, voici ma solution de contournement: Comme je l'ai mentionné, je ne veux pas ajouter une dépendance circulaire en faisant savoir à TimeRecord sur DayRecord. J'ai donc créé une classe wrapper juste pour insérer Time Records:

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

D'abord, je stocke le DayRecord et obtenir son ID.Je crée ensuite l'objet d'emballage et de stocker les Time Records:

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

De cette façon, je peux utiliser mon beau modèle d'objet à sens unique et que la mise en correspondance « droit » dans la base de données.

Questions connexes