mysql - 使用嵌入式模型的 Spring Boot Hibernate ManyToMany Relation

标签 mysql spring hibernate spring-boot spring-data-jpa

我有一个关于多对多关系的问题。假设我们有两个模型域,例如 Menu 和 RoleGroup,我的 Menu 模型包含一个名为“private RoleGroup roleGroup ”的字段,具有 @ManyToMany 关系和 @JoinTable 以及 JoinColumns 和 InverseJoinColumns。 想象一下,我已经创建了一个像 Menu 这样的对象,其中包含带有EntityRepository.save 的 RoleGroup 字段在我的数据库中这是我的问题,有没有办法在不使用 native 查询的情况下更新我的对象(考虑ManyToMany 关系)?因为当我们使用 ManyToMany 关系时,hibernate 通过在数据库中创建第三个表(如“Menu_RoleGroup”)来处理它,而我们没有像 Menu_RoleGroup 这样的域。

//这是我的申请

   package org.sayar.layout.domain;

    import java.util.HashSet;
    import java.util.Set;

    import javax.persistence.Column;
    import javax.persistence.Entity;
    import javax.persistence.FetchType;
    import javax.persistence.JoinColumn;




    import javax.persistence.JoinTable;
    import javax.persistence.ManyToMany;
    import javax.persistence.OneToMany;
    import javax.persistence.Table;

    import org.hibernate.annotations.Nationalized;
    import org.sayar.layout.base.general.domain.GeneralDomain;
    import org.sayar.layout.constants.SchemaList;
    import org.sayar.layout.domain.uaa.Role;
    import org.sayar.layout.domain.uaa.RoleGroup;
    import org.springframework.data.annotation.Transient;

    import com.fasterxml.jackson.annotation.JsonInclude;
    import com.fasterxml.jackson.annotation.JsonManagedReference;

    import lombok.AllArgsConstructor;
    import lombok.Getter;
    import lombok.NoArgsConstructor;
    import lombok.Setter;

    /**
     * This domain for store and transfer Menu
     *
     * @author Ehsan
     */
    @Setter
    @Getter
    @AllArgsConstructor
    @NoArgsConstructor
    @JsonInclude(JsonInclude.Include.NON_NULL)
    @Entity(name = Menu.TABLE_NAME)
    @Table(name = Menu.TABLE_NAME, schema = SchemaList.LAYOUT)
    public class Menu extends GeneralDomain {
        @Transient
        public final static String TABLE_NAME = "Menu";


        public class CN {
            public final static String title = "title";
            public final static String description = "description";
            public final static String banner = "banner";
        }

        @Nationalized
        @Column(name = CN.title, length = 128, nullable = false)
        private String title;

        @Nationalized
        @Column(name = CN.description, length = 1000)
        private String description;

        @Nationalized
        @Column(name = CN.banner, length = 128)
        private String banner;

        /* Relationships */

        @ManyToMany(fetch = FetchType.EAGER)
        @JoinTable(name = "Menu_RoleGroup",
                schema = SchemaList.LAYOUT,
                joinColumns = @JoinColumn(name = "menuId", referencedColumnName = GCN.id), //
                inverseJoinColumns = @JoinColumn(name = "roleGroupId", referencedColumnName = GCN.id))
        private Set<RoleGroup> roleGroupSet;

        @OneToMany(mappedBy = MenuItem.CN.menu, fetch = FetchType.EAGER)
        @JsonManagedReference
        private Set<MenuItem> menuItemSet = new HashSet<>();

        /* Constructors */
        public Menu(String title, String banner, String description) {
            this.title = title;
            this.banner = banner;
            this.description = description;
        }

        public Menu(String title, String banner, String description, Set<RoleGroup> roleGroupSet) {
            this.title = title;
            this.banner = banner;
            this.description = description;
            this.roleGroupSet = roleGroupSet;
        }

        public Menu(String id) {
            super(id);
        }
        /* Other classes or enumerations */

    }
    .
    .
    .
    .
    .

    package org.sayar.layout.domain.uaa;

    import java.util.Date;

    import javax.persistence.Column;
    import javax.persistence.Entity;
    import javax.persistence.EnumType;
    import javax.persistence.Enumerated;
    import javax.persistence.Table;

    import org.hibernate.annotations.Nationalized;
    import org.sayar.layout.base.general.domain.GeneralDomain;
    import org.sayar.layout.constants.SchemaList;
    import org.springframework.data.annotation.Transient;

    import com.fasterxml.jackson.annotation.JsonInclude;

    import lombok.AllArgsConstructor;
    import lombok.Getter;
    import lombok.NoArgsConstructor;
    import lombok.Setter;

    /**
     * This domain for store and transfer RoleGroup
     *
     * @author Ehsan
     *
     */
    @Setter
    @Getter
    @AllArgsConstructor
    @NoArgsConstructor
    @JsonInclude(JsonInclude.Include.NON_NULL)
    @Entity(name = RoleGroup.TABLE_NAME)
    @Table(name = RoleGroup.TABLE_NAME, schema = SchemaList.UAA)
    public class RoleGroup extends GeneralDomain {
        @Transient
        public final static String TABLE_NAME = "RoleGroup";

        public class CN {
            public final static String title = "title";
            public final static String status = "status";
        }

        @Nationalized
        @Column(name = CN.title, length = 128, nullable = false)
        private String title;

        @Enumerated(EnumType.STRING)
        @Column(name = CN.status, nullable = false)
        private Status status;

        public RoleGroup(String id) {
            super(id);
        }

        /* Relationships */
        /* Constructors */
        /* Other classes or enumerations */
        public enum Status {
            ACTIVE, DE_ACTIVE
        }
    }
    .
    .
    .
    package org.sayar.layout.service.menu;

    import org.sayar.layout.base.util.Print;
    import org.sayar.layout.domain.Menu;
    import org.sayar.layout.repository.megaitem.MegaItemRepository;
    import org.sayar.layout.repository.menu.MenuRepository;
    import org.sayar.layout.repository.menuitem.MenuItemRepository;
    import org.sayar.layout.rest.menu.dto.*;
    import org.springframework.stereotype.Service;
    import org.sayar.layout.dao.menu.MenuDaoImpl;
    import org.springframework.data.domain.Page;
    import org.springframework.data.domain.Pageable;
    import org.springframework.http.ResponseEntity;

    import java.util.List;

    import lombok.RequiredArgsConstructor;
    import org.springframework.transaction.annotation.Transactional;
    import reactor.core.publisher.Mono;

    /**
     * Spring service implementation for the Menu entity.
     *
     * @author Ehsan
     */
    @Service
    @RequiredArgsConstructor
    public class MenuServiceImpl implements MenuService {

        private final MenuDaoImpl entityDao;
        private final MenuRepository entityRepository;
        private final MenuItemRepository menuItemRepository;
        private final MegaItemRepository megaItemRepository;

        @Override
        public Mono<ResponseEntity<Boolean>> create(ReqMenuCreateDTO entity, String userId) {
            return Mono.just(entityRepository.save(entity.map(userId)))
                    .flatMap(createdEntity -> Mono.just(ResponseEntity.ok().body(true))
                    )
                    .defaultIfEmpty(ResponseEntity.ok().body(false));
        }

        @Transactional
        @Override
        public Mono<ResponseEntity<Boolean>> update(String id, ReqMenuUpdateDTO entity) {

            Mono.just(entityRepository.update(id, entity.getTitle(), entity.getBanner(), entity.getDescription())).subscribe();
            Mono.just(entityRepository.deleteRoleMenu(id)).subscribe();
            Print.print("title", entity);

            if (entity.getRoleGroupIdSet() != null && !entity.getRoleGroupIdSet().isEmpty())
                for (String roleId : entity.getRoleGroupIdSet()) {
                    Mono.just(entityRepository.updateRoleMenu(id, roleId)).subscribe();
                }
            return Mono.just(ResponseEntity.ok().body(true));

        }
    .
    .
    .
    .
    .
    package org.sayar.layout.repository.menu;


    import org.sayar.layout.constants.SchemaList;
    import org.sayar.layout.repository.menu.dto.ResRoleGetListRepoDTO;
    import org.sayar.layout.rest.menu.dto.ResMenuGetListDTO;
    import org.sayar.layout.repository.menu.dto.ResMenuGetOneRepoDTO;
    import org.sayar.layout.rest.menu.dto.ResMenuGetOneDTO;
    import org.sayar.layout.rest.menu.dto.ResMenuGetPageDTO;
    import org.springframework.data.jpa.repository.JpaRepository;
    import org.springframework.stereotype.Repository;

    import java.util.List;
    import java.util.Optional;

    import org.sayar.layout.domain.Menu;
    import org.springframework.data.domain.Page;
    import org.springframework.data.domain.Pageable;
    import org.springframework.data.jpa.repository.Modifying;
    import org.springframework.data.jpa.repository.Query;
    import org.springframework.data.repository.query.Param;
    import org.springframework.transaction.annotation.Transactional;

    /**
     * Spring Data SQL Server repository for the Menu entity.
     *
     * @author Ehsan
     */
    @Repository
    public interface MenuRepository extends JpaRepository<Menu, String> {

        //  UPDATE ALL STARTS HERE
        @Transactional
        @Modifying
        @Query(value = "UPDATE Menu AS m SET m.title = :title , m.description = :description, m.banner = :banner WHERE m.id = :id")
        Integer update(@Param("id") String id, @Param("title") String title, @Param("description") String description, @Param("banner") String banner);

        @Transactional
        @Modifying
        @Query(value = "DELETE FROM layout.Menu_RoleGroup WHERE menuId = :id", nativeQuery = true)
        Integer deleteRoleMenu(@Param("id") String id);

        @Transactional
        @Modifying
        @Query(value = "INSERT INTO layout.Menu_RoleGroup (menuId,roleGroupId) VALUES (:menuId,:roleGroupId)", nativeQuery = true)
        Integer updateRoleMenu(@Param("menuId") String menuId, @Param("roleGroupId") String roleGroupId);
    }

最佳答案

其实我已经知道怎么解决了! 在这种情况下,我必须创建一个像 MenuRoleGroup 这样的域模型作为实体,然后添加一个 Embeddable 字段,例如 MenuRoleGroupEmbeddable 并在 MenuRoleGroup 中使用 create @EmbeddedId 字段。 然后在MenuRoleGroupEmbeddable中添加Menu和RoleGroup的主键。

因此 Spring Data 能够创建扩展 JPA Repository 的 MenuRoleGroupRepository,但请注意该表有两个主键,而不是一个。

请注意,MenuRoleGroup 中的 MenuRoleGroupEmbeddable 字段没有关系,但 Menu 和 RoleGroup 都与 MenuRoleGroupEmbeddable 模型具有 @ManyToOne 关系。

这是示例。

package org.sayar.wms.domain.Menu;

import com.fasterxml.jackson.annotation.JsonInclude;
import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;
import org.hibernate.annotations.GenericGenerator;
import org.sayar.wms.base.general.domain.GeneralDomain;
import org.sayar.wms.constants.SchemaList;
import org.sayar.wms.domain.container.Container;
import org.sayar.wms.domain.product.ProductContainerEmbeddable;
import org.springframework.data.annotation.Transient;

import javax.persistence.*;
import java.util.Date;


@Setter
@Getter
@AllArgsConstructor
@NoArgsConstructor
@JsonInclude(JsonInclude.Include.NON_NULL)
@Entity(name = MenuRoleGroup.TABLE_NAME)
@Table(name = MenuRoleGroup.TABLE_NAME, schema = SchemaList.WMS)
public class MenuRoleGroup {

    @Transient
    public final static String TABLE_NAME = "MenuRoleGroup";

    public class CN {
        public final static String startDate = "startDate";
    }

    @EmbeddedId
    private MenuRoleGroupEmbeddable menuRoleGroupEmbeddable;

    @JoinColumn(name = CN.startDate, referencedColumnName = GeneralDomain.GCN.id)
    private Date startDate;

}


package org.sayar.wms.domain.Menu;

import com.fasterxml.jackson.annotation.JsonInclude;
import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;
import org.sayar.wms.base.general.domain.GeneralDomain;
import org.sayar.wms.domain.container.Container;

import javax.persistence.CascadeType;
import javax.persistence.Embeddable;
import javax.persistence.JoinColumn;
import javax.persistence.ManyToOne;
import java.io.Serializable;
import java.util.Set;

/**
 * This domain for store and transfer Warehouse
 *
 * @author masoud
 */
@Setter
@Getter
@AllArgsConstructor
@NoArgsConstructor
@JsonInclude(JsonInclude.Include.NON_NULL)
@Embeddable
public class ProductContainerEmbeddable implements Serializable {

    public class CN {
        public final static String menuId = "menuId";
        public final static String roleGroupId = "roleGroupId";
    }

    /* Relationships */

    @ManyToOne
    @JoinColumn(name = CN.menu, referencedColumnName = "id")
    private Menu menu;

    @ManyToOne
    @JoinColumn(name = CN.roleGroup, referencedColumnName ="id")
    private RoleGroup roleGroup;

    /* Constructors */


    /* Other classes or enumerations */

}

menuId 和 roleGroupId 都是 MenuRoleGroup 实体的主键。

关于mysql - 使用嵌入式模型的 Spring Boot Hibernate ManyToMany Relation,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/58312769/

相关文章:

php - 将分隔符从 textarea 发送到 mysql。列为 ",",行为 "\n"

mysql - 如何保存多语言网站的翻译和属性?

php - PDO 错误 : Call to a member function prepare() on null

java - Hibernate 替换字符串条件

java - hibernate 无故插入

hibernate - JPA实体关系: Cascade on delete

java - JBoss AS 7.1 中 MySQL 数据库的事务错误

java - 是否可以使用 Spring-WS 从 WSDL 文件创建 WS 客户端? (好像没有)

java - Spring Boot 或 Node js 应用程序的管理 UI

java - 当一个 @Around 建议无法继续时,建议优先级问题