【问题标题】:One-to-Many relationship with ORMLite与 ORMLite 的一对多关系
【发布时间】:2014-04-28 13:23:15
【问题描述】:

我能找到解决这种情况的唯一例子已经很老了,我想知道用最新版本的 ORMLite 来做这件事的最好方法是什么......

假设我有两个表(简化):

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

患者可以在不同“级别”(主要、次要等)拥有多个保险单。我理解将保险信息作为字典类型对象并将其直接添加到 [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; }
}

...但我需要将保险信息作为单独的表格存在于数据库中,以供以后报告时使用。

我知道我可以在 ORMLite 中加入这些表,或者在 SQL 中创建一个加入的视图/存储过程来返回数据,但它显然会为同一个患者返回多行。

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"

如何将其映射到单个 JSON 响应对象中?

我希望能够将 GET 请求映射到“/patients/1234”以返回 JSON 对象,例如:

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

我不希望在单个查询中实现这一点。可以分两次完成吗(一个在 Patient 表上,另一个在 Insurance 表上)?如何以这种嵌套方式将每个查询的结果添加到同一个响应对象中?

非常感谢您对此提供的任何帮助!

更新 - 2014 年 4 月 29 日

这就是我所在的位置...在“患者”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
}

然后,当我想返回一个拥有多项保险的患者时,我会执行两个查询:

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;

这行得通!在数据库中维护单独的相关表时,我得到了带有嵌套项目的漂亮 JSON。

我不喜欢的是这个对象不能来回传递给数据库。也就是说,我不能使用同一个嵌套对象同时自动插入/更新 Patient 和 InsurancePolicy 表。如果我删除“[Ignore]”装饰器,我会在 Patient 表中获得一个名为“Insurances”的字段,类型为 varchar(max)。不好,对吧?

我想我需要为我的 PUT/POST 方法编写一些额外的代码来从 JSON 中提取“保险”节点,对其进行迭代,并使用每个保险对象来更新数据库?我只是希望我不会在这里重新发明轮子或做太多不必要的工作。

评论仍将不胜感激!神话开启了吗? :-) 谢谢...

【问题讨论】:

    标签: sql json ormlite ormlite-servicestack


    【解决方案1】:

    另一个更简洁的例子:

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

    【讨论】:

    • 这太棒了!谢谢神话。非常感谢您的工作和投入。
    【解决方案2】:

    参考在这里拯救世界!

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

    然后我可以使用这样的嵌套“保险”数组接受 JSON 请求:

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

    ...创建一个新记录并像这样保存它:

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

    宾果!我得到了新的 Patient 记录,以及 Insurance 表中的 2 条新记录,其中包含正确的外键引用,返回到刚刚创建的 PatientId。这太棒了!

    【讨论】:

      【解决方案3】:

      首先你应该在 Patient 类中定义一个外部集合。 (使用 get 和 set 方法)

      @ForeignCollectionField
      private Collection<Insurance> insurances;
      

      当您查询患者时,您可以通过调用 getInsurances 方法获取其保险。

      要将所有内容转换为包含数组的单个 json 对象,您可以使用 json 处理器。我使用 Jackson (https://github.com/FasterXML/jackson),效果很好。下面将为您提供 json 对象作为字符串。

      new ObjectMapper().writeValueAsString(patientObject);
      

      要正确映射外部字段,您应该定义杰克逊引用。在您的患者类中添加托管引用。

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

      在您的保险类别中添加反向引用。

      @JsonBackReference("InsurancePatient")
      private Patient patient;
      

      更新: 您可以使用 Jackson 从 json 字符串生成对象,然后迭代和更新/创建数据库行。

      objectMapper.readValue(jsonString, Patient.class);
      

      【讨论】:

      • 有趣...我使用 C#.NET 作为后端,所以 Jackson 不能工作(仅限 Java)?你对 .NET 有什么建议吗?我会调查一下 ForeignCollectionField...谢谢。
      • Dang...@ForeignCollectionField 看起来正是我所需要的,但我不知道如何在 Java 之外使用它?有什么指点吗?
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2013-06-30
      • 1970-01-01
      • 2013-08-20
      • 2018-03-16
      • 2012-06-14
      • 2011-06-22
      • 2018-11-02
      相关资源
      最近更新 更多