如何有条件地包含一个Hibernate注释?

时间:2017-12-27 16:26:54

标签: mysql scala hibernate playframework hana

我在Play for Scala中有以下代码,可以使用Hibernate访问SAP Hana表。我需要用MySql实现相同的代码,但问题是MySql不支持序列(它适用于AUTO_INCREMENT列)和代码中断,因为我必须为Hana指定#include <iostream> #include <tuple> template<typename T> void f(T t) { std::cout << "templated f()" << std::endl; } template<> void f(int t) { std::cout << "specialized f()" << std::endl; } template<typename A, typename B> void fn() { f(A()); } template<int, char> void fn() { int a; f(a); } // Can't seem to define this correctly. //using MyType = std::tuple<int, char>()::type; int main(int, char**) { fn<char, char>(); // I have fn<int, char>(); // I want some alias; //fn<MyType>(); return 0; } 。有没有办法编译这个代码,条件是排除@SequenceGenerator注释,所以它同时适用于MySql和Hana?

@SequenceGenerator

5 个答案:

答案 0 :(得分:2)

可能不是你想听到的,但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 = _
}

答案 1 :(得分:2)

假设我正确理解您的问题,我有2个潜在的解决方案。两者都是一般性的想法,你必须做一些实际的实施。

  1. 使用宏。这是一个bit old article,它执行一些AST操作来丰富案例类。你应该能够为你的案件做那样的事情。 Here是一种在编译时将参数传递给宏的方法。这条路线的主要原因是宏api依赖于scala版本,有点凌乱,不稳定,上次检查时很难找到好的文档。

  2. 使用AspectJ。您应该能够在构建时对类进行declare注释。这里主要的是你必须在构建中添加AspectJ编织,这可能是也可能不容易。

答案 2 :(得分:2)

这个答案试图实施Eugene's suggestion(所以如果它有效,请归功于尤金)。

给出@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 = _

此实施基于scalamacros/sbt-example-paradise

答案 3 :(得分:0)

我认为这样做的方法是提供自定义IdGeneratorStrategyInterpreter并使用MetadataBuilder.applyIdGenerationTypeInterpreter进行注册。在您的自定义IdGeneratorStrategyInterpreter中,如果您知道代码是针对MySql运行并返回determineGeneratorName,那么您可以覆盖"identity"以返回GenerationType.SEQUENCE null的常量允许FallbackInterpreter执行其默认作业的情况(字符串"identity"也来自FallbackInterpreter.determineGeneratorName实现)。你不能在其他方法中做任何事情,让FallbackInterpreter做它的常规工作。

P.S。另请注意,Hibernate的默认SequenceStyleGenerator实际上意识到DB不支持&#34;序列&#34; (通过Dialect.supportsSequences公开)并且能够使用附加表模拟类似的行为。对于您的方案,这可能适用也可能不适用。

答案 4 :(得分:0)

如果mysql中的ID被赋予自动递增,那么在hibernate中映射ID应该是IDENTITY

将其替换为

@Entity
@Table(name="clients")
class ClientJpa{
  @Id
  @GeneratedValue(strategy = GenerationType.IDENTITY, generator = "generator")
  var surrogateKey: Int = _
  var code: String = _
  var name: String = _

 }

希望它有效......