【问题标题】:Neo4j - Custom converter for field of type ListNeo4j - List 类型字段的自定义转换器
【发布时间】:2019-01-30 00:30:02
【问题描述】:

我正在尝试为嵌套对象编写自定义转换器,以便该对象在 Neo4j 数据库中保存为字符串。

我在我的字段上使用@Convert 注释并传递ImageConverter.class 这是我的AttributeConverter 类。

一切正常,我可以在 Neo4j db 中保存 Image 类的字符串表示形式。

但是,现在我希望将List<Image> 作为我的嵌套字段,而不是单个图像。在这种情况下,输入@Convert(ImageConverter.class) 不起作用。

我看到有一个名为 ConverterBasedCollectionConverter 的类,当我有一个 List<LocalDateTime 类型的字段时会使用它。

但是,在自定义转换器的情况下,我找不到任何有关如何使用此类的示例。

请任何人帮助我,或者如果有任何其他方法可以在 List 类型的字段上使用自定义转换器。

我在我的应用程序中使用 Neo4j(版本 3.4.1)和 Spring-data-neo4j(5.0.10.RELEASE)。我也在使用 OGM。

PS:我知道建议将嵌套对象存储为与父对象建立关系的单独节点。但是,我的用例要求将对象存储为字符串属性而不是单独的节点。

问候,

V

【问题讨论】:

  • 您是否也可以将它们存储在Map 中?
  • @meistermeier,我更愿意将其存储在List 中,因为它使更新和删除更容易。但是如果列表不可能,你知道如何使用Map

标签: neo4j spring-data-neo4j neo4j-ogm


【解决方案1】:

这并不像我想象的那么难。

给定一个类(sn-p)

@NodeEntity
public class Actor {

  @Id @GeneratedValue
  private Long id;

  @Convert(MyImageListConverter.class)
  public List<MyImage> images = new ArrayList<>();
  // ....
}

MyImage 尽可能简单

public class MyImage {

  public String blob;

  public MyImage(String blob) {
      this.blob = blob;
  }

  public static MyImage of(String value) {
      return new MyImage(value);
  }
}

还有一个转换器

public class MyImageListConverter implements AttributeConverter<List<MyImage>, String[]> {

  @Override
  public String[] toGraphProperty(List<MyImage> value) {
      if (value == null) {
          return null;
      }
      String[] values = new String[(value.size())];
      int i = 0;
      for (MyImage image : value) {
          values[i++] = image.blob;
      }
      return values;
    }

    @Override
    public List<MyImage> toEntityAttribute(String[] values) {
      List<MyImage> images = new ArrayList<>(values.length);
      for (String value : values) {
          images.add(MyImage.of(value));
      }
      return images;
    }
}

将在保存时打印以下调试输出,我认为这是您想要的:

UNWIND {rows} as row CREATE (n:Actor) SET n=row.props RETURN row.nodeRef as ref, ID(n) as id, {type} as type with params {type=node, rows=[{nodeRef=-1, props={images=[blobb], name=Jeff}}]}

尤其是图片部分。

这个测试方法看起来像

@Test
public void test() {
    Actor jeff = new Actor("Jeff");
    String blobValue = "blobb";
    jeff.images.add(new MyImage(blobValue));
    session.save(jeff);
    session.clear();
    Actor loadedActor = session.load(Actor.class, jeff.getId());
    assertThat(loadedActor.images.get(0).blob).isEqualTo(blobValue);

}

【讨论】:

  • 谢谢@meistermeier。你打败了我的解决方案。我想出了一个非常相似的解决方案。我扩展了ConverterBasedCollectionConverter 来为对象列表创建一个转换器。我将接受您的回答作为已接受的答案。感谢您的时间和精力。真的很感激!
【解决方案2】:

我想出了解决问题的方法。因此,如果您想要其他解决方案以及@meistermeier 提供的解决方案,您可以使用以下代码。

public class ListImageConverter extends ConverterBasedCollectionConverter<Image, String>{

public ListImageConverter() {
    super(List.class, new ImageConverter());
}

@Override
public String[] toGraphProperty(Collection<Image> values) {
    Object[] graphProperties = super.toGraphProperty(values);
    String[] stringArray = Arrays.stream(graphProperties).toArray(String[]::new);
    return stringArray;
}

@Override
public Collection<Image> toEntityAttribute(String[] values) {
    return super.toEntityAttribute(values);
}

}

ImageConverter 类只实现了AttributeConverter&lt;Image, String&gt;,我在其中将我的 Image 对象序列化和反序列化到 json。

我选择采用这种方法,因为我在一个对象中有 Image 字段,在另一个对象中有 List&lt;Image&gt;。因此,只需将@Convert(ListImageConverter.class) 更改为@Convert(ImageConverter.class),我就可以在 Neo4j 数据库中保存列表以及单个对象。

注意:如果需要,您可以跳过覆盖 toEntityAttribute 方法。它没有增加太多价值。 但是,您必须覆盖 toGraphProperty,因为在 Neo4j 代码中它会检查名称为 toGraphProperty 的声明方法是否存在。

希望这对某人有所帮助!

问候,

V

【讨论】:

    猜你喜欢
    • 2015-09-04
    • 2013-07-27
    • 2017-06-22
    • 1970-01-01
    • 2020-09-13
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多