Добавьте столбец в таблицы с именем «метаданные» и вставьте в него XML. Сервер SQL позволяет вам смотреть на блоб, полный XML, как на дополнительные столбцы (с ограничениями).
Для ORM это зависит от того, как структурирован ваш объект.
- Бесконечно настраиваемые элементы метаданных: вы помещаете пары имя-значение из XML в коллекцию. Если ваш ORM не разрешит этого, поместите его прямо в строковое свойство, установщик может проанализировать его в XML-документе (или более быстром объекте, если вам нужна скорость). Геттер вернет строку. Затем отдельное свойство MetaDataItem (ItemName-> string), которое не является ORM, будет считывать значения из списка метаданных и обновлять / добавлять их с помощью своего установщика.
- Метадета - это жестко закодированные свойства - сопоставьте их с помощью запроса, извлекающего их из XML.
- Гибрид двух из них - жестко закодированные свойства для некоторых элементов - имеют свои методы установки / получения, вызывающие MetaDataItem.
- Обратный гибрид, если определенные свойства должны храниться напрямую (особенно если вы сортируете по ним большие списки): вам нужно жестко закодировать свойства для этих метаданных с их собственными закрытыми членами, но не ORM эти свойства. Жестко запрограммировали сохранение / загрузку этих значений в строковое свойство ORM'd, и, если вы хотите иметь возможность обновлять эти жестко закодированные элементы метаданных из свойства MetaDataItem, также жестко закодируйте их в этом месте!
Если у вас есть целый набор жестко закодированных свойств метаданных, в дополнение к бесконечному количеству, вы можете упростить использование свойства XML и свойства MetaDataItem со списками и отражениями. Если все они жестко закодированы, вы все равно можете использовать текстовое свойство XML для их загрузки / сохранения, сопоставить одно свойство, а не другие.
Сортируйте их с помощью запроса LINQ к объекту.
Я делал это с большим успехом, и с каждой закодированной пулей все работало все лучше и лучше! 2005 / .Net 1.1, поэтому нет ORM, LINQ, моей первой программы VB.net и т. Д. Но другие разработчики использовали SQL-запросы SQL-сервера для чтения моего XML. Конечно, я забыл об этом, изменил и споткнулся: - (
Вот фрагменты. Ключом всего этого является: ORM friendly = ORM одни свойства, а не другие; Разрешите потребителям использовать другие свойства, но не некоторые. Если ваш ORM не позволяет такой выбор свойств по выбору, вы можете использовать наследование или композицию, чтобы обмануть его. Извините, у меня нет времени выложить полный пример для вашей цели.
Ну, у меня нет примера кода здесь, дома. Я буду редактировать и вставлять его завтра.
РЕДАКТИРОВАТЬ как и было обещано, вот фрагмент кода:
Public Property ItemType(ByVal stTagName As String) As String
Get
Dim obj As Object
obj = Me.lstMemberList.Item(stTagName)
If Not obj Is Nothing Then
Return CType(obj, foDataItem).Type
End If
End Get
Set(ByVal Value As String)
Dim obj As Object
obj = Me.lstMemberList.Item(stTagName)
If Not obj Is Nothing Then
CType(obj, foDataItem).Type = Value
End If
End Set
End Property
Public Function ItemExists(ByVal stTagName As String) As Boolean
Return Me.lstMemberList.ContainsKey(stTagName)
End Function
Public Property ItemValue(ByVal stTagName As String, Optional ByVal Type4NewItem As String = "") As String
Get
Dim obj As Object
obj = Me.lstMemberList.Item(stTagName)
If obj Is Nothing Then
Dim stInternalKey As String = ""
Try
stInternalKey = Me.InternalKey.ToString
Catch
End Try
If stTagName <> "InternalKey" Then '' // avoid deadlock if internalkey errs!
Throw New ApplicationException("Tag '" & stTagName & _
"' does not exist in FO w/ internal key of " & stInternalKey)
End If
Else
Return CType(obj, foDataItem).Value
End If
End Get
Set(ByVal Value As String)
'' // if child variation form...
If bLocked4ChildVariation Then
'' // protect properties not in the list of allowed updatable items
If Not Me.GetChildVariationDifferentFields.Contains(stTagName) Then
Exit Property
End If
End If
'' // WARNING - DON'T FORGET TO UPDATE THIS LIST OR YOU WILL NEVER FIND THE BUG!
Select Case stTagName
Case "PageNum"
_PageNum = CInt(Value)
Case "Left"
_Left = CInt(Value)
Case "Top"
_Top = CInt(Value)
Case "Width"
_Width = CInt(Value)
Case "Height"
_Height = CInt(Value)
Case "Type"
_Type = String2Type(Value)
Case "InternalKey"
_InternalKey = CInt(Value)
Case "UniqueID"
_UniqueID = Value
End Select
Static MyError As frmErrorMessage
Dim obj As Object
If Me.lstMemberList.ContainsKey(stTagName) Then
Dim foi As foDataItem = CType(Me.lstMemberList.Item(stTagName), foDataItem)
If foi.Type = "Number" Then
Value = CStr(Val(Value))
End If
If foi.Value <> Value Then
If bMonitorRefreshChanges Then
LogObject.LoggIt("Gonna Send Update for Change " & stTagName & " from " & _
foi.Value & " to " & Value)
If Not Me.FormObjectChanged_Address Is Nothing Then
FormObjectChanged_Address(Me, stTagName)
End If
End If
End If
foi.Value = Value
Else
Me.lstMemberList.Add(stTagName, New foDataItem(Value, Type4NewItem))
Me.alOrderAdded.Add(stTagName)
End If
End Set
End Property
Public Function StringVal(ByVal st As String, Optional ByVal stDefault As String = "") As String
Try
StringVal = stDefault
Return CType(Me.ItemValue(st), String)
Catch ex As Exception
Dim bThrowError As Boolean = True
RaiseEvent ConversionError(ex, "String=" & Me.ItemValue(st), Me, st, bThrowError)
If bThrowError Then
LogObject.LoggIt("Error setting tag value in fo.StringVal: " & st)
Throw New Exception("Rethrown Exception getting value of " & Me.ID & "." & st, ex)
End If
End Try
End Function
Public Function IntVal(ByVal st As String, Optional ByVal iDefault As Integer = 0) As Integer
...
'' // 'native' values - are normal properties instead of XML properties, which
'' // actually makes it harder to deal with b/c of extra updates to sync them, BUT,
'' // worth it - as they are read much more than written (sorts, wizard builds,
'' // screen redraws, etc) I can afford to be slow when writing to them, PLUS
'' // retain the benefits of referencing everything else via ItemValue, PLUS
'' // these are just the more 'popular' items.
Private _Top As Integer
Private _Left As Integer
Private _Width As Integer
Private _Height As Integer
Private _PageNum As Integer
Private _Type As pfoType
Private _InternalKey As Integer
Private _UniqueID As String
Public Sub SetNativeValuesFromMyXML()
_Top = CInt(CType(Me.lstMemberList("Top"), foDataItem).Value)
_Left = CInt(CType(Me.lstMemberList("Left"), foDataItem).Value)
_Width = CInt(CType(Me.lstMemberList("Width"), foDataItem).Value)
_Height = CInt(CType(Me.lstMemberList("Height"), foDataItem).Value)
_PageNum = CInt(CType(Me.lstMemberList("PageNum"), foDataItem).Value)
_Type = String2Type(CType(Me.lstMemberList("Type"), foDataItem).Value)
_InternalKey = CInt(CType(Me.lstMemberList("InternalKey"), foDataItem).Value)
_UniqueID = CType(Me.lstMemberList("UniqueID"), foDataItem).Value
End Sub
Public Property Top() As Integer
Get
Return _Top '' // CInt(ItemValue("Top"))
End Get
Set(ByVal Value As Integer)
ItemValue("Top") = Value.ToString
End Set
End Property
Public Property Left() As Integer
Get
Return _Left '' //CInt(ItemValue("Left"))
End Get
...