11

我正在为我的 play2/slick2 项目开发一个抽象的 CRUD-DAO。为了获得方便的类型安全主 ID,我使用UnicornMappedTo作为 slicks &之上的额外抽象和便利ColumnBaseType

Unicorn 提供了一个基本的 CRUD-DAO 类BaseIdRepository,我想进一步扩展它以满足项目的特定需求。类的签名是

class BaseIdRepository[I <: BaseId, A <: WithId[I], T <: IdTable[I, A]]
  (tableName: String, val query: TableQuery[T])
  (implicit val mapping: BaseColumnType[I])
  extends BaseIdQueries[I, A, T]

这导致 DAO 实现看起来像

class UserDao extends 
  BaseIdRepository[UserId, User, Users]("USERS", TableQuery[Users])

这对我来说似乎非常多余。我能够提供tableNamequery来自T,在我自己的 Abstract DAO 上给我以下签名

abstract class AbstractIdDao[I <: BaseId, A <: WithId[I], T <: IdTable[I, A]] 
  extends BaseIdRepository[I,A,T](TableQuery[T].baseTableRow.tableName, TableQuery[T])

在 Scala 中是否有可能以某种方式推断类型IA进行如下签名?(Users是一个类扩展IdTable

class UserDao extends AbstractIdDao[Users]

如果没有运行时反射,这可能吗?如果仅通过运行时反射:我如何在类定义中使用清单以及反应式应用程序中的性能影响有多大?

另外,由于我对这门语言还很陌生并且自己工作:这在 scala 中是不是很好?

谢谢你的帮助。随意批评我的问题和英语。改进当然会提交给 Unicorn git-repo

编辑: 实际上,TableQuery[T].baseTableRow.tableName, TableQuery[T]由于需要错误类类型,但 T found不起作用,IDEA 表面上很好,但 scalac 不是。

4

1 回答 1

0

至于你的第一个问题,我在使用 Slick 时也遇到过这个问题。但是如果你仔细想想,你会发现你不能在编译时这样做。这是因为此类型信息是指定类型参数之间的关系所必需的。如果您不这样做,您将能够构建BaseIdRepository类型没有意义的类,例如IdTables表格不代表投影。由于每个关系都需要名称,因此需要 3 个命名类型参数。如果省略第一个,则可以在没有包含 Id 的投影的情况下构造 IdRepository;如果省略第二个,则可能有一个没有 ID 列的表;如果省略第三个,则可以查询没有表和带有 ID 的投影组合的表。您的应用程序中可能没有定义当前会破坏任何这些规则的类型,但编译器不知道这一点。提供正确的类型信息是不可避免的。

至于你的第二个问题,仅仅因为你认为语法冗长而使用反射是非常不可取的。如果您可以通过简单地提供类型参数来保证类型安全,我建议您这样做。以这种方式编写 Scala 的品味和风格都非常糟糕。具有讽刺意味的是,在 Unicorn 中使用类型安全 ID,然后通过反射绕过其类型安全。

此外, aManifest不是您想要的:清单不允许您向编译器提供更少类型信息,它只允许您更灵活地指定在哪里这样做。它允许您在编译时利用编译器的类型知识来规避类型擦除引入的一些问题。您在这里遇到的问题与类型擦除无关,因此Manifests 不起作用。最后,运行时反射在这里对您没有多大帮助,因为如果您尚未提供类型信息,Slick 的内部函数将不允许您进行编译。

所以,是的,你想要的是不可能的。Scala(和 Slick)在编译时需要完整的信息,没有任何技巧可以有效地规避这一点。

于 2014-04-25T18:35:47.373 回答