2015-12-31 2 views
1

Мы используем последнюю версию IdeaBlade 2012 в нашем проекте, в нашей вспомогательной функции, она показывает «имя таблицы». «Имя поля», и пользователь может добавлять комментарии и сохранять их в одной таблице. В EF он может получить dbContext.MetadataWorkspace для получения метаданных в edmx, но как мы можем получить его в EntityManager?Как получить имя таблицы/поля в IdeaBlade 2012?

+0

EntityManager не имеет доступа к именам таблиц и столбцов базы данных, поскольку он работает только с «концептуальным» уровнем модели. Однако у вас есть несколько вариантов, если вы хотите сделать это в DevForce. Один из них заключается в настройке шаблона генерации кода для включения этой информации в вашу сгенерированную модель в качестве, возможно, настраиваемых свойств или атрибутов. Другой - построить DbContext самостоятельно в DF-серверном коде, таком как перехватчик сохранения. –

+0

Спасибо! Вариант № 1 работает. –

+0

Есть некоторая информация о Центре ресурсов DevForce, чтобы начать работу - http://drc.ideablade.com/devforce-2012/bin/view/Documentation/custom-code-generation-template. Если вам нужно больше, вы можете открыть запрос поддержки через веб-сайт IdeaBlade. –

ответ

0

Как упоминал Ким Джонсон в своем комментарии, настройка генерации кода может работать очень хорошо для этого. Мы сделали это в нашем приложении, чтобы добавить дополнительные комментарии к каждому объекту и полю, содержащему имя таблицы/столбца. Это помогает разработчикам C#, поскольку мы иногда переименовываем объекты/свойства и пытаемся отобразить их обратно на бэкэнд, может быть сложно.

Однако в последнее время нам нужны еще данные из модели EF и приступили к анализу XML EDMX напрямую. Это дает нам всю необходимую информацию. Он даже коррелировал данные EDMX с метаданными DevForce и даже данными отражения.

Вот полный код для любого заинтересованного. Это много кода, но, надеюсь, легко следовать. И это, вероятно, делает больше, чем нужно большинству людей.

/// <summary> 
/// Helper class for parsing the EDMX model, looking up DevForce metadata as well as C# reflection data and then combining it all 
/// into organized data structures. 
/// </summary> 
public static class ModelDataExtractor 
{ 
    /// <summary> 
    /// Information about a property/column from an EDMX. 
    /// </summary> 
    public class EdmxColumnInfo 
    { 
     public string TableName { get; set; } 
     public string ColumnName { get; set; } 
     public string SqlType { get; set; } 
     public bool? Nullable { get; set; } 
     public int? MaxLength { get; set; } 
     public bool? FixedLength { get; set; } 
     public bool? IsUnicode { get; set; } 
    } 

    /// <summary> 
    /// Collection of information about a property. 
    /// </summary> 
    public class ExtraPropertyInfo 
    { 
     public PropertyInfo CSharpProperty { get; set; } 
     public EntityProperty DevForceProperty { get; set; } 
     public EdmxColumnInfo EdmxData { get; set; } 
     public string TypeHierarchy { get; set; } 
    } 

    /// <summary> 
    /// Extracts the data from the EDMX's embeded in the Business assembly. 
    /// </summary> 
    public static List<ExtraPropertyInfo> ExtractData() 
    { 
     var assembly = typeof(MyFavoriteEntity).Assembly; 
     var all = from name in assembly.GetManifestResourceNames() 
        where name.EndsWith(".csdl") || name.EndsWith(".msl") || name.EndsWith(".ssdl") 
        let xml = XElement.Load(assembly.GetManifestResourceStream(name)) 
        select new EdmxFragment(name.Replace(".csdl", "").Replace(".msl", "").Replace(".ssdl", ""), xml); 

     return ExtractData(all.ToList()); 
    } 

    /// <summary> 
    /// Extracts the data from the EDMX's in the given directory 
    /// </summary> 
    public static List<ExtraPropertyInfo> ExtractData(string dataModelPath) 
    { 
     return ExtractData(
      Directory.GetFiles(dataModelPath, "*.edmx") 
       .Select(fileName => new EdmxFragment(fileName, XElement.Load(fileName))) 
       .ToList()); 
    } 

    /// <summary> 
    /// Provides the ability for multiple XElements to be treated as multiple fragments of the same logical EDMX. 
    /// </summary> 
    private class EdmxFragment 
    { 
     public EdmxFragment(string edmxName, XElement documentRoot) 
     { 
      EdmxName = edmxName; 
      DocumentRoot = documentRoot; 
     } 

     public string EdmxName { get; private set; } 
     public XElement DocumentRoot { get; private set; } 
    } 

    private static List<ExtraPropertyInfo> ExtractData(IList<EdmxFragment> edmxFragments) 
    { 
     //If we aren't given any fragments...well, nothing to do really 
     if (edmxFragments.Count == 0) 
     { 
      return new List<ExtraPropertyInfo>(); 
     } 

     //Derive the correct namespaces to use 
     var ns = EdmxNamespaceHelper.DeriveNamespaces(edmxFragments[0].DocumentRoot); 

     //First extract data out of the EDMXs 'sections' 

     //Parse the SSDL data for each XML document 
     var storageTypes = from fragment in edmxFragments 
          from entityType in fragment.DocumentRoot.Descendants(XName.Get("EntityType", ns.Ssdl)) 
          from prop in entityType.Elements(XName.Get("Property", ns.Ssdl)) 
          select new 
          { 
           TableName = entityType.GetString("Name"), 
           ColumnName = prop.GetString("Name"), 
           SqlType = prop.GetString("Type"), 
           Nullable = prop.GetBool("Nullable"), 
           MaxLength = prop.GetInt("MaxLength"), 
           fragment.EdmxName 
          }; 

     //Parse the CSDL data for each XML document 
     var conceptualTypes = from fragment in edmxFragments 
           from entityType in fragment.DocumentRoot.Descendants(XName.Get("EntityType", ns.Csdl)) 
           from prop in entityType.Elements(XName.Get("Property", ns.Csdl)) 
           select new 
           { 
            TypeName = entityType.GetString("Name"), 
            PropertyName = prop.GetString("Name"), 
            FixedLength = prop.GetBool("FixedLength"), 
            IsUnicode = prop.GetBool("Unicode"), 
            fragment.EdmxName 
           }; 

     //Parse the MSDL data for each XML document 
     var mappings = from fragment in edmxFragments 
         from setMap in fragment.DocumentRoot.Descendants(XName.Get("EntitySetMapping", ns.Msdl)) 
         let typeMap = setMap.Elements(XName.Get("EntityTypeMapping", ns.Msdl)).Single() 
         let mapFragment = typeMap.Elements(XName.Get("MappingFragment", ns.Msdl)).Single() 
         from prop in mapFragment.Elements(XName.Get("ScalarProperty", ns.Msdl)) 
         let fullTypeName = typeMap.GetString("TypeName") 
         let typeName = fullTypeName.Substring(fullTypeName.LastIndexOf(".", StringComparison.Ordinal) + 1) 
         select new 
         { 
          TypeName = typeName, 
          TableName = mapFragment.GetString("StoreEntitySet"), 
          PropertyName = prop.GetString("Name"), 
          ColumnName = prop.GetString("ColumnName"), 
          fragment.EdmxName 
         }; 

     //Using the mapping info to join the Conceptual and Storage info 
     var tempCombined = from storageInfo in storageTypes 
          join mapping in mappings 
           on new { storageInfo.ColumnName, storageInfo.TableName, storageInfo.EdmxName } 
           equals new { mapping.ColumnName, mapping.TableName, mapping.EdmxName } 
          join conceptualInfo in conceptualTypes 
           on new { mapping.PropertyName, mapping.TypeName, mapping.EdmxName } equals 
           new { conceptualInfo.PropertyName, conceptualInfo.TypeName, conceptualInfo.EdmxName } 
          select new 
          { 
           storageInfo, 
           mapping, 
           conceptualInfo 
          }; 
     //Flatten the information from the Conceptual and Storage info 
     var edmxInfo = from c in tempCombined 
         select new 
         { 
          c.mapping.TypeName, 
          c.mapping.PropertyName, 
          ColumnInfo = new EdmxColumnInfo 
          { 
           TableName = c.storageInfo.TableName, 
           ColumnName = c.storageInfo.ColumnName, 
           SqlType = c.storageInfo.SqlType, 
           Nullable = c.storageInfo.Nullable, 
           MaxLength = c.storageInfo.MaxLength, 
           IsUnicode = c.conceptualInfo.IsUnicode, 
           FixedLength = c.conceptualInfo.FixedLength, 
          } 
         }; 

     //Build a dictionary for easy retrieval 
     var fullEdmxData = edmxInfo.ToDictionary(d => d.TypeName + "." + d.PropertyName, 
               d => d.ColumnInfo); 

     //Use Reflection and DevForce metadata to inspect the C# code 
     var results = 
      //Go through all the Types in assembly that 'my favorite entity' is in 
      from cSharpType in typeof(MyFavorateEntity).Assembly.GetTypes() 
      //Ignore abstract classes (the virtual entities probably) 
      where !cSharpType.IsAbstract 
      //Only process types that are Entities 
      where cSharpType.IsSubclassOf(typeof(Entity)) 
      //Build the class hierarchy as a string 
      let hierarchy = GetAncestors(cSharpType).GetDelimitedString(" > ", t => t.Name) 
      //Let all the C# properties (except the XYZProperty ones) 
      let codeProperties = cSharpType.GetProperties() 
      //Get the metadata from DevForce 
      let modelMetadata = EntityMetadataStore.Instance.GetEntityMetadata(cSharpType) 
      //Combine the C# data, the DevForce data and the EDMX data 
      let combined = from codeProperty in codeProperties 
          join modelProperty in modelMetadata.EntityProperties 
           on codeProperty.Name equals modelProperty.Name into 
           matchedModelProperties 
          let singleMatchedModelProperty = matchedModelProperties.SingleOrDefault() 
          let typePropString = cSharpType.Name + "." + codeProperty.Name 
          let edmxData = 
           fullEdmxData.ContainsKey(typePropString) 
            ? fullEdmxData[typePropString] 
            : null 
          select new ExtraPropertyInfo 
          { 
           TypeHierarchy = hierarchy, 
           CSharpProperty = codeProperty, 
           DevForceProperty = singleMatchedModelProperty, 
           EdmxData = edmxData 
          } 
      from c in combined 
      select c; 


     return results.ToList(); 
    } 

    private static IEnumerable<Type> GetAncestors(Type t) 
    { 
     var parent = t.BaseType; 
     while (parent != typeof(Entity) && parent != null) 
     { 
      yield return parent; 
      parent = parent.BaseType; 
     } 
    } 
} 

/// <summary> 
/// Helper class to dynamically determine the EDMX version (and therefore namespace names) of a particular EDMX file (or fragment) 
/// </summary> 
internal class EdmxNamespaceHelper 
{ 
    public string Edmx { get; private set; } 
    public string Csdl { get; private set; } 
    public string Ssdl { get; private set; } 
    public string Msdl { get; private set; } 

    /// <summary> 
    /// Version 2 namespaces 
    /// </summary> 
    private static readonly EdmxNamespaceHelper V2 = new EdmxNamespaceHelper 
    { 
     Edmx = "http://schemas.microsoft.com/ado/2008/10/edmx", 
     Csdl = "http://schemas.microsoft.com/ado/2008/09/edm", 
     Ssdl = "http://schemas.microsoft.com/ado/2009/02/edm/ssdl", 
     Msdl = "http://schemas.microsoft.com/ado/2008/09/mapping/cs" 
    }; 

    /// <summary> 
    /// Version 3 namespaces 
    /// </summary> 
    private static readonly EdmxNamespaceHelper V3 = new EdmxNamespaceHelper 
    { 
     Edmx = "http://schemas.microsoft.com/ado/2009/11/edmx", 
     Csdl = "http://schemas.microsoft.com/ado/2009/11/edm", 
     Ssdl = "http://schemas.microsoft.com/ado/2009/11/edm/ssdl", 
     Msdl = "http://schemas.microsoft.com/ado/2009/11/mapping/cs" 
    }; 

    /// <summary> 
    /// Sees is this instance's namespaces seem to be valid for the given <see cref="XElement"/> root. 
    /// </summary> 
    private bool IsValid(XElement xmlRoot) 
    { 
     try 
     { 
      //See if the top element is the Runtime element (for .edmx files) 
      return xmlRoot.Element(XName.Get("Runtime", Edmx)) != null || 
       //or if the root has a namespace of one of the individual sections (for fragments) 
        xmlRoot.Name.NamespaceName.In(Edmx, Csdl, Ssdl, Msdl); 
     } 
     catch 
     { 
      return false; 
     } 
    } 

    /// <summary> 
    /// Determines the correct <see cref="EdmxNamespaceHelper"/> for the given <see cref="XElement"/> root. 
    /// </summary> 
    public static EdmxNamespaceHelper DeriveNamespaces(XElement xmlRoot) 
    { 
     //Try V2 and V3. If none of them seem to match, just error out. 
     if (V2.IsValid(xmlRoot)) 
      return V2; 
     if (V3.IsValid(xmlRoot)) 
      return V3; 

     throw new InvalidOperationException("Could not determine EDMX type of given XML Document"); 
    } 
} 
Смежные вопросы