当嵌入式键包含 SQL Server 上的标识列时,Hibernate 插入失败

2024-06-24

我正在尝试使用 hibernate 映射实体,但是使用 SQL Server,我无法继续。

以下是详细信息。

SQL Server 实体

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]

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

嵌入式密钥

@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.

任何帮助将不胜感激。


使其工作的唯一方法是覆盖SQLInsert并欺骗 Hibernate 来设置标识符列。如果您提供自己的自定义 INSERT 语句,则可以完成此操作,而不是设置rowId为 null,则将版本设置为:

@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 https://github.com/vladmihalcea/high-performance-java-persistence/blob/1fcd846f5fb6f356e4509218f9bd5dd38127b7fe/core/src/test/java/com/vladmihalcea/book/hpjp/hibernate/identifier/composite/CompositeIdGeneratedIdClassTest.java.

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

当嵌入式键包含 SQL Server 上的标识列时,Hibernate 插入失败 的相关文章

随机推荐