JPA 2.0 many-to-many with extra column





.everyoneloves__top-leaderboard:empty,.everyoneloves__mid-leaderboard:empty,.everyoneloves__bot-mid-leaderboard:empty{ height:90px;width:728px;box-sizing:border-box;
}







13















I'm trying to do a ManyToMany relationship in JPA 2.0 (JBoss 7.1.1) with an extra column (in bold, below) in the relationship, like:



Employer           EmployerDeliveryAgent             DeliveryAgent
(id,...) (employer_id, deliveryAgent_id, **ref**) (id,...)


I wouldn't like to have duplicate attributes, so I would like to apply the second solution presented in http://giannigar.wordpress.com/2009/09/04/mapping-a-many-to-many-join-table-with-extra-column-using-jpa/ . But I can't get it to work, I get several errors like:




  1. Embedded ID class should not contain relationship mappings (in fact the spec says so);

  2. In attribute 'employerDeliveryAgent', the "mapped by" value 'pk.deliveryAgent' cannot be resolved to an attribute on the target entity;

  3. In attribute 'employerDeliveryAgent', the "mapped by" value 'pk.employer' cannot be resolved to an attribute on the target entity;

  4. Persistent type of override attribute "pk.deliveryAgent" cannot be resolved;

  5. Persistent type of override attribute "pk.employer" cannot be resolved;


Many people on that link said that it worked fine, so I suppose something is different in my environment, perhaps JPA or Hibernate version. So my question is: how do I achieve such scenario with JPA 2.0 (Jboss 7.1.1 / using Hibernate as JPA implementation)? And to complement that question: should I avoid using composite keys and instead use plain generated id and a unique constraint?



Thanks in advance.



Obs.: I didn't copy my source code here because it is essentially a copy of the one at the link above, just with different classes and attributes names, so I guess it is not necessary.










share|improve this question





























    13















    I'm trying to do a ManyToMany relationship in JPA 2.0 (JBoss 7.1.1) with an extra column (in bold, below) in the relationship, like:



    Employer           EmployerDeliveryAgent             DeliveryAgent
    (id,...) (employer_id, deliveryAgent_id, **ref**) (id,...)


    I wouldn't like to have duplicate attributes, so I would like to apply the second solution presented in http://giannigar.wordpress.com/2009/09/04/mapping-a-many-to-many-join-table-with-extra-column-using-jpa/ . But I can't get it to work, I get several errors like:




    1. Embedded ID class should not contain relationship mappings (in fact the spec says so);

    2. In attribute 'employerDeliveryAgent', the "mapped by" value 'pk.deliveryAgent' cannot be resolved to an attribute on the target entity;

    3. In attribute 'employerDeliveryAgent', the "mapped by" value 'pk.employer' cannot be resolved to an attribute on the target entity;

    4. Persistent type of override attribute "pk.deliveryAgent" cannot be resolved;

    5. Persistent type of override attribute "pk.employer" cannot be resolved;


    Many people on that link said that it worked fine, so I suppose something is different in my environment, perhaps JPA or Hibernate version. So my question is: how do I achieve such scenario with JPA 2.0 (Jboss 7.1.1 / using Hibernate as JPA implementation)? And to complement that question: should I avoid using composite keys and instead use plain generated id and a unique constraint?



    Thanks in advance.



    Obs.: I didn't copy my source code here because it is essentially a copy of the one at the link above, just with different classes and attributes names, so I guess it is not necessary.










    share|improve this question

























      13












      13








      13


      8






      I'm trying to do a ManyToMany relationship in JPA 2.0 (JBoss 7.1.1) with an extra column (in bold, below) in the relationship, like:



      Employer           EmployerDeliveryAgent             DeliveryAgent
      (id,...) (employer_id, deliveryAgent_id, **ref**) (id,...)


      I wouldn't like to have duplicate attributes, so I would like to apply the second solution presented in http://giannigar.wordpress.com/2009/09/04/mapping-a-many-to-many-join-table-with-extra-column-using-jpa/ . But I can't get it to work, I get several errors like:




      1. Embedded ID class should not contain relationship mappings (in fact the spec says so);

      2. In attribute 'employerDeliveryAgent', the "mapped by" value 'pk.deliveryAgent' cannot be resolved to an attribute on the target entity;

      3. In attribute 'employerDeliveryAgent', the "mapped by" value 'pk.employer' cannot be resolved to an attribute on the target entity;

      4. Persistent type of override attribute "pk.deliveryAgent" cannot be resolved;

      5. Persistent type of override attribute "pk.employer" cannot be resolved;


      Many people on that link said that it worked fine, so I suppose something is different in my environment, perhaps JPA or Hibernate version. So my question is: how do I achieve such scenario with JPA 2.0 (Jboss 7.1.1 / using Hibernate as JPA implementation)? And to complement that question: should I avoid using composite keys and instead use plain generated id and a unique constraint?



      Thanks in advance.



      Obs.: I didn't copy my source code here because it is essentially a copy of the one at the link above, just with different classes and attributes names, so I guess it is not necessary.










      share|improve this question














      I'm trying to do a ManyToMany relationship in JPA 2.0 (JBoss 7.1.1) with an extra column (in bold, below) in the relationship, like:



      Employer           EmployerDeliveryAgent             DeliveryAgent
      (id,...) (employer_id, deliveryAgent_id, **ref**) (id,...)


      I wouldn't like to have duplicate attributes, so I would like to apply the second solution presented in http://giannigar.wordpress.com/2009/09/04/mapping-a-many-to-many-join-table-with-extra-column-using-jpa/ . But I can't get it to work, I get several errors like:




      1. Embedded ID class should not contain relationship mappings (in fact the spec says so);

      2. In attribute 'employerDeliveryAgent', the "mapped by" value 'pk.deliveryAgent' cannot be resolved to an attribute on the target entity;

      3. In attribute 'employerDeliveryAgent', the "mapped by" value 'pk.employer' cannot be resolved to an attribute on the target entity;

      4. Persistent type of override attribute "pk.deliveryAgent" cannot be resolved;

      5. Persistent type of override attribute "pk.employer" cannot be resolved;


      Many people on that link said that it worked fine, so I suppose something is different in my environment, perhaps JPA or Hibernate version. So my question is: how do I achieve such scenario with JPA 2.0 (Jboss 7.1.1 / using Hibernate as JPA implementation)? And to complement that question: should I avoid using composite keys and instead use plain generated id and a unique constraint?



      Thanks in advance.



      Obs.: I didn't copy my source code here because it is essentially a copy of the one at the link above, just with different classes and attributes names, so I guess it is not necessary.







      hibernate java-ee orm jboss7.x jpa-2.0






      share|improve this question













      share|improve this question











      share|improve this question




      share|improve this question










      asked May 23 '14 at 20:03









      RenanRenan

      5841527




      5841527
























          3 Answers
          3






          active

          oldest

          votes


















          34














          First of all You need to generate a EmployerDeliveryAgentPK class because It has a multiple PK:



          @Embeddable
          public class EmployerDeliveryAgentPK implements Serializable {

          @Column(name = "EMPLOYER_ID")
          private Long employer_id;

          @Column(name = "DELIVERY_AGENT_ID")
          private Long deliveryAgent_id;
          }


          Next, You need to create a EmployerDeliveryAgent class. This class represent many to many table of Employer and DeliveryAgent:



          @Entity
          @Table(name = " EmployerDeliveryAgent")
          public class EmployerDeliveryAgent implements Serializable {

          @EmbeddedId
          private EmployerDeliveryAgentPK id;

          @ManyToOne
          @MapsId("employer_id") //This is the name of attr in EmployerDeliveryAgentPK class
          @JoinColumn(name = "EMPLOYER_ID")
          private Employer employer;

          @ManyToOne
          @MapsId("deliveryAgent_id")
          @JoinColumn(name = "DELIVERY_AGENT_ID")
          private DeliveryAgent deliveryAgent;
          }


          After that, in Employer class You need to add:



          @OneToMany(mappedBy = "deliveryAgent")
          private Set<EmployerDeliveryAgent> employerDeliveryAgent = new HashSet<EmployerDeliveryAgent>();


          And in DeliveryAgent class You need to add:



          @OneToMany(mappedBy = "employer")
          private Set<EmployerDeliveryAgent> employer = new HashSet<EmployerDeliveryAgent>();


          This is all! Good luck!!






          share|improve this answer


























          • Thank you very much, I wasted two days tryng to figure out this problem.

            – Paolo
            Mar 28 '17 at 9:58











          • I think in the DeliveryAgent class we should map EmployerDeliveryAgent class instead of Employer class. So, the code in the DeliveryAgent class should look like private Set<EmployerDeliveryAgent> employerDeliveryAgent = new HashSet<EmployerDeliveryAgent>();, same as in the Employer class.

            – tylerdurden
            Oct 4 '17 at 7:10











          • @tylerdurden You are rigth! I have already modified it!

            – Erik Lucio
            Oct 4 '17 at 7:21











          • Is it required to override equals() and hashcode() ? (assumimng I will not intend to put instances of persistent classes in a Set AND intend to use reattachment of detached instances )

            – user3529850
            Oct 29 '18 at 21:13





















          35














          Both answers from Eric Lucio and Renan helped, but there use of the ids in the association table is redundant. You have both the associated entities and their ids in the class. This is not required. You can simple map the associated entity in the association class with the @Id on the associated entity field.



          @Entity
          public class Employer {

          @Id
          @GeneratedValue(strategy = GenerationType.IDENTITY)
          private int id;

          @OneToMany(mappedBy = "employer")
          private List<EmployerDeliveryAgent> deliveryAgentAssoc;

          // other properties and getters and setters
          }

          @Entity
          public class DeliveryAgent {

          @Id
          @GeneratedValue(strategy = GenerationType.IDENTITY)
          private int id;

          @OneToMany(mappedBy = "deliveryAgent")
          private List<EmployerDeliveryAgent> employerAssoc;

          // other properties and getters and setters
          }


          The association class



          @Entity
          @Table(name = "employer_delivery_agent")
          @IdClass(EmployerDeliveryAgentId.class)
          public class EmployerDeliveryAgent {

          @Id
          @ManyToOne
          @JoinColumn(name = "employer_id", referencedColumnName = "id")
          private Employer employer;

          @Id
          @ManyToOne
          @JoinColumn(name = "delivery_agent_id", referencedColumnName = "id")
          private DeliveryAgent deliveryAgent;

          @Column(name = "is_project_lead")
          private boolean isProjectLead;
          }


          Still need the association PK class. Notice the fields names should correspond exactly to the field names in the association class, but the types should be the type of the id in the associated type.



          public class EmployerDeliveryAgentId implements Serializable {

          private int employer;
          private int deliveryAgent;

          // getters/setters and most importantly equals() and hashCode()
          }





          share|improve this answer


























          • Good solution, thanks

            – Renan
            Oct 3 '15 at 15:43






          • 1





            This is the cleanest solution you can get, well done.

            – FrancescoM
            Feb 3 '18 at 14:37











          • anyone can provide insert or delete example too.

            – VK321
            Oct 21 '18 at 7:37











          • Very cool, thank you thank you. Question... ...i get a NPE if i also put a generated @id column in the association class (EmployerDeliveryAgent in your example). But I want a RDBMS long PK... what say you? is there a way to do it? screw my surrogate key?

            – tom
            Nov 20 '18 at 18:42





















          10














          OK, I got it working based on the solution available at



          http://en.wikibooks.org/wiki/Java_Persistence/ManyToMany#Mapping_a_Join_Table_with_Additional_Columns.



          This solution does not generate duplicate attributes on the database, but it does generate duplicate attributes in my JPA entities (which is very acceptable, since you can relay the extra work to a constructor or method - it ends up being transparent). The primary and foreign keys generated in the database are 100% correct.



          As stated on the link, I couldn't use @PrimaryKeyJoinColumn and instead used @JoinColumn(name = "projectId", updatable = false, insertable = false, referencedColumnName = "id"). Another thing worth mentioning: I had to use EntityManager.persist(association), which is missing on the example at the link.



          So my final solution is:



          @Entity
          public class Employee {
          @Id
          private long id;
          ...
          @OneToMany(mappedBy="employee")
          private List<ProjectAssociation> projects;
          ...
          }




          @Entity
          public class Project {

          @PersistenceContext
          EntityManager em;

          @Id
          private long id;
          ...
          @OneToMany(mappedBy="project")
          private List<ProjectAssociation> employees;
          ...
          // Add an employee to the project.
          // Create an association object for the relationship and set its data.
          public void addEmployee(Employee employee, boolean teamLead) {
          ProjectAssociation association = new ProjectAssociation();
          association.setEmployee(employee);
          association.setProject(this);
          association.setEmployeeId(employee.getId());
          association.setProjectId(this.getId());
          association.setIsTeamLead(teamLead);
          em.persist(association);

          this.employees.add(association);
          // Also add the association object to the employee.
          employee.getProjects().add(association);
          }
          }




          @Entity
          @Table(name="PROJ_EMP")
          @IdClass(ProjectAssociationId.class)
          public class ProjectAssociation {
          @Id
          private long employeeId;
          @Id
          private long projectId;
          @Column(name="IS_PROJECT_LEAD")
          private boolean isProjectLead;
          @ManyToOne
          @JoinColumn(name = "employeeId", updatable = false, insertable = false,
          referencedColumnName = "id")

          private Employee employee;
          @ManyToOne
          @JoinColumn(name = "projectId", updatable = false, insertable = false,
          referencedColumnName = "id")

          private Project project;
          ...
          }




          public class ProjectAssociationId implements Serializable {

          private long employeeId;

          private long projectId;
          ...

          public int hashCode() {
          return (int)(employeeId + projectId);
          }

          public boolean equals(Object object) {
          if (object instanceof ProjectAssociationId) {
          ProjectAssociationId otherId = (ProjectAssociationId) object;
          return (otherId.employeeId == this.employeeId)
          && (otherId.projectId == this.projectId);
          }
          return false;
          }

          }





          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%2f23837561%2fjpa-2-0-many-to-many-with-extra-column%23new-answer', 'question_page');
            }
            );

            Post as a guest















            Required, but never shown

























            3 Answers
            3






            active

            oldest

            votes








            3 Answers
            3






            active

            oldest

            votes









            active

            oldest

            votes






            active

            oldest

            votes









            34














            First of all You need to generate a EmployerDeliveryAgentPK class because It has a multiple PK:



            @Embeddable
            public class EmployerDeliveryAgentPK implements Serializable {

            @Column(name = "EMPLOYER_ID")
            private Long employer_id;

            @Column(name = "DELIVERY_AGENT_ID")
            private Long deliveryAgent_id;
            }


            Next, You need to create a EmployerDeliveryAgent class. This class represent many to many table of Employer and DeliveryAgent:



            @Entity
            @Table(name = " EmployerDeliveryAgent")
            public class EmployerDeliveryAgent implements Serializable {

            @EmbeddedId
            private EmployerDeliveryAgentPK id;

            @ManyToOne
            @MapsId("employer_id") //This is the name of attr in EmployerDeliveryAgentPK class
            @JoinColumn(name = "EMPLOYER_ID")
            private Employer employer;

            @ManyToOne
            @MapsId("deliveryAgent_id")
            @JoinColumn(name = "DELIVERY_AGENT_ID")
            private DeliveryAgent deliveryAgent;
            }


            After that, in Employer class You need to add:



            @OneToMany(mappedBy = "deliveryAgent")
            private Set<EmployerDeliveryAgent> employerDeliveryAgent = new HashSet<EmployerDeliveryAgent>();


            And in DeliveryAgent class You need to add:



            @OneToMany(mappedBy = "employer")
            private Set<EmployerDeliveryAgent> employer = new HashSet<EmployerDeliveryAgent>();


            This is all! Good luck!!






            share|improve this answer


























            • Thank you very much, I wasted two days tryng to figure out this problem.

              – Paolo
              Mar 28 '17 at 9:58











            • I think in the DeliveryAgent class we should map EmployerDeliveryAgent class instead of Employer class. So, the code in the DeliveryAgent class should look like private Set<EmployerDeliveryAgent> employerDeliveryAgent = new HashSet<EmployerDeliveryAgent>();, same as in the Employer class.

              – tylerdurden
              Oct 4 '17 at 7:10











            • @tylerdurden You are rigth! I have already modified it!

              – Erik Lucio
              Oct 4 '17 at 7:21











            • Is it required to override equals() and hashcode() ? (assumimng I will not intend to put instances of persistent classes in a Set AND intend to use reattachment of detached instances )

              – user3529850
              Oct 29 '18 at 21:13


















            34














            First of all You need to generate a EmployerDeliveryAgentPK class because It has a multiple PK:



            @Embeddable
            public class EmployerDeliveryAgentPK implements Serializable {

            @Column(name = "EMPLOYER_ID")
            private Long employer_id;

            @Column(name = "DELIVERY_AGENT_ID")
            private Long deliveryAgent_id;
            }


            Next, You need to create a EmployerDeliveryAgent class. This class represent many to many table of Employer and DeliveryAgent:



            @Entity
            @Table(name = " EmployerDeliveryAgent")
            public class EmployerDeliveryAgent implements Serializable {

            @EmbeddedId
            private EmployerDeliveryAgentPK id;

            @ManyToOne
            @MapsId("employer_id") //This is the name of attr in EmployerDeliveryAgentPK class
            @JoinColumn(name = "EMPLOYER_ID")
            private Employer employer;

            @ManyToOne
            @MapsId("deliveryAgent_id")
            @JoinColumn(name = "DELIVERY_AGENT_ID")
            private DeliveryAgent deliveryAgent;
            }


            After that, in Employer class You need to add:



            @OneToMany(mappedBy = "deliveryAgent")
            private Set<EmployerDeliveryAgent> employerDeliveryAgent = new HashSet<EmployerDeliveryAgent>();


            And in DeliveryAgent class You need to add:



            @OneToMany(mappedBy = "employer")
            private Set<EmployerDeliveryAgent> employer = new HashSet<EmployerDeliveryAgent>();


            This is all! Good luck!!






            share|improve this answer


























            • Thank you very much, I wasted two days tryng to figure out this problem.

              – Paolo
              Mar 28 '17 at 9:58











            • I think in the DeliveryAgent class we should map EmployerDeliveryAgent class instead of Employer class. So, the code in the DeliveryAgent class should look like private Set<EmployerDeliveryAgent> employerDeliveryAgent = new HashSet<EmployerDeliveryAgent>();, same as in the Employer class.

              – tylerdurden
              Oct 4 '17 at 7:10











            • @tylerdurden You are rigth! I have already modified it!

              – Erik Lucio
              Oct 4 '17 at 7:21











            • Is it required to override equals() and hashcode() ? (assumimng I will not intend to put instances of persistent classes in a Set AND intend to use reattachment of detached instances )

              – user3529850
              Oct 29 '18 at 21:13
















            34












            34








            34







            First of all You need to generate a EmployerDeliveryAgentPK class because It has a multiple PK:



            @Embeddable
            public class EmployerDeliveryAgentPK implements Serializable {

            @Column(name = "EMPLOYER_ID")
            private Long employer_id;

            @Column(name = "DELIVERY_AGENT_ID")
            private Long deliveryAgent_id;
            }


            Next, You need to create a EmployerDeliveryAgent class. This class represent many to many table of Employer and DeliveryAgent:



            @Entity
            @Table(name = " EmployerDeliveryAgent")
            public class EmployerDeliveryAgent implements Serializable {

            @EmbeddedId
            private EmployerDeliveryAgentPK id;

            @ManyToOne
            @MapsId("employer_id") //This is the name of attr in EmployerDeliveryAgentPK class
            @JoinColumn(name = "EMPLOYER_ID")
            private Employer employer;

            @ManyToOne
            @MapsId("deliveryAgent_id")
            @JoinColumn(name = "DELIVERY_AGENT_ID")
            private DeliveryAgent deliveryAgent;
            }


            After that, in Employer class You need to add:



            @OneToMany(mappedBy = "deliveryAgent")
            private Set<EmployerDeliveryAgent> employerDeliveryAgent = new HashSet<EmployerDeliveryAgent>();


            And in DeliveryAgent class You need to add:



            @OneToMany(mappedBy = "employer")
            private Set<EmployerDeliveryAgent> employer = new HashSet<EmployerDeliveryAgent>();


            This is all! Good luck!!






            share|improve this answer















            First of all You need to generate a EmployerDeliveryAgentPK class because It has a multiple PK:



            @Embeddable
            public class EmployerDeliveryAgentPK implements Serializable {

            @Column(name = "EMPLOYER_ID")
            private Long employer_id;

            @Column(name = "DELIVERY_AGENT_ID")
            private Long deliveryAgent_id;
            }


            Next, You need to create a EmployerDeliveryAgent class. This class represent many to many table of Employer and DeliveryAgent:



            @Entity
            @Table(name = " EmployerDeliveryAgent")
            public class EmployerDeliveryAgent implements Serializable {

            @EmbeddedId
            private EmployerDeliveryAgentPK id;

            @ManyToOne
            @MapsId("employer_id") //This is the name of attr in EmployerDeliveryAgentPK class
            @JoinColumn(name = "EMPLOYER_ID")
            private Employer employer;

            @ManyToOne
            @MapsId("deliveryAgent_id")
            @JoinColumn(name = "DELIVERY_AGENT_ID")
            private DeliveryAgent deliveryAgent;
            }


            After that, in Employer class You need to add:



            @OneToMany(mappedBy = "deliveryAgent")
            private Set<EmployerDeliveryAgent> employerDeliveryAgent = new HashSet<EmployerDeliveryAgent>();


            And in DeliveryAgent class You need to add:



            @OneToMany(mappedBy = "employer")
            private Set<EmployerDeliveryAgent> employer = new HashSet<EmployerDeliveryAgent>();


            This is all! Good luck!!







            share|improve this answer














            share|improve this answer



            share|improve this answer








            edited Oct 4 '17 at 7:19

























            answered Mar 18 '15 at 7:53









            Erik LucioErik Lucio

            63358




            63358













            • Thank you very much, I wasted two days tryng to figure out this problem.

              – Paolo
              Mar 28 '17 at 9:58











            • I think in the DeliveryAgent class we should map EmployerDeliveryAgent class instead of Employer class. So, the code in the DeliveryAgent class should look like private Set<EmployerDeliveryAgent> employerDeliveryAgent = new HashSet<EmployerDeliveryAgent>();, same as in the Employer class.

              – tylerdurden
              Oct 4 '17 at 7:10











            • @tylerdurden You are rigth! I have already modified it!

              – Erik Lucio
              Oct 4 '17 at 7:21











            • Is it required to override equals() and hashcode() ? (assumimng I will not intend to put instances of persistent classes in a Set AND intend to use reattachment of detached instances )

              – user3529850
              Oct 29 '18 at 21:13





















            • Thank you very much, I wasted two days tryng to figure out this problem.

              – Paolo
              Mar 28 '17 at 9:58











            • I think in the DeliveryAgent class we should map EmployerDeliveryAgent class instead of Employer class. So, the code in the DeliveryAgent class should look like private Set<EmployerDeliveryAgent> employerDeliveryAgent = new HashSet<EmployerDeliveryAgent>();, same as in the Employer class.

              – tylerdurden
              Oct 4 '17 at 7:10











            • @tylerdurden You are rigth! I have already modified it!

              – Erik Lucio
              Oct 4 '17 at 7:21











            • Is it required to override equals() and hashcode() ? (assumimng I will not intend to put instances of persistent classes in a Set AND intend to use reattachment of detached instances )

              – user3529850
              Oct 29 '18 at 21:13



















            Thank you very much, I wasted two days tryng to figure out this problem.

            – Paolo
            Mar 28 '17 at 9:58





            Thank you very much, I wasted two days tryng to figure out this problem.

            – Paolo
            Mar 28 '17 at 9:58













            I think in the DeliveryAgent class we should map EmployerDeliveryAgent class instead of Employer class. So, the code in the DeliveryAgent class should look like private Set<EmployerDeliveryAgent> employerDeliveryAgent = new HashSet<EmployerDeliveryAgent>();, same as in the Employer class.

            – tylerdurden
            Oct 4 '17 at 7:10





            I think in the DeliveryAgent class we should map EmployerDeliveryAgent class instead of Employer class. So, the code in the DeliveryAgent class should look like private Set<EmployerDeliveryAgent> employerDeliveryAgent = new HashSet<EmployerDeliveryAgent>();, same as in the Employer class.

            – tylerdurden
            Oct 4 '17 at 7:10













            @tylerdurden You are rigth! I have already modified it!

            – Erik Lucio
            Oct 4 '17 at 7:21





            @tylerdurden You are rigth! I have already modified it!

            – Erik Lucio
            Oct 4 '17 at 7:21













            Is it required to override equals() and hashcode() ? (assumimng I will not intend to put instances of persistent classes in a Set AND intend to use reattachment of detached instances )

            – user3529850
            Oct 29 '18 at 21:13







            Is it required to override equals() and hashcode() ? (assumimng I will not intend to put instances of persistent classes in a Set AND intend to use reattachment of detached instances )

            – user3529850
            Oct 29 '18 at 21:13















            35














            Both answers from Eric Lucio and Renan helped, but there use of the ids in the association table is redundant. You have both the associated entities and their ids in the class. This is not required. You can simple map the associated entity in the association class with the @Id on the associated entity field.



            @Entity
            public class Employer {

            @Id
            @GeneratedValue(strategy = GenerationType.IDENTITY)
            private int id;

            @OneToMany(mappedBy = "employer")
            private List<EmployerDeliveryAgent> deliveryAgentAssoc;

            // other properties and getters and setters
            }

            @Entity
            public class DeliveryAgent {

            @Id
            @GeneratedValue(strategy = GenerationType.IDENTITY)
            private int id;

            @OneToMany(mappedBy = "deliveryAgent")
            private List<EmployerDeliveryAgent> employerAssoc;

            // other properties and getters and setters
            }


            The association class



            @Entity
            @Table(name = "employer_delivery_agent")
            @IdClass(EmployerDeliveryAgentId.class)
            public class EmployerDeliveryAgent {

            @Id
            @ManyToOne
            @JoinColumn(name = "employer_id", referencedColumnName = "id")
            private Employer employer;

            @Id
            @ManyToOne
            @JoinColumn(name = "delivery_agent_id", referencedColumnName = "id")
            private DeliveryAgent deliveryAgent;

            @Column(name = "is_project_lead")
            private boolean isProjectLead;
            }


            Still need the association PK class. Notice the fields names should correspond exactly to the field names in the association class, but the types should be the type of the id in the associated type.



            public class EmployerDeliveryAgentId implements Serializable {

            private int employer;
            private int deliveryAgent;

            // getters/setters and most importantly equals() and hashCode()
            }





            share|improve this answer


























            • Good solution, thanks

              – Renan
              Oct 3 '15 at 15:43






            • 1





              This is the cleanest solution you can get, well done.

              – FrancescoM
              Feb 3 '18 at 14:37











            • anyone can provide insert or delete example too.

              – VK321
              Oct 21 '18 at 7:37











            • Very cool, thank you thank you. Question... ...i get a NPE if i also put a generated @id column in the association class (EmployerDeliveryAgent in your example). But I want a RDBMS long PK... what say you? is there a way to do it? screw my surrogate key?

              – tom
              Nov 20 '18 at 18:42


















            35














            Both answers from Eric Lucio and Renan helped, but there use of the ids in the association table is redundant. You have both the associated entities and their ids in the class. This is not required. You can simple map the associated entity in the association class with the @Id on the associated entity field.



            @Entity
            public class Employer {

            @Id
            @GeneratedValue(strategy = GenerationType.IDENTITY)
            private int id;

            @OneToMany(mappedBy = "employer")
            private List<EmployerDeliveryAgent> deliveryAgentAssoc;

            // other properties and getters and setters
            }

            @Entity
            public class DeliveryAgent {

            @Id
            @GeneratedValue(strategy = GenerationType.IDENTITY)
            private int id;

            @OneToMany(mappedBy = "deliveryAgent")
            private List<EmployerDeliveryAgent> employerAssoc;

            // other properties and getters and setters
            }


            The association class



            @Entity
            @Table(name = "employer_delivery_agent")
            @IdClass(EmployerDeliveryAgentId.class)
            public class EmployerDeliveryAgent {

            @Id
            @ManyToOne
            @JoinColumn(name = "employer_id", referencedColumnName = "id")
            private Employer employer;

            @Id
            @ManyToOne
            @JoinColumn(name = "delivery_agent_id", referencedColumnName = "id")
            private DeliveryAgent deliveryAgent;

            @Column(name = "is_project_lead")
            private boolean isProjectLead;
            }


            Still need the association PK class. Notice the fields names should correspond exactly to the field names in the association class, but the types should be the type of the id in the associated type.



            public class EmployerDeliveryAgentId implements Serializable {

            private int employer;
            private int deliveryAgent;

            // getters/setters and most importantly equals() and hashCode()
            }





            share|improve this answer


























            • Good solution, thanks

              – Renan
              Oct 3 '15 at 15:43






            • 1





              This is the cleanest solution you can get, well done.

              – FrancescoM
              Feb 3 '18 at 14:37











            • anyone can provide insert or delete example too.

              – VK321
              Oct 21 '18 at 7:37











            • Very cool, thank you thank you. Question... ...i get a NPE if i also put a generated @id column in the association class (EmployerDeliveryAgent in your example). But I want a RDBMS long PK... what say you? is there a way to do it? screw my surrogate key?

              – tom
              Nov 20 '18 at 18:42
















            35












            35








            35







            Both answers from Eric Lucio and Renan helped, but there use of the ids in the association table is redundant. You have both the associated entities and their ids in the class. This is not required. You can simple map the associated entity in the association class with the @Id on the associated entity field.



            @Entity
            public class Employer {

            @Id
            @GeneratedValue(strategy = GenerationType.IDENTITY)
            private int id;

            @OneToMany(mappedBy = "employer")
            private List<EmployerDeliveryAgent> deliveryAgentAssoc;

            // other properties and getters and setters
            }

            @Entity
            public class DeliveryAgent {

            @Id
            @GeneratedValue(strategy = GenerationType.IDENTITY)
            private int id;

            @OneToMany(mappedBy = "deliveryAgent")
            private List<EmployerDeliveryAgent> employerAssoc;

            // other properties and getters and setters
            }


            The association class



            @Entity
            @Table(name = "employer_delivery_agent")
            @IdClass(EmployerDeliveryAgentId.class)
            public class EmployerDeliveryAgent {

            @Id
            @ManyToOne
            @JoinColumn(name = "employer_id", referencedColumnName = "id")
            private Employer employer;

            @Id
            @ManyToOne
            @JoinColumn(name = "delivery_agent_id", referencedColumnName = "id")
            private DeliveryAgent deliveryAgent;

            @Column(name = "is_project_lead")
            private boolean isProjectLead;
            }


            Still need the association PK class. Notice the fields names should correspond exactly to the field names in the association class, but the types should be the type of the id in the associated type.



            public class EmployerDeliveryAgentId implements Serializable {

            private int employer;
            private int deliveryAgent;

            // getters/setters and most importantly equals() and hashCode()
            }





            share|improve this answer















            Both answers from Eric Lucio and Renan helped, but there use of the ids in the association table is redundant. You have both the associated entities and their ids in the class. This is not required. You can simple map the associated entity in the association class with the @Id on the associated entity field.



            @Entity
            public class Employer {

            @Id
            @GeneratedValue(strategy = GenerationType.IDENTITY)
            private int id;

            @OneToMany(mappedBy = "employer")
            private List<EmployerDeliveryAgent> deliveryAgentAssoc;

            // other properties and getters and setters
            }

            @Entity
            public class DeliveryAgent {

            @Id
            @GeneratedValue(strategy = GenerationType.IDENTITY)
            private int id;

            @OneToMany(mappedBy = "deliveryAgent")
            private List<EmployerDeliveryAgent> employerAssoc;

            // other properties and getters and setters
            }


            The association class



            @Entity
            @Table(name = "employer_delivery_agent")
            @IdClass(EmployerDeliveryAgentId.class)
            public class EmployerDeliveryAgent {

            @Id
            @ManyToOne
            @JoinColumn(name = "employer_id", referencedColumnName = "id")
            private Employer employer;

            @Id
            @ManyToOne
            @JoinColumn(name = "delivery_agent_id", referencedColumnName = "id")
            private DeliveryAgent deliveryAgent;

            @Column(name = "is_project_lead")
            private boolean isProjectLead;
            }


            Still need the association PK class. Notice the fields names should correspond exactly to the field names in the association class, but the types should be the type of the id in the associated type.



            public class EmployerDeliveryAgentId implements Serializable {

            private int employer;
            private int deliveryAgent;

            // getters/setters and most importantly equals() and hashCode()
            }






            share|improve this answer














            share|improve this answer



            share|improve this answer








            edited May 23 '17 at 12:34









            Community

            11




            11










            answered Oct 3 '15 at 8:37









            Paul SamsothaPaul Samsotha

            155k21304499




            155k21304499













            • Good solution, thanks

              – Renan
              Oct 3 '15 at 15:43






            • 1





              This is the cleanest solution you can get, well done.

              – FrancescoM
              Feb 3 '18 at 14:37











            • anyone can provide insert or delete example too.

              – VK321
              Oct 21 '18 at 7:37











            • Very cool, thank you thank you. Question... ...i get a NPE if i also put a generated @id column in the association class (EmployerDeliveryAgent in your example). But I want a RDBMS long PK... what say you? is there a way to do it? screw my surrogate key?

              – tom
              Nov 20 '18 at 18:42





















            • Good solution, thanks

              – Renan
              Oct 3 '15 at 15:43






            • 1





              This is the cleanest solution you can get, well done.

              – FrancescoM
              Feb 3 '18 at 14:37











            • anyone can provide insert or delete example too.

              – VK321
              Oct 21 '18 at 7:37











            • Very cool, thank you thank you. Question... ...i get a NPE if i also put a generated @id column in the association class (EmployerDeliveryAgent in your example). But I want a RDBMS long PK... what say you? is there a way to do it? screw my surrogate key?

              – tom
              Nov 20 '18 at 18:42



















            Good solution, thanks

            – Renan
            Oct 3 '15 at 15:43





            Good solution, thanks

            – Renan
            Oct 3 '15 at 15:43




            1




            1





            This is the cleanest solution you can get, well done.

            – FrancescoM
            Feb 3 '18 at 14:37





            This is the cleanest solution you can get, well done.

            – FrancescoM
            Feb 3 '18 at 14:37













            anyone can provide insert or delete example too.

            – VK321
            Oct 21 '18 at 7:37





            anyone can provide insert or delete example too.

            – VK321
            Oct 21 '18 at 7:37













            Very cool, thank you thank you. Question... ...i get a NPE if i also put a generated @id column in the association class (EmployerDeliveryAgent in your example). But I want a RDBMS long PK... what say you? is there a way to do it? screw my surrogate key?

            – tom
            Nov 20 '18 at 18:42







            Very cool, thank you thank you. Question... ...i get a NPE if i also put a generated @id column in the association class (EmployerDeliveryAgent in your example). But I want a RDBMS long PK... what say you? is there a way to do it? screw my surrogate key?

            – tom
            Nov 20 '18 at 18:42













            10














            OK, I got it working based on the solution available at



            http://en.wikibooks.org/wiki/Java_Persistence/ManyToMany#Mapping_a_Join_Table_with_Additional_Columns.



            This solution does not generate duplicate attributes on the database, but it does generate duplicate attributes in my JPA entities (which is very acceptable, since you can relay the extra work to a constructor or method - it ends up being transparent). The primary and foreign keys generated in the database are 100% correct.



            As stated on the link, I couldn't use @PrimaryKeyJoinColumn and instead used @JoinColumn(name = "projectId", updatable = false, insertable = false, referencedColumnName = "id"). Another thing worth mentioning: I had to use EntityManager.persist(association), which is missing on the example at the link.



            So my final solution is:



            @Entity
            public class Employee {
            @Id
            private long id;
            ...
            @OneToMany(mappedBy="employee")
            private List<ProjectAssociation> projects;
            ...
            }




            @Entity
            public class Project {

            @PersistenceContext
            EntityManager em;

            @Id
            private long id;
            ...
            @OneToMany(mappedBy="project")
            private List<ProjectAssociation> employees;
            ...
            // Add an employee to the project.
            // Create an association object for the relationship and set its data.
            public void addEmployee(Employee employee, boolean teamLead) {
            ProjectAssociation association = new ProjectAssociation();
            association.setEmployee(employee);
            association.setProject(this);
            association.setEmployeeId(employee.getId());
            association.setProjectId(this.getId());
            association.setIsTeamLead(teamLead);
            em.persist(association);

            this.employees.add(association);
            // Also add the association object to the employee.
            employee.getProjects().add(association);
            }
            }




            @Entity
            @Table(name="PROJ_EMP")
            @IdClass(ProjectAssociationId.class)
            public class ProjectAssociation {
            @Id
            private long employeeId;
            @Id
            private long projectId;
            @Column(name="IS_PROJECT_LEAD")
            private boolean isProjectLead;
            @ManyToOne
            @JoinColumn(name = "employeeId", updatable = false, insertable = false,
            referencedColumnName = "id")

            private Employee employee;
            @ManyToOne
            @JoinColumn(name = "projectId", updatable = false, insertable = false,
            referencedColumnName = "id")

            private Project project;
            ...
            }




            public class ProjectAssociationId implements Serializable {

            private long employeeId;

            private long projectId;
            ...

            public int hashCode() {
            return (int)(employeeId + projectId);
            }

            public boolean equals(Object object) {
            if (object instanceof ProjectAssociationId) {
            ProjectAssociationId otherId = (ProjectAssociationId) object;
            return (otherId.employeeId == this.employeeId)
            && (otherId.projectId == this.projectId);
            }
            return false;
            }

            }





            share|improve this answer






























              10














              OK, I got it working based on the solution available at



              http://en.wikibooks.org/wiki/Java_Persistence/ManyToMany#Mapping_a_Join_Table_with_Additional_Columns.



              This solution does not generate duplicate attributes on the database, but it does generate duplicate attributes in my JPA entities (which is very acceptable, since you can relay the extra work to a constructor or method - it ends up being transparent). The primary and foreign keys generated in the database are 100% correct.



              As stated on the link, I couldn't use @PrimaryKeyJoinColumn and instead used @JoinColumn(name = "projectId", updatable = false, insertable = false, referencedColumnName = "id"). Another thing worth mentioning: I had to use EntityManager.persist(association), which is missing on the example at the link.



              So my final solution is:



              @Entity
              public class Employee {
              @Id
              private long id;
              ...
              @OneToMany(mappedBy="employee")
              private List<ProjectAssociation> projects;
              ...
              }




              @Entity
              public class Project {

              @PersistenceContext
              EntityManager em;

              @Id
              private long id;
              ...
              @OneToMany(mappedBy="project")
              private List<ProjectAssociation> employees;
              ...
              // Add an employee to the project.
              // Create an association object for the relationship and set its data.
              public void addEmployee(Employee employee, boolean teamLead) {
              ProjectAssociation association = new ProjectAssociation();
              association.setEmployee(employee);
              association.setProject(this);
              association.setEmployeeId(employee.getId());
              association.setProjectId(this.getId());
              association.setIsTeamLead(teamLead);
              em.persist(association);

              this.employees.add(association);
              // Also add the association object to the employee.
              employee.getProjects().add(association);
              }
              }




              @Entity
              @Table(name="PROJ_EMP")
              @IdClass(ProjectAssociationId.class)
              public class ProjectAssociation {
              @Id
              private long employeeId;
              @Id
              private long projectId;
              @Column(name="IS_PROJECT_LEAD")
              private boolean isProjectLead;
              @ManyToOne
              @JoinColumn(name = "employeeId", updatable = false, insertable = false,
              referencedColumnName = "id")

              private Employee employee;
              @ManyToOne
              @JoinColumn(name = "projectId", updatable = false, insertable = false,
              referencedColumnName = "id")

              private Project project;
              ...
              }




              public class ProjectAssociationId implements Serializable {

              private long employeeId;

              private long projectId;
              ...

              public int hashCode() {
              return (int)(employeeId + projectId);
              }

              public boolean equals(Object object) {
              if (object instanceof ProjectAssociationId) {
              ProjectAssociationId otherId = (ProjectAssociationId) object;
              return (otherId.employeeId == this.employeeId)
              && (otherId.projectId == this.projectId);
              }
              return false;
              }

              }





              share|improve this answer




























                10












                10








                10







                OK, I got it working based on the solution available at



                http://en.wikibooks.org/wiki/Java_Persistence/ManyToMany#Mapping_a_Join_Table_with_Additional_Columns.



                This solution does not generate duplicate attributes on the database, but it does generate duplicate attributes in my JPA entities (which is very acceptable, since you can relay the extra work to a constructor or method - it ends up being transparent). The primary and foreign keys generated in the database are 100% correct.



                As stated on the link, I couldn't use @PrimaryKeyJoinColumn and instead used @JoinColumn(name = "projectId", updatable = false, insertable = false, referencedColumnName = "id"). Another thing worth mentioning: I had to use EntityManager.persist(association), which is missing on the example at the link.



                So my final solution is:



                @Entity
                public class Employee {
                @Id
                private long id;
                ...
                @OneToMany(mappedBy="employee")
                private List<ProjectAssociation> projects;
                ...
                }




                @Entity
                public class Project {

                @PersistenceContext
                EntityManager em;

                @Id
                private long id;
                ...
                @OneToMany(mappedBy="project")
                private List<ProjectAssociation> employees;
                ...
                // Add an employee to the project.
                // Create an association object for the relationship and set its data.
                public void addEmployee(Employee employee, boolean teamLead) {
                ProjectAssociation association = new ProjectAssociation();
                association.setEmployee(employee);
                association.setProject(this);
                association.setEmployeeId(employee.getId());
                association.setProjectId(this.getId());
                association.setIsTeamLead(teamLead);
                em.persist(association);

                this.employees.add(association);
                // Also add the association object to the employee.
                employee.getProjects().add(association);
                }
                }




                @Entity
                @Table(name="PROJ_EMP")
                @IdClass(ProjectAssociationId.class)
                public class ProjectAssociation {
                @Id
                private long employeeId;
                @Id
                private long projectId;
                @Column(name="IS_PROJECT_LEAD")
                private boolean isProjectLead;
                @ManyToOne
                @JoinColumn(name = "employeeId", updatable = false, insertable = false,
                referencedColumnName = "id")

                private Employee employee;
                @ManyToOne
                @JoinColumn(name = "projectId", updatable = false, insertable = false,
                referencedColumnName = "id")

                private Project project;
                ...
                }




                public class ProjectAssociationId implements Serializable {

                private long employeeId;

                private long projectId;
                ...

                public int hashCode() {
                return (int)(employeeId + projectId);
                }

                public boolean equals(Object object) {
                if (object instanceof ProjectAssociationId) {
                ProjectAssociationId otherId = (ProjectAssociationId) object;
                return (otherId.employeeId == this.employeeId)
                && (otherId.projectId == this.projectId);
                }
                return false;
                }

                }





                share|improve this answer















                OK, I got it working based on the solution available at



                http://en.wikibooks.org/wiki/Java_Persistence/ManyToMany#Mapping_a_Join_Table_with_Additional_Columns.



                This solution does not generate duplicate attributes on the database, but it does generate duplicate attributes in my JPA entities (which is very acceptable, since you can relay the extra work to a constructor or method - it ends up being transparent). The primary and foreign keys generated in the database are 100% correct.



                As stated on the link, I couldn't use @PrimaryKeyJoinColumn and instead used @JoinColumn(name = "projectId", updatable = false, insertable = false, referencedColumnName = "id"). Another thing worth mentioning: I had to use EntityManager.persist(association), which is missing on the example at the link.



                So my final solution is:



                @Entity
                public class Employee {
                @Id
                private long id;
                ...
                @OneToMany(mappedBy="employee")
                private List<ProjectAssociation> projects;
                ...
                }




                @Entity
                public class Project {

                @PersistenceContext
                EntityManager em;

                @Id
                private long id;
                ...
                @OneToMany(mappedBy="project")
                private List<ProjectAssociation> employees;
                ...
                // Add an employee to the project.
                // Create an association object for the relationship and set its data.
                public void addEmployee(Employee employee, boolean teamLead) {
                ProjectAssociation association = new ProjectAssociation();
                association.setEmployee(employee);
                association.setProject(this);
                association.setEmployeeId(employee.getId());
                association.setProjectId(this.getId());
                association.setIsTeamLead(teamLead);
                em.persist(association);

                this.employees.add(association);
                // Also add the association object to the employee.
                employee.getProjects().add(association);
                }
                }




                @Entity
                @Table(name="PROJ_EMP")
                @IdClass(ProjectAssociationId.class)
                public class ProjectAssociation {
                @Id
                private long employeeId;
                @Id
                private long projectId;
                @Column(name="IS_PROJECT_LEAD")
                private boolean isProjectLead;
                @ManyToOne
                @JoinColumn(name = "employeeId", updatable = false, insertable = false,
                referencedColumnName = "id")

                private Employee employee;
                @ManyToOne
                @JoinColumn(name = "projectId", updatable = false, insertable = false,
                referencedColumnName = "id")

                private Project project;
                ...
                }




                public class ProjectAssociationId implements Serializable {

                private long employeeId;

                private long projectId;
                ...

                public int hashCode() {
                return (int)(employeeId + projectId);
                }

                public boolean equals(Object object) {
                if (object instanceof ProjectAssociationId) {
                ProjectAssociationId otherId = (ProjectAssociationId) object;
                return (otherId.employeeId == this.employeeId)
                && (otherId.projectId == this.projectId);
                }
                return false;
                }

                }






                share|improve this answer














                share|improve this answer



                share|improve this answer








                edited Nov 22 '18 at 12:20









                Sofia Paixão

                119113




                119113










                answered May 26 '14 at 20:25









                RenanRenan

                5841527




                5841527






























                    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%2f23837561%2fjpa-2-0-many-to-many-with-extra-column%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

                    Guess what letter conforming each word

                    Port of Spain

                    Run scheduled task as local user group (not BUILTIN)