MS SQL Server 2008 R2 IDENTITY 列的 JPA 注释

Posted

技术标签:

【中文标题】MS SQL Server 2008 R2 IDENTITY 列的 JPA 注释【英文标题】:JPA annotation for MS SQL Server 2008 R2 IDENTITY column 【发布时间】:2015-09-01 15:59:35 【问题描述】:

我想知道正确的 JPA 注释设置来处理 MS Server 2008 R2 IDENTITY 列。

MS Server 2008 R2 (RTM) 不支持 SEQUENCE,但是当我通过原始 sql 测试时,IDENTITY 会自动递增。

但是,通过 JPA,我无法通过 @GeneratedValue 注释上的任何策略(IDENTITY、AUTO、TABLE)使其工作,并且我不允许更改数据库架构,因为它是其他架构。我没有尝试使用 SEQUENCE,因为没有序列。

数据库表架构

CREATE TABLE [dbo].[invoice_header](
    [invoice_id] [int] IDENTITY(1,1) NOT NULL,
    [ApprovalDate] [datetime] NULL,
    [ApproverUserName] [nvarchar](50) NULL,
 CONSTRAINT [PK_invoice_header] PRIMARY KEY CLUSTERED 
(
    [invoice_id] ASC
)WITH (PAD_INDEX  = OFF, STATISTICS_NORECOMPUTE  = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS  = ON, ALLOW_PAGE_LOCKS  = ON) ON [PRIMARY]
) ON [PRIMARY]

GO

JPA 注释

@Entity
@Table(name = "invoice_header")
public class InvoiceHeader 

    @Id
    @GeneratedValue( strategy = GenerationType.IDENTITY )
    @Column(name="invoice_id")
    private Long invoiceId;

休眠错误

Hibernate: insert into tbl_acct_textura_invoice_header (invoice_id, ApprovalDate, ApproverUserName) values (null, ?, ?)
2015-06-16 11:12:24.149 ERROR 7157 --- [tp1024240671-18] o.h.engine.jdbc.spi.SqlExceptionHelper   : DEFAULT or NULL are not allowed as explicit identity values.

由于在 Id 上传递了 null 而失败。我可以通过 @Column 注释上的 insertable=false 和 updatable=false 在插入期间使 HQL 不包括 invoice_id 列,但是休眠对不包括如下所示的 Id 列不满意。有什么建议吗?仅供参考,我正在使用 spring-data JpaRepository

插入期间不包含 id 列时出现休眠错误

nested exception is org.hibernate.id.IdentifierGenerationException: ids for this class must be manually assigned before calling save(): ...InvoiceHeader

【问题讨论】:

IDENTITY 数据库字段应该使用“IDENTITY”策略,这就是它的用途,并且在我尝试过时可以与 DataNucleus 一起使用。如果 Hibernate 不支持,请报告针对他们的错误或查找更新的版本 感谢 Neil 的建议,但我发现我错过了在 LocalContainerEntityManagerFactoryBean 上设置方言 【参考方案1】:

我刚刚发现我错过了在 LocalContainerEntityManagerFactoryBean 上设置休眠方言。在将 org.hibernate.dialect.SQLServer2008Dialect 设置为休眠方言后,GenerationType.IDENTITY 工作正常,正如 Neil 所说。

下面是我的spring数据配置和application.properties。 仅供参考,我有多个数据源,一个是 H2 嵌入式数据源供内部使用,另一个是 MS SQL 2008 服务器,用于远程数据访问,我遇到了问题。

MS SQL 2008 服务器的 Spring 数据配置

@Configuration
@EnableTransactionManagement
@EnableJpaRepositories(
        entityManagerFactoryRef = "adapterEntityManagerFactory",
        transactionManagerRef = "adapterTransactionManager",
        basePackages = "com.textura.client.erp.database.repository")
public class ErpRepositoryConfig 
    @Autowired
    JpaVendorAdapter jpaVendorAdapter;

    @Value("$adapter.datasource.url")
    private String databaseUrl;

    @Value("$adapter.datasource.username")
    private String username;

    @Value("$adapter.datasource.password")
    private String password;

    @Value("$adapter.datasource.hibernate.dialect")
    private String dialect;

    public DataSource dataSource() 
        return new DriverManagerDataSource(databaseUrl, username, password);
    
    @Bean(name = "adapterEntityManager")
    public EntityManager entityManager() 
        return entityManagerFactory().createEntityManager();
    

    @Bean(name = "adapterEntityManagerFactory")
    public EntityManagerFactory entityManagerFactory() 
        Properties properties = new Properties();
        properties.setProperty("hibernate.dialect", dialect);  //"org.hibernate.dialect.SQLServer2008Dialect"
        LocalContainerEntityManagerFactoryBean lef = new LocalContainerEntityManagerFactoryBean();
        lef.setDataSource(dataSource());
        lef.setJpaVendorAdapter(jpaVendorAdapter);
        lef.setPackagesToScan("com.textura.client.erp.database.model");
        lef.setPersistenceUnitName("adapterPersistenceUnit");
        lef.setJpaProperties(properties);
        lef.afterPropertiesSet();
        return lef.getObject();
    

    @Bean(name = "adapterTransactionManager")
    public PlatformTransactionManager transactionManager() 
        return new JpaTransactionManager(entityManagerFactory());
    

类路径中的application.properties文件

# database configuration
spring.datasource.url=jdbc:h2:file:~/internal;AUTO_SERVER=TRUE
spring.datasource.username=sa
spring.datasource.password=
spring.datasource.driver-class-name=org.h2.Driver
spring.datasource.schema=schema.sql
spring.datasource.data=data.sql
spring.datasource.initialize=false
#spring.datasource.initialize=true only for first time to create table, after that switch to false

# JPA. Hibernate
spring.jpa.database=H2
spring.jpa.database-platform=org.hibernate.dialect.H2Dialect
spring.jpa.hibernate.ddl-auto=create-drop
#spring.jpa.hibernate.ddl-auto=choose one of [create-drop, create, update, validate, none]
spring.jpa.hibernate.naming-strategy: org.hibernate.cfg.ImprovedNamingStrategy
spring.jpa.show-sql=true
spring.data.jpa.repositories.enabled=true


# MS SQL Server 2008 datasource
adapter.datasource.url=jdbc:sqlserver://some.ip.address:1433;databaseName=Remote
adapter.datasource.username=sa
adapter.datasource.password=password
adapter.datasource.hibernate.dialect=org.hibernate.dialect.SQLServer2008Dialect

在那之后,我看到 GenerationType.IDENTITY 的作用就像魅力

Hibernate: insert into invoice_header (ApprovalDate, ApproverUserName) values (?, ?)

【讨论】:

以上是关于MS SQL Server 2008 R2 IDENTITY 列的 JPA 注释的主要内容,如果未能解决你的问题,请参考以下文章

无法使用 Liferay 6.2 连接 MS SQL Server management studio 2008 r2

SQL Server 2008r2 <--> 前端 MS Access 的最佳版本

Window 2008 Tomcat 7 MS SQL Server 2008R2 - 无法识别JNDI JDBC驱动程序

ms sql2012 能否安装在win2008 server

MS Access 2007 查询不在 SQL Server 2008 上运行

从 SQL Server 2008 迁移到 MS access 2007