2014-09-20 9 views
5

için hiçbir şey infers: filterById(id: Id)Scala derleyici önce farklı bağlamlarda farklı şekillerde gördüğüm şey çalışıyorum jenerik argümanlar

Bu Scala sorgusu uzantılarını uzanan denedim budur:

trait TableWithId { self: Profile => 

    import profile.simple._ 

    trait HasId[Id] { self: Table[_] => 
     def id: Column[Id] 
    } 

    implicit class HasIdQueryExt[Id: BaseColumnType, U] 
    (query: Query[Table[U] with HasId[Id], U]) { 
     def filterById(id: Id)(implicit s: Session) = query.filter(_.id === id) 
     def insertReturnId(m: U)(implicit s: Session): Id = query.returning(query.map(_.id)) += m 
    } 
} 

Bu iyi çalışıyor, orada gerçek bir sihir yok. Ancak Tablo türünde hiçbir kısıtlama olmadığından, filterById uyguladığım herhangi bir sorgu, özgünlüğünü kaybeder (şimdi bir jenerik Table with HasId[Id]) ve artık sütunlarına erişemiyorum (_.id ofcourse hariç).

Bu örtülü dönüştürme nasıl yazılacağını bilmiyorum, bu önlenir. Mümkün mü? Scala şimdi Kimliği türü için hiçbir şey infers çünkü şu "naieve" çözüm çalışmaz:

implicit class HasIdQueryExt[Id: BaseColumnType, U, T <: Table[U] with HasId[Id]] 
(query: Query[T, U]) { ... } 

aniden Kimliği tipi Hiçbir şey olarak anlaşılmaktadır ki bu tür garip buluyorum. Derleyici'yi bu Id türünü nerede arayacağımı nasıl anlarım?

+0

Ben Slick aşina değilim, ama benim tahminim sizin çözüm bir genel parametre gerektirecektir olmasındandır: Ama kimliği için belirli türü kullanmak .: sonra

trait GenericComponent { this: Profile => import profile.simple._ abstract class TableWithId[A](tag:Tag, name:String) extends Table[A](tag:Tag, name) { def id = column[Option[UUID]]("id", O.PrimaryKey) } abstract class genericTable[T <: Table[A] , A] { val table: TableQuery[T] /** * generic methods */ def insert(entry: A)(implicit session:Session): A = session.withTransaction { table += entry entry } def insertAll(entries: List[A])(implicit session:Session) = session.withTransaction { table.insertAll(entries:_*) } def all: List[A] = database.withSession { implicit session => table.list.map(_.asInstanceOf[A]) } } /** * generic queries for any table which has id:Option[UUID] */ abstract class genericTableWithId[T <: TableWithId[A], A <:ObjectWithId ] extends genericTable[T, A] { def forIds(ids:List[UUID]): List[A] = database.withSession { implicit session => ids match { case Nil => Nil case x::xs =>table.filter(_.id inSet(ids)).list.map(_.asInstanceOf[A]) } } def forId(id:UUID):Option[A] = database.withSession { implicit session =>table.filter(_.id === id).firstOption } } } 

ve beton bileşeni için yaptığımız Bu, masanızın gerçek tipini alır ... 'HasId [Id, T <: HasId [Id, T]]' gibi bir şey. Ardından masanın gerçek tipini HasId ile T parametresi olarak geçirebilirsiniz. Edit: Ayrıca, yapısal tipler kullanmayı denediniz mi? http://java.dzone.com/articles/duck-typing-scala-structural Bu, yansımayı kullanacaktır ancak yine de statik güvenlik sağlar. –

+0

Bunun en son yazdığım yaklaşımdan nasıl farklı olduğunu göremiyorum. Bu eşdeğer değil mi? Ve ben yapısal yazımın bu durumda yardımcı olduğunu düşünmüyorum. Sorun, yapısını korur. –

cevap

0

Bu, benzer bir sorun için benim çözümümdür.

case class SomeObjectRecord(
    override val id:Option[UUID] = None, 
    name:String) extends ObjectWithId(id){ 
    // your function definitions there 
} 

trait SomeObjectComponent extends GenericComponent { this: Profile => 
    import profile.simple._ 

    class SomeObjects(tag: Tag) extends TableWithId[SomeObjectRecord](tag, "some_objects") { 
    def name = column[String]("name", O.NotNull) 

    def * = (id, name) <> (SomeObjectRecord.tupled, SomeObjectRecord.unapply) 
    def nameIdx = index("u_name", (name), unique = true) 
    } 

    object someobjects extends genericTableWithId[SomeObjects, SomeObjectRecord] { 
    val table = TableQuery[Units] 

    // your additional methods there; you get insert and insertAll from the parent  
    } 
} 
+0

Teşekkürler. Ama bu elbette sorumu cevaplamıyor; sorun etrafında çalışır. Önerdiğiniz şey şudur: Id jenerik parametresini kaldırın. Ayrıca, QueryExtensions'ı, eşlik eden nesnenizin üzerinde yöntemlerle tercih ederim. Çünkü Sorgular'daki uzantılar, bir sorgu belirli bir sonuç şekli verirse yeniden kullanılabilir, ancak ek yöntemleriniz yalnızca an-sich olarak kullanılabilir. –

İlgili konular