如何使用 Spring Boot JPA 从具有 @ManyToMany 关系的任务中删除标签?

问题描述 投票:0回答:1

我目前正在使用 Java 开发一个任务/项目/标签 Web 应用程序,并广泛使用 Spring Boot JPA(我对这个框架还比较陌生,所以请耐心等待)。我已经声明了任务和标签实体之间的 @ManyToMany 关系(定义如下)。

任务实体:

@JsonAutoDetect(fieldVisibility = JsonAutoDetect.Visibility.ANY)
@Entity()
@Table(name = "tasks_dim")
@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
public class Task {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    @Column(updatable = false, nullable = false)
    private Long id;

    @Column(nullable = false)
    private String name;

    private String status;

    private String priority;

    @Column(name = "task_id_number", unique = true)
    private String taskIdNumber;

    @JsonIgnore
    @ManyToOne(optional = false)
    @JoinColumn(name = "user_id", referencedColumnName = "id")
    private User user;

    @ManyToMany(fetch = FetchType.LAZY, cascade = {CascadeType.MERGE, CascadeType.PERSIST, CascadeType.DETACH})
    @JoinTable(name = "task_tags_dim",
            joinColumns = @JoinColumn(name = "task_id"),
            inverseJoinColumns = @JoinColumn(name = "tag_id"))
    private Set<Tag> tags = new LinkedHashSet<>();

    @Temporal(TemporalType.DATE)
    @Column(name = "due_date")
    private Date dueDate;

    public Task(String name, String status, String priority, User user) {
        setName(name);
        setDescription(description);
        setStatus(status);
        setPriority(priority);
        setTaskIdNumber(new TaskIdNumberBuilder().buildTaskIdNumber());
        setUser(user);
        setDueDate(dueDate);
        Timestamp currentTime = new Timestamp(new Date().getTime());
        setCreatedOn(currentTime);
        setLastUpdatedOn(currentTime);
    }

标签实体:

@JsonAutoDetect(fieldVisibility = JsonAutoDetect.Visibility.ANY)
@Entity()
@Table(name = "tags_dim")
@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
public class Tag {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    @Column(updatable = false, nullable = false)
    private Long id;

    @Column(nullable = false, unique = true)
    private String name;


    @ManyToMany(mappedBy = "tags", fetch = FetchType.LAZY)
    private Set<Task> tasks = new LinkedHashSet<>();

    public Tag(String name) {
        setName(name);
    }

但是,我的 TagService 类遇到问题,因为我无法在 removeTag 方法中使用 getTags() 。它返回一个空集,因此即使我在 create() 和 addTag() 方法中添加标签,也无需删除任何内容。如果我在 create() 中使用 setTags(),我仍然无法从其他方法中的 getTags() 获取任何数据。 注:

  • create()创建一个新的Tag对象,在Tag对象之间添加一个链接 新创建的标签对象及其各自的任务,并将其保存到 数据库
  • addTag() 在现有标签和给定标签之间添加链接
  • task removeTag() 删除现有标签和给定标签之间的链接
  • task delete() 一起删除标签(标签之间的所有链接) 并且任何任务都应该被删除)
@Service
@Transactional
public class TagService {
    @Autowired
    private TagRepository tagRepository;
    @Autowired
    private TaskRepository taskRepository;

    public Tag create(User user, Tag tag, Long task_id) {
        try {
            Optional<Task> optionalTask = taskRepository.findById(task_id);
            if (optionalTask.isPresent()) {
                Tag tagDetails = new Tag(tag.getName());
                Tag savedTag = tagRepository.save(tagDetails);
                Task currentTask = optionalTask.get();

                currentTask.getTags().add(savedTag);
                taskRepository.save(currentTask);
                return savedTag;
            }
        } catch(IllegalArgumentException e) {
            throw new IllegalArgumentException("Tag '" + tag.getName() + "' already exists.");
        }
        throw new NoSuchElementException("Task not found for the given task_id: " + task_id);
    }

    public Tag addTag(Tag tag, Long task_id) {
        Optional<Task> optionalTask = taskRepository.findById(task_id);
        if(optionalTask.isPresent()) {
            Task task = optionalTask.get();
            try {
                task.getTags().add(tag);
                taskRepository.save(task);
                return tag;
            } catch(Exception e) {
                throw new IllegalArgumentException("Tag '" + tag.getName() + "' is a duplicate entry.");
            }
        }
        throw new NoSuchElementException("Task not found for the given task_id: " + task_id);
    }


    public Set<Tag> getByTask(Long task_id) {
        Optional<Task> optionalTask = taskRepository.findById(task_id);
        if(optionalTask.isPresent()) {
            Set<Tag> myTags = optionalTask.get().getTags();
            for(Tag tag: myTags) {
                System.out.println(tag.getName());
            }
            return tagRepository.findByTasks(optionalTask.get());
        }
        throw new IllegalArgumentException("Task not found for the given task_id: " + task_id);
    }

    public Set<Tag> removeTag(Tag tag, Long task_id) {
        Optional<Task> optionalTask = taskRepository.findById(task_id);
        try {
            if(optionalTask.isPresent()) {

                Task currentTask = optionalTask.get();
                System.out.println(currentTask.getTags());
                return currentTask.getTags();
            }
        } catch(IllegalArgumentException e) {
            throw new IllegalArgumentException("Tag not found for the given task_id: " + task_id);
        }
        throw new NoSuchElementException("Request to remove tag from given task id '" + task_id + "' could not be processed");
    }

    public void delete(Tag tag) {
        tagRepository.deleteById(tag);
    }
}

我尝试使用 Hibernate.initialize 但没有运气。 “FetchType.LAZY”是此用例的理想类型吗?

java spring spring-boot spring-data-jpa many-to-many
1个回答
0
投票

可选解决方案1:在Task类中使用@Getter和@Setter代替@Data。

可选解决方案 2:

@ToString
注释中的
@EqualsAndHashCode
@Data
注释可能会导致问题。如果你想使用
@Data
,你应该重写 toString()、equals() 和 hashCode() 方法。

可选解决方案 3:只需将

@EqualsAndHashCode(of = "id")
添加到 Task 类即可。

© www.soinside.com 2019 - 2024. All rights reserved.