Java 弹簧&x27;当使用findAll或findById时,s crudepository会对对象进行不同的组装

Java 弹簧&x27;当使用findAll或findById时,s crudepository会对对象进行不同的组装,java,spring,hibernate,spring-data-jpa,jpa-2.0,Java,Spring,Hibernate,Spring Data Jpa,Jpa 2.0,我使用Spring的Crudepository来持久化一个对象(WorkingDays),它包含一个其他对象的列表(Filter),基本上包含一组枚举。 使用Crudepository的findAll函数时,对象按预期进行组装;使用findById函数时,返回的WorkingDays对象包含错误的筛选项列表 请参见下面的示例 package com.example.jpastackoverflow.model; import lombok.Data; import javax.persisten

我使用Spring的Crudepository来持久化一个对象(WorkingDays),它包含一个其他对象的列表(Filter),基本上包含一组枚举。 使用Crudepository的findAll函数时,对象按预期进行组装;使用findById函数时,返回的WorkingDays对象包含错误的筛选项列表

请参见下面的示例

package com.example.jpastackoverflow.model;
import lombok.Data;
import javax.persistence.*;
import java.util.List;

@Entity
@Table(name = "working_days")
@Data
public class WorkingDays {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;

    private String someFiled;

    @OneToMany(cascade = CascadeType.ALL, fetch = FetchType.EAGER)
    @JoinColumn(name = "working_days_id")
    private List<Filter> filterList;

}
package com.example.jpastackoverflow.model;
导入org.springframework.data.repository.crudepository;
导入org.springframework.stereotype.Repository;
导入javax.transaction.Transactional;
@存储库(“存储库”)
@交易的
公共接口Repo扩展了crudepository{}
最后是测试:

@SpringBootTest
class WorkingDaysTest {
    @Autowired
    private Repo repo;

    @BeforeEach
    void setUp() {
        Set<DAYS> days1 = new HashSet<>();
        Set<DAYS> days2 = new HashSet<>();

        days1.add(DAYS.MONDAY);
        days1.add(DAYS.TUESDAY);
        days1.add(DAYS.WEDNESDAY);

        days2.add(DAYS.THURSDAY);
        days2.add(DAYS.FRIDAY);
        days2.add(DAYS.SATURDAY);
        days2.add(DAYS.SUNDAY);

        Filter filter1 = new Filter();
        Filter filter2 = new Filter();

        filter1.setSomeFiled("foo");
        filter2.setSomeFiled("bar");

        filter1.setDays(days1);
        filter2.setDays(days2);

        List<Filter> filterList = new ArrayList<>();
        filterList.add(filter1); //just add one entry to the list (Mon, Tue, Wed)
        filterList.add(filter2); //just add one entry to the list (Thu, Fri, Sat, Sun)

        WorkingDays workingDays1 = new WorkingDays();
        workingDays1.setSomeFiled("foo1");
        workingDays1.setFilterList(filterList);

        repo.save(workingDays1);
    }

    @Test
    void findAll() {
        Iterable<WorkingDays> it = repo.findAll();
        it.forEach(wd -> System.out.println(wd.toString()));
        /*
        WorkingDays(id=1,
        someFiled=foo1,
        filterList=[
        Filter(id=1, someFiled=foo, days=[TUESDAY, MONDAY, WEDNESDAY]),
        Filter(id=2, someFiled=bar, days=[SUNDAY, THURSDAY, FRIDAY, SATURDAY])])
         */
    }

    @Test
    void findById() {
        Optional<WorkingDays> oWorkingDays1 = repo.findById(1L);
        assertTrue(oWorkingDays1.isPresent());

        System.out.println(oWorkingDays1.get().toString());
        /*
        WorkingDays(id=1,
        someFiled=foo1,
        filterList=[
        Filter(id=1, someFiled=foo, days=[MONDAY, TUESDAY, WEDNESDAY]),
        Filter(id=1, someFiled=foo, days=[MONDAY, TUESDAY, WEDNESDAY]),
        Filter(id=1, someFiled=foo, days=[MONDAY, TUESDAY, WEDNESDAY]),
        Filter(id=2, someFiled=bar, days=[SATURDAY, SUNDAY, THURSDAY, FRIDAY]),
        Filter(id=2, someFiled=bar, days=[SATURDAY, SUNDAY, THURSDAY, FRIDAY]),
        Filter(id=2, someFiled=bar, days=[SATURDAY, SUNDAY, THURSDAY, FRIDAY]),
        Filter(id=2, someFiled=bar, days=[SATURDAY, SUNDAY, THURSDAY, FRIDAY])])
         */
    }
}
@SpringBootTest
类工作日测试{
@自动连线
私人回购;
@之前
无效设置(){
Set days1=新的HashSet();
Set days2=新的HashSet();
days1.添加(DAYS.周一);
days1.add(天,星期二);
天1.添加(天,星期三);
days2.add(天,星期四);
days2.add(天,星期五);
days2.add(天,星期六);
days2.add(DAYS.SUNDAY);
过滤器过滤器1=新过滤器();
过滤器过滤器2=新过滤器();
过滤器1.设置文件(“foo”);
过滤器2.设置文件(“bar”);
过滤器1.设置天数(第1天);
过滤器2.设置天数(第2天);
List filterList=new ArrayList();
filterList.add(filter1);//只需在列表中添加一个条目(周一、周二、周三)
filterList.add(filter2);//只需在列表中添加一个条目(周四、周五、周六、周日)
工作日工作日1=新工作日();
工作日1.设置文件(“foo1”);
工作日1.设置过滤器列表(过滤器列表);
回购保存(工作日1);
}
@试验
void findAll(){
Iterable it=repo.findAll();
it.forEach(wd->System.out.println(wd.toString());
/*
工作日(id=1,
somefield=foo1,
过滤列表=[
过滤器(id=1,somefield=foo,days=[周二、周一、周三],
过滤器(id=2,somefield=bar,days=[星期日、星期四、星期五、星期六])
*/
}
@试验
void findById(){
可选oWorkingDays1=回购findById(1L);
assertTrue(oWorkingDays1.isPresent());
System.out.println(oWorkingDays1.get().toString());
/*
工作日(id=1,
somefield=foo1,
过滤列表=[
过滤器(id=1,somefield=foo,days=[周一、周二、周三],
过滤器(id=1,somefield=foo,days=[周一、周二、周三],
过滤器(id=1,somefield=foo,days=[周一、周二、周三],
过滤器(id=2,somefield=bar,days=[周六、周日、周四、周五],
过滤器(id=2,somefield=bar,days=[周六、周日、周四、周五],
过滤器(id=2,somefield=bar,days=[周六、周日、周四、周五],
过滤器(id=2,somefield=bar,days=[周六、周日、周四、周五])
*/
}
}
findAll在存储时使用带有两个条目的“filterList”组合工作日(参见测试用例中的注释)

findById用一个包含七个条目的“filterList”组合工作日。对于“天”集合中的每个条目,似乎都会创建一个新的“过滤器”对象并将其添加到“过滤器列表”(请参见测试用例中的注释)


有人能解释一下为什么会发生这种情况,并提出一个可行的解决方案吗?

这就是你在一个袋子里找到加入协会的机会。使用
设置过滤器列表而不是
列表过滤器列表以避免这种情况。

您能再解释一下吗?为什么它对findAll有效,而对findById无效?我认为原因是
findAll
使用了一个查询,该查询不进行fetch连接,从而导致基数增加,而
findById
使用select fetching(发出单独的select语句)来初始化关联,它保留了基数。我想知道有没有办法用列表来解决它?我需要一个列表,以防我想添加两次相同的过滤器,所以应该有可能吗?如果你想使用一个没有顺序索引的列表,你需要使用选择抓取(
@Fetch(FetchMode.select)
),除非你指定一个合适的
@BatchSize
package com.example.jpastackoverflow.model;

public enum DAYS {
    MONDAY(0),
    TUESDAY(1),
    WEDNESDAY(2),
    THURSDAY(3),
    FRIDAY(4),
    SATURDAY(5),
    SUNDAY(6);

    private final Integer day;
    DAYS(final Integer day) {
        this.day = day;
    }
    public final Integer getDay() {
        return day;
    }
}
package com.example.jpastackoverflow.model;

import org.springframework.data.repository.CrudRepository;
import org.springframework.stereotype.Repository;
import javax.transaction.Transactional;

@Repository("Repository")
@Transactional
public interface Repo extends CrudRepository<WorkingDays, Long> {}
@SpringBootTest
class WorkingDaysTest {
    @Autowired
    private Repo repo;

    @BeforeEach
    void setUp() {
        Set<DAYS> days1 = new HashSet<>();
        Set<DAYS> days2 = new HashSet<>();

        days1.add(DAYS.MONDAY);
        days1.add(DAYS.TUESDAY);
        days1.add(DAYS.WEDNESDAY);

        days2.add(DAYS.THURSDAY);
        days2.add(DAYS.FRIDAY);
        days2.add(DAYS.SATURDAY);
        days2.add(DAYS.SUNDAY);

        Filter filter1 = new Filter();
        Filter filter2 = new Filter();

        filter1.setSomeFiled("foo");
        filter2.setSomeFiled("bar");

        filter1.setDays(days1);
        filter2.setDays(days2);

        List<Filter> filterList = new ArrayList<>();
        filterList.add(filter1); //just add one entry to the list (Mon, Tue, Wed)
        filterList.add(filter2); //just add one entry to the list (Thu, Fri, Sat, Sun)

        WorkingDays workingDays1 = new WorkingDays();
        workingDays1.setSomeFiled("foo1");
        workingDays1.setFilterList(filterList);

        repo.save(workingDays1);
    }

    @Test
    void findAll() {
        Iterable<WorkingDays> it = repo.findAll();
        it.forEach(wd -> System.out.println(wd.toString()));
        /*
        WorkingDays(id=1,
        someFiled=foo1,
        filterList=[
        Filter(id=1, someFiled=foo, days=[TUESDAY, MONDAY, WEDNESDAY]),
        Filter(id=2, someFiled=bar, days=[SUNDAY, THURSDAY, FRIDAY, SATURDAY])])
         */
    }

    @Test
    void findById() {
        Optional<WorkingDays> oWorkingDays1 = repo.findById(1L);
        assertTrue(oWorkingDays1.isPresent());

        System.out.println(oWorkingDays1.get().toString());
        /*
        WorkingDays(id=1,
        someFiled=foo1,
        filterList=[
        Filter(id=1, someFiled=foo, days=[MONDAY, TUESDAY, WEDNESDAY]),
        Filter(id=1, someFiled=foo, days=[MONDAY, TUESDAY, WEDNESDAY]),
        Filter(id=1, someFiled=foo, days=[MONDAY, TUESDAY, WEDNESDAY]),
        Filter(id=2, someFiled=bar, days=[SATURDAY, SUNDAY, THURSDAY, FRIDAY]),
        Filter(id=2, someFiled=bar, days=[SATURDAY, SUNDAY, THURSDAY, FRIDAY]),
        Filter(id=2, someFiled=bar, days=[SATURDAY, SUNDAY, THURSDAY, FRIDAY]),
        Filter(id=2, someFiled=bar, days=[SATURDAY, SUNDAY, THURSDAY, FRIDAY])])
         */
    }
}