'How do I set up a recursive, many-to-many relationship WITH an association class using JPA?
So I'm trying to create a pharmacy database that, among other things, keeps track of drug-to-drug interactions. I have a Drug entity with various members and associations and they all seem to work out fine thus far. The one implementation I'm not sure I have down correct is a recursive, many-to-many relationship with the Drug entity using an association class. The association class (DrugDrugIX) has 2 foreign keys - one from each drug - and a description and assignment of how severe is that interaction.
What I have so far works, in that it will compile and run and let me add Drugs and interactions. However, I certainly don't think what I'm doing is the most optimal -- or even correct. Any advice on how to optimize what I'm trying to do?
The Drug entity (some members omitted for brevity):
@Entity
@Table (name = "drugs")
@NamedQueries({
        @NamedQuery (name = Drug.FIND_ALL_BY_NAME,
                     query = "SELECT d FROM Drug d WHERE LOWER (d.chemical_name) LIKE LOWER (CONCAT ('%', :searchString, '%'))" )
})
public class Drug
{
    // QUERY STRING(S)
    public static final String FIND_ALL_BY_NAME = "Drug.findAllByName";
    @Id
    @GeneratedValue (strategy = GenerationType.IDENTITY)
    private long did;
    private String chemical_name;
    private String description;
    // ASSOCIATION(S)
    is this the correct implementation (???)
<----------------------------------------------------------------------------------->
    @OneToMany (mappedBy = "base", cascade = CascadeType.PERSIST)
    private List<DrugDrugIX> interxAsBase;
    
    @OneToMany (mappedBy = "offender", cascade = CascadeType.PERSIST)
    private List<DrugDrugIX> interxAsOffender;
<----------------------------------------------------------------------------------->
    @ManyToOne (cascade = CascadeType.PERSIST)
    private DEA_Class schedule;
    @OneToOne (cascade = CascadeType.PERSIST)
    private Pharmacology PK_profile;
    (...) other associations, getters and setters here (...)
    public void addInterxAsBase (DrugDrugIX interaction)
    {
        if (this.interxAsBase == null)
            interxAsBase = new ArrayList<>();
        interxAsBase.add (interaction);
    }
    public void addInterxAsOffender (DrugDrugIX interaction)
    {
        if (this.interxAsOffender == null)
            interxAsOffender = new ArrayList<>();
        interxAsOffender.add (interaction);
    }
}
The DrugDrugIX association entity:
@Entity
@Table (name = "drug_drug_interactions")
public class DrugDrugIX
{
    @EmbeddedId
    private DrugDrugIX_PK interaction_CPK;
    private int severityLevel = -1;
    
    // ASSOCIATION(S)
    @ManyToOne
    @MapsId ("base")
    private Drug base;
    
    @ManyToOne
    @MapsId ("offender")
    private Drug offender;
    (...) getters, setters omitted for brevity (...)
    public void registerInteraction (Drug object, Drug precipitate)
    {
        if (this.base == null)
            this.base = object;
        if (this.offender == null)
            this.offender = precipitate;
        if ((this.base == object && this.offender == precipitate) && (severityLevel == -1))
        {
            object.addInterxAsBase(this);
            precipitate.addInterxAsOffender(this);
        }
    }
}
...and just for posterity, the Embeddable that comprises the primary key of the DrugDrugIX entity:
@Embeddable
public class DrugDrugIX_PK implements Serializable
{
    private long base;
    private long offender;
    private String description;
    // CONSTRUCTORS
    public DrugDrugIX_PK () {}
    public DrugDrugIX_PK (Drug base, Drug offender, String description)
    {
        this.base = base.getDID();
        this.offender = offender.getDID();
        this.description = description;
    }
    
    // ACCESSORS
    public String getDescription () { return this.description; }
    // MISCELLANEOUS
    @Override
    public boolean equals (Object other)
    {
        if (other instanceof DrugDrugIX_PK)
        {
            DrugDrugIX_PK second = (DrugDrugIX_PK) other;
            return (this.base == second.base) && (offender == second.offender) && (this.description.equals (description));
        }
        else
            return false;
    }
    @Override
    public int hashCode () { return (int) (base + offender); }
}
I pray to the stackoverflow gods for guidance..
Solution 1:[1]
You do not need to use recursion. Just use two nested loops. Something like this pseudo code:
int[] drugs = {1, 4, 6};
for (i=0; i<drugs.length; i++) {
    drug1 = drugs[i];
    for (int j=i+1; j<drugs.length; j++) {
         drug2 = drugs[j];
         get_interaction(drug1, drug2);
    }
}
Drugs being administered are represented by integers in the drugs array.
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
| Solution | Source | 
|---|---|
| Solution 1 | 
