将面向对象的数据直接编码到关系数据库中的单行中被认为是不好的形式吗


Is it considered bad form to encode object-oriented data directly into single rows in a relational database?

我对数据库还比较陌生,所以如果有明显的方法可以解决这个问题,或者我缺少一些基本的过程,我很抱歉。我在一个涉及患者医疗记录的web应用程序中使用PHP和MySQL。一个要求是用户能够从网页上查看和编辑医疗记录。

正如我所设想的,单个Patient对象具有基本属性,如idnameaddress,然后每个Patient还具有Medication对象(med_name, dose, reason)、Condition对象(cond_name, date, notes)和其他此类对象(过敏、家族史等)的阵列

  • 患者(身份证、姓名、地址…)
  • 药物(patient_id、med_name、剂量、原因)
  • 条件(patient_id、cond_name、日期、注释)

然而,这对我来说似乎是错误的。添加新的药物或条件很容易,但删除或编辑现有的药物或情况似乎效率低得离谱——比如说,我必须在medications表中搜索一行,该行将patient_id与旧的med_namedosereason字段相匹配,然后用新数据删除/编辑它。我可以在medicationsconditions表中添加一些主键,以便更有效地查找要编辑的行,但这看起来像是一段任意的数据。

那么,如果我只有一个具有以下模式的表呢

  • 患者(id、姓名、地址、药物、conds…)

其中medscondsMedicationCondition对象的数组的简单表示(例如二进制)?PHP可以解释这些数据,并根据需要在数据库中获取和更新这些数据。

欢迎对这里的最佳实践有任何想法。我也在考虑改用RubyonRails,所以如果这影响了我应该做出的任何决定,我也很想听听。非常感谢各位。

这样编码数据的"好坏"取决于您的需求。如果NEVER需要引用那些"meds"answers"conds"表中的单个较小数据块,那么就没有问题。

然而,您实际上是在将数据库简化为一个比愚蠢的存储系统稍微智能一点的存储系统,并失去了SQL数据库中"关系"部分的好处。

例如,如果你需要运行一个查询"查找所有服用伟哥并患有心脏病的患者",那么DBMS将无法直接运行该查询,因为它不知道你是如何在这两个字段中"隐藏"伟哥/心脏病数据的,而如果有一个适当规范的数据库,你会有:

SELECT ...
FROM patients
LEFT JOIN conditions ON patients.id = conditions.patient_id
LEFT JOIN meds ON patients.id = meds.patient_id
WHERE (meds.name = 'Viagra') AND (condition.name = 'Heart Disease')

并且DBMS自动地处理一切。如果你把所有的东西都编码到一个字段中,那么你就会陷入子字符串操作的困境(假设数据是可读的ascii格式),或者更糟的是,你必须把整个数据库拖到你的客户端应用程序中,解码每个字段,检查其内容,然后扔掉所有不含伟哥或心脏病的东西——效率很低。

这打破了第一个范式。你永远不能用这种方式查询对象属性。

如果您有对象,我建议您使用ORM解决方案,或者使用对象数据库。

比如说,我必须在药物表中搜索一排将patient_id与旧的med_name、dose和reason字段进行匹配,然后用新数据删除/编辑它。

假设密钥是{patient_id,med_name,start_date},那么您只需要进行一次更新。没有搜索。

update medications
set reason = 'Your newly edited reason, for example.'
where patient_id = ?
  and med_name = ?
  and start_date = ?

您的应用程序将已经知道患者id、医疗名称和开始日期,因为用户必须以某种方式"选择"他们所在的行,才能做出任何更改。

如果你要改变剂量,你需要两个改变,一个更新和一个插入,才能有意义。

update medications
set stop_date = '2012-01-12'
where patient_id = ?
  and med_name = ?
  and start_date = ?
-- I'm using fake data in this one.
insert into medications (patient_id, med_name, start_date, stop_date, dosage)
values (1, 'that same med', '2012-01-12', '2012-01-22', '40mg bid')