简体   繁体   中英

Spring Data / Neo4J Repository : findByXXX returns Map, not Entity

I'm using Spring Data Neo4J.

I have extended the basic GraphRepository interface, adding a method, as follows:

/**
 * Extension to the repository interface for standard Spring Data repo's that
 * perform operations on graph entities that have a related RDBMS entity.
 * 
 * @author martypitt
 *
 * @param <T>
 */
public interface RelatedEntityRepository<T> extends GraphRepository<T>, 
RelationshipOperationsRepository<T>,CypherDslRepository<T>  {
    public T findByEntityId(Long id);
}

However, I'm finding that subclasses of this interface don't behave as expected.

public interface UserRepository extends RelatedEntityRepository<UserNode>{
}

When I call UserRepository.findByEntityId(1L) , I expect to get a single instance of UserNode returned, or null .

Instead, I get a scala.collection.JavaConversions$MapWrapper .

However, if I change the UserRepository to specify the type, then everything works (though, defeats the purpose of the baseclass)

public interface UserRepository extends RelatedEntityRepository<UserNode>{
    public UserNode findByEntityId(Long id);
}

Here's a test:

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration({"/graph-test-context.xml"})
@Transactional
public class UserRepositoryTests {

    @Autowired
    private UserRepository userRepository;

    // For Bug
    @Test
    public void canFindByEntityId()
    {
        UserNode userNode = new UserNode(1L);
        userRepository.save(userNode);

        UserNode node = userRepository.findByEntityId(1L);
        assertThat(node, notNullValue());
        assertThat(node, isA(UserNode.class));
    }
}

Running this test with the extra line in UserRepository commented out fails. Otherwsie, the test passes.

Is this a bug? Have I written the repo interface correctly?

remigio is right, it returns a wrapped object which you'll have to convert.

However, this won't be possible using a common baseclass for different entity types.

Here's why:

You'd think creating a wrapper class for the query result annotated with @MapResult should work, eg.

@MapResult
public interface ResultMap<T> {
    @ResultColumn("usernode") <T> getNode();
}

And use it like this in your repository class:

ResultMap<T> findByEntityId(Long id);

And like this in your test:

ReultMap<UserNode> = userRepository.findByEntityId(1L);

Unfortunately that doesn't work, for two reasons:

  • The repository returns a NodeProxy class inside the map instead of a UserNode
  • @ResultColumn annotation has to be configured with a column name, which seems to be automatically generated in the result based on the type of class, "usernode" in your case.

What does work is this then:

@MapResult
public interface ResultMap {
    @ResultColumn("usernode") NodeProxy getNode();
}

ResultMap rm = userRepository.findByEntityId(1L);
NodeProxy proxy = rm.getNode();
UserNode userNode = template.convert(proxy, UserNode.class);

template is AutoWired like this:

@Autowired Neo4jOperations template;

Unfortunately that doesn't really work either, due to point 2 above :(

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM