Java Persistence/OneToMany

From Wikibooks, open books for an open world
Jump to: navigation, search

 

 

OneToMany[edit]

ObjectRelational-ManyToOne2.jpg

A OneToMany relationship in Java is where the source object has an attribute that stores a collection of target objects and if those target objects had the inverse relationship back to the source object it would be a ManyToOne relationship. All relationships in Java and JPA are unidirectional, in that if a source object references a target object there is no guarantee that the target object also has a relationship to the source object. This is different than a relational database, in which relationships are defined through foreign keys and querying such that the inverse query always exists.

JPA also defines a ManyToMany relationship, which is similar to a OneToMany relationship except that the inverse relationship (if it were defined) is a ManyToMany relationship. The main difference between a OneToMany and a ManyToMany relationship in JPA is that a ManyToMany always makes use of an intermediate relational join table to store the relationship, whereas a OneToMany can either use a join table, or a foreign key in target object's table referencing the source object table's primary key. If the OneToMany uses a foreign key in the target object's table JPA requires that the relationship be bi-directional (inverse ManyToOne relationship must be defined in the target object), and the source object must use the mappedBy attribute to define the mapping.

In JPA a OneToMany relationship is defined through the @OneToMany annotation or the <one-to-many> element.

Example of a OneToMany relationship database[edit]

EMPLOYEE (table)

EMP_ID FIRSTNAME LASTNAME SALARY MANAGER_ID
1 Bob Way 50000 2
2 Sarah Smith 75000 null

PHONE (table)

ID TYPE AREA_CODE P_NUMBER OWNER_ID
1 home 613 792-0000 1
2 work 613 896-1234 1
3 work 416 123-4444 2

Example of a OneToMany relationship and inverse ManyToOne annotations[edit]

@Entity
public class Employee {
  @Id
  @Column(name="EMP_ID")
  private long id;
  ...
  @OneToMany(mappedBy="owner")
  private List<Phone> phones;
  ...
}
@Entity
public class Phone {
  @Id
  private long id;
  ...
  @ManyToOne(fetch=FetchType.LAZY)
  @JoinColumn(name="OWNER_ID")
  private Employee owner;
  ...
}

Example of a OneToMany relationship and inverse ManyToOne XML[edit]

<entity name="Employee" class="org.acme.Employee" access="FIELD">
    <attributes>
        <id name="id"/>
        <one-to-many name="phones" target-entity="org.acme.Phone" mapped-by="owner"/>
    </attributes>
</entity>
<entity name="Phone" class="org.acme.Phone" access="FIELD">
    <attributes>
        <id name="id"/>
        <many-to-one name="owner" fetch="LAZY">
            <join-column name="OWNER_ID"/>
        </many-to-one>
    </attributes>
</entity>

Note this @OneToMany mapping requires an inverse @ManyToOne mapping to be complete, see ManyToOne.

Getters and Setters[edit]

The relationship is bi-directional so, as the application updates one side of the relationship, the other side should also get updated, and be in sync. In JPA, as in Java in general it is the responsibility of the application, or the object model to maintain relationships. If your application adds to one side of a relationship, then it must add to the other side.

This can be resolved through add or set methods in the object model that handle both sides of the relationships, so the application code does not need to worry about it. There are two ways to go about this, you can either only add the relationship maintenance code to one side of the relationship, and only use the setter from one side (such as making the other side protected), or add it to both sides and ensure you avoid an infinite loop.

For example:

public class Employee {
    private List phones;
    ...
    public void addPhone(Phone phone) {
        this.phones.add(phone);
        if (phone.getOwner() != this) {
            phone.setOwner(this);
        }
    }
    ...
}
public class Phone {
    private Employee owner;
    ...

   /**
    * You have to ensure that the previous owner of this phone is no longer the owner of this 
    * phone before you atribute it a new owner. Ensure this either by a 
    * @requires !this.employee.getPhones().contains(this) or by adding to the beginning of 
    * the method body:
    * if(this.employee != null)
    *     this.employee.removePhone(this);
    */
    public void setOwner(Employee employee) {
        this.owner = employee;
        if (!employee.getPhones().contains(this)) { // warning this may cause performance issues if you have a large data set since this operation is O(n)
            employee.getPhones().add(this);
        }
    }
    ...
}

Some expect the JPA provider to have magic that automatically maintains relationships. This was actually part of the EJB CMP 2 specification. However the issue is if the objects are detached or serialized to another VM, or new objects are related before being managed, or the object model is used outside the scope of JPA, then the magic is gone, and the application is left figuring things out, so in general it may be better to add the code to the object model. However some JPA providers do have support for automatically maintaining relationships.

In some cases it is undesirable to instantiate a large collection when adding a child object. One solution is to not map the bi-directional relationship, and instead query for it as required. Also some JPA providers optimize their lazy collection objects to handle this case, so you can still add to the collection without instantiating it.

Join Table[edit]

A common mismatch between objects and relational tables is that a OneToMany does not require a back reference in Java, but requires a back reference foreign key in the database. Normally it is best to define the ManyToOne back reference in Java, if you cannot or don't want to do this, then you can use an intermediate join table to store the relationship. This is similar to a ManyToMany relationship, but if you add a unique constraint to the target foreign key you can enforce that it is OneToMany.

JPA defines a join table using the @JoinTable annotation and <join-table> XML element. A JoinTable can be used on a ManyToMany or OneToMany mappings.

경축! 아무것도 안하여 에스천사게임즈가 새로운 모습으로 재오픈 하였습니다.
어린이용이며, 설치가 필요없는 브라우저 게임입니다.
https://s1004games.com

See also, Undirectional OneToMany

Example of a OneToMany using a JoinTable database[edit]

EMPLOYEE (table)

EMP_ID FIRSTNAME LASTNAME
1 Bob May
2 Sarah Smith
3 Sarah Smith

EMP_PHONE (table)

EMP_ID PHONE_ID
1 1
1 2
2 3

PHONE (table)

ID TYPE PHONE_ID P_NUMBER
1 home 1 792-0000
2 work 1 896-1234
3 work 2 123-4444

Example of a OneToMany using a JoinTable annotation[edit]

@Entity
public class Employee {
  @Id
  @Column(name="EMP_ID")
  private long id;
  ...
  @OneToMany
  @JoinTable
  (
      name="EMP_PHONE",
      joinColumns={ @JoinColumn(name="EMP_ID", referencedColumnName="EMP_ID") },
      inverseJoinColumns={ @JoinColumn(name="PHONE_ID", referencedColumnName="ID", unique=true) }
  )
// While Update this will also insert collection row another insert
  private List<Phone> phones;
  ...
}

Example of a OneToMany using a JoinTable XML[edit]

<entity name="Employee" class="org.acme.Employee" access="FIELD">
    <attributes>
        <id name="id">
            <column name="EMP_ID"/>
        </id>
        <one-to-many name="phones">
            <join-table name="EMP_PHONE">
                <join-column name="EMP_ID" referenced-column-name="EMP_ID"/>
                <inverse-join-column name="PHONE_ID" referenced-column-name="ID" unique="true" />
            </join-table>
        </one-to-many>
    </attributes>
</entity>

See Also[edit]

Common Problems[edit]

Object not in collection after refresh.[edit]
See Object corruption.

Advanced[edit]

Unidirectional OneToMany, No Inverse ManyToOne, No Join Table (JPA 2.x ONLY)[edit]

JPA 1.0 does not support a unidirectional OneToMany relationship without a JoinTable. Since JPA 2.0 there is a support for unidirectional OneToMany. In JPA 2.x a @JoinColumn can be used on a OneToMany to define the foreign key, some JPA providers may support this already.

The main issue with an unidirectional OneToMany is that the foreign key is owned by the target object's table, so if the target object has no knowledge of this foreign key, inserting and updating the value is difficult. In a unidirectional OneToMany the source object take ownership of the foreign key field, and is responsible for updating its value.

The target object in a unidirectional OneToMany is an independent object, so it should not rely on the foreign key in any way, i.e. the foreign key cannot be part of its primary key, nor generally have a not null constraint on it. You can model a collection of objects where the target has no foreign key mapped, but uses it as its primary key, or has no primary key using a Embeddable collection mapping, see Embeddable Collections.

If your JPA provider does not support unidirectional OneToMany relationships, then you will need to either add a back reference ManyToOne or a JoinTable. In general it is best to use a JoinTable if you truly want to model a unidirectional OneToMany on the database.

There are some creative workarounds to defining a unidirectional OneToMany. One is to map it using a JoinTable, but make the target table the JoinTable. This will cause an extra join, but work for the most part for reads, writes of course will not work correctly, so this is only a read-only solution and a hacky one at that.

Example of a JPA 2.x unidirectional OneToMany relationship database[edit]

EMPLOYEE (table)

EMP_ID FIRSTNAME LASTNAME
1 Bob May
2 Sarah Smith

PHONE (table)

ID TYPE AREA_CODE P_NUMBER OWNER_ID
1 home 613 792-0000 1
2 work 613 896-1234 1
3 work 416 123-4444 2

Example of a JPA 2.x unidirectional OneToMany relationship annotations[edit]

@Entity
public class Employee {
  @Id
  @Column(name="EMP_ID")
  private long id;
  ...
  @OneToMany
  @JoinColumn(name="OWNER_ID", referencedColumnName="EMP_ID")
  private List<Phone> phones;
  ...
}
@Entity
public class Phone {
  ...
  @Column(name="OWNER_ID")
  private long ownerId;
  ...
}

Example for a non-null join column[edit]

In case your join column is non-null you need to specify @JoinColumn(name="OWNER_ID", referencedColumnName="EMP_ID", nullable = false)

@Entity
public class Employee {
  @Id
  @Column(name="EMP_ID")
  private long id;
  ...
  @OneToMany
  @JoinColumn(name="OWNER_ID", referencedColumnName="EMP_ID", nullable = false)
  private List<Phone> phones;
  ...
}

 

[출처] https://en.wikibooks.org/wiki/Java_Persistence/OneToMany

 

 

본 웹사이트는 광고를 포함하고 있습니다.
광고 클릭에서 발생하는 수익금은 모두 웹사이트 서버의 유지 및 관리, 그리고 기술 콘텐츠 향상을 위해 쓰여집니다.
번호 제목 글쓴이 날짜 조회 수
35 [EMF] EMF Tutorial EMF 튜터리얼 file 졸리운_곰 2023.08.23 283
34 Eclipse RAP Tutorial for Beginners - Workbench Application (OLD) file 졸리운_곰 2021.01.30 323
33 Learn Eclipse GMF in 15 minutes file 졸리운_곰 2019.11.27 253
32 [Eclipse] GEF entry series (10, an implementation of the form) file 졸리운_곰 2019.11.25 212
31 GEF Programmer Guide 번역 졸리운_곰 2019.11.25 227
30 Learn Eclipse GMF in 15 minutes file 졸리운_곰 2019.11.20 224
29 RCP 에디터 정리 졸리운_곰 2019.11.20 333
28 다른 그림과 관련하여 GEF 편집기 레이아웃에서 그림의 위치 제한 조건을 동적으로 계산 Dynamically calculating the position constraints for a figure in a GEF editor layout in relation to another figure file 졸리운_곰 2019.11.20 277
27 RCP 등에서 .mf 파일로 다른 프로젝트 익스포트 포함시 라이브러리(메소드)를 찾지 못할 때, Eclipse RCP - cant resolve importing libraries in final build file 졸리운_곰 2019.10.15 410
26 ESE2006-EclipseModelingSymposium15_GMF.pdf file 졸리운_곰 2019.09.21 302
25 GMF_Creation_Review.pdf file 졸리운_곰 2019.09.21 366
24 Eclipse EMF and GMF Tutorial file 졸리운_곰 2019.09.21 222
23 GMF Tutorial/ko file 졸리운_곰 2019.09.20 347
22 Model Driven Architecture approach to domain of graphical editors file 졸리운_곰 2019.09.20 268
21 Single_Sourcing_RAP_RCP_en.pdf file 졸리운_곰 2019.05.15 311
20 Rich client platform 설명 및 배우기 참고 졸리운_곰 2019.05.15 309
19 Rich Ajax Platform, Part 1: 소개 file 졸리운_곰 2019.05.15 320
18 또 하나의 크로스 플랫폼: Eclipse RAP file 졸리운_곰 2019.05.15 319
17 Eclipse 4 RCP 튜토리얼(완료) file 졸리운_곰 2019.05.14 977
16 Updating UI in Eclipse RCP 졸리운_곰 2015.11.07 408
대표 김성준 주소 : 경기 용인 분당수지 U타워 등록번호 : 142-07-27414
통신판매업 신고 : 제2012-용인수지-0185호 출판업 신고 : 수지구청 제 123호 개인정보보호최고책임자 : 김성준 sjkim70@stechstar.com
대표전화 : 010-4589-2193 [fax] 02-6280-1294 COPYRIGHT(C) stechstar.com ALL RIGHTS RESERVED