当嵌入式密钥包含SQL Server上的标识列时,Hibernate插入失败 [英] Hibernate insert failing when embedded key contains identity column on SQL Server

查看:127
本文介绍了当嵌入式密钥包含SQL Server上的标识列时,Hibernate插入失败的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在尝试使用hibernate映射一个实体,但是对于SQL Server,我无法继续.

I'm trying to map an entity with hibernate, but with SQL Server, I am not able to proceed.

以下是详细信息.

SQL Server实体

SQL Server Entity

CREATE TABLE [dbo].[BOOK_EMBEDDED](

[row_id] [bigint] IDENTITY(1,1) NOT NULL,

[group_no] [int] NOT NULL,

[book_name] [varchar](255) NULL,

 CONSTRAINT [PK_BOOK_EMBEDDED] PRIMARY KEY CLUSTERED 

(

[group_no] ASC,

[row_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]

============================

=============================

嵌入式密钥

---------------------------

@Embeddable 

public class EmbeddedKey implements Serializable { 


    private static final long serialVersionUID = 1L; 



    @GeneratedValue(strategy = GenerationType.IDENTITY) 

    @Column(name = "row_id") 

    private Long rowId; 



    @Column(name = "group_no") 

    private int groupNo; 



    public Long getRowId() { 

        return rowId; 

    } 



    public void setRowId(Long rowId) { 

        this.rowId = rowId; 

    } 



    public static long getSerialversionuid() { 

        return serialVersionUID; 

    } 



    @Override 

    public int hashCode() { 

        final int prime = 31; 

        int result = 1; 

        result = (int) (prime * result + rowId); 

        result = prime * result + groupNo; 

        return result; 

    } 



    @Override 

    public boolean equals(Object obj) { 

        if (this == obj) 

            return true; 

        if (obj == null) 

            return false; 

        if (getClass() != obj.getClass()) 

            return false; 

        EmbeddedKey other = (EmbeddedKey) obj; 

        if (rowId != other.rowId) 

            return false; 

        if (groupNo != other.groupNo) 

            return false; 

        return true; 

    } 



    @Override 

    public String toString() { 

        return this.getRowId() + "  " + this.getGroupNo() + " "; 

    } 



    public int getGroupNo() { 

        return groupNo; 

    } 



    public void setGroupNo(int groupNo) { 

        this.groupNo = groupNo; 

    } 



} 

实体

--------------

@Entity(name = "BOOK_EMBEDDED") 

public class BookMySQL implements Serializable { 



    /** 

     *  

     */ 

    private static final long serialVersionUID = 1L; 



    @Column(name = "BOOK_NAME") 

    private String book_Name; 



    @EmbeddedId 

    private EmbeddedKey key; 



    public BookMySQL() { 

    } 



    public String getBook_Name() { 

        return book_Name; 

    } 



    public void setBook_Name(String book_Name) { 

        this.book_Name = book_Name; 

    } 



    public static long getSerialversionuid() { 

        return serialVersionUID; 

    } 



    public EmbeddedKey getKey() { 

        return key; 

    } 



    public void setKey(EmbeddedKey key) { 

        this.key = key; 

    } 



    @Override 

    public String toString() { 

        return this.getKey().toString() + "  " + this.getBook_Name(); 

    } 



} 

实体管理器类

------------------------------

public class LocalEntityManager { 

    private static EntityManagerFactory emf; 

    private static EntityManager em; 



    private LocalEntityManager() { 

    } 



    public static EntityManager getEntityManger() { 

        if (emf == null) { 

            synchronized (LocalEntityManager.class) { 

                if (emf == null) { 

                    emf = Persistence.createEntityManagerFactory("BookEntities"); 

                    em = emf.createEntityManager(); 

                } 

            } 

        } 

        return em; 

    } 

} 

图书服务

------------------

public class MySQLBookService { 



    public Long persistBook(String bookName) { 

        EmbeddedKey key = new EmbeddedKey(); 

        key.setGroupNo(1); 



        BookMySQL book = new BookMySQL(); 

        book.setBook_Name(bookName); 

        book.setKey(key); 



        EntityManager em = LocalEntityManager.getEntityManger(); 

        EntityTransaction tx = em.getTransaction(); 

        tx.begin(); 

        em.persist(book); 

        tx.commit(); 

        em.close(); 



        return book.getKey().getRowId(); 

    } 



    public BookMySQL findBook(int bookId) { 

        EntityManager em = LocalEntityManager.getEntityManger(); 

        EmbeddedKey key = new EmbeddedKey(); 

        key.setGroupNo(1); 

        key.setRowId(1L); 

        BookMySQL bookMySQL = em.find(BookMySQL.class, key); 

        System.out.println(bookMySQL); 

        return bookMySQL; 

    } 



    public static void main(String... args) { 

        MySQLBookService bookService = new MySQLBookService(); 

        // bookService.findBook(1); 



        bookService.persistBook("Lord of the rings"); 

    } 



} 

问题是我无法使用序列,无法执行此序列 findBook始终有效,并因错误而持久失败.

The problem is I cannot use a sequence and by executing this findBook always works and persist fails with error.

ERROR: Cannot insert explicit value for identity column in table 'BOOK_EMBEDDED' when IDENTITY_INSERT is set to OFF.

任何帮助将不胜感激.

Any help will be greatly appreciated.

推荐答案

我喜欢这个问题,所以我决定写一个

I liked this question, so I decided to write an in-depth article about it.

使其生效的唯一方法是覆盖SQLInsert并欺骗希望设置标识符列的Hibernate.如果您提供自己的自定义INSERT语句,则可以这样做,而不是将rowId设置为null,而是设置版本:

The only way to make it work is to overwrite the SQLInsert and trick Hibernate which expects to set the identifier column. This can be done if you provide your own custom INSERT statement so that, instead of setting the rowId to null, you set the version instead:

@Entity(name = "BOOK_EMBEDDED")
@SQLInsert( sql = "insert into BOOK_EMBEDDED (BOOK_NAME, group_no, version) values (?, ?, ?)")
public static class Book implements Serializable {

    @EmbeddedId
    private EmbeddedKey key;

    @Column(name = "BOOK_NAME")
    private String bookName;

    @Version
    @Column(insertable = false)
    private Integer version;

    public EmbeddedKey getKey() {
        return key;
    }

    public void setKey(EmbeddedKey key) {
        this.key = key;
    }

    public String getBookName() {
        return bookName;
    }

    public void setBookName(String bookName) {
        this.bookName = bookName;
    }
}

进行此更改后,您将运行以下测试:

With this change in place, you run the following test:

doInJPA(entityManager -> {

    EmbeddedKey key = new EmbeddedKey();
    key.setGroupNo(1);

    Book book = new Book();
    book.setBookName( "High-Performance Java Persistence");

    book.setKey(key);

    entityManager.persist(book);
});

doInJPA(entityManager -> {
    EmbeddedKey key = new EmbeddedKey();

    key.setGroupNo(1);
    key.setRowId(1L);

    Book book = entityManager.find(Book.class, key);
    assertEquals( "High-Performance Java Persistence", book.getBookName() );
});

然后Hibernate将生成正确的SQL语句:

And Hibernate will generate the right SQL statements:

Query:["insert into BOOK_EMBEDDED (BOOK_NAME, group_no, version) values (?, ?, ?)"], Params:[(High-Performance Java Persistence, 1, NULL(BIGINT))]

Query:["select compositei0_.group_no as group_no1_0_0_, compositei0_.row_id as row_id2_0_0_, compositei0_.BOOK_NAME as BOOK_NAM3_0_0_, compositei0_.version as version4_0_0_ from BOOK_EMBEDDED compositei0_ where compositei0_.group_no=? and compositei0_.row_id=?"], Params:[(1, 1)]

该测试可在 查看全文

登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆