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

5uzkadbs  于 4个月前  发布在  Spring
关注(0)|答案(1)|浏览(55)

我目前正在使用Java开发一个task/project/tags Web应用程序,广泛使用Sping Boot JPA(我对这个框架相对较新,所以请原谅我)。我已经在Task和Tag实体之间声明了@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'是这个用例的理想类型吗?

7dl7o3gd

7dl7o3gd1#

可选解决方案1:在Task类中使用@Getter和@Setter而不是@Data。
可选解决方案2:@Data annotation中的@ToString@EqualsAndHashCode annotation可能会导致问题。如果你想使用@Data,你应该覆盖toString(),equals()和hashCode()方法。
可选解决方案3:只需将@EqualsAndHashCode(of = "id")添加到Task类。

相关问题