Skip to content

Conversation

Copy link
Contributor

Copilot AI commented Nov 5, 2025

@MapsId creates bidirectional coupling between the embedded composite key and relationship associations, causing JPA mapping conflicts in entities with @EmbeddedId.

Changes

  • Removed @MapsId annotations from resourceGroup and containerImage associations
  • Made associations read-only via insertable=false, updatable=false on @JoinColumn
  • Initialize id in constructor when both entities are provided:
    @Builder
    public ResourceGroupImage(ResourceGroup resourceGroup, ContainerImage containerImage) {
        this.resourceGroup = resourceGroup;
        this.containerImage = containerImage;
        if (resourceGroup != null && containerImage != null) {
            this.id = new ResourceGroupImageId(resourceGroup.getRsgroupId(), containerImage.getImageId());
        }
    }
  • Kept @PrePersist guard as safety mechanism

The embedded ID now controls FK columns exclusively, eliminating mapping ambiguity while maintaining proper entity relationships.

Original prompt

Goal

  • Remove @mapsid usage from ResourceGroupImage to avoid composite-key mapping coupling issues and rely on @EmbeddedId for persistence, while keeping associations read-only (insertable/updatable false).
  • Keep ResourceGroupImageId unchanged.
  • Ensure id is synchronized via constructor and @PrePersist.

Context

  • You previously refactored away @mapsid patterns and it worked, but @mapsid was reintroduced in ResourceGroupImage.
  • Current files:
    • src/main/java/DGU_AI_LAB/admin_be/domain/resourceGroupImages/entity/ResourceGroupImage.java
    • src/main/java/DGU_AI_LAB/admin_be/domain/resourceGroupImages/entity/ResourceGroupImageId.java

Changes to implement

  1. In ResourceGroupImage.java
    • Remove @mapsid("rsgroupId") and @mapsid("imageId") from the associations.
    • Add insertable = false, updatable = false on both @joincolumn annotations so the association columns are controlled by the embedded id only.
    • In the @builder constructor, when both ResourceGroup and ContainerImage are provided, set this.id = new ResourceGroupImageId(resourceGroup.getRsgroupId(), containerImage.getImageId()).
    • Keep the existing @PrePersist guard to set id when missing.

Exact target file and replacement content
Please replace the contents of src/main/java/DGU_AI_LAB/admin_be/domain/resourceGroupImages/entity/ResourceGroupImage.java with the following:

package DGU_AI_LAB.admin_be.domain.resourceGroupImages.entity;

import DGU_AI_LAB.admin_be.domain.containerImage.entity.ContainerImage;
import DGU_AI_LAB.admin_be.domain.resourceGroups.entity.ResourceGroup;
import DGU_AI_LAB.admin_be.global.common.BaseTimeEntity;
import jakarta.persistence.*;
import lombok.*;

@Entity
@Table(name = "resource_group_images")
@Access(AccessType.FIELD)
@Getter
@NoArgsConstructor(access = AccessLevel.PROTECTED)
@EqualsAndHashCode(of = "id", callSuper = false)
public class ResourceGroupImage extends BaseTimeEntity {

    @EmbeddedId
    private ResourceGroupImageId id;

    @ManyToOne(fetch = FetchType.LAZY)
    @JoinColumn(name = "rsgroup_id", nullable = false, insertable = false, updatable = false)
    private ResourceGroup resourceGroup;

    @ManyToOne(fetch = FetchType.LAZY)
    @JoinColumn(name = "image_id", nullable = false, insertable = false, updatable = false)
    private ContainerImage containerImage;

    @Builder
    public ResourceGroupImage(ResourceGroup resourceGroup, ContainerImage containerImage) {
        this.resourceGroup = resourceGroup;
        this.containerImage = containerImage;
        if (resourceGroup != null && containerImage != null) {
            this.id = new ResourceGroupImageId(resourceGroup.getRsgroupId(), containerImage.getImageId());
        }
    }

    @PrePersist
    void onCreate() {
        if (id == null && resourceGroup != null && containerImage != null) {
            id = new ResourceGroupImageId(resourceGroup.getRsgroupId(), containerImage.getImageId());
        }
    }
}

Validation

  • The repository compiles and tests (if any) still pass.
  • No DB schema changes are required; only JPA mapping is adjusted.

Deliverables

  • Create a new branch for this refactor.
  • Commit the changes with a clear message (e.g., "refactor: remove @mapsid from ResourceGroupImage and rely on EmbeddedId").
  • Open a PR targeting the default branch with a concise description of the rationale and changes.

PR description (use this text or refine):

Title: Refactor: remove @mapsid from ResourceGroupImage and rely on EmbeddedId

Summary:

  • Removed @mapsid from ResourceGroupImage associations to prevent composite-key coupling issues.
  • Associations are now read-only via insertable=false, updatable=false; the actual FK columns are set via the embedded id.
  • Constructor and @PrePersist ensure id is synchronized from associated entities.

Notes:

  • ResourceGroupImageId remains unchanged.
  • If desired, we can apply the same refactor pattern to RequestGroup in a follow-up PR.

This pull request was created as a result of the following prompt from Copilot chat.

Goal

  • Remove @mapsid usage from ResourceGroupImage to avoid composite-key mapping coupling issues and rely on @EmbeddedId for persistence, while keeping associations read-only (insertable/updatable false).
  • Keep ResourceGroupImageId unchanged.
  • Ensure id is synchronized via constructor and @PrePersist.

Context

  • You previously refactored away @mapsid patterns and it worked, but @mapsid was reintroduced in ResourceGroupImage.
  • Current files:
    • src/main/java/DGU_AI_LAB/admin_be/domain/resourceGroupImages/entity/ResourceGroupImage.java
    • src/main/java/DGU_AI_LAB/admin_be/domain/resourceGroupImages/entity/ResourceGroupImageId.java

Changes to implement

  1. In ResourceGroupImage.java
    • Remove @mapsid("rsgroupId") and @mapsid("imageId") from the associations.
    • Add insertable = false, updatable = false on both @joincolumn annotations so the association columns are controlled by the embedded id only.
    • In the @builder constructor, when both ResourceGroup and ContainerImage are provided, set this.id = new ResourceGroupImageId(resourceGroup.getRsgroupId(), containerImage.getImageId()).
    • Keep the existing @PrePersist guard to set id when missing.

Exact target file and replacement content
Please replace the contents of src/main/java/DGU_AI_LAB/admin_be/domain/resourceGroupImages/entity/ResourceGroupImage.java with the following:

package DGU_AI_LAB.admin_be.domain.resourceGroupImages.entity;

import DGU_AI_LAB.admin_be.domain.containerImage.entity.ContainerImage;
import DGU_AI_LAB.admin_be.domain.resourceGroups.entity.ResourceGroup;
import DGU_AI_LAB.admin_be.global.common.BaseTimeEntity;
import jakarta.persistence.*;
import lombok.*;

@Entity
@Table(name = "resource_group_images")
@Access(AccessType.FIELD)
@Getter
@NoArgsConstructor(access = AccessLevel.PROTECTED)
@EqualsAndHashCode(of = "id", callSuper = false)
public class ResourceGroupImage extends BaseTimeEntity {

    @EmbeddedId
    private ResourceGroupImageId id;

    @ManyToOne(fetch = FetchType.LAZY)
    @JoinColumn(name = "rsgroup_id", nullable = false, insertable = false, updatable = false)
    private ResourceGroup resourceGroup;

    @ManyToOne(fetch = FetchType.LAZY)
    @JoinColumn(name = "image_id", nullable = false, insertable = false, updatable = false)
    private ContainerImage containerImage;

    @Builder
    public ResourceGroupImage(ResourceGroup resourceGroup, ContainerImage containerImage) {
        this.resourceGroup = resourceGroup;
        this.containerImage = containerImage;
        if (resourceGroup != null && containerImage != null) {
            this.id = new ResourceGroupImageId(resourceGroup.getRsgroupId(), containerImage.getImageId());
        }
    }

    @PrePersist
    void onCreate() {
        if (id == null && resourceGroup != null && containerImage != null) {
            id = new ResourceGroupImageId(resourceGroup.getRsgroupId(), containerImage.getImageId());
        }
    }
}

Validation

  • The repository compiles and tests (if any) still pass.
  • No DB schema changes are required; only JPA mapping is adjusted.

Deliverables

  • Create a new branch for this refactor.
  • Commit the changes with a clear message (e.g., "refactor: remove @mapsid from ResourceGroupImage and rely on EmbeddedId").
  • Open a PR targeting the default branch with a concise description of the rationale and changes.

PR description (use this text or refine):

Title: Refactor: remove @mapsid from ResourceGroupImage and rely on EmbeddedId

Summary:

  • Removed @mapsid from ResourceGroupImage associations to prevent composite-key coupling issues.
  • Associations are now read-only via insertable=false, updatable=false; the actual FK columns are set via the embedded id.
  • Constructor and @PrePersist ensure id is synchronized from associated entities.

Notes:

  • ResourceGroupImageId remains unchanged.
  • If desired, we can apply the same refactor pattern to RequestGroup in a follow-up PR.

✨ Let Copilot coding agent set things up for you — coding agent works faster and does higher quality work when set up for your repo.

Co-authored-by: kwdahun <101495753+kwdahun@users.noreply.github.com>
Copilot AI changed the title [WIP] Remove MapsId usage from ResourceGroupImage Remove @MapsId from ResourceGroupImage to fix composite key coupling Nov 5, 2025
Copilot AI requested a review from kwdahun November 5, 2025 07:35
@saokiritoni saokiritoni marked this pull request as ready for review December 30, 2025 06:02
@saokiritoni saokiritoni requested a review from a team as a code owner December 30, 2025 06:02
@saokiritoni saokiritoni merged commit 38cb6f0 into develop Dec 30, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants