Spring Hibernate许多To Many数据库预先填充

时间:2017-07-21 12:31:53

标签: hibernate spring-data many-to-many spring-data-jpa

所以我有2个实体 - 发布标记,并且它们之间存在多对多关系。我还有一个CSV文件,需要预先填充数据库(它包含帖子详细信息,包括匹配的标签实体的ID)。此外,在DDD之后,Post实体是具有PostRepository的Aggregate根。以下是java类: -

@Entity
public class Post{
@Id
@GeneratedValue
private long id;

  @ManyToMany(cascadeType = {MERGE, PERSIST})
  @JoinTable(name = "post_tag",
        joinColumns = @JoinColumn(name = "post_id"),
        inverseJoinColumns = @JoinColumn(name = "tag_id"))
  private List<Tag> tags = new ArrayList<>();

  // getters, setters ommited.

  public void addTag(Tag tag){
    tags.add(tag);
    tag.getPosts().add(this);
  }
}

@Entity
public class Tag{
@Id
private long id;

  @ManyToMany(mappedBy = "tags")
  private List<Post> posts = new ArrayList<>();

  // getters, setters ommited.
  }
}

下面的存储库界面: -

public interface PostRepo extends Repository<Post, Long>{
  void save(Post p);
}

下面的数据库预加载代码: -

@Service
public class Service {

  @Inject
  private PostRepo repo; 

  @PostConstruct
  void init(){
   // parse CSV file and get a Stream<String[]> stream

      stream.foreach( splits -> {
        long tagId = Long.parseLong(splits[0]);
         Post post = new Post();
         post.add(new Tag(tagId);
         repo.save(post);
     }
  }
}

使用

预填充数据库时
  

PostRepo ::保存(后)

方法我遇到了主键约束验证错误,我认为在添加Post实体时背后的原因我也在尝试添加一个与预先存在的Tag实体具有相同ID的新Tag。 / p>

所以我的问题是如何在不添加TagRepository并使用TagRepository的saveOrUpdate方法的情况下正确执行此操作?

1 个答案:

答案 0 :(得分:0)

尝试这种方法:

@Component
public class DataLoader implements ApplicationRunner {

    @Autoware
    private PostRepo repo;

    @Override
    public void run(ApplicationArguments args) throws Exception {

        // parse CSV file and get a Stream<String[]> stream

        Map<Long, Tag> tagCache = new HashMap<>(); // The cache for persisted tags

        /* Outer loop by posts */ {

            Post post = new Post();

            stream.forEach(splits -> {
                Long tagId = Long.parseLong(splits[0]);

                // Get already persisted Tag or create new one
                Tag tag = tagCache.getOrDefault(tagId, new Tag(tagId));

                post.addTag(tag);
            });

            Post savedPost = repo.save(post);
            List<Tag> tags = savedPost.getTags(); // get persisted tags
            tags.forEach(tag -> tagCache.put(tag.getId(), tag)); // put it into the cache
        }
    }
}

如果实体已经持久化(例如某些Tag),我们无法再创建它 - 这将只是另一个实体,所以我们必须从数据库中获取它,然后重用。

所以我们在这里使用一个简单的缓存&#39;存储持久标签。 我认为这应该有用。

稍微info

  

如果在SpringApplication启动后需要运行某些特定代码,则可以实现ApplicationRunner或CommandLineRunner接口。两个接口以相同的方式工作,并提供单个run方法,该方法将在SpringApplication.run(...)完成之前调用。