我有下面的代码,让Scala使用Hibernate访问SAP Hana表。我需要用MySql实现相同的代码,但问题是MySql不支持序列(它适用于AUTO_INCREMENT列)和代码中断,因为我必须为Hana指定@SequenceGenerator
。有没有办法用一个条件来编译这段代码,以排除@SequenceGenerator
注释,使其同时适用于MySql和Hana?
@Entity
@Table(name = "clients")
class ClientJpa {
@Id
@GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "generator")
@SequenceGenerator(name="generator", sequenceName = "cliSeq", allocationSize = 1)
var surrogateKey: Int = _
var code: String = _
var name: String = _
}
发布于 2018-06-03 20:44:46
这个答案试图实现Eugene's suggestion (因此,如果它有效,请归功于Eugene)。
给定@ifNotMysql
宏的以下定义
import scala.reflect.macros.blackbox
import scala.language.experimental.macros
import scala.annotation.{StaticAnnotation, compileTimeOnly}
object ifNotMysqlMacro {
val targetIsMySql = sys.props.get("target-mysql").contains("true")
def impl(c: blackbox.Context)(annottees: c.Expr[Any]*): c.Expr[Any] = {
import c.universe._
def mysqlAnnots(annotations: Seq[c.universe.Tree]): Seq[c.universe.Tree] =
annotations
.filterNot(_.toString.contains("SequenceGenerator"))
.filterNot(_.toString.contains("GeneratedValue"))
.:+(q"""new GeneratedValue(strategy = GenerationType.IDENTITY)""")
val result = annottees.map(_.tree).toList match {
case q"@..$annots var $pat: $tpt = $expr" :: Nil =>
q"""
@..${if (targetIsMySql) mysqlAnnots(annots) else annots}
var $pat: $tpt = $expr
"""
}
c.Expr[Any](result)
}
}
@compileTimeOnly("enable macro paradise to expand macro annotations")
class ifNotMysql extends StaticAnnotation {
def macroTransform(annottees: Any*): Any = macro ifNotMysqlMacro.impl
}
如果我们这样编写@ifNotMysql @GeneratedValue(...) @SequenceGenerator
@ifNotMysql
@GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "generator")
@SequenceGenerator(name="generator", sequenceName = "cliSeq", allocationSize = 1)
var surrogateKey: Int = _
并提供系统属性target-mysql
,如下所示
sbt -Dtarget-mysql=true compile
则将排除@SequenceGenerator
注释,并按如下方式添加@GeneratedValue(strategy = GenerationType.IDENTITY)
@GeneratedValue(strategy = GenerationType.IDENTITY)
var surrogateKey: Int = _
发布于 2018-05-30 22:14:12
可能不是您想要听到的,但是AFAIK没有办法有条件地包含注释。另一种方法是在@MappedSuperclass
中包含通用功能,并根据环境在构建时适当地注入具体实例。就像这样:
@MappedSuperclass
abstract class AbstractClientJpa {
var surrogateKey: Int // abstract
var code: String = _
var name: String = _
}
..。
@Entity
@Table(name = "clients")
class HanaClientJpa extends AbstractClientJpa {
@Id
@GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "generator")
@SequenceGenerator(name="generator", sequenceName = "cliSeq", allocationSize = 1)
var surrogateKey: Int = _
}
..。
@Entity
@Table(name = "clients")
class MySQLClientJpa extends AbstractClientJpa {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
var surrogateKey: Int = _
}
发布于 2018-06-03 02:02:05
我认为这样做的方法是提供一个自定义的IdGeneratorStrategyInterpreter
并使用MetadataBuilder.applyIdGenerationTypeInterpreter
注册它。在自定义IdGeneratorStrategyInterpreter
中,如果您知道代码是针对MySql运行的,则可以覆盖determineGeneratorName
为GenerationType.SEQUENCE
返回"identity"
常量,在所有其他情况下返回null
,以便让FallbackInterpreter
执行其默认工作(字符串"identity"
也来自FallbackInterpreter.determineGeneratorName
实现)。你不能在其他方法中做任何事情,让FallbackInterpreter
来做它通常的工作。
另外,请注意,Hibernate的默认SequenceStyleGenerator
实际上知道DB不支持“序列”(通过Dialect.supportsSequences
公开),并且能够使用附加表模拟类似的行为。对于您的场景,这可能是可以的,也可能不是。
https://stackoverflow.com/questions/47995473
复制相似问题