无法在存储库查询中使用枚举(neo4j / Spring Data)

3
我是一名有用的助手,可以为您翻译文本。

我遇到了一个问题,需要根据我的NodeEntity的Enum属性进行查询。

所涉及的NodeEntity的定义如下:

@NodeEntity(label = "Entity")
public class MyEntity {

    @GraphId
    private Long internalId;

    ....

    private State state;

    @Transient
    public enum State {
        STATEONE, STATETWO, STATETHREE
    }
    ....

它可以完美地保存状态枚举,并且我可以毫无问题地使用其他属性(字符串)进行查询。然而,在存储库中遇到的问题是以下查询:

@Query("MATCH (entity:Entity {state:{0}})" +
       "RETURN entity")
List<MyEntity> findByState(MyEntity.State state)

即查找所有具有指定状态的实体。

然而,使用此方法仅返回一个空实体列表,没有任何异常。

我尝试了各种变化,例如使用WHERE子句等,但都没有成功。

实体已正确持久化,使用同一测试中的findAll()方法返回预期的实体列表,其状态与我的预期完全相同。

有什么想法吗?


1
嗨@R.B!你确定属性状态在neo4j数据库中正确保存了吗?我尝试重现你的用例并声明枚举@Transient,但是属性状态没有被持久化。移除瞬态注释后,状态被正确持久化,并且查询也正常工作。你可以试试吗? - troig
1
它确实被持久化了。对我来说,实体可以无问题地保存,而“状态”属性甚至可以使用事务方法进行修改。然而,枚举定义中的瞬态确实导致了问题。谢谢,没有它我可以查询,没问题。 - R.B.
2个回答

5
我不太确定@Transient对枚举值有什么意义。无论如何,在Neo4j中它都不能作为一个节点或关系进行持久化。只需将字段定义为应该保留的字段即可:private State state;,不需要在枚举中添加@Transient注释。如果这样做,SDN将忽略发送到派生查询的字段。然而,如果您有充分的理由将枚举标记为@Transient,请分享一下,我们将重新审视此案例。

谢谢,这就是答案。Transient引起了问题。它被添加为一种预防措施,以确保SDN不会尝试对枚举执行任何操作。然而,即使没有@Transient,它的行为也是合理的。感谢您的指导。 - R.B.

2

使用Spring Data REST接口搜索枚举字段存在一般性问题。仅使用枚举到字符串转换器无法处理希望查找值是否在值集合中的搜索:

public interface AppointmentRepository extends Neo4jRepository<Appointment, Long> {

  Page<Appointment> findByDayOfWeekIn(@Param("days") List<DayOfWeek> days, Pageable pageable);

}

上述内容无法直接使用,因为neo4j会尝试将List转换为DayOfWeek属性类型。

为了解决这个问题,我需要一个自定义转换器,它可以处理请求提供值的集合(搜索),以及单个值(正常读写实体):

@SuppressWarnings({ "unchecked", "rawtypes" })
public abstract class SearchQueryEnumConverter<T extends Enum> {
    private Class<T> enumType;

    public SearchQueryEnumConverter() {
        enumType = (Class<T>) ((ParameterizedType) this.getClass()).getActualTypeArguments();
    }

    public Object toGraphProperty(Object value) {
        if (Collection.class.isAssignableFrom(value.getClass())) {
            List<T> values = (List<T>) value;
            return values.stream().map(Enum::name).collect(Collectors.toList());
        }
        return ((Enum) value).name();
    }

    public Object toEntityAttribute(Object value) {
        if (Collection.class.isAssignableFrom(value.getClass())) {
            List<String> values = (List<String>) value;
            return values.stream().map(v -> (T) T.valueOf(enumType, v)).collect(Collectors.toList());
        }
        return (T) T.valueOf(enumType, value.toString());
    }

}

抽象转换器可由所有枚举类型实例化,并用作 @Convert 注解的参数:
 public enum EnumType {
     VALUE_A, VALUE_B;

     public static class Converter extends SearchQueryEnumConverter<EnumType> implements AttributeConverter {
     }
 }

 @NodeEntity
 public Entity {
     @Property
     @Convert(EnumType.Converter.class)
     EnumType type;
 }

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接