2010-06-02 4 views
3

Je me demandais quelle est la meilleure pratique pour un modèle JPA dans Lift? Je remarqué que dans l'application de démonstration jpa, il y a juste un objet modèle qui est comme un super objet qui fait tout. Je ne pense pas que ce soit l'approche la plus évolutive, non?Qu'est-ce qu'une bonne architecture pour une application Lift-JPA?

Est-il sage de toujours faire le modèle DAO dans Lift? Par exemple, il y a un code qui ressemble un peu ballonné et pourrait être simplifié dans tous les objets du modèle:

Model.remove(Model.getReference(classOf[Author], someId)) 

Peut-être:

AuthorDao.remove(someId) 

J'apprécierais des conseils pour la mise en place quelque chose qui travaillera avec de la façon dont Lift veut travailler et est également facile à organiser et à entretenir. De préférence quelqu'un qui a utilisé JPA sur un site de levage moyen plutôt que de simplement postuler ce que Spring fait (nous savons comment faire cela);)

La première phase de développement sera d'environ 30-40 tables, et finira par atteindre plus de 100 ... nous avons besoin d'une approche évolutive et soignée.

Répondre

2

Republiée de la liste de diffusion Lift pour la postérité (source here):

je peux jeter un peu de lumière sur la façon dont nous utilisons JPA. Je ne suis pas sûr quel type de conteneur vous travaillez avec, mais nous utilisons JBoss 4.2.2, et en utilisant ses installations de la piscine de connexion.

Nous utilisons la bibliothèque scalajpa pour initialiser la substance JPA et conserver une référence au gestionnaire d'entités dans une variable locale de thread. Nous spécifiquement n'utilisons pas l'ascenseur RequestVarEM, parce que le cycle de vie de un RequestVar est un peu plus compliqué qu'une demande HTTP régulière, et cela peut conduire à des connexions ne pas être retournées à la piscine dans un délai opportun.

La première étape consiste à créer le « modèle » et pointer au nom de l'unité de votre persistence.xml:

object MyDBModel extends LocalEMF("unitName", false) with 
ThreadLocalEM 

Et nous avons créé un peu de code pour faire des opérations simple. Chacune de nos classes persistantes se mélange dans un qui fournit quelques opérations de base JPA :

trait Persistent { 
    def persist = DBModel.persist(this) 
    def merge = DBModel.merge(this) 
    def remove = DBModel.remove(this) 

} 

Par exemple,

@Entity 
@Table{val name="person"} 
class Person extends Persistent { 

@Id 
var id:String = _ 

@Column {val name="first_name", val nullable = false, val 
updatable=false} 
var firstName:String = _ 

@Column {val name="last_name", val nullable = false, val 
updatable=false} 
var lastName:String = _ 

@OneToMany{ ... } 
var roles:Set[Role] = new HashSet[Role]() 

// etc. 

} 

Nous utilisons principalement les collections qui sont mappées pour naviguer dans le modèle d'objet, et mettre plus méthodes de base de données complexes sur l'objet compagnon, de sorte que nous n'avons pas de références à MyDBModel dispersés dans le code (comme vous l'avez noté, une pratique indésirable).Par exemple:

object Person { 
def findByLastName = MyDBModel.createQuery[Person] 
("...").findAll.toList 

// etc. 

} 

Enfin, notre intégration avec ascenseur est sous la forme d'un morceau de code qui enveloppements chaque demande:

S.addAround(new LoanWrapper { 
    def apply[T](f: => T):T = { 
     try { 
     f 
     } 
     catch { 
     case e => MyDBModel.getTransaction.setRollbackOnly 
     } 
     finally { 
     MyDBModel.cleanup 
     } 
    } 

}) 

J'ai omis une erreur de manipulation ici pour faire la idée plus claire, mais l'intention est que chaque demande HTTP s'exécute dans une transaction, qui réussit ou échoue dans son intégralité. Depuis MyDBModel est initialisé lors de son premier contact, dans votre code de test, vous pouvez gréer le EM comme vous le souhaitez, et les objets de données sont isolés de cette configuration .

Espérons que cela soit utile.

Sean

+0

Comment tester du code qui dépend tellement des variables globales (comme 'MyDBModel' dans votre exemple). N'est-ce pas compliqué à faire sans impliquer toute la pile? – Theo

Questions connexes