代码之家  ›  专栏  ›  技术社区  ›  Jeff

EntityFramework 4.0获取complexType映射

  •  4
  • Jeff  · 技术社区  · 14 年前

    我正在尝试从MetadataWorkspace中查找映射到我的函数import的complexType。

    相关的XML存在于edmx的csspace中,但我无法弄清楚如何将其取出。

    我可以从sspace中找到edmfunction本身,但这并不能告诉我它映射到的complexType,是吗?我也可以在cspace中查找complexType本身,但这并不能告诉我它映射到的函数import…

    EDMX中的相关XML是:

          <FunctionImportMapping FunctionImportName="GetContactsByName" FunctionName="Test2Model.Store.GetContactsByName">
            <ResultMapping>
              <ComplexTypeMapping TypeName="Test2Model.GetContactsByName_Result">
                <ScalarProperty Name="FirstName" ColumnName="FirstName" />
                <ScalarProperty Name="LastName" ColumnName="LastName" />
                <ScalarProperty Name="Address1" ColumnName="Address1" />
                <ScalarProperty Name="Address2" ColumnName="Address2" />
                <ScalarProperty Name="City" ColumnName="City" />
                <ScalarProperty Name="StateID" ColumnName="StateID" />
                <ScalarProperty Name="Country" ColumnName="Country" />
              </ComplexTypeMapping>
            </ResultMapping>
          </FunctionImportMapping>
    

    在运行时,我可以获取一个StorageEntityMappingCollection,但我不确定从中可以找到什么:

    ((System.Data.Mapping.StorageMappingItemCollection)  
    metadataWorkspace.GetItemCollection(DataSpace.CSSpace)).First() // then what....all I see after this is a bunch of MetadataProperties which seem to take me in circles...
    
    1 回复  |  直到 11 年前
        1
  •  3
  •   Jeff    14 年前

    根据各种来源,几乎所有的CSspace都是完全内化的,开发人员无法访问。我看到了一些建议,建议我直接使用映射XML,但我真的不想这样做……所以最终我提出了这个解决方案,它似乎可以很好地从ObjectContext中获取所有映射。

    注意……这是很昂贵的……所以如果其他人发现这很有用并且采用这种方法,他们应该确保缓存它。

    internal class Resource
    {
         public string Name {get; set; }
         public Type Type { get; set; }
         public IEnumerable<ResourceParameter> Parameters { get; private set; }
    }
    
    internal class ResourceParameter
    {
         public string Name { get; set; }
         public Type Type { get; set; }
    }
    
    internal class EntityFrameworkExtensions 
    {
        public static IEnumerable<Resource> GetResources(this ObjectContext objectContext, IEnumerable<Assembly> assemblies)
        {
            MetadataWorkspace metadataWorkspace = objectContext.MetadataWorkspace;
    
            foreach (Assembly assembly in assemblies)
            {
                metadataWorkspace.LoadFromAssembly(assembly);
            }
    
            ReadOnlyCollection<EntityType> cSpaceEntityTypes = metadataWorkspace.GetItems<EntityType>(DataSpace.CSpace);
            if (cSpaceEntityTypes != null)
            {
                foreach (Type type in cSpaceEntityTypes.Select(t => metadataWorkspace.GetClrType(t, assemblies)))
                {
                    yield return new Resource { Type = type, Name = type.Name };
                }
            }
    
            IEnumerable<EdmFunction> cSpaceFunctions = metadataWorkspace.GetItems<EntityContainer>(DataSpace.CSpace).SelectMany(c => c.FunctionImports));
            if (cSpaceFunctions != null)
            {
                foreach (EdmFunction function in cSpaceFunctions)
                {
                    Type returnType = metadataWorkspace.GetClrType(function.ReturnParameter.TypeUsage.EdmType, assemblies);
                    IEnumerable<ResourceParameter> parameters = function.Parameters.Select(p => new ResourceParameter(metadataWorkspace.GetClrType(p.TypeUsage.EdmType, assemblies), p.Name));
                    yield return new Resource { Type = returnType, Name = function.Name, Parameters = parameters };
                }
            }
        }
    
        public static string GetClrTypeName(this MetadataWorkspace metadataWorkspace, StructuralType cSpaceType)
        {
            if (cSpaceType != null)
            {
                StructuralType oSpaceType;
    
                if (metadataWorkspace.TryGetObjectSpaceType(cSpaceType, out oSpaceType))
                {
                    // interesting note: oSpaceType is of type ClrType - an internal EF type that contains a EdmType to CLR type mapping...  
                    // so instead of getting the type name, we could go straight for the type  
                    // by doing: oSpaceType.GetProperty("ClrType",BindingFlags.Instance|BindingFlags.NonPublic).GetValue(oSpaceType, null);  
                    // but the classes are internal, so they might change and I don't want to touch them directly...
                    return oSpaceType.FullName;
                }
            }
    
            return null;
        }
    
        public static Type GetClrType(this MetadataWorkspace metadataWorkspace, EdmType cSpaceEdmType, IEnumerable<Assembly> assemblies)
        {
            var collectionType = cSpaceEdmType as CollectionType;
            if (collectionType != null)
            {
                Type elementType = metadataWorkspace.GetClrType(collectionType.TypeUsage.EdmType, assemblies);
    
                return elementType;
            }
    
            var structuralType = cSpaceEdmType as StructuralType;
            if (structuralType != null)
            {
                var name =  metadataWorkspace.GetClrTypeName(structuralType);
                foreach(var asm in assemblies) 
                {
                     var clrType = asm.GetType(name);
                     if (clrType != null) 
                     {
                           return clrType;
                     }
                }
            }
    
            var primitiveType = cSpaceEdmType as PrimitiveType;
            if (primitiveType != null)
            {
                return primitiveType.ClrEquivalentType;
            }
    
            return null;
        }
    }