ConstraintViolationException after switching from hibernate annotations to xml

I switched from hibernate annotations to xml and now I’m getting constraints violation exception when I try to save my objects. Here is the full exception https://pastebin.com/qpnkGiZf

My module was originally built with openmrs-2-0 but the implementation is still on 1.9.11 and not planning to upgrade to 2.0 anytime soon. So I had to downgrade my openmrs version to 1.9.11. This caused a lot of errors which included errors with using annotations so I just decided to switch from annotations to xml and was able to make my module build.

Now when I make a request with the sample data below, i get a constraint violation exception when trying to save my object.

{
    "patient": "ea90b89a-b4c3-11e6-9ca8-c668c368a15f",
    "encounterDate": "2018-01-31T23:00:00.000Z",
    "encounterLocation": "f8f7fdfa-5ba4-11e5-b713-040166f22240",
    "encounterProvider": "prov7ab0-2170-482c-afb7-0a7bf11ba8cf",
    "result1": "6",
    "result2": "6",
    "date1": "2018-01-31T23:00:00.000Z",
    "date2":"2018-01-31T23:00:00.000Z"
 }

Below is my liquibase changeset for the object above

And my hibernate mapping is

When that request is made, an encounter is created, saved then added to the HivTestResult object before attempting to save this object, but this throws a ConstraintVoilationException.

What could I be doing wrong. I’m getting this exception for all classes in my module.

I see that the encounter field is mapped as one-to-one and that might be the problem, a one-to-one mapping can be tricky to configure because the primary key values of the joined tables MUST match for hibernate to be able to establish the relationship. Since you don’t have control over the encounter table because it’s in core, this automatically makes your table the child and encounter the parent in the relationship, so the rows in your table MUST inherit their primary key values from their parents and this is achieved by setting the primary key generator strategy to foreign and the value of the property param on the generator should be set to the property name of the encounter field in the hbm file. You also need to set the constrained attribute on the one-to-one tag to true to ensure that the encounter exists.

FYI it’s meaningless to set default value to 0 for the non-nullable foreign key columns that are mapped as one-to-one or many-to-one. And why do you have encounter details like date, location and provider in your domain class if you are referencing the encounter object which also already has these fields?

@wyclif thanks for your response.

I originally built this for openmrs 2.0. My module was generated with the SDK and it came with annotations instead of mapping files. After completing the module, I realized the implementation were not ready to upgrade to 2.0 yet so I had to make this work on their 1.9.11 platform. Downgrading to 1.9.11 was giving me a lot of errors with the annotations so I decided to use xml files as that’s what I could see in a lot of modules that were still depending on 1.9.x. Below is the equivalent of the entity using annotations that worked on 2.0

Please how can I fix this?

I did not quite understand this point. I saved the encounter using

Context.getEncounterService().saveEncounter(encounter);

And then added added this saved encounter to my object

hivTestResult.setEncounter(encounter);
// then save the result

Is that not enough to satisfy the foreign key relationship? And why did it work on 2.0 when I was using annotations.

Yeah I only noticed this when I was asking this question. I’ll fix it but that shouldn’t be the problem as it worked like that on 2.0. I only copied that and forgot to properly edit it.

Ok so I don’t want to make two rest calls for when saving those forms. That is

  1. creating an encounter
  2. Using the encounter id to save the form

That is why my json looks as above. I am passing the encounter properties and I construct an encounter object then save using the Java API.

The reason I did it that way was because that page is behind a service worker and is expected to work offline. That is if the form was filled when there is no internet, the data should sync when they regain internet. But if I have to make this two API calls where the second call will depend on the uuid of the first, the background sync becomes very complex.

It’s typical for developers including myself to say it worked before or it works on my machine when actually it doesn’t and bugs are meant disprove us, sometimes it works can be different from am getting the correct expected behavior. If that test is the same test you had before, there’s nothing in it that ensures that the correct behavior is getting achieved because in memory state can be completely different from database state, it’s only testing saving and not testing that actually the value of the encounter field on your hivTestResult instance is written to the DB and that you can fully load a fresh copy of the hivTestResult instance from the DB with the encounter field populated, all you are dealing with is what is in memory and hibernate session.

With that said, you also need to fully understand the meaning of a one-to-one relationship, it means only one encounter should be associated to an hivTestResult and vice versa, I think this constraint is normally only caught at load time in case you end up with multiple hivTestResults pointing to the same encounter and that’s when hibernate will fail to establish the relationship, from the annotation mapping you had before that wasn’t any different from a many-to-one relationship, is that what you intended to have? Otherwise it would still work but doesn’t meaning it’s the right thing and that you’re getting the correct expected behavior.

I understand. But that is not the case here. I’m not a hibernate expert. I just need my problem to be solved. What good will it do me if I mislead my potential helpers. When asking my question, I always give as much information I think will help in answering my question.

I originally built this to run on 2.0 using annotations. And it worked here means I launched the application saved my form and my encounter was created successfully and I was taken to the patient dashboard unlike what is happening now. It’s not about the test.

Sorry but I’m not very proficient with hibernate so I’m lost here. Do you mean this is a many-to-one not a one-to-one?

I only want one encounter to be attached to hivTestResults just like with html forms. Or I’m wrong?

What do you think is the cause of my error and how do I fix it?

@wyclif do you think the version of mysql has any role to play in this? I just noticed the implementation is running on 5.5 but I tested on 5.6.

So I changed to many-to-one and I no longer get the foreign key constraint error. I’m tempted to leave it that way as my code does not create a many-to-one relation though. On each request, a new encounter is created for the hivTestResult, so I don’t see an instance where 2 different hivTestResults will be linked to the same encounter. I need to upgrade my hibernate knowledge before I can tackle this problem.

I’ve been trying clarify something from you and I haven’t yet been successful to be able to help, for me it’s not about what works, am more interested in knowing what behavior you wish to have, it’s more like a semantics vs syntax issue to me. I can tell you what change you need to make for the error to go away but it might not necessarily address what the intended behavior needs to be.

If you want each hivTestResult to be linked to exactly one encounter and vice versa it needs to be a one-to-one relationship for purposes of data integrity and you would need more configurations otherwise it can be a many-to-one, the concept of many-to-one vs one-to-one is a general logical concept rather than a hibernate specific concept.

Seems like the right thing to do, and if that’s the case then it needs to be a one-to-one and you need to read my initial response for how to setup the mapping to work, I’ll quote it for you below: