0

我在 java/spring 中有以下问题。

我试图用一个更具体的案例来最大程度地简化我的问题。总而言之,我们有一个国家类,每个国家都与许多城市相关联。每个城市都通过一条中级道路与另一个城市相连。

我以这种方式实现了它(见下文),但这并不让我满意,因为我们在 Road 对象中有冗余,通过其城市和国家属性链接到 Country(例如,假设我们不关心复制品,即 Road Paris-Lyon 和 Road Lyon-Paris)。

另一个精度,我们没有跨国。国家下的所有道路和城市都属于同一个国家。

public class Country implements Serializable {
    ...

    @OneToMany(fetch = FetchType.LAZY, cascade = CascadeType.ALL, mappedBy = "country")
    private List<City> cities;

    @OneToMany(fetch = FetchType.LAZY, cascade = CascadeType.ALL, mappedBy = "country")
    private List<Road> roads;
}

public class City implements Serializable {
    ...

    @ManyToOne(optional = false)
    @JoinColumn(name = "countryId", referencedColumnName = "id")
    private Country country;
}

public class Road implements Serializable {
    // Unicity by the corresponding 3 items countryId, cityFromId and cityToId
    ...

    @ManyToOne(optional = false)
    @JoinColumn(name = "countryId", referencedColumnName = "id")
    private Country country;


    @ManyToOne(optional = false)
    @JoinColumn(name = "cityFromId", referencedColumnName = "id")
    private City cityFrom;


    @ManyToOne(optional = false)
    @JoinColumn(name = "cityToId", referencedColumnName = "id")
    private City cityTo;
}

为了避免这种重复引用,我们可以设想在 Road 类中取消对 Country 类的引用,但这意味着在类 City 中添加引用 @OneToMany 或 Road。由于这条道路连接了 2 个城市(见下文),因此我们将处于循环参考中。

public class Country implements Serializable {
    ...

    @OneToMany(fetch = FetchType.LAZY, cascade = CascadeType.ALL, mappedBy = "country")
    private List<City> cities;
}

public class City implements Serializable {
    ...

    @ManyToOne(optional = false)
    @JoinColumn(name = "countryId", referencedColumnName = "id")
    private Country country;

    @OneToMany(fetch = FetchType.LAZY, cascade = CascadeType.ALL, mappedBy = "cityFrom")
    private List<Road> cityFromRoad;

    @OneToMany(fetch = FetchType.LAZY, cascade = CascadeType.ALL, mappedBy = "cityTo")
    private List<Road> cityToRoad;
}

public class Road implements Serializable {
    // Unicity by the corresponding 3 items countryId, cityFromId and cityToId
    ...


    @ManyToOne(optional = false)
    @JoinColumn(name = "cityFromId", referencedColumnName = "id")
    private City cityFrom;


    @ManyToOne(optional = false)
    @JoinColumn(name = "cityToId", referencedColumnName = "id")
    private City cityTo;
}

你能帮我找到一个更好的方法来制作我的模型吗?

非常感谢!

4

1 回答 1

3

我认为您对实际模型没有很好的概念。道路应该是一个独立的实体,而不仅仅是两个城市之间的连接。例如,一条道路可以穿过许多城市。此外,一个城市可以有许多条道路。您所描述的是,城市可以连接到许多城市。

在此处输入图像描述

但是你要描述的是,ManyToMany道路和城市之间是有关系的。

在此处输入图像描述

只有单向映射的简单 JPA 模型如下所示。

@Entity
public class Country {
    @Id
    private String name;

@Entity
public class City {
    @Id
    private String name;    
    @ManyToOne
    private Country country;
    @ManyToMany
    private Set<Road> roads;

@Entity
public class Road {
    @Id
    private String name;    

为了保留地图,您创建一个县,添加城市,添加道路,并描述每个城市有哪些道路。

tx.begin();
Country france = new Country("France");
City paris = new City("Paris");
paris.setCountry(france);
City nice = new City("Nice");
nice.setCountry(france);
City normandy = new City("Normandy");
normandy.setCountry(france);
Road r1 = new Road("R1");
Road r2 = new Road("R2");
Set<Road> roads = new HashSet<>();
roads.add(r1);
roads.add(r2);
paris.setRoads(roads);
roads = new HashSet<>();
roads.add(r2);
normandy.setRoads(roads);
roads = new HashSet<>();
roads.add(r1);
nice.setRoads(roads);

em.persist(france);
em.persist(paris);
em.persist(nice);
em.persist(normandy);
em.persist(r1);
em.persist(r2);

tx.commit();

为了获得一个城市的道路列表,您选择带有道路列表的城市。要查看道路连接到哪些城市,请选择道路列表中包含该道路的城市。

TypedQuery<City> roadsForCityQuery = em.createQuery("select c from City c join fetch c.roads join fetch c.country where c = :city", City.class);

City normandyRoads = roadsForCityQuery.setParameter("city", normandy).getSingleResult();    
System.out.println("normandyRoads = " + normandyRoads);

City parisRoads = roadsForCityQuery.setParameter("city", paris).getSingleResult();
System.out.println("parisRoads = " + parisRoads);

TypedQuery<City> citiesForRoadQuery = em.createQuery("select distinct c from City c join fetch c.roads road join fetch c.country where road = :road", City.class);

List<City> r1Cities = citiesForRoadQuery.setParameter("road", r1).getResultList();  
System.out.println("r1Cities = " + r1Cities);

List<City> r2Cities = citiesForRoadQuery.setParameter("road", r2).getResultList();  
System.out.println("r2Cities = " + r2Cities);

这给出了以下结果:

normandyRoads = City(name=Normandy, roads=[Road(name=R2)])
parisRoads = City(name=Paris, roads=[Road(name=R1), Road(name=R2)])
r1Cities = [City(name=Nice, roads=[Road(name=R1)]), City(name=Paris, roads=[Road(name=R1), Road(name=R2)])]
r2Cities = [City(name=Normandy, roads=[Road(name=R2)]), City(name=Paris, roads=[Road(name=R1), Road(name=R2)])]
于 2019-01-06T01:10:42.063 回答