[英]Spring Data Neo4J hierarchy mapping on multi-level projection
我在 neo4j 中有一個簡單的層次結構,直接源自業務模型。
@Node
public class Team {
@Id private String teamId;
private String name;
}
@Node
public class Driver {
@Id private String driverId;
private String name;
@Relationship(direction = Relationship.Direction.OUTGOING)
private Team team;
}
@Node
public class Car {
@Id private String carId;
private String name;
@Relationship(direction = Relationship.Direction.OUTGOING)
private Driver driver;
}
這導致相應的圖表(Team)<--(Driver)<--(Car)
通常所有請求都從Car
開始。
一個新的用例需要從Team
節點開始創建一個樹結構。 Cypher 查詢聚合 neo 上的數據並將其返回給 SDN。
public List<Projection> loadHierarchy() {
return neo4jClient.query("""
MATCH(t:Team)<--(d:Driver)<--(c:Car)
WITH t, d, collect(distinct c{.carId, .name}) AS carsEachDriver
WITH t, collect({driver: d{.driverId, .name}, cars: carsEachDriver }) AS driverEachTeam
WITH collect({team: t{.teamId, .name}, drivers: driverEachTeam }) as teams
RETURN teams
""")
.fetchAs(Projection.class)
.mappedBy((typeSystem, record) -> new Projection() {
@Override
public Team getTeam() {
return record.get... // how to access single object?
}
@Override
public List<Retailers> getRetailers() {
return record.get... // how to access nested list objects?
}
})
.all();
}
結果是以下對象的列表:
{
"drivers": [
{
"driver": {
"name": "Mike",
"driverId": "15273c10"
},
"cars": [
{
"carId": "f4ca4581",
"name": "green car"
},
{
"carId": "11f3bcae",
"name": "red car"
}
]
}
],
"team": {
"teamId": "4586b33f",
"name": "Blue Racing Team"
}
}
現在的問題是,如何將響應映射到相應的 Java 模型中。 我不使用實體類。
我嘗試使用嵌套接口進行多級投影。
public interface Projection {
Team getTeam();
List<Drivers> getDrivers();
interface Drivers {
Driver getDriver();
List<Cars> getCars();
}
interface Driver {
String getDriverId();
String getName();
}
interface Car {
String getCarId();
String getName();
}
interface Team {
String getTeamId();
String getName();
}
}
我很難訪問嵌套列表和對象,將它們放入模型中。
SDN 是 2.6.3 版本的 Spring Boot Starter。
如何在列表中映射嵌套對象的示例將是一個很好的起點。
或者可能是我的方法完全錯誤? 任何幫助表示贊賞。
投影並不意味着類似於任意數據的視圖或包裝器。
在上下文中,您可以獲得Neo4jMappingContext
實例。 您可以使用它來獲取現有實體的映射函數。 有了這個,您不必關心映射Car
和(部分由於團隊關系) Drivers
。
BiFunction<TypeSystem, MapAccessor, Car> mappingFunction = neo4jMappingContext.getRequiredMappingFunctionFor(Car.class);
映射函數接受MapAccessor
類型的對象。 這是一種 Neo4j Java 驅動程序類型,除其他外還由Node
和MapValue
。
您可以在循環中使用結果中的這些值,例如drivers
(應該可以在記錄上調用asList
),並且在此循環中您還可以分配cars
。
當然,只有當您有更多要映射的屬性時,使用映射函數才有意義,因為返回結構中的任何內容(正如您在兩行之間已經說過的那樣)適用於有關關系的實體結構。
這是使用映射功能和直接映射的示例。 您必須決定最適合您的用例的內容。
public Collection<Projection> loadHierarchy() {
var teamMappingFunction = mappingContext.getRequiredMappingFunctionFor(Team.class);
var driverMappingFunction = mappingContext.getRequiredMappingFunctionFor(Driver.class);
return neo4jClient.query("""
MATCH(t:Team)<--(d:Driver)<--(c:Car)
WITH t, d, collect(distinct c{.carId, .name}) AS carsEachDriver
WITH t, collect({driver: d{.driverId, .name}, cars: carsEachDriver }) AS driverEachTeam
WITH {team: t{.teamId, .name}, drivers: driverEachTeam } as team
RETURN team
""")
.fetchAs(Projection.class)
.mappedBy((typeSystem, record) -> {
Team team = teamMappingFunction.apply(typeSystem, record.get("team"));
List<DriverWithCars> drivers = record.get("team").get("drivers").asList(value -> {
var driver = driverMappingFunction.apply(typeSystem, value);
var cars = value.get("carsEachDriver").asList(carValue -> {
return new Car(value.get("name").asString());
});
return new DriverWithCars(driver, cars); // create wrapper object incl. cars
});
return new Projection(team, drivers);
})
.all();
}
(免責聲明:我沒有在數據集上執行此操作,因此可能存在拼寫錯誤或對記錄的錯誤訪問)請注意,我稍微更改了密碼語句,以使每條記錄獲得一個Team
,而不是整個列表。 也許這已經是你所要求的。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.