Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to conditionally include a Hibernate annotation?

I have the code below in Play for Scala to access a SAP Hana table with Hibernate. I need to implement the same code with MySql, but the problem is that MySql doesn't support sequences (it works with AUTO_INCREMENT columns) and the code breaks because I have to specify @SequenceGenerator for Hana. Is there a way to compile this code with a condition to exclude the @SequenceGenerator annotation, so it works for MySql and Hana at the same time?

@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 = _
}
like image 592
ps0604 Avatar asked Dec 27 '17 16:12

ps0604


2 Answers

I think the way to do it is to provide a custom IdGeneratorStrategyInterpreter and register it using MetadataBuilder.applyIdGenerationTypeInterpreter. In your custom IdGeneratorStrategyInterpreter you can override determineGeneratorName to return "identity" constant for GenerationType.SEQUENCE if you know that the code is run against MySql and return null in all other cases to let the FallbackInterpreter do its default job (the string "identity" also comes from FallbackInterpreter.determineGeneratorName implementation). And you can do nothing in other methods and let the FallbackInterpreter do it's usual job.

P.S. Please also note that Hibernate's default SequenceStyleGenerator is actually aware of DBs not supporting "sequences" (exposed via Dialect.supportsSequences) and is able to emulate similar behavior using additional table. This might or might not be OK for your scenario.

like image 163
SergGr Avatar answered Sep 24 '22 10:09

SergGr


Probably not what you want to hear but AFAIK there's no way to conditionally include annotations. An alternative would be to include the common functionality in a @MappedSuperclass and inject the concrete instance as appropriate at build time depending on the environment. Something like this:-

@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 = _
}
like image 32
Steve Chambers Avatar answered Sep 25 '22 10:09

Steve Chambers