У меня есть приложение управления списком, которое хранит его данные в many-many базе данных отношений.
Т.Е. примечание может быть в любом количестве списков, и список может иметь любое количество примечаний.
Я также могу экспортировать эти данные в и XML-файл и импортировать его в другом экземпляре моего приложения для совместного использования списков между пользователями. Однако это основано на унаследованной системе, где список для замечания отношений был one-many (идеал для XML).
Теперь примечание, которое находится в нескольких списках, по существу разделяется на две идентичных строки в DB, и все отношение между ними потеряно.
Вопрос: Как я могу представить эти many-many отношения в простом, стандартном формате файла? (Предпочтительно XML для поддержания назад совместимости)
Я думаю, что ваш формат XML должен использовать что-то вроде "ссылок". Если вы предпочитаете, чтобы связь между списками и заметками была видимой, то может подойти что-то вроде следующего:
<notes>
<note id="Note1"> ... </note>
<note id="Note2"> ... </note>
...
</notes>
<lists>
<list id="List1">
<note_refs>
<note_ref id="Note1"/>
<note_ref id="Note4"/>
</note_refs>
</list>
...
</lists>
Если, с другой стороны, вы хотите легко видеть списки, связанные с данной заметкой, то вы можете просто перевернуть роли списков и заметок в моем примере.
В качестве альтернативы, вы можете представить отношение "многие-ко-многим" более симметрично, как математическое отношение: определить все заметки, определить все списки, а затем определить отображение, состоящее из пар [ссылка на список, ссылка на заметку].
Моим первым шагом было бы что-нибудь простое:
<notes>
<note>
<title>Groceries to get</title>
<list>shopping</list>
<list>urgent</list>
<body>eggs, cheese, milk</body>
</note>
</notes>
Подойдет ли это для ваших нужд?
Единственный способ, который я могу придумать, чтобы действительно представить отношения "многие-ко-многим" в XML или любой другой иерархической структуре, - это использовать множество отношений "один-ко-многим".
Вот простой пример:
<list name="listA">
<notes name="noteA" />
<notes name="noteB" />
<notes name="noteC" />
</list>
<list name="listB">
<notes name="noteB" />
<notes name="noteC" />
<notes name="noteD" />
</list>
Другими словами, каждый список будет иметь свои заметки в качестве дочерних узлов.
Многие дочерние узлы заметок будут дублироваться в XML-файле. Процесс, который заполняет базу данных из XML-файла, должен будет учитывать дубликаты дочерних узлов заметок.
Другая альтернатива - выбрать один список для каждой заметки. Заметка будет дочерним узлом только одного из списков. Преимуществом является отсутствие дубликатов заметок. Недостатком является то, что XML-файл не представляет отношения между заметками и списками должным образом, что может быть важно или не важно.
В базе данных инструментом для представления отношений «многие ко многим» является таблица ассоциаций. Каждая строка в таблице представляет связь между двумя объектами. Таким образом, если заметка с идентификатором 1 появляется в списках с идентификаторами 1, 2 и 3, в таблице ассоциации будет три строки:
ID NoteID ListID
-- ------ ------
1 1 1
2 1 2
3 1 3
Вы можете получить заметку и все связанные с ней списки с помощью запроса типа это:
SELECT [columns] FROM Association
JOIN Notes ON Note.ID = Association.NoteID
JOIN Lists ON List.ID = Association.ListID
WHERE Association.NoteID = @NoteID
И все примечания к списку:
SELECT [columns] FROM Association
JOIN Notes ON Note.ID = Association.NoteID
JOIN Lists ON List.ID = Association.ListID
WHERE Association.ListID = @ListID
Вот как вы представляете его в XML:
<Lists>
<List ID='1'>...</List>
<List ID='2'>...</List>
<List ID='3'>...</List>
...
<Lists>
<Notes>
<Note ID='1'>...</Note>
</Notes>
<Associations>
<Association ID='1' NoteID='1' ListID='1'/>
<Association ID='2' NoteID='1' ListID='2'/>
<Association ID='3' NoteID='1' ListID='3'/>
</Associations>
В XSLT вы можете получить доступ к этой ассоциации следующим образом:
<xsl:template match="List" mode="AssociatedNotes">
<xsl:variable name="Associations" select="/*/Associations/Association[@ListID=current()/@ID]"/>
<xsl:apply-templates select="/*/Notes[@ID=$Associations/@NoteID]"/>
</xsl:template>
<xsl:template match="Note" mode="AssociatedLists">
<xsl:variable name="Associations" select="/*/Associations/Association[@NoteID=current()/@ID]"/>
<xsl:apply-templates select="/*/Lists[@ID=$Associations/@ListID]"/>
</xsl:template>
(Обратите внимание на использование атрибут режима
, чтобы эти шаблоны не вызывали друг друга, пока не произойдет переполнение стека.)