微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

Hibernate left join fetch to soft-deleted entity 映射到@ManyToMany 关联生成无效查询?

如何解决Hibernate left join fetch to soft-deleted entity 映射到@ManyToMany 关联生成无效查询?

我不知道这是 Hiberante 的问题还是我做错了什么。

我试图让这个例子尽可能简单。

我的实体:

Book.java:

@Entity
@Table(name="books")
@sqlDelete(sql="UPDATE books set is_deleted = true where id = ?")
@Where(clause="is_deleted = false")
public class Book implements Serializable {

    @Id
    @Column(name = "id",updatable = false,nullable = false)
    private long id;

    @Column (name="is_deleted")
    private boolean deleted;

    @Column(name="title")
    private String title;
    
    @ManyToMany(fetch = FetchType.LAZY,cascade = CascadeType.ALL)
    @JoinTable(
            name="books_authors",joinColumns = {
                    @JoinColumn(name="id_books")
            },inverseJoinColumns = {
                    @JoinColumn(name="id_authors")
            }
    )
    private Set<Author> authors = new HashSet<>();

    //getters/setters
}

作者.java:

@Entity
@Table(name="autors")
@sqlDelete(sql="UPDATE autors set is_deleted = true where id = ?")
@Where(clause="is_deleted = false")
public class Author implements Serializable {

    @Id
    @Column(name = "id",nullable = false)
    private long id;

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

    @Column (name="is_deleted")
    private boolean deleted;

    @ManyToMany(mappedBy = "authors",fetch = FetchType.LAZY)
    private Set<Book> books = new HashSet<>();

    //getters/setters
}

底层表:

create table autors (
    id int8 not null,is_deleted boolean,name varchar(255),primary key (id)
); 
   
create table books (
    id int8 not null,title varchar(255),primary key (id)
); 
   
create table books_authors (
    id_books int8 not null,id_authors int8 not null,primary key (id_books,id_authors)
);
alter table if exists books_authors add constraint FK9xru8ocoxufr5eva6atfyfjxh foreign key (id_authors) references autors;
alter table if exists books_authors add constraint FKx5d5025t9ct5kcbwwxm6tipo foreign key (id_books) references books;

数据:

select * from books;
id is_deleted 标题
1 TITLE_1
2 TITLE_2
select * from authors;
id is_deleted 姓名
1 删除
2 真实 删除
select * from books b
join books_authors ba on b.id = ba.id_books 
join autors a on a.id = ba.id_authors;
id is_deleted 标题 id_books id_authors id is_deleted 姓名
1 TITLE_1 1 1 1 删除
2 TITLE_2 2 2 2 真实 删除

JPQL:

public Optional<Book> getBookWithSoftDeletedAuthor(long bookId) {
    List<Book> myBooks = em.createquery(
            "select b from " +
            "Book b " +
            "left join fetch b.authors a " +
            "where b.id = :bookId",Book.class)
            .setParameter("bookId",bookId)
            .getResultList();
    return myBooks.size() > 0 ? Optional.of(myBooks.get(0)) : Optional.empty();
}

持久性.xml:

<persistence xmlns="http://xmlns.jcp.org/xml/ns/persistence"
             xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
             xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/persistence
             http://xmlns.jcp.org/xml/ns/persistence/persistence_2_1.xsd"
             version="2.1">
    <persistence-unit name="WildflyUnit">
        <description> Persistence unit for Wildfly </description>
        <jta-data-source>java:jboss/datasources/WildflyDataSource</jta-data-source>
        <properties>
            <property name="hibernate.dialect" value="org.hibernate.dialect.Postgresql95Dialect"/> 
            <property name="hibernate.hbm2ddl.auto" value="update" />
            <property name="hibernate.show_sql" value="true" />
            <property name="hibernate.format_sql" value="true" />
            <property name="hibernate.generate_statistics" value="true" />
        </properties>
    </persistence-unit>
</persistence>

来自 Wildfly 的 standalone.xml 的数据源:

<datasource jndi-name="java:jboss/datasources/WildflyDataSource" pool-name="WildflyDataSource" enabled="true" use-java-context="true" statistics-enabled="true">
    <connection-url>jdbc:postgresql://localhost:5432/TestDB</connection-url>
    <driver>postgresql</driver>
    <security>
        <user-name>wildfly_user</user-name>
        <password>********</password>
    </security>
</datasource>

Hibernate 生成 sql 语句如下:

select
    book0_.id as id1_1_0_,author2_.id as id1_0_1_,book0_.is_deleted as is_delet2_1_0_,book0_.title as title3_1_0_,author2_.is_deleted as is_delet2_0_1_,author2_.name as name3_0_1_,authors1_.id_books as id_books1_2_0__,authors1_.id_authors as id_autho2_2_0__ -- this column is not null even if the author is soft-deleted
from
    books book0_ 
left outer join
    books_authors authors1_ 
        on book0_.id=authors1_.id_books 
left outer join
    authors author2_ 
        on authors1_.id_authors=author2_.id 
        and (
            author2_.is_deleted = false
        ) 
where
    (
        book0_.is_deleted = false
    ) 
    and book0_.id=2
    

imho Hibernate 应该像这样生成这个查询

 select
    book0_.id as id1_1_0_,book0_.id as id_books1_2_0__,author2_.id as id_autho2_2_0__ 
from
    books book0_ 
left outer join
    books_authors authors1_ 
        on book0_.id=authors1_.id_books 
left outer join
    authors author2_ 
        on authors1_.id_authors=author2_.id 
        and (
            author2_.is_deleted = false
        ) 
where
    (
        book0_.is_deleted = false
    ) 
    and book0_.id=2

id_autho2_2_0__ 列应该来自author2_(authors 表),而不是authors1_(books_authors 表)。由于authors1_.id_authors 列的值不为空,hibernate 尝试从authors 表中获取删除的实体。

我使用 Hibernate 5.4.27.Final

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。

相关推荐


Selenium Web驱动程序和Java。元素在(x,y)点处不可单击。其他元素将获得点击?
Python-如何使用点“。” 访问字典成员?
Java 字符串是不可变的。到底是什么意思?
Java中的“ final”关键字如何工作?(我仍然可以修改对象。)
“loop:”在Java代码中。这是什么,为什么要编译?
java.lang.ClassNotFoundException:sun.jdbc.odbc.JdbcOdbcDriver发生异常。为什么?
这是用Java进行XML解析的最佳库。
Java的PriorityQueue的内置迭代器不会以任何特定顺序遍历数据结构。为什么?
如何在Java中聆听按键时移动图像。
Java“Program to an interface”。这是什么意思?