1

I've a question about One to One unidirectional Mapping in Spring Boot. I've a Customer class with a One to One unidirectional mapping to an Address class.

But when I try to associate a new customer with an existing Address, the database is updated. So two Customers are now associated with the one Address.

As I understand it only one Customer should be associated with one unique Address. Do I understand the concept correctly, or am I doing something wrong in Spring Boot/ Spring Data JPA/ Hibernate?

Customer

@Entity
public class Customer {
    @Id
    private Long cId;
    private String cName;
    @OneToOne(cascade = CascadeType.ALL)
    @JoinColumn(name="aid")
    private Address cAddr;
    :
}

Address

@Entity
public class Address {
    @Id
    private Long aid;
    private String town;
    private String county;
    :
}

data.sql

insert into address values (100, "New York", "NY");
insert into customer values (1, "John Smith", 100);

Application.java

@Override
public void run(String... args) throws Exception {
    Customer c1 = new Customer((long)5, "Mr. Men");
    Optional<Address> a100 = ar.findById((long)100);
    c1.setcAddr(a100.get());
    cr.save(c1);
}

Database Both Customers have aid 100

3 Answers3

0

This is not One-to-Many relation. It's One-to-Many as One object has multiple related objects. Checkout this article.

Example:

Post.java

@Getter
@Setter
@AllArgsConstructor
@NoArgsConstructor
@Entity
@Table
public class Post {

    @Id
    @GeneratedValue
    @Column(name = "post_id")
    private Long id;

    @Column
    private String postHeader;

    @OneToMany(
            cascade = CascadeType.ALL,
            orphanRemoval = true
    )
    private List<Comment> comments = new ArrayList<>();

    public void addComment(Comment comment) {
        comments.add(comment);
    }

    public void removeComment(Comment comment) {
        comments.remove(comment);
    }

    // equals() and hashCode()
}

Comment:

@Getter
@Setter
@AllArgsConstructor
@NoArgsConstructor
@Entity
@Table
public class Comment {

    @Id
    @GeneratedValue
    @Column(name = "postcom_id")
    private Long id;

    @Column
    private String text;

    // equals() and hashCode()
}
Antonio112009
  • 415
  • 2
  • 7
  • 21
0

There are 2 options on how to make @OneToOne relation: unidirectional and bidirectional: see hibernate doc.

When you scroll down a little bit you will find the following:

When using a bidirectional @OneToOne association, Hibernate enforces the unique constraint upon fetching the child-side. If there are more than one children associated with the same parent, Hibernate will throw a org.hibernate.exception.ConstraintViolationException

It means that you'll have the exception only on fetching and when you have a bidirectional association. Because Hibernate will make an additional query to find the dependent entities, will find 2 of them, which doesn't fit @OneToOne relation and will have to throw an exception.

One way to "fix" uniqueness for your entities, is to make cAddr unique:

@OneToOne(cascade = CascadeType.ALL)
@JoinColumn(name="aid", unique=true)
private Address cAddr;

If you create your db tables, by setting hbm2ddl property this will add a unique constraint to the aid column.

I really recommend to read the following:

  1. @OneToOne javadoc itself provides examples of how to do everything correctly (for you Examples 1 and 2 are the most useful)
  2. Check Vlad's blog about @OneToOne. It must be the best you can find. At least jump to the chapter "The most efficient mapping" and implement it bidirectional and sharing the PK, using @MapsId.

Also maybe you will come up to the idea to use @ManyToOne option (at least i can imagine that customer can have multiple addresses)

Dmitrii Bocharov
  • 872
  • 6
  • 21
-1

Check out step "3. Uni-directional one-to-one mapping demonstration" at this site basically carbon copy of what you're trying to do.

Wade Watts
  • 16
  • 3
  • Thanks for the info, but it doesn't answer the question of how in a one-to-one mapping 2 rows from one table can map to the same row of another table. Unless I've understood a one-to-one mapping incorrectly? – user1714161 Nov 24 '20 at 09:28