Warning: file_get_contents(/data/phpspider/zhask/data//catemap/0/jpa/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Spring数据JPA-多通空_Spring_Jpa_Spring Data - Fatal编程技术网

Spring数据JPA-多通空

Spring数据JPA-多通空,spring,jpa,spring-data,Spring,Jpa,Spring Data,我正在学习Spring数据和JPA,在我的实体中建立简单的多通-一通连接时遇到困难 示例:模拟汽车和人(所有者)之间的关系,一个人可以拥有多辆汽车,但一辆汽车只能由一个人拥有 问题:车主(用ManyToOne注释)总是空的 App.java @EnableJpaRepositories @SpringBootApplication public class App { @Autowired private PersonRepository personRepository; @

我正在学习Spring数据和JPA,在我的实体中建立简单的多通-一通连接时遇到困难

示例:模拟汽车和人(所有者)之间的关系,一个人可以拥有多辆汽车,但一辆汽车只能由一个人拥有

问题:车主(用ManyToOne注释)总是空的

App.java

@EnableJpaRepositories
@SpringBootApplication
public class App {

    @Autowired private PersonRepository personRepository;
    @Autowired private CarRepository carRepository;

    @EventListener
    @Transactional
    public void handleContextRefresh(ContextRefreshedEvent event) {
        Car car1 = new Car();
        Car car2 = new Car();
        Person person = new Person();

        car1.setName("Ferrari");
        car2.setName("Porsche");
        person.setName("Person Name");

        carRepository.save(car1);
        carRepository.save(car2);

        person.getCars().add(car1);
        person.getCars().add(car2);

        personRepository.save(person);

        carRepository.findAll().forEach(System.out::println);   // TODO owner should not be null
        personRepository.findAll().forEach(System.out::println);
    }

    public static void main(String[] args) throws IOException, URISyntaxException {
        SpringApplication.run(App.class, args);
    }

}
java

@Entity
public class Car {

    @Id
    @GeneratedValue
    private UUID id;

    private String name;

    @ManyToOne
    private Person owner;

    public String getName() { return name; }
    public void setName(String name) { this.name = name; }

    public Person getOwner() { return owner; }
    public void setOwner(Person owner) { this.owner = owner; }

    @Override
    public String toString() {
        return "Car [id=" + id + ", name=" + name + ", owner=" + owner + "]";
    }

}
CarRepository.java

@Repository
public interface CarRepository extends CrudRepository<Car, UUID>  { }
@Repository
public interface PersonRepository extends CrudRepository<Person, UUID>  { }

两辆车的车主均为空。如何解决此问题?

问题是您未通过car.setOwner(…)设置车主。

而且,由于您在
OneToMany
注释上有
cascade=CascadeType.ALL
,因此您不需要先保存单个汽车,然后保存车主

只需调用
personRepository.save(person)应该足够了

因此,通过上述更改,您可以编写以下代码:

            Car car1 = new Car();
            Car car2 = new Car();
            Person person = new Person();

            car1.setName("Ferrari");
            car2.setName("Porsche");
            person.setName("Person Name");
            person.getCars().add(car1);
            person.getCars().add(car2);
            car1.setOwner(person);
            car2.setOwner(person);

            personRepository.save(person);
还有一件事,您需要修改
Car
对象的toString方法。Person对象的toString正在调用Car的toString,Car的toString在内部再次调用
Person
toString。这将导致
StackOverflowException
。考虑不要在<代码> Car toStrug()/<代码>方法中打印整个<代码>人对象< /代码>。 可能是
Car[id=“+id+”,name=“+name+”,owner=“+owner.getName()+”]

**更新**

如果您正在寻找一种特定的解决方案,希望确保车主在DB中填充,而无需调用
Car.setOwner(…)
方法,则可以更新
OneToMany
映射,如下所示:

    @OneToMany(cascade=CascadeType.ALL)
    @JoinColumn(name="owner")
    private Set<Car> cars = new HashSet<>();
@OneToMany(cascade=CascadeType.ALL)
@JoinColumn(name=“owner”)
私家车=新的HashSet();
基本上,
mappedBy
决定谁是双向关系的所有者。在第一种情况下,您提到了关系的所有权由
Car
实体通过
mappedBy
属性拥有。因此,除非我们在car对象上设置owner,否则ORM将不会填充
owner

第二种方法是删除mappedBy,
oneToMany
将成为关系的所有者,因此,一旦您添加到此人的车辆列表中,该人员id将用作所有者,并将在DB中根据车辆的“所有者”列填充


但是,在第二种情况下,会触发额外的更新来更新所有者列(与正常插入不同),因此所有者列应该可以为空。

这都是在单个事务的上下文中进行的,不同的存储库处理保存,而不进行刷新,所以我不确定你能否从carRepo检索personRepo所做的更改。简单的回答就是打电话给car.setOwner,然后把这个人传进来。否则,您需要使用
flush
,使用
entityManager
实例而不是两个单独的回购,使用
personRepo
检索汽车,或者重新构造代码以用不同的方法处理事情。据我所知,这是少数几种可能的解决方案之一。如果没有更详细的答案,我会接受的。感谢您指出,由于CascadeType.ALL以及潜在的StackOverFlowException,不需要进行任何保存。不确定您是否正在寻找一种特定的解决方案,在这种解决方案中,您希望在不调用
Car.setOwner(…)
方法的情况下,确保车主在DB中进行填充?如果是这样,您可以查看更新后的答案。如果我使用第一种方法(Car拥有关系),为什么还需要person.getCars().add(car1)调用?因为cascadeType.ALL位于
OneToMany
字段中。因为我们希望persist on
Person
传播到集合中的元素,所以我们需要填充它。否则,您将需要先对Person进行持久化,然后对单个车辆调用persist。
            Car car1 = new Car();
            Car car2 = new Car();
            Person person = new Person();

            car1.setName("Ferrari");
            car2.setName("Porsche");
            person.setName("Person Name");
            person.getCars().add(car1);
            person.getCars().add(car2);
            car1.setOwner(person);
            car2.setOwner(person);

            personRepository.save(person);
    @OneToMany(cascade=CascadeType.ALL)
    @JoinColumn(name="owner")
    private Set<Car> cars = new HashSet<>();