Scala slick 2使用mappedColumn映射多对一关系

Scala slick 2使用mappedColumn映射多对一关系,scala,slick-2.0,Scala,Slick 2.0,我正试着用slick来描绘我的班级,这样我就能坚持下去。 我的业务对象是这样定义的 case class Book(id : Option[Long], author : Author, title : String, readDate : Date, review : String){} case class Author(id : Option[Long], name : String, surname : String) {} 然后我为作者定义了“table”类: class Autho

我正试着用slick来描绘我的班级,这样我就能坚持下去。 我的业务对象是这样定义的

case class Book(id : Option[Long], author : Author, title : String, readDate : Date, review : String){}
case class Author(id : Option[Long], name : String, surname : String) {}
然后我为作者定义了“table”类:

class Authors(tag : Tag) extends Table[Author](tag,"AUTHORS") {
    def id = column[Option[Long]]("AUTHOR_ID", O.PrimaryKey, O.AutoInc)
    def name = column[String]("NAME")
    def surname = column[String]("SURNAME")
    def * = (id, name, surname) <> ((Author.apply _).tupled , Author.unapply)
}
类作者(tag:tag)扩展表[Author](tag,“Authors”){
def id=列[Option[Long]](“作者id”,O.PrimaryKey,O.AutoInc)
def名称=列[字符串](“名称”)
定义姓氏=列[字符串](“姓氏”)
def*=(id、姓名、姓氏)((Author.apply..tuple,Author.unapply)
}
至于书籍:

class Books (tag : Tag) extends Table[Book](tag, "BOOKS") {
    implicit val authorMapper = MappedColumnType.base[Author, Long](_.id.get, AuthorDAO.DAO.findById(_))

    def id = column[Option[Long]]("BOOK_ID", O.PrimaryKey, O.AutoInc)
    def author = column[Author]("FK_AUTHOR")
    def title = column[String]("TITLE")
    def readDate = column[Date]("DATE")
    def review = column[Option[String]]("REVIEW")

    def * = (id, author, title, readDate, review) <> ((Book.apply _).tupled , Book.unapply)
}
类图书(tag:tag)扩展表[Book](tag,“Books”){
隐式val authorMapper=MappedColumnType.base[Author,Long](u.id.get,AuthorDAO.DAO.findById(u))
def id=列[Option[Long]](“BOOK_id”,O.PrimaryKey,O.AutoInc)
def author=列[作者](“FK_作者”)
def title=列[字符串](“标题”)
def readDate=列[日期](“日期”)
def review=列[选项[字符串]](“审阅”)
def*=(id、作者、标题、阅读日期、评论)((Book.apply u41;).tuple、Book.unapply)
}
但是当我编译时,我得到了这个错误

Error:(24, 51) No matching Shape found.
Slick does not know how to map the given types.
Possible causes: T in Table[T] does not match your * projection. Or you use an unsupported type in a Query (e.g. scala List).
Required level: scala.slick.lifted.FlatShapeLevel
Source type: (scala.slick.lifted.Column[Option[Long]], scala.slick.lifted.Column[model.Author], scala.slick.lifted.Column[String], scala.slick.lifted.Column[java.sql.Date], scala.slick.lifted.Column[Option[String]])
Unpacked type: (Option[Long], model.Author, String, java.sql.Date, String)
Packed type: Any
def * = (id, author, title, readDate, review) <> ((Book.apply _).tupled , Book.unapply)
                                              ^
错误:(24,51)未找到匹配形状。
Slick不知道如何映射给定的类型。
可能原因:表[T]中的T与您的*投影不匹配。或者在查询中使用不受支持的类型(例如scala列表)。
所需级别:scala.slick.lifted.FlatShapeLevel
源类型:(scala.slick.lified.Column[Option[Long]],scala.slick.lified.Column[model.Author],scala.slick.lified.Column[String],scala.slick.lified.Column[java.sql.Date],scala.slick.lified.Column[Option[String]]
解包类型:(选项[Long],model.Author,字符串,java.sql.Date,字符串)
包装类型:任何
def*=(id、作者、标题、阅读日期、评论)((Book.apply u41;).tuple、Book.unapply)
^
还有这个:

Error:(24, 51) not enough arguments for method <>: (implicit evidence$2: scala.reflect.ClassTag[model.Book], implicit shape: scala.slick.lifted.Shape[_ <: scala.slick.lifted.FlatShapeLevel, (scala.slick.lifted.Column[Option[Long]], scala.slick.lifted.Column[model.Author], scala.slick.lifted.Column[String], scala.slick.lifted.Column[java.sql.Date], scala.slick.lifted.Column[Option[String]]), (Option[Long], model.Author, String, java.sql.Date, String), _])scala.slick.lifted.MappedProjection[model.Book,(Option[Long], model.Author, String, java.sql.Date, String)].
Unspecified value parameter shape.
def * = (id, author, title, readDate, review) <> ((Book.apply _).tupled , Book.unapply)
                ^

错误:(24,51)方法参数不足:(隐式证据$2:scala.reflect.ClassTag[model.Book],隐式形状:scala.slick.lifted.shape[\up>Ende Neu的答案更具知识性,与问题中描述的用例相关,并且可能是更正确的答案

以下仅是我所做的一个观察,它可能通过回答这个问题对tmnd91有所帮助:

这里怎么了

我注意到:

case class Book( ... review : String){}
与以下内容不匹配:

def review = column[Option[String]]("REVIEW")
应该是:

def review = column[String]("REVIEW")

Slick不是ORM,所以没有从外键到实体的自动映射,这个问题已经被问了很多次了(仅举两个例子)

让我们假设您正在尝试做的事情是可能的:

implicit val authorMapper = 
  MappedColumnType.base[Author, Long](_.id.get, AuthorDAO.DAO.findById(_))
因此,您告诉投影使用行id并获取与该id相关的实体,在您的情况下有三个问题,首先您不处理失败(
id.get
),其次您的主键是可选的(不应该是可选的)

第三个问题是,slick将以单独的方式获取每个实体,我的意思是,您执行一些查询并获取100本书,slick将进行100次其他查询仅获取相关实体,性能方面是自杀,您完全绕过了SQL层(连接)只有在缩短DAO的可能性下才有最好的性能


幸运的是,这似乎不可能,slick将映射器用于不受支持的类型(例如,不必显式使用函数的不同日期格式)或在获取/插入行时插入格式转换,请查看有关如何使用的文档(取决于您的版本).

我对Scala或Slick一无所知,但我注意到
案例类书(…review:String){}
def review=column[Option[String]]
不匹配。它不应该是
def review=column[String]
?你不能用映射器代替外键,无论如何,你不应该这样做,slick不是ORM,在ORM中你可以将外键映射到实体,你必须使用通用SQL中使用的标准方法,拥有一个带有
的列作为外键ad use连接。@Ende NEU:如果这样做,我需要另一个级别的BookImpl来检索作者通过DAO。我认为这太冗长了!我的方法有什么缺点???@tmnd91不客气,随机公民。我发布了解决方案作为答案。虽然你发现了一个错误,但我认为这几乎不能解决op问题。是的,从你的评论来看,他可能没有正确使用Slick,但我无法对此发表评论我不知道斯里克。但就“这里的错误是什么?”这个问题而言,这将是答案(因为有理由相信提问者感谢我指出了这一点)。在任何情况下,你都可以发布一个答案,详细说明应该如何做(并回答“我的方法有哪些缺点?”)是的,我想是的,我的只是给你答案的一个便条。好的,现在我明白了。非常感谢。