2014-02-12 5 views
9

Я устал всегда делать что-то вроде следующего, чтобы сделать доступ к базе данных, используя пятно для каждого из объектов моего домена.Создание общего DAO для slick

database withSession { 
    implicit session => 
    val entities = TableQuery[EntityTable] 
    val id = //Some ID 
    val q = for { 
     e <- entities if e.id === id 
    } yield (e) 
    val entity = q.first 
} 

(Примечание: EntityTable был определен как описанная here)

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

[...] 
val entityDAO = new GenericDAO[Entity, EntityTable, String]() 
[...] 

database withSession { implicit session => 
    val id = // Some ID 
    val entity = entityDAO.get(id) 
} 

Мой попытки осуществления в GenericDAO выглядит следующим образом

class GenericDAO[T, TB, PK](implicit session: Session) { 
    val entities = TableQuery[TB] // Line 1 

    def get(id: PK): T = { 
    val q = for { 
     e <- entities 
    } yield (e) 
    val res: T = q.first 
    res 
    } 
} 

Но линия 1 оставляет меня ошибка компилятора о том, что что-то не так с аргументом ТБ.

Множественные маркеры на этой линии - типа аргументы [TB] соответствовать границам ни один из перегруженных вариантов ценностей применяются: [E <: scala.slick.lifted.AbstractTable []] => scala.slick.lifted.TableQuery [Е, Е # TableElementType] [E <: scala.slick.lifted.AbstractTable []] (минусы: scala.slick.lifted.Tag => Е) scala.slick. lifted.TableQuery [E, E # TableElementType] - неверное количество параметров типа для значения перегруженного метода применяется с альтернативами: [E <: scala.slick.lifted.AbstractTable []] => scala.slick.lifted.TableQuery [Е, Е # TableElementType] [E <:
scala.slick.lifted.AbstractTable [
]] (минусы: scala.slick.lifted.Tag => E) scala.slick.lifted.TableQuery [E, E # TableElementType]

Любые предложения по этому вопросу? Или, может быть, я ошибаюсь, и предполагается, что он будет реализован по-другому. Я открыт для любого решения. Благодаря!

ответ

8

Прежде всего, вы могли бы написать

val entities = TableQuery[EntityTable] // put in a central place for re-use 

, а затем

database.withSession(
    (for { 
     e <- entities if e.id === /*Some ID*/ 
    } yield e).first()(_) 
) 

или это

database.withSession(entities.filter(_.id === /*Some ID*/).first()(_)) 

или это

val get = entities.findBy(_.id) // <- reuse this 
database.withSession(get(/*Some ID*/).first()(_)) 

для краткости. Вероятно, это делает ваш DAO ненужным (что здорово :)!).

Относительно сообщения об ошибке, которое вы получили. TableQuery[TB] - макрос, который является короткой рукой для TableQuery(tag => new TB(tag)), TB должен быть Table и создавать объекты поддержки. Вы не можете просто использовать макрос TableQuery по параметру неограниченного типа, полученному вами из обертки DAO. Вы можете ограничить TB <: Table[_], но он все равно не будет поддерживать создание объекта, которое вы не можете ограничить в Scala.Вы могли бы предоставить фабрику только DAO (общий шаблон - это получить неявный аргумент), но все это не имеет смысла, когда вы можете просто написать свой TableQuery один раз и сохранить его в глобально доступном месте.

Update:

Ярлык работает для всех этих методов таким же образом. Это просто Скала. Вы просто превращаете метод в функцию и передаете его функции более высокого порядка с помощью функции Session, которая требует функции от сеанса к чему-либо. Просто имейте в виду, что некоторые методы Slick имеют пустой список аргументов, для чего требуется ()(_), чтобы превратить их в функцию, а некоторые имеют список неявных аргументов, который требует только (_). Например. database.withSession(entities.filter(_.id === /*Some ID*/).delete(_)).

Если вы задаетесь вопросом о _. Scala отличает методы от функций. def foo(a: A, b: B, ...): R - метод, но его можно превратить в функцию типа (A,B,C) => R с использованием foo _. Это преобразование называется расширением eta и googling, так как оно станет больше информации. Иногда, когда ожидается функция, но вы предоставляете метод, компилятор Scala указывает на _, и вам не нужно писать его явно. Вы также можете указать некоторые параметры и использовать _ вместо тех параметров, которые вы еще не хотите применять. В этом случае вы частично применяете метод и возвращаете функцию. Это то, что мы делаем здесь. Мы используем _ в том месте, где методы обычно ожидают сеанса и возвращают функцию, которая занимает сеанс. Когда вы должны использовать _ или (_) или ()(_), это связано с сигнатурами методов и взаимодействием деталей между неявными списками аргументов, методами с нулевым методом, с пустым списком аргументов, который является общим знанием Scala, которое стоит исследовать в какой-то момент.

+0

Есть ли также ярлык для удаления строк? Можете ли вы указать ссылку, где можно найти все доступные методы? – Coxer

+0

Вставка/обновление/удаление/запуск/список/первая и т. Д. - это методы ответственных черт Invoker, которые связаны в документах http://slick.typesafe.com/doc/2.0.0/queries.html – cvogt

+0

Работа с ярлыками для всех этих методов. Это просто Скала. Вы просто превращаете метод в функцию и передаете его функции более высокого порядка 'withSession', которая требует функции от сеанса к чему-либо. Просто имейте в виду, что некоторые методы Slick имеют пустой список аргументов, который требует '() (_)', чтобы превратить их в функцию, а некоторые имеют список неявных аргументов, для которого требуется только '(_)'. Например. 'database.withSession (entities.filter (_. id ===/* Some ID * /). delete (_))'. – cvogt

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