spring-data-neo4j: 无法创建两个具有相同标签的关系属性
spring-data-neo4j: Can't create two relationship properties with same label
使用 spring-data-neo4j,我无法在具有相同标签的相同 class 中设置两个关系属性。
以下代码可以在我的分支https://github.com/spencerhrob/gs-accessing-data-neo4j/tree/same-name-relationships.
中找到
Person.java:
@NodeEntity
public class Person {
@GraphId Long id;
public String name;
public Person() {}
public Person(String name) { this.name = name; }
@RelatedTo(type="MEMBER_OF", direction=Direction.OUTGOING)
Dojo dojo;
@RelatedTo(type="MEMBER_OF", direction=Direction.OUTGOING)
MailingList mailingList;
public void setDojo(Dojo dojo) {
this.dojo = dojo;
}
public void setMailingList(MailingList mailingList) {
this.mailingList = mailingList;
}
@Override
public String toString() {
return "Person [name=" + name + "]";
}
}
Dojo.java:
@NodeEntity
public class Dojo {
@GraphId Long id;
public String name;
public Dojo() { }
public Dojo(String name) { this.name = name; }
@Override
public String toString() {
return "Dojo [name=" + name + "]";
}
}
MailingList.java:
@NodeEntity
public class MailingList {
@GraphId Long id;
public String name;
public MailingList() { }
public MailingList(String name) { this.name = name; }
@Override
public String toString() {
return "MailingList [name=" + name + "]";
}
}
Application.java:
@Configuration
@EnableNeo4jRepositories(basePackages = "hello")
public class Application extends Neo4jConfiguration implements CommandLineRunner {
public Application() {
setBasePackage("hello");
}
@Bean
GraphDatabaseService graphDatabaseService() {
return new GraphDatabaseFactory().newEmbeddedDatabase("accessingdataneo4j.db");
}
@Autowired
PersonRepository personRepository;
@Autowired
GraphDatabase graphDatabase;
public void run(String... args) throws Exception {
Transaction tx = graphDatabase.beginTx();
try {
Person linus = new Person("Linus");
linus.setDojo(new Dojo("Coding Dojo"));
linus.setMailingList(new MailingList("Kernel Mailing List"));
personRepository.save(linus);
tx.success();
} finally {
tx.close();
}
}
public static void main(String[] args) throws Exception {
FileUtils.deleteRecursively(new File("accessingdataneo4j.db"));
SpringApplication.run(Application.class, args);
}
}
当我 运行 这段代码时,我得到以下异常:
java.lang.IllegalStateException: Failed to execute CommandLineRunner
at
org.springframework.boot.SpringApplication.runCommandLineRunners(SpringApplication.java:680)
at
org.springframework.boot.SpringApplication.afterRefresh(SpringApplication.java:695)
at
org.springframework.boot.SpringApplication.run(SpringApplication.java:321)
at
org.springframework.boot.SpringApplication.run(SpringApplication.java:952)
at
org.springframework.boot.SpringApplication.run(SpringApplication.java:941)
at hello.Application.main(Application.java:56) Caused by:
org.springframework.data.mapping.model.MappingException: Setting
property mailingList to Dojo [name=null] on Person [name=Linus] at
org.springframework.data.neo4j.support.mapping.SourceStateTransmitter.setProperty(SourceStateTransmitter.java:85)
at
org.springframework.data.neo4j.support.mapping.SourceStateTransmitter.copyEntityStatePropertyValue(SourceStateTransmitter.java:91)
at
org.springframework.data.neo4j.support.mapping.SourceStateTransmitter.access[=16=]0(SourceStateTransmitter.java:40)
at
org.springframework.data.neo4j.support.mapping.SourceStateTransmitter.doWithAssociation(SourceStateTransmitter.java:61)
at
org.springframework.data.mapping.model.BasicPersistentEntity.doWithAssociations(BasicPersistentEntity.java:324)
at
org.springframework.data.neo4j.support.mapping.SourceStateTransmitter.copyPropertiesFrom(SourceStateTransmitter.java:57)
at
org.springframework.data.neo4j.support.mapping.Neo4jEntityConverterImpl.loadEntity(Neo4jEntityConverterImpl.java:112)
at
org.springframework.data.neo4j.support.mapping.Neo4jEntityConverterImpl.read(Neo4jEntityConverterImpl.java:104)
at
org.springframework.data.neo4j.support.mapping.Neo4jEntityPersister$CachedConverter.read(Neo4jEntityPersister.java:170)
at
org.springframework.data.neo4j.support.mapping.Neo4jEntityPersister.createEntityFromState(Neo4jEntityPersister.java:189)
at
org.springframework.data.neo4j.support.mapping.Neo4jEntityPersister.persist(Neo4jEntityPersister.java:244)
at
org.springframework.data.neo4j.support.mapping.Neo4jEntityPersister.persist(Neo4jEntityPersister.java:231)
at
org.springframework.data.neo4j.support.Neo4jTemplate.save(Neo4jTemplate.java:356)
at
org.springframework.data.neo4j.support.Neo4jTemplate.save(Neo4jTemplate.java:350)
at
org.springframework.data.neo4j.repository.AbstractGraphRepository.save(AbstractGraphRepository.java:91)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) at
sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
at
sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:606) at
org.springframework.data.repository.core.support.RepositoryFactorySupport$QueryExecutorMethodInterceptor.executeMethodOn(RepositoryFactorySupport.java:405)
at
org.springframework.data.repository.core.support.RepositoryFactorySupport$QueryExecutorMethodInterceptor.doInvoke(RepositoryFactorySupport.java:390)
at
org.springframework.data.repository.core.support.RepositoryFactorySupport$QueryExecutorMethodInterceptor.invoke(RepositoryFactorySupport.java:344)
at
org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179)
at
org.springframework.transaction.interceptor.TransactionInterceptor.proceedWithInvocation(TransactionInterceptor.java:98)
at
org.springframework.transaction.interceptor.TransactionAspectSupport.invokeWithinTransaction(TransactionAspectSupport.java:262)
at
org.springframework.transaction.interceptor.TransactionInterceptor.invoke(TransactionInterceptor.java:95)
at
org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179)
at
org.springframework.dao.support.PersistenceExceptionTranslationInterceptor.invoke(PersistenceExceptionTranslationInterceptor.java:136)
at
org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179)
at
org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:207)
at com.sun.proxy.$Proxy43.save(Unknown Source) at
hello.Application.run(Application.java:44) at
org.springframework.boot.SpringApplication.runCommandLineRunners(SpringApplication.java:677)
... 5 common frames omitted Caused by:
org.springframework.core.convert.ConverterNotFoundException: No
converter found capable of converting from type hello.Dojo to type
hello.MailingList at
org.springframework.core.convert.support.GenericConversionService.handleConverterNotFound(GenericConversionService.java:291)
at
org.springframework.core.convert.support.GenericConversionService.convert(GenericConversionService.java:177)
at
org.springframework.core.convert.support.GenericConversionService.convert(GenericConversionService.java:158)
at
org.springframework.data.mapping.model.BeanWrapper.getPotentiallyConvertedValue(BeanWrapper.java:155)
at
org.springframework.data.mapping.model.BeanWrapper.setProperty(BeanWrapper.java:75)
at
org.springframework.data.neo4j.support.mapping.SourceStateTransmitter.setProperty(SourceStateTransmitter.java:83)
... 37 common frames omitted
那里有很多,但真正的错误是 Spring 试图将 Dojo 转换为 MailingList。
同时,如果我用不同的名称命名关系(如在我的分支 https://github.com/spencerhrob/gs-accessing-data-neo4j/tree/different-name-relationships 中),则此代码有效。 Person.java:
@NodeEntity
public class Person {
@GraphId Long id;
public String name;
public Person() {}
public Person(String name) { this.name = name; }
@RelatedTo(type="MEMBER_OF_DOJO", direction=Direction.OUTGOING)
Dojo dojo;
@RelatedTo(type="MEMBER_OF_LIST", direction=Direction.OUTGOING)
MailingList mailingList;
public void setDojo(Dojo dojo) {
this.dojo = dojo;
}
public void setMailingList(MailingList mailingList) {
this.mailingList = mailingList;
}
@Override
public String toString() {
return "Person [name=" + name + "]";
}
}
不对 Application.java(或 Dojo.java 或 MailingList.java)进行任何更改,此代码成功执行。
我对这个例子的理解是 spring-data-neo4j 不允许 class 有两个具有相同标签的属性。在某些情况下,不同的关系需要具有相同的标签——例如,为了符合建模标准。是否可以在spring-data-neo4j中设置多个同名关系?如果是,怎么做?
我找到了这个问题的答案。我一直在寻找 "enforceTargetType" 属性 described in the documentation。
我创建了一个使用此修复程序的存储库分支。它位于 https://github.com/spencerhrob/gs-accessing-data-neo4j/tree/same-name-enforce-target.
Person.java:
@NodeEntity
public class Person {
@GraphId Long id;
public String name;
public Person() {}
public Person(String name) { this.name = name; }
@RelatedTo(type="MEMBER_OF", direction=Direction.OUTGOING, enforceTargetType=true)
Dojo dojo;
@RelatedTo(type="MEMBER_OF", direction=Direction.OUTGOING, enforceTargetType=true)
MailingList mailingList;
public void setDojo(Dojo dojo) {
this.dojo = dojo;
}
public void setMailingList(MailingList mailingList) {
this.mailingList = mailingList;
}
@Override
public String toString() {
return "Person [name=" + name + "]";
}
}
在没有对存储库进行其他更改的情况下,此代码运行时没有任何错误,并且检查创建的 Neo4j 数据库表明它的行为符合预期。
使用 spring-data-neo4j,我无法在具有相同标签的相同 class 中设置两个关系属性。
以下代码可以在我的分支https://github.com/spencerhrob/gs-accessing-data-neo4j/tree/same-name-relationships.
中找到Person.java:
@NodeEntity
public class Person {
@GraphId Long id;
public String name;
public Person() {}
public Person(String name) { this.name = name; }
@RelatedTo(type="MEMBER_OF", direction=Direction.OUTGOING)
Dojo dojo;
@RelatedTo(type="MEMBER_OF", direction=Direction.OUTGOING)
MailingList mailingList;
public void setDojo(Dojo dojo) {
this.dojo = dojo;
}
public void setMailingList(MailingList mailingList) {
this.mailingList = mailingList;
}
@Override
public String toString() {
return "Person [name=" + name + "]";
}
}
Dojo.java:
@NodeEntity
public class Dojo {
@GraphId Long id;
public String name;
public Dojo() { }
public Dojo(String name) { this.name = name; }
@Override
public String toString() {
return "Dojo [name=" + name + "]";
}
}
MailingList.java:
@NodeEntity
public class MailingList {
@GraphId Long id;
public String name;
public MailingList() { }
public MailingList(String name) { this.name = name; }
@Override
public String toString() {
return "MailingList [name=" + name + "]";
}
}
Application.java:
@Configuration
@EnableNeo4jRepositories(basePackages = "hello")
public class Application extends Neo4jConfiguration implements CommandLineRunner {
public Application() {
setBasePackage("hello");
}
@Bean
GraphDatabaseService graphDatabaseService() {
return new GraphDatabaseFactory().newEmbeddedDatabase("accessingdataneo4j.db");
}
@Autowired
PersonRepository personRepository;
@Autowired
GraphDatabase graphDatabase;
public void run(String... args) throws Exception {
Transaction tx = graphDatabase.beginTx();
try {
Person linus = new Person("Linus");
linus.setDojo(new Dojo("Coding Dojo"));
linus.setMailingList(new MailingList("Kernel Mailing List"));
personRepository.save(linus);
tx.success();
} finally {
tx.close();
}
}
public static void main(String[] args) throws Exception {
FileUtils.deleteRecursively(new File("accessingdataneo4j.db"));
SpringApplication.run(Application.class, args);
}
}
当我 运行 这段代码时,我得到以下异常:
java.lang.IllegalStateException: Failed to execute CommandLineRunner at org.springframework.boot.SpringApplication.runCommandLineRunners(SpringApplication.java:680) at org.springframework.boot.SpringApplication.afterRefresh(SpringApplication.java:695) at org.springframework.boot.SpringApplication.run(SpringApplication.java:321) at org.springframework.boot.SpringApplication.run(SpringApplication.java:952) at org.springframework.boot.SpringApplication.run(SpringApplication.java:941) at hello.Application.main(Application.java:56) Caused by: org.springframework.data.mapping.model.MappingException: Setting property mailingList to Dojo [name=null] on Person [name=Linus] at org.springframework.data.neo4j.support.mapping.SourceStateTransmitter.setProperty(SourceStateTransmitter.java:85) at org.springframework.data.neo4j.support.mapping.SourceStateTransmitter.copyEntityStatePropertyValue(SourceStateTransmitter.java:91) at org.springframework.data.neo4j.support.mapping.SourceStateTransmitter.access[=16=]0(SourceStateTransmitter.java:40) at org.springframework.data.neo4j.support.mapping.SourceStateTransmitter.doWithAssociation(SourceStateTransmitter.java:61) at org.springframework.data.mapping.model.BasicPersistentEntity.doWithAssociations(BasicPersistentEntity.java:324) at org.springframework.data.neo4j.support.mapping.SourceStateTransmitter.copyPropertiesFrom(SourceStateTransmitter.java:57) at org.springframework.data.neo4j.support.mapping.Neo4jEntityConverterImpl.loadEntity(Neo4jEntityConverterImpl.java:112) at org.springframework.data.neo4j.support.mapping.Neo4jEntityConverterImpl.read(Neo4jEntityConverterImpl.java:104) at org.springframework.data.neo4j.support.mapping.Neo4jEntityPersister$CachedConverter.read(Neo4jEntityPersister.java:170) at org.springframework.data.neo4j.support.mapping.Neo4jEntityPersister.createEntityFromState(Neo4jEntityPersister.java:189) at org.springframework.data.neo4j.support.mapping.Neo4jEntityPersister.persist(Neo4jEntityPersister.java:244) at org.springframework.data.neo4j.support.mapping.Neo4jEntityPersister.persist(Neo4jEntityPersister.java:231) at org.springframework.data.neo4j.support.Neo4jTemplate.save(Neo4jTemplate.java:356) at org.springframework.data.neo4j.support.Neo4jTemplate.save(Neo4jTemplate.java:350) at org.springframework.data.neo4j.repository.AbstractGraphRepository.save(AbstractGraphRepository.java:91) at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57) at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) at java.lang.reflect.Method.invoke(Method.java:606) at org.springframework.data.repository.core.support.RepositoryFactorySupport$QueryExecutorMethodInterceptor.executeMethodOn(RepositoryFactorySupport.java:405) at org.springframework.data.repository.core.support.RepositoryFactorySupport$QueryExecutorMethodInterceptor.doInvoke(RepositoryFactorySupport.java:390) at org.springframework.data.repository.core.support.RepositoryFactorySupport$QueryExecutorMethodInterceptor.invoke(RepositoryFactorySupport.java:344) at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179) at org.springframework.transaction.interceptor.TransactionInterceptor.proceedWithInvocation(TransactionInterceptor.java:98) at org.springframework.transaction.interceptor.TransactionAspectSupport.invokeWithinTransaction(TransactionAspectSupport.java:262) at org.springframework.transaction.interceptor.TransactionInterceptor.invoke(TransactionInterceptor.java:95) at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179) at org.springframework.dao.support.PersistenceExceptionTranslationInterceptor.invoke(PersistenceExceptionTranslationInterceptor.java:136) at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179) at org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:207) at com.sun.proxy.$Proxy43.save(Unknown Source) at hello.Application.run(Application.java:44) at org.springframework.boot.SpringApplication.runCommandLineRunners(SpringApplication.java:677) ... 5 common frames omitted Caused by: org.springframework.core.convert.ConverterNotFoundException: No converter found capable of converting from type hello.Dojo to type hello.MailingList at org.springframework.core.convert.support.GenericConversionService.handleConverterNotFound(GenericConversionService.java:291) at org.springframework.core.convert.support.GenericConversionService.convert(GenericConversionService.java:177) at org.springframework.core.convert.support.GenericConversionService.convert(GenericConversionService.java:158) at org.springframework.data.mapping.model.BeanWrapper.getPotentiallyConvertedValue(BeanWrapper.java:155) at org.springframework.data.mapping.model.BeanWrapper.setProperty(BeanWrapper.java:75) at org.springframework.data.neo4j.support.mapping.SourceStateTransmitter.setProperty(SourceStateTransmitter.java:83) ... 37 common frames omitted
那里有很多,但真正的错误是 Spring 试图将 Dojo 转换为 MailingList。
同时,如果我用不同的名称命名关系(如在我的分支 https://github.com/spencerhrob/gs-accessing-data-neo4j/tree/different-name-relationships 中),则此代码有效。 Person.java:
@NodeEntity
public class Person {
@GraphId Long id;
public String name;
public Person() {}
public Person(String name) { this.name = name; }
@RelatedTo(type="MEMBER_OF_DOJO", direction=Direction.OUTGOING)
Dojo dojo;
@RelatedTo(type="MEMBER_OF_LIST", direction=Direction.OUTGOING)
MailingList mailingList;
public void setDojo(Dojo dojo) {
this.dojo = dojo;
}
public void setMailingList(MailingList mailingList) {
this.mailingList = mailingList;
}
@Override
public String toString() {
return "Person [name=" + name + "]";
}
}
不对 Application.java(或 Dojo.java 或 MailingList.java)进行任何更改,此代码成功执行。
我对这个例子的理解是 spring-data-neo4j 不允许 class 有两个具有相同标签的属性。在某些情况下,不同的关系需要具有相同的标签——例如,为了符合建模标准。是否可以在spring-data-neo4j中设置多个同名关系?如果是,怎么做?
我找到了这个问题的答案。我一直在寻找 "enforceTargetType" 属性 described in the documentation。
我创建了一个使用此修复程序的存储库分支。它位于 https://github.com/spencerhrob/gs-accessing-data-neo4j/tree/same-name-enforce-target.
Person.java:
@NodeEntity
public class Person {
@GraphId Long id;
public String name;
public Person() {}
public Person(String name) { this.name = name; }
@RelatedTo(type="MEMBER_OF", direction=Direction.OUTGOING, enforceTargetType=true)
Dojo dojo;
@RelatedTo(type="MEMBER_OF", direction=Direction.OUTGOING, enforceTargetType=true)
MailingList mailingList;
public void setDojo(Dojo dojo) {
this.dojo = dojo;
}
public void setMailingList(MailingList mailingList) {
this.mailingList = mailingList;
}
@Override
public String toString() {
return "Person [name=" + name + "]";
}
}
在没有对存储库进行其他更改的情况下,此代码运行时没有任何错误,并且检查创建的 Neo4j 数据库表明它的行为符合预期。