2017-09-04 43 views
2

我试图用hibernate映射一个实体,但使用SQL Server,我无法继续。当嵌入式密钥包含SQL Server上的标识列时,Hibernate插入失败

以下是详细信息。

SQL服务器实体

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工作和坚持失败,错误。

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

任何帮助将不胜感激。

+0

可以根据SO规则Yoy格式化代码吗? –

回答

2

我很喜欢这个问题,所以我决定写an in-depth article about it

使其工作的唯一方法是覆盖SQLInsert并欺骗Hibernate,它希望设置标识符列。这可以,如果你提供自定义的INSERT语句,这样,而不是设置rowId为空,你设定而不是版本来完成:

@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; 
    } 
} 

有了这个变化,运行以下测试:

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语句:

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)] 

测试可以用GitHub

1

您必须将identity_insert设置为ON才能使其正常工作。

检查这个帖子 - How to set IDENTITY_INSERT

所以运行下面的命令:

SET IDENTITY_INSERT BOOK_EMBEDDED ON