Question

The only examples I can find addressing this sort of scenario are pretty old, and I'm wondering what the best way is to do this with the latest version of ORMLite...

Say I have two tables (simplified):

public class Patient
{
   [Alias("PatientId")]
   [Autoincrement]
   public int Id { get; set; }
   public string Name { get; set; }
}

public class Insurance
{
   [Alias("InsuranceId")]
   [Autoincrement]
   public int Id { get; set; }
   [ForeignKey(typeof("Patient"))]
   public int PatientId { get; set; }
   public string Policy { get; set; }
   public string Level { get; set; }
}

Patients can have multiple Insurance policies at different "levels" (primary, secondary, etc). I understand the concept of blobbing the insurance information as a Dictionary type object and adding it directly to the [Patient] POCO like this:

public class Patient
{
   public Patient() {
      this.Insurances = new Dictionary<string, Insurance>();  // "string" would be the Level, could be set as an Enum...
   }

   [Alias("PatientId")]
   [Autoincrement]
   public int Id { get; set; }
   public string Name { get; set; }
   public Dictionary<string, Insurance> Insurances { get; set; }
}

public class Insurance
{
   public string Policy { get; set; }
}

...but I need the insurance information to exist in the database as a separate table for use in reporting later.

I know I can join those tables in ORMLite, or create a joined View/Stored Proc in SQL to return the data, but it will obviously return multiple rows for the same Patient.

SELECT Pat.Name, Ins.Policy, Ins.Level
FROM Patient AS Pat JOIN
   Insurance AS Ins ON Pat.PatientId = Ins.PatientId

(Result)
"Johnny","ABC123","Primary"
"Johnny","987CBA","Secondary"

How can I map that into a single JSON response object?

I'd like to be able to map a GET request to "/patients/1234" to return a JSON object like:

[{
   "PatientId":"1234",
   "Name":"Johnny",
   "Insurances":[
      {"Policy":"ABC123","Level":"Primary"},
      {"Policy":"987CBA","Level":"Secondary"}
   ]
}]

I don't have a lot of hope in this being do-able in a single query. Can it be done in two (one on the Patient table, and a second on the Insurance table)? How would the results of each query be added to the same response object in this nested fashion?

Thanks a ton for any help on this!

Update - 4/29/14

Here's where I'm at...In the "Patient" POCO, I have added the following:

public class Patient
{
   [Alias("PatientId")]
   [Autoincrement]
   public int Id { get; set; }
   public string Name { get; set; }
   [Ignore]
   public List<Insurance> Insurances { get; set; }  // ADDED
}

Then, when I want to return a patient with multiple Insurances, I do two queries:

var patientResult = dbConn.Select<Patient>("PatientId = " + request.PatientId);

List<Insurance> insurances = new List<Insurance>();
var insuranceResults = dbConn.Select<Insurance>("PatientId = " + patientResult[0].PatientId);
foreach (patientInsurance pi in insuranceResults)
{
    insurances.Add(pi);
}

patientResult[0].Insurances = insurances;
patientResult[0].Message = "Success";

return patientResult;

This works! I get nice JSON with nested items for Insurances while maintaining separate related tables in the db.

What I don't like is that this object cannot be passed back and forth to the database. That is, I can't use the same nested object to automatically insert/update both the Patient and InsurancePolicy tables at the same time. If I remove the "[Ignore]" decorator, I get a field in the Patient table called "Insurances" of type varchar(max). No good, right?

I guess I'm going to need to write some additional code for my PUT/POST methods to extract the "Insurances" node from the JSON, iterate over it, and use each Insurance object to update the database? I'm just hoping I'm not re-inventing the wheel here or doing a ton more work than is necessary.

Comments would still be appreciated! Is Mythz on? :-) Thanks...

Was it helpful?

Solution

An alternate more succinct example:

public void Put(CreatePatient request)
{
   var patient = new Patient
   {
      Name = request.Name,
      Insurances = request.Insurances.Map(x => 
          new Insurance { Policy = i.Policy, Level = i.Level })
   };

   db.Save<Patient>(patient, references:true);
}

OTHER TIPS

References are here to save the day!

public class Patient
{
   [Alias("PatientId")]
   [Autoincrement]
   public int Id { get; set; }
   public string Name { get; set; }
   [Reference]
   public List<Insurance> Insurances { get; set; }
}

public class Insurance
{
   [Alias("InsuranceId")]
   [Autoincrement]
   public int Id { get; set; }
   [ForeignKey(typeof("Patient"))]
   public int PatientId { get; set; }
   public string Policy { get; set; }
   public string Level { get; set; }
}

I can then take a JSON request with a nested "Insurance" array like this:

{
   "Name":"Johnny",
   "Insurances":[
      {"Policy":"ABC123","Level":"Primary"},
      {"Policy":"987CBA","Level":"Secondary"}
   ]
}

...to create a new record and save it like this:

public bool Put(CreatePatient request)
{
   List<Insurance> insurances = new List<Insurance>();
   foreach (Insurance i in request.Insurances)
   {
      insurances.Add(new Insurance
      {
         Policy = i.Policy,
         Level = i.Level
      });
   }
   var patient = new Patient
   {
      Name = request.Name,
      Insurances = insurances
   };

   db.Save<Patient>(patient, references:true);

   return true;
}

Bingo! I get the new Patient record, plus 2 new records in the Insurance table with correct foreign key references back to the PatientId that was just created. This is amazing!

First you should define a foreign collection in Patient class. (with get and set methods)

@ForeignCollectionField
private Collection<Insurance> insurances;

When you query for a patient, you can get its insurances by calling getInsurances method.

To convert all into a single json object with arrays inside you can use a json processor. I use Jackson (https://github.com/FasterXML/jackson) and it works very well. Below will give you json object as a string.

new ObjectMapper().writeValueAsString(patientObject);

To correctly map foreign fields you should define jackson references. In your patient class add a managed reference.

@ForeignCollectionField
@JsonManagedReference("InsurancePatient")
private Collection<Insurance> insurances;

In your insurance class add a back reference.

@JsonBackReference("InsurancePatient")
private Patient patient;

Update: You can use Jackson to generate objects from json string then iterate and update/create database rows.

objectMapper.readValue(jsonString, Patient.class);
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top