简体   繁体   English

与ORMLite的一对多关系

[英]One-to-Many relationship with ORMLite

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... 我能找到解决这种情况的唯一例子已经很老了,我想知道用最新版本的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: 我理解将保险信息作为字典类型对象填充并将其直接添加到[Patient] POCO的概念,如下所示:

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. 我知道我可以在ORMLite中加入这些表,或者在SQL中创建一个联合的View / Stored Proc来返回数据,但它显然会为同一个患者返回多行。

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? 如何将其映射到单个JSON响应对象?

I'd like to be able to map a GET request to "/patients/1234" to return a JSON object like: 我希望能够将GET请求映射到“/ patients / 1234”以返回一个JSON对象,如:

[{
   "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)? 它可以用两个来完成(一个在Patient表上,另一个在Insurance表上)? 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 更新 - 2014年4月29日

Here's where I'm at...In the "Patient" POCO, I have added the following: 这就是我所处的位置......在“患者”POCO中,我添加了以下内容:

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. 我在保险中使用嵌套项目获得了不错的JSON,同时在数据库中维护了单独的相关表。

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. 也就是说,我不能使用相同的嵌套对象同时自动插入/更新Patient和InsurancePolicy表。 If I remove the "[Ignore]" decorator, I get a field in the Patient table called "Insurances" of type varchar(max). 如果我删除“[Ignore]”装饰器,我会在Patient表中获得一个名为varchar(max)类型的“Insurances”的字段。 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? 我想我需要为我的PUT / POST方法编写一些额外的代码来从JSON中提取“Insurances”节点,迭代它,并使用每个Insurance对象来更新数据库? 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? 是Mythz吗? :-) Thanks... :-) 谢谢...

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: 然后,我可以使用嵌套的“Insurance”数组获取JSON请求,如下所示:

{
   "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. 我获得了新的患者记录,加上保险表中的2条新记录,正确的外键引用回到刚刚创建的PatientId。 This is amazing! 这真太了不起了!

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);
}

First you should define a foreign collection in Patient class. 首先,您应该在Patient类中定义外部集合。 (with get and set methods) (使用get和set方法)

@ForeignCollectionField
private Collection<Insurance> insurances;

When you query for a patient, you can get its insurances by calling getInsurances method. 当您查询患者时,您可以通过调用getInsurances方法获得保险。

To convert all into a single json object with arrays inside you can use a json processor. 要将all转换为包含数组的单个json对象,可以使用json处理器。 I use Jackson ( https://github.com/FasterXML/jackson ) and it works very well. 我使用Jackson( https://github.com/FasterXML/jackson )并且效果很好。 Below will give you json object as a string. 下面将以json对象的形式给出一个字符串。

new ObjectMapper().writeValueAsString(patientObject);

To correctly map foreign fields you should define jackson references. 要正确映射外部字段,您应该定义jackson引用。 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. 更新:您可以使用Jackson从json字符串生成对象,然后迭代并更新/创建数据库行。

objectMapper.readValue(jsonString, Patient.class);

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM