EntityFramework 4.0获取ComplexType映射

时间:2010-11-04 19:48:41

标签: .net entity-framework entity-framework-4

我正在尝试从MetadataWorkspace中找到映射到我的FunctionImport的ComplexType。

相关的xml存在于edmx的CSSpace中,但我无法弄清楚如何解决它。

我可以从SSpace中找到EdmFunction本身,但这并没有告诉我它映射到的ComplexType,是吗?我也可以在CSpace中找到ComplexType本身,但这并没有告诉我它映射到的FunctionImport ......

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 个答案:

答案 0 :(得分:3)

根据各种消息来源,几乎所有的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;
    }
}