How to update existing entries in @OneToMany collection?












1















I'm storing a collection of free proxies in database. Proxy entity consists of:




  • IP Address

  • Port

  • List of sources


Source is basically a website where I found this proxy information. Here's my schema:



proxy table:



+--------------+-------------+------+-----+---------+-------+
| Field | Type | Null | Key | Default | Extra |
+--------------+-------------+------+-----+---------+-------+
| id | varchar(45) | NO | PRI | NULL | |
| ip_address | varchar(40) | NO | | NULL | |
| port | smallint(6) | NO | | NULL | |
+--------------+-------------+------+-----+---------+-------+


source:



+----------+--------------+------+-----+---------+----------------+
| Field | Type | Null | Key | Default | Extra |
+----------+--------------+------+-----+---------+----------------+
| id | int(11) | NO | PRI | NULL | auto_increment |
| resource | varchar(200) | NO | | NULL | |
+----------+--------------+------+-----+---------+----------------+


proxy_sources which joins first two tables:



+-----------+-------------+------+-----+---------+-------+
| Field | Type | Null | Key | Default | Extra |
+-----------+-------------+------+-----+---------+-------+
| proxy_id | varchar(45) | NO | MUL | NULL | |
| source_id | int(11) | NO | MUL | NULL | |
+-----------+-------------+------+-----+---------+-------+


My Java ORM classes:



@Entity
@Table(name = "proxy")
public class Proxy {

@Id
@Column(name = "id")
private String id;

@Column(name = "ip_address")
private String ipAddress;

@Column(name = "port")
private int port;

@OneToMany(cascade = CascadeType.MERGE, fetch = FetchType.EAGER)
@JoinTable(
name = "proxy_sources",
joinColumns = @JoinColumn(name = "proxy_id"),
inverseJoinColumns = @JoinColumn(name = "source_id")
)
private List<Source> sources = new ArrayList<>();

...
}


@Entity
@Table(name = "source")
public class Source {

@Id
@Column(name = "id")
@GeneratedValue(strategy = GenerationType.IDENTITY)
private long id;

@Column(name = "resource")
private String resource;

...
}


Whenever I save a proxy object I want to avoid duplicating existing sources. For example:



Proxy object has 2 sources:




  1. with resource = "res1"

  2. with resource = "res2"


If source table already contains entry with source = "res1" I want to populate it's id property in java object from database to avoid creating duplicate.



For now I do it manually in my Repository class:



public String save(Proxy proxy) {
populate(proxy.getSources());
return (String) sessionFactory.getCurrentSession().save(proxy);
}


Here's populate method:



private void populate(List<Source> sources) {
if (sources.isEmpty()) {
return;
}

List<String> resources = sources.stream().map(Source::getResource).collect(toList());

List<Source> existing = sessionFactory.getCurrentSession()
.createQuery("FROM Source source WHERE source.resource IN (:resources)", Source.class)
.setParameterList("resources", resources)
.list();

sources.forEach(source -> existing.stream()
.filter(s -> s.getResource().equals(source.getResource()))
.findAny()
.ifPresent(s -> source.setId(s.getId())));
}


Basically what I do is checking for existence every source in sources collection. If source with same resource value already exists, I populate it's id from database. Non-empty id avoids creating duplicates.



It works, but probably there's a cleaner solution for this problem?










share|improve this question



























    1















    I'm storing a collection of free proxies in database. Proxy entity consists of:




    • IP Address

    • Port

    • List of sources


    Source is basically a website where I found this proxy information. Here's my schema:



    proxy table:



    +--------------+-------------+------+-----+---------+-------+
    | Field | Type | Null | Key | Default | Extra |
    +--------------+-------------+------+-----+---------+-------+
    | id | varchar(45) | NO | PRI | NULL | |
    | ip_address | varchar(40) | NO | | NULL | |
    | port | smallint(6) | NO | | NULL | |
    +--------------+-------------+------+-----+---------+-------+


    source:



    +----------+--------------+------+-----+---------+----------------+
    | Field | Type | Null | Key | Default | Extra |
    +----------+--------------+------+-----+---------+----------------+
    | id | int(11) | NO | PRI | NULL | auto_increment |
    | resource | varchar(200) | NO | | NULL | |
    +----------+--------------+------+-----+---------+----------------+


    proxy_sources which joins first two tables:



    +-----------+-------------+------+-----+---------+-------+
    | Field | Type | Null | Key | Default | Extra |
    +-----------+-------------+------+-----+---------+-------+
    | proxy_id | varchar(45) | NO | MUL | NULL | |
    | source_id | int(11) | NO | MUL | NULL | |
    +-----------+-------------+------+-----+---------+-------+


    My Java ORM classes:



    @Entity
    @Table(name = "proxy")
    public class Proxy {

    @Id
    @Column(name = "id")
    private String id;

    @Column(name = "ip_address")
    private String ipAddress;

    @Column(name = "port")
    private int port;

    @OneToMany(cascade = CascadeType.MERGE, fetch = FetchType.EAGER)
    @JoinTable(
    name = "proxy_sources",
    joinColumns = @JoinColumn(name = "proxy_id"),
    inverseJoinColumns = @JoinColumn(name = "source_id")
    )
    private List<Source> sources = new ArrayList<>();

    ...
    }


    @Entity
    @Table(name = "source")
    public class Source {

    @Id
    @Column(name = "id")
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private long id;

    @Column(name = "resource")
    private String resource;

    ...
    }


    Whenever I save a proxy object I want to avoid duplicating existing sources. For example:



    Proxy object has 2 sources:




    1. with resource = "res1"

    2. with resource = "res2"


    If source table already contains entry with source = "res1" I want to populate it's id property in java object from database to avoid creating duplicate.



    For now I do it manually in my Repository class:



    public String save(Proxy proxy) {
    populate(proxy.getSources());
    return (String) sessionFactory.getCurrentSession().save(proxy);
    }


    Here's populate method:



    private void populate(List<Source> sources) {
    if (sources.isEmpty()) {
    return;
    }

    List<String> resources = sources.stream().map(Source::getResource).collect(toList());

    List<Source> existing = sessionFactory.getCurrentSession()
    .createQuery("FROM Source source WHERE source.resource IN (:resources)", Source.class)
    .setParameterList("resources", resources)
    .list();

    sources.forEach(source -> existing.stream()
    .filter(s -> s.getResource().equals(source.getResource()))
    .findAny()
    .ifPresent(s -> source.setId(s.getId())));
    }


    Basically what I do is checking for existence every source in sources collection. If source with same resource value already exists, I populate it's id from database. Non-empty id avoids creating duplicates.



    It works, but probably there's a cleaner solution for this problem?










    share|improve this question

























      1












      1








      1








      I'm storing a collection of free proxies in database. Proxy entity consists of:




      • IP Address

      • Port

      • List of sources


      Source is basically a website where I found this proxy information. Here's my schema:



      proxy table:



      +--------------+-------------+------+-----+---------+-------+
      | Field | Type | Null | Key | Default | Extra |
      +--------------+-------------+------+-----+---------+-------+
      | id | varchar(45) | NO | PRI | NULL | |
      | ip_address | varchar(40) | NO | | NULL | |
      | port | smallint(6) | NO | | NULL | |
      +--------------+-------------+------+-----+---------+-------+


      source:



      +----------+--------------+------+-----+---------+----------------+
      | Field | Type | Null | Key | Default | Extra |
      +----------+--------------+------+-----+---------+----------------+
      | id | int(11) | NO | PRI | NULL | auto_increment |
      | resource | varchar(200) | NO | | NULL | |
      +----------+--------------+------+-----+---------+----------------+


      proxy_sources which joins first two tables:



      +-----------+-------------+------+-----+---------+-------+
      | Field | Type | Null | Key | Default | Extra |
      +-----------+-------------+------+-----+---------+-------+
      | proxy_id | varchar(45) | NO | MUL | NULL | |
      | source_id | int(11) | NO | MUL | NULL | |
      +-----------+-------------+------+-----+---------+-------+


      My Java ORM classes:



      @Entity
      @Table(name = "proxy")
      public class Proxy {

      @Id
      @Column(name = "id")
      private String id;

      @Column(name = "ip_address")
      private String ipAddress;

      @Column(name = "port")
      private int port;

      @OneToMany(cascade = CascadeType.MERGE, fetch = FetchType.EAGER)
      @JoinTable(
      name = "proxy_sources",
      joinColumns = @JoinColumn(name = "proxy_id"),
      inverseJoinColumns = @JoinColumn(name = "source_id")
      )
      private List<Source> sources = new ArrayList<>();

      ...
      }


      @Entity
      @Table(name = "source")
      public class Source {

      @Id
      @Column(name = "id")
      @GeneratedValue(strategy = GenerationType.IDENTITY)
      private long id;

      @Column(name = "resource")
      private String resource;

      ...
      }


      Whenever I save a proxy object I want to avoid duplicating existing sources. For example:



      Proxy object has 2 sources:




      1. with resource = "res1"

      2. with resource = "res2"


      If source table already contains entry with source = "res1" I want to populate it's id property in java object from database to avoid creating duplicate.



      For now I do it manually in my Repository class:



      public String save(Proxy proxy) {
      populate(proxy.getSources());
      return (String) sessionFactory.getCurrentSession().save(proxy);
      }


      Here's populate method:



      private void populate(List<Source> sources) {
      if (sources.isEmpty()) {
      return;
      }

      List<String> resources = sources.stream().map(Source::getResource).collect(toList());

      List<Source> existing = sessionFactory.getCurrentSession()
      .createQuery("FROM Source source WHERE source.resource IN (:resources)", Source.class)
      .setParameterList("resources", resources)
      .list();

      sources.forEach(source -> existing.stream()
      .filter(s -> s.getResource().equals(source.getResource()))
      .findAny()
      .ifPresent(s -> source.setId(s.getId())));
      }


      Basically what I do is checking for existence every source in sources collection. If source with same resource value already exists, I populate it's id from database. Non-empty id avoids creating duplicates.



      It works, but probably there's a cleaner solution for this problem?










      share|improve this question














      I'm storing a collection of free proxies in database. Proxy entity consists of:




      • IP Address

      • Port

      • List of sources


      Source is basically a website where I found this proxy information. Here's my schema:



      proxy table:



      +--------------+-------------+------+-----+---------+-------+
      | Field | Type | Null | Key | Default | Extra |
      +--------------+-------------+------+-----+---------+-------+
      | id | varchar(45) | NO | PRI | NULL | |
      | ip_address | varchar(40) | NO | | NULL | |
      | port | smallint(6) | NO | | NULL | |
      +--------------+-------------+------+-----+---------+-------+


      source:



      +----------+--------------+------+-----+---------+----------------+
      | Field | Type | Null | Key | Default | Extra |
      +----------+--------------+------+-----+---------+----------------+
      | id | int(11) | NO | PRI | NULL | auto_increment |
      | resource | varchar(200) | NO | | NULL | |
      +----------+--------------+------+-----+---------+----------------+


      proxy_sources which joins first two tables:



      +-----------+-------------+------+-----+---------+-------+
      | Field | Type | Null | Key | Default | Extra |
      +-----------+-------------+------+-----+---------+-------+
      | proxy_id | varchar(45) | NO | MUL | NULL | |
      | source_id | int(11) | NO | MUL | NULL | |
      +-----------+-------------+------+-----+---------+-------+


      My Java ORM classes:



      @Entity
      @Table(name = "proxy")
      public class Proxy {

      @Id
      @Column(name = "id")
      private String id;

      @Column(name = "ip_address")
      private String ipAddress;

      @Column(name = "port")
      private int port;

      @OneToMany(cascade = CascadeType.MERGE, fetch = FetchType.EAGER)
      @JoinTable(
      name = "proxy_sources",
      joinColumns = @JoinColumn(name = "proxy_id"),
      inverseJoinColumns = @JoinColumn(name = "source_id")
      )
      private List<Source> sources = new ArrayList<>();

      ...
      }


      @Entity
      @Table(name = "source")
      public class Source {

      @Id
      @Column(name = "id")
      @GeneratedValue(strategy = GenerationType.IDENTITY)
      private long id;

      @Column(name = "resource")
      private String resource;

      ...
      }


      Whenever I save a proxy object I want to avoid duplicating existing sources. For example:



      Proxy object has 2 sources:




      1. with resource = "res1"

      2. with resource = "res2"


      If source table already contains entry with source = "res1" I want to populate it's id property in java object from database to avoid creating duplicate.



      For now I do it manually in my Repository class:



      public String save(Proxy proxy) {
      populate(proxy.getSources());
      return (String) sessionFactory.getCurrentSession().save(proxy);
      }


      Here's populate method:



      private void populate(List<Source> sources) {
      if (sources.isEmpty()) {
      return;
      }

      List<String> resources = sources.stream().map(Source::getResource).collect(toList());

      List<Source> existing = sessionFactory.getCurrentSession()
      .createQuery("FROM Source source WHERE source.resource IN (:resources)", Source.class)
      .setParameterList("resources", resources)
      .list();

      sources.forEach(source -> existing.stream()
      .filter(s -> s.getResource().equals(source.getResource()))
      .findAny()
      .ifPresent(s -> source.setId(s.getId())));
      }


      Basically what I do is checking for existence every source in sources collection. If source with same resource value already exists, I populate it's id from database. Non-empty id avoids creating duplicates.



      It works, but probably there's a cleaner solution for this problem?







      java mysql spring hibernate orm






      share|improve this question













      share|improve this question











      share|improve this question




      share|improve this question










      asked Jan 19 at 20:30









      Dmitry PapkaDmitry Papka

      345310




      345310
























          1 Answer
          1






          active

          oldest

          votes


















          0














          The first modification you can make to avoid duplication is creating a unique key in the source table, on the resource column. This way even if you make a mistake in your code the database will thrown an error if you try to save a duplicate register.



          With that said, there is no easy way around to save only objects that don't exist in the database. You either make the resource column be your primary key and throw the id column out (which I don't believe is a good choice), or you have to make a select on the database.



          This question has more details on the second option



          If you are willing to change your application flow, one way that might fix this problem is to break the proxy saving into two steps. First you register all the sources and after you have all sources saved then you start registering proxies. This way you know that when you are saving the proxy it will already have all sources saved beforehand, making your job at that point only to link to existing sources on the Proxy entity.






          share|improve this answer























            Your Answer






            StackExchange.ifUsing("editor", function () {
            StackExchange.using("externalEditor", function () {
            StackExchange.using("snippets", function () {
            StackExchange.snippets.init();
            });
            });
            }, "code-snippets");

            StackExchange.ready(function() {
            var channelOptions = {
            tags: "".split(" "),
            id: "1"
            };
            initTagRenderer("".split(" "), "".split(" "), channelOptions);

            StackExchange.using("externalEditor", function() {
            // Have to fire editor after snippets, if snippets enabled
            if (StackExchange.settings.snippets.snippetsEnabled) {
            StackExchange.using("snippets", function() {
            createEditor();
            });
            }
            else {
            createEditor();
            }
            });

            function createEditor() {
            StackExchange.prepareEditor({
            heartbeatType: 'answer',
            autoActivateHeartbeat: false,
            convertImagesToLinks: true,
            noModals: true,
            showLowRepImageUploadWarning: true,
            reputationToPostImages: 10,
            bindNavPrevention: true,
            postfix: "",
            imageUploader: {
            brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
            contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
            allowUrls: true
            },
            onDemand: true,
            discardSelector: ".discard-answer"
            ,immediatelyShowMarkdownHelp:true
            });


            }
            });














            draft saved

            draft discarded


















            StackExchange.ready(
            function () {
            StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f54271117%2fhow-to-update-existing-entries-in-onetomany-collection%23new-answer', 'question_page');
            }
            );

            Post as a guest















            Required, but never shown

























            1 Answer
            1






            active

            oldest

            votes








            1 Answer
            1






            active

            oldest

            votes









            active

            oldest

            votes






            active

            oldest

            votes









            0














            The first modification you can make to avoid duplication is creating a unique key in the source table, on the resource column. This way even if you make a mistake in your code the database will thrown an error if you try to save a duplicate register.



            With that said, there is no easy way around to save only objects that don't exist in the database. You either make the resource column be your primary key and throw the id column out (which I don't believe is a good choice), or you have to make a select on the database.



            This question has more details on the second option



            If you are willing to change your application flow, one way that might fix this problem is to break the proxy saving into two steps. First you register all the sources and after you have all sources saved then you start registering proxies. This way you know that when you are saving the proxy it will already have all sources saved beforehand, making your job at that point only to link to existing sources on the Proxy entity.






            share|improve this answer




























              0














              The first modification you can make to avoid duplication is creating a unique key in the source table, on the resource column. This way even if you make a mistake in your code the database will thrown an error if you try to save a duplicate register.



              With that said, there is no easy way around to save only objects that don't exist in the database. You either make the resource column be your primary key and throw the id column out (which I don't believe is a good choice), or you have to make a select on the database.



              This question has more details on the second option



              If you are willing to change your application flow, one way that might fix this problem is to break the proxy saving into two steps. First you register all the sources and after you have all sources saved then you start registering proxies. This way you know that when you are saving the proxy it will already have all sources saved beforehand, making your job at that point only to link to existing sources on the Proxy entity.






              share|improve this answer


























                0












                0








                0







                The first modification you can make to avoid duplication is creating a unique key in the source table, on the resource column. This way even if you make a mistake in your code the database will thrown an error if you try to save a duplicate register.



                With that said, there is no easy way around to save only objects that don't exist in the database. You either make the resource column be your primary key and throw the id column out (which I don't believe is a good choice), or you have to make a select on the database.



                This question has more details on the second option



                If you are willing to change your application flow, one way that might fix this problem is to break the proxy saving into two steps. First you register all the sources and after you have all sources saved then you start registering proxies. This way you know that when you are saving the proxy it will already have all sources saved beforehand, making your job at that point only to link to existing sources on the Proxy entity.






                share|improve this answer













                The first modification you can make to avoid duplication is creating a unique key in the source table, on the resource column. This way even if you make a mistake in your code the database will thrown an error if you try to save a duplicate register.



                With that said, there is no easy way around to save only objects that don't exist in the database. You either make the resource column be your primary key and throw the id column out (which I don't believe is a good choice), or you have to make a select on the database.



                This question has more details on the second option



                If you are willing to change your application flow, one way that might fix this problem is to break the proxy saving into two steps. First you register all the sources and after you have all sources saved then you start registering proxies. This way you know that when you are saving the proxy it will already have all sources saved beforehand, making your job at that point only to link to existing sources on the Proxy entity.







                share|improve this answer












                share|improve this answer



                share|improve this answer










                answered Jan 20 at 6:36









                Daniel PereiraDaniel Pereira

                2,26212037




                2,26212037






























                    draft saved

                    draft discarded




















































                    Thanks for contributing an answer to Stack Overflow!


                    • Please be sure to answer the question. Provide details and share your research!

                    But avoid



                    • Asking for help, clarification, or responding to other answers.

                    • Making statements based on opinion; back them up with references or personal experience.


                    To learn more, see our tips on writing great answers.




                    draft saved


                    draft discarded














                    StackExchange.ready(
                    function () {
                    StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f54271117%2fhow-to-update-existing-entries-in-onetomany-collection%23new-answer', 'question_page');
                    }
                    );

                    Post as a guest















                    Required, but never shown





















































                    Required, but never shown














                    Required, but never shown












                    Required, but never shown







                    Required, but never shown

































                    Required, but never shown














                    Required, but never shown












                    Required, but never shown







                    Required, but never shown







                    Popular posts from this blog

                    Liquibase includeAll doesn't find base path

                    How to use setInterval in EJS file?

                    Petrus Granier-Deferre