簡體   English   中英

多級投影上的 Spring Data Neo4J 層次映射

[英]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 驅動程序類型,除其他外還由NodeMapValue

您可以在循環中使用結果中的這些值,例如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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM