代码之家  ›  专栏  ›  技术社区  ›  Swordfish

关系实体具有属性的重复关系

  •  0
  • Swordfish  · 技术社区  · 7 年前

    @NodeEntity
    public class User {
    
        private Long id;    
    
        @Id 
        @GeneratedValue(strategy = UserIdStrategy.class)
        @Convert(UuidStringConverter.class)
        private UUID userId;
    
        @Relationship(type = UserInterest.TYPE, direction = Relationship.OUTGOING)
        private Set<UserInterest> interests = new HashSet<>();
    
        ... getters/setters
    
    @NodeEntity
    public class Interest {
    
        private Long id;
    
        @Id 
        @GeneratedValue(strategy = InterestIdStrategy.class)
        private String interestId;
    
        private String name;
    
        ... getters/setters
    
    @RelationshipEntity(type = UserInterest.TYPE)
    public class UserInterest {
    
        public static final String TYPE = "INTERESTED_IN";
    
        private Long id;
    
        @StartNode
        private User start;
    
        @EndNode
        private Interest end;
    
        //private Long weight;
    
        ... getters/setters
    

    当我在relationship实体中启用weight属性时,即使weight属性值是相同的,关系似乎也是重复的。

    我记得我读过一篇文章说,只要属性相同,就不应该创建另一个关系,对吗?

    这是预期行为吗?我需要做些什么来防止重复关系?

    1 回复  |  直到 7 年前
        1
  •  3
  •   Michael Simons    7 年前

    这里有一个可行的解决方案。在我进入细节之前:关键是你坚持什么东西。您应该以一个明确的有界上下文为目标,只访问一个聚合的兴趣。我决定将用户作为事物的入口点。用户有兴趣,应该通过用户添加和操纵兴趣。

    OGM和Spring数据Neo4j负责保存从用户传出的关系。

    所以要点是:不要每次都保存 NodeEntity 你自己。以隐式方式保存实体之间的关联,即:仅保存父对象。您可以通过会话本身来完成,也可以像我那样,通过存储库来完成。请注意,您不需要为每个实体都提供存储库。

    我们有兴趣:

    @NodeEntity
    public class Interest {
        @Id
        @GeneratedValue
        private Long id;
    
        private String name;
    
        public String getName() {
            return name;
        }
    
        public void setName(String name) {
            this.name = name;
        }
    }
    

    用户感兴趣的是:

    @RelationshipEntity(type = UserInterest.TYPE)
    public class UserInterest {
    
        public static final String TYPE = "INTERESTED_IN";
    
        private Long id;
    
        @StartNode
        private User start;
    
        @EndNode
        private Interest end;
    
        private Long weight;
    
        public void setStart(User start) {
            this.start = start;
        }
    
        public Interest getEnd() {
            return end;
        }
    
        public void setEnd(Interest end) {
            this.end = end;
        }
    
        public void setWeight(Long weight) {
            this.weight = weight;
        }
    }
    

    public class User {
        @Id
        @GeneratedValue
        private Long id;
    
        private String name;
    
        @Relationship(type = UserInterest.TYPE, direction = Relationship.OUTGOING)
        private Set<UserInterest> interests = new HashSet<>();
    
        public void setName(String name) {
            this.name = name;
        }
    
        public Interest setInterest(String interstName, long weight) {
    
            final UserInterest userInterest = this.interests.stream()
                .filter(i -> interstName.equalsIgnoreCase(i.getEnd().getName()))
                .findFirst()
                .orElseGet(() -> {
                    // Create a new interest for the user
                    Interest interest = new Interest();
                    interest.setName(interstName);
    
                    // add it here to the interests of this user
                    UserInterest newUserInterest = new UserInterest();
                    newUserInterest.setStart(this);
                    newUserInterest.setEnd(interest);
                    this.interests.add(newUserInterest);
                    return newUserInterest;
                });
            userInterest.setWeight(weight);
            return userInterest.getEnd();
        }
    }
    

    看到了吗 setInterest . 这是使用 User UserInterest ,将其添加到用户兴趣中,最后设置权重,然后返回以供进一步使用。

    那么,我宣布

    public interface UserRepository extends Neo4jRepository<User, Long> {
        Optional<User> findByName(String name);
    }
    

    现在是应用程序:

    @SpringBootApplication
    public class SorelationshipsApplication implements CommandLineRunner {
    
        public static void main(String[] args) {
            SpringApplication.run(SorelationshipsApplication.class, args);
        }
    
        private final UserRepository userRepository;
    
        private final SessionFactory sessionFactory;
    
        public SorelationshipsApplication(UserRepository userRepository, SessionFactory sessionFactory) {
            this.userRepository = userRepository;
            this.sessionFactory = sessionFactory;
        }
    
        @Override
        public void run(String... args) throws Exception {
            Optional<User> optionalUser = this.userRepository
                .findByName("Michael");
            User user;
    
            ThreadLocalRandom random = ThreadLocalRandom.current();
            if(optionalUser.isPresent()) {
    
                // Redefine interests and add a new one
                user = optionalUser.get();
                user.setInterest("Family", random.nextLong(100));
                user.setInterest("Bikes", random.nextLong(100));
                user.setInterest("Music", random.nextLong(100));
            } else {
                user = new User();
                user.setName("Michael");
    
                user.setInterest("Bikes", random.nextLong(100));
                user.setInterest("Music", random.nextLong(100));
    
            }
    
            userRepository.save(user);
            // As an alternative, this works as well...
            // sessionFactory.openSession().save(user);
        }
    }
    

    这只是一个针对我的本地Neo4j实例运行的命令行示例,但我认为它解释得足够好了。

    我检查用户是否存在。如果没有,创建它并添加一些兴趣。在下一次运行时,修改现有的兴趣并创建一个新的兴趣。任何进一步的运行只是修改现有的利益。

    User and interests

    ifPresentOrElse Optional

    userRepository.findByName("Michael").ifPresentOrElse(existingUser -> {
        existingUser.setInterest("Family", random.nextLong(100));
        existingUser.setInterest("Bikes", random.nextLong(100));
        existingUser.setInterest("Music", random.nextLong(100));
        userRepository.save(existingUser);
    }, () -> {
        User user = new User();
        user.setName("Michael");
    
        user.setInterest("Bikes", random.nextLong(100));
        user.setInterest("Music", random.nextLong(100));
        userRepository.save(user);
    });
    

    我希望这有帮助。

    编辑:以下是我的依赖项:

    <?xml version="1.0" encoding="UTF-8"?>
    <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
             xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
        <modelVersion>4.0.0</modelVersion>
        <groupId>com.example</groupId>
        <artifactId>sorelationships</artifactId>
        <version>0.0.1-SNAPSHOT</version>
        <packaging>jar</packaging>
        <name>sorelationships</name>
        <description>Demo project for Spring Boot</description>
        <parent>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-parent</artifactId>
            <version>2.0.5.RELEASE</version>
            <relativePath/> <!-- lookup parent from repository -->
        </parent>
        <properties>
            <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
            <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
            <java.version>11</java.version>
        </properties>
        <dependencies>
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-starter-data-neo4j</artifactId>
            </dependency>
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-starter-test</artifactId>
                <scope>test</scope>
            </dependency>
        </dependencies>
        <build>
            <plugins>
                <plugin>
                    <groupId>org.springframework.boot</groupId>
                    <artifactId>spring-boot-maven-plugin</artifactId>
                </plugin>
            </plugins>
        </build>
    </project>