Что такое хорошая архитектура для приложения Lift-JPA? - PullRequest
3 голосов
/ 02 июня 2010

Мне было интересно, что является лучшей практикой для модели JPA в Lift? я заметил, что в демонстрационном приложении jpa есть только объект Model это как супер объект, который делает все. Я так не думаю может быть самый масштабируемый подход, нет?

Разумно ли все еще использовать шаблон DAO в Lift? Например, есть некоторый код, который выглядит немного раздутым и может быть упрощен по всем модельным объектам:

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

Может быть:

AuthorDao.remove(someId)

Буду признателен за советы по настройке того, с чем можно работать способ, которым Lift хочет работать, а также легко организовать и поддерживать. Желательно от кого-то, кто действительно использовал JPA на средних и больших сайтах Lift, а не просто постулировал, что делает Spring (мы знаем, как это сделать);)

Первый этап разработки будет около 30-40 таблиц, и будет в конечном итоге мы получим более 100 ... нам нужен масштабируемый аккуратный подход.

1 Ответ

2 голосов
/ 14 июня 2010

Перемещено из списка рассылки Lift для потомков ( источник здесь ):

Я могу пролить немного света на то, как мы используем JPA. Я не уверен, что это за контейнер, с которым вы работаете, но мы используем JBoss 4.2.2, и используя свой пул подключений.

Мы используем библиотеку scalajpa для инициализации содержимого JPA и сохранения ссылка на менеджер сущностей в локальной переменной потока. Мы в частности, не используйте Lift RequestVarEM, потому что жизненный цикл RequestVar несколько сложнее, чем обычный HTTP-запрос, и это может привести к тому, что соединения не будут возвращены в пул в своевременная мода.

Первый шаг - создать «модель» и указать ее имя из вашего файла persistence.xml:

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

И мы создали небольшой код, чтобы упростить некоторые операции. Каждый из наших постоянных классов смешивается в a, который обеспечивает некоторые базовые JPA операции:

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

}

Например,

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

}

Мы в основном используем сопоставленные коллекции для навигации по объектной модели, и поместить более сложные методы базы данных в объект-компаньон, чтобы у нас нет ссылок на MyDBModel, разбросанных по всему коду (как вы заметили, нежелательная практика). Например:

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

// etc.

}

Наконец, наша интеграция с Lift представлена ​​в виде небольшого кода, который упаковывает каждый запрос:

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

})

Я оставил здесь некоторую обработку ошибок, чтобы прояснить идею, но намерение состоит в том, что каждый HTTP-запрос выполняется в транзакции, которая либо удастся, либо не получится полностью. Поскольку MyDBModel является инициализируется при первом касании, в вашем тестовом коде вы можете настроить EM, как вы считаете нужным, и объекты данных изолированы от этого конфигурации.

Надеюсь, это полезно.

Шон

...