Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 9 additions & 4 deletions api/src/main/java/org/openmrs/DrugIngredient.java
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@
package org.openmrs;


import jakarta.persistence.EmbeddedId;
import jakarta.persistence.MapsId;
import org.hibernate.envers.Audited;

import jakarta.persistence.Column;
Expand All @@ -31,14 +33,17 @@ public class DrugIngredient extends BaseOpenmrsObject implements Serializable, O
public static final long serialVersionUID = 94023L;

// Fields
@EmbeddedId
private DrugIngredientId id = new DrugIngredientId();

@ManyToOne
@JoinColumn(name = "drug_id", updatable = false, insertable = false)
@Id
@MapsId("drugId")
@JoinColumn(name = "drug_id", nullable = false)
private Drug drug;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

How are these changes related to the ticket?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks — great question!
The change is part of the migration from Hibernate XML mapping to JPA annotations and doesn’t alter the model itself.

Explanation:

. drug_id and ingredient_id are a composite primary key (both were primaryKey="true" in the Liquibase snapshot).

. JPA doesn’t support having two separate @id annotations directly on @manytoone relations in a clean, maintainable way.
To represent the same composite key structure using annotations, we:

  1. Introduced DrugIngredientId (@embeddable) to hold drugId and ingredientId.

  2. Annotated the entity with @EmbeddedId private DrugIngredientId id.

  3. Used @mapsid("drugId") and @mapsid("ingredientId") on the @manytoone relations so they map into the embedded ID fields — this mirrors the composite-id behavior from the old .hbm.xml.

In short:
Both drug_id and ingredient_id form a composite primary key, so we switched to using @EmbeddedId + @mapsid, which is the standard JPA approach for this case.
If you’d prefer the older style mapping, I can adjust accordingly.

Also, if you think it would help, I can add a one-line comment near the @mapsid annotations to make this intent clearer in the code.


@ManyToOne
@JoinColumn(name = "ingredient_id", updatable = false, insertable = false)
@Id
@MapsId("ingredientId")
@JoinColumn(name = "ingredient_id", nullable = false)
private Concept ingredient;

@Column(name = "strength")
Expand Down
68 changes: 68 additions & 0 deletions api/src/main/java/org/openmrs/DrugIngredientId.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
/**
* This Source Code Form is subject to the terms of the Mozilla Public License,
* v. 2.0. If a copy of the MPL was not distributed with this file, You can
* obtain one at http://mozilla.org/MPL/2.0/. OpenMRS is also distributed under
* the terms of the Healthcare Disclaimer located at http://openmrs.org/license.
*
* Copyright (C) OpenMRS Inc. OpenMRS is a registered trademark and the OpenMRS
* graphic logo is a trademark of OpenMRS Inc.
*/
package org.openmrs;

import jakarta.persistence.Column;
import jakarta.persistence.Embeddable;

import java.io.Serializable;
import java.util.Objects;

/**
* Composite primary key for DrugIngredient.
*/
@Embeddable
public class DrugIngredientId implements Serializable {
private static final long serialVersionUID = 1L;

@Column(name = "drug_id")
private Integer drugId;

@Column(name = "ingredient_id")
private Integer ingredientId;

public DrugIngredientId() {
}

public DrugIngredientId(Integer drugId, Integer ingredientId) {
this.drugId = drugId;
this.ingredientId = ingredientId;
}

public Integer getDrugId() {
return drugId;
}

public void setDrugId(Integer drugId) {
this.drugId = drugId;
}

public Integer getIngredientId() {
return ingredientId;
}

public void setIngredientId(Integer ingredientId) {
this.ingredientId = ingredientId;
}

@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
DrugIngredientId that = (DrugIngredientId) o;
return Objects.equals(drugId, that.drugId) &&
Objects.equals(ingredientId, that.ingredientId);
}

@Override
public int hashCode() {
return Objects.hash(drugId, ingredientId);
}
}
Loading