На самом деле, мы занимаемся тем, чем занимается любой ORM (Object-Relation Mapper...)
Неплохо некоторые идеи описаны у Усова (
http://alexus.ru/russian/articles/dbms/oop_rm/index.htm).
Контекст проекта: небольшой заказ на сбор данных с трёх медицинских анализаторов.
Делают мои студенты, архитектуру-каркас, естественно, пришлось с ними вместе выстроить.
Проектировалась не реляционная БД, проектировалась объектная модель - и ровно нужные функции хранения и выборки объектов. А потом уже это проецировалось на реляционку (а можно без изменения приложения реализовать на чём угодно). Я бы охотнее взял NoSQL - Mongo ту же самую (у нас она применяется, но не из ББ). Но ввиду отсутствия драйвера....
Если интересно, выглядит примерно так модель и хранение.
Это объектная модель:
Код:
DEFINITION HemoData;
IMPORT Dates;
CONST
maxParamCount = 64;
TYPE
PersonalCode = ARRAY 64 OF SHORTCHAR;
DateTime = RECORD
date: Dates.Date;
time: Dates.Time
END;
Result = POINTER TO LIMITED RECORD (* Result почти неизменен, создаётся и "накачивается" данными однократно - при получении с анализатора, потом отправляется в базу. После считывания из базы возможно только одно изменение - FixPersonalCode. *)
readOnly-: BOOLEAN;
dbCode-: INTEGER;
personalCode-: PersonalCode;
analyzerType-: INTEGER;
analyzeTime-, registerTime-: DateTime;
values-: Value;
(r: Result) AddInt (param, x: INTEGER), NEW;
(r: Result) AddReal (param: INTEGER; x: REAL), NEW;
(r: Result) AddString (param: INTEGER; IN s: ARRAY OF CHAR), NEW;
(r: Result) Lock, NEW; (* Переводит объект в режим readOnly, после добавления всех параметров *)
(r: Result) FixPersonalCode (IN newCode: ARRAY OF SHORTCHAR), NEW; (* Единственная операция, изменяющая уже существующий в базе результат *)
(r: Result) Param (param: INTEGER): Value, NEW
END;
Value = POINTER TO ABSTRACT RECORD
next-: Value;
param-: INTEGER
END;
IntValue = POINTER TO LIMITED RECORD (Value)
x-: INTEGER
END;
RealValue = POINTER TO LIMITED RECORD (Value)
x-: REAL
END;
StringValue = POINTER TO LIMITED RECORD (Value)
x-: POINTER TO ARRAY OF CHAR
END;
VAR
nullTime-: DateTime;
PROCEDURE NewResult (dbCode: INTEGER; IN personalCode: ARRAY OF SHORTCHAR; analyzerType: INTEGER; IN analyzeTime, registerTime: DateTime): Result;
END HemoData.
А это хранилище:
Код:
DEFINITION HemoDB;
IMPORT HemoData, Dates, HemoCollections;
CONST
compareAnalyzeDate = 2; compareAnalyzerType = 1; comparePersonalCode = 0; compareRegisterDate = 3;
TYPE
Criteria = RECORD
compare: SET;
personalCode: HemoData.PersonalCode;
analyzerType: INTEGER;
analyzeDates, registerDates: RECORD
from, to: Dates.Date
END
END;
VAR
connected-: BOOLEAN;
PROCEDURE Connect;
PROCEDURE Close;
PROCEDURE RegisterResults (results: HemoCollections.Collection);
PROCEDURE UpdatePersonalCodes (results: HemoCollections.Collection);
PROCEDURE Select (IN criteria: Criteria): HemoCollections.Collection;
END HemoDB.
База имеет следующий вид:
Код:
CREATE TABLE results (
id INT UNSIGNED AUTO_INCREMENT PRIMARY KEY NOT NULL,
personalCode VARCHAR(255) NOT NULL,
analyzerType INT UNSIGNED NOT NULL,
analyzeDate DATE NOT NULL,
analyzeTime TIME NOT NULL,
registerDate DATE NOT NULL,
registerTime TIME NOT NULL
);
CREATE TABLE real_values (
result_id INT UNSIGNED NOT NULL,
param INT UNSIGNED NOT NULL,
value REAL NOT NULL,
FOREIGN KEY (result_id) REFERENCES results(id),
UNIQUE(result_id, param)
);
CREATE TABLE string_values (
result_id INT UNSIGNED NOT NULL,
param INT UNSIGNED NOT NULL,
value VARCHAR(255) NOT NULL,
FOREIGN KEY (result_id) REFERENCES results(id),
UNIQUE(result_id, param)
);
CREATE TABLE int_values (
result_id INT UNSIGNED NOT NULL,
param INT UNSIGNED NOT NULL ,
value INT UNSIGNED NOT NULL,
FOREIGN KEY (result_id) REFERENCES results(id),
UNIQUE(result_id, param)
);
Плюс, конечно, индексы.
Таким образом, при реализации на базе SQL RegisterResults продуцирует последовательность INSERT INTO results ...; INSERT INTO xx_values VALUES (LAST_INSERT_ID()).........
Select продуцирует UNION SELECT следующего вида (где условие WHERE приходится трижды помещать в каждый SELECT):
Код:
SELECT id, personalCode, analyzerType, analyzeDate, analyzeTime, registerDate, registerTime, param, 1 AS param_type, value AS int_value, NULL AS real_value, NULL AS string_value FROM results, int_values WHERE result_id = id " + where +
"UNION SELECT id, personalCode, analyzerType, analyzeDate, analyzeTime, registerDate, registerTime, param, 2 AS param_type, NULL AS int_value, NULL AS real_value, value AS string_value FROM results, string_values WHERE result_id = id " + where +
"UNION SELECT id, personalCode, analyzerType, registerDate, registerTime, registerDate, registerTime, param, 3 AS param_type, NULL AS int_value, value AS real_value, NULL AS string_value FROM results, real_values WHERE result_id = id ORDER BY id";