Свойства кода карты Entity Framework для столбцов базы данных (CSpace-SSpace)

Я пытаюсь реализовать атрибут, который я могу применить к свойствам в моей первой модели данных Entity Framework кода, чтобы указать уникальные ограничения, которые будут применяться при создании базы данных. Я читал об извлечении информации сопоставления таблицы EF, используя API-интерфейс отображения, открытый для EF 6.1, и у меня прочитайте о реализации настраиваемого атрибута, чтобы указать, какие свойства представляют собой естественный ключ. Но, если я не ошибаюсь в коде, я думаю, что это будет работать только тогда, когда имя свойства CLR (OSpace/CSpace) соответствует имени столбца SQL (SSpace). Я хотел бы иметь возможность включать свойства ассоциации (внешние ключи) в свой уникальный ключ, например EnumList, в этом примере:

Public Class EnumValue
   Public Property EnumValueId As Integer
   Public Property Sequence As Integer
   Public Overridable Property Label As TranslatedString
   <MaxLength(5), MyUnique()> _
   Public Property Value As String
   <MyUnique()> _
   Public Overridable Property EnumList As EnumList
End Class

Я начал с этого большого кода, который был основан на связанной статье о именах таблиц сопоставления

Dim ws = DirectCast(context, System.Data.Entity.Infrastructure.IObjectContextAdapter).ObjectContext.MetadataWorkspace
Dim oSpace = ws.GetItemCollection(Core.Metadata.Edm.DataSpace.OSpace)
Dim entityTypes = oSpace.GetItems(Of EntityType)()
Dim entityContainer = ws.GetItems(Of EntityContainer)(DataSpace.CSpace).Single()
Dim mapping = ws.GetItems(Of EntityContainerMapping)(DataSpace.CSSpace).Single.EntitySetMappings
For Each setType In entityTypes
   Dim cSpaceEntitySet = entityContainer.EntitySets.Single(Function(t) t.ElementType.Name = setType.Name)
   Dim sSpaceEntitySet = mapping.Single(Function(t) t.EntitySet Is cSpaceEntitySet)
   Dim tableInfo = sSpaceEntitySet.EntityTypeMappings.Single.Fragments.Single
   Dim tableName = If(tableInfo.StoreEntitySet.Table, tableInfo.StoreEntitySet.Name)
   Dim schema = tableInfo.StoreEntitySet.Schema

И этого достаточно, чтобы получить необходимую информацию о имени таблицы, но теперь мне нужно каким-то образом связать имя свойства CLR с именем столбца SQL и медленно отслеживать структуру метаданных EF. Я надеюсь, что кто-то более знакомый с этим может ускорить процесс.

Ответ 1

Я не уверен, что он завершен или надежный, но я, наконец, разработал код, который работает для моего первого тестового примера:

Dim ws = DirectCast(context, System.Data.Entity.Infrastructure.IObjectContextAdapter).ObjectContext.MetadataWorkspace
Dim oSpace = ws.GetItemCollection(Core.Metadata.Edm.DataSpace.OSpace)
Dim entityTypes = oSpace.GetItems(Of EntityType)()
Dim entityContainer = ws.GetItems(Of EntityContainer)(DataSpace.CSpace).Single()
Dim entityMapping = ws.GetItems(Of EntityContainerMapping)(DataSpace.CSSpace).Single.EntitySetMappings
Dim associations = ws.GetItems(Of EntityContainerMapping)(DataSpace.CSSpace).Single.AssociationSetMappings
For Each setType In entityTypes
   Dim cSpaceEntitySet = entityContainer.EntitySets.SingleOrDefault( _
      Function(t) t.ElementType.Name = setType.Name)
   If cSpaceEntitySet Is Nothing Then Continue For ' Derived entities will be skipped
   Dim sSpaceEntitySet = entityMapping.Single(Function(t) t.EntitySet Is cSpaceEntitySet)
   Dim tableInfo As MappingFragment
   If sSpaceEntitySet.EntityTypeMappings.Count = 1 Then
      tableInfo = sSpaceEntitySet.EntityTypeMappings.Single.Fragments.Single
   Else
      ' Select only the mapping (esp. PropertyMappings) for the base class
      tableInfo = sSpaceEntitySet.EntityTypeMappings.Where(Function(m) m.IsOfEntityTypes.Count _
         = 1 AndAlso m.IsOfEntityTypes.Single.Name Is setType.Name).Single().Fragments.Single
   End If
   Dim tableName = If(tableInfo.StoreEntitySet.Table, tableInfo.StoreEntitySet.Name)
   Dim schema = tableInfo.StoreEntitySet.Schema
   Dim clrType = Type.GetType(setType.FullName)
   Dim uniqueCols As IList(Of String) = Nothing
   For Each propMap In tableInfo.PropertyMappings.OfType(Of ScalarPropertyMapping)()
      Dim clrProp = clrType.GetProperty(propMap.Property.Name)
      If Attribute.GetCustomAttribute(clrProp, GetType(UniqueAttribute)) IsNot Nothing Then
         If uniqueCols Is Nothing Then uniqueCols = New List(Of String)
         uniqueCols.Add(propMap.Column.Name)
      End If
   Next
   For Each navProp In setType.NavigationProperties
      Dim clrProp = clrType.GetProperty(navProp.Name)
      If Attribute.GetCustomAttribute(clrProp, GetType(UniqueAttribute)) IsNot Nothing Then
         Dim assocMap = associations.SingleOrDefault(Function(a) _
            a.AssociationSet.ElementType.FullName = navProp.RelationshipType.FullName)
         Dim sProp = assocMap.Conditions.Single
         If uniqueCols Is Nothing Then uniqueCols = New List(Of String)
         uniqueCols.Add(sProp.Column.Name)
      End If
   Next
   If uniqueCols IsNot Nothing Then
      Dim propList = uniqueCols.ToArray()
      context.Database.ExecuteSqlCommand("CREATE UNIQUE INDEX IX_" & tableName & "_" & String.Join("_", propList) _
         & " ON " & schema & "." & tableName & "(" & String.Join(",", propList) & ")")
   End If
Next