EntityFramework 4.0 Get ComplexType Mapping
I'm trying to find the ComplexType that's mapped to my FunctionImport from my MetadataWorkspace.
The related xml is there in the CSSpace of the edmx, but I can't figure out how to get it out.
I can go for the EdmFunction itself from the SSpace, but that doesn't tell me the ComplexType that it's mapped to, does it? I can also go for the ComplexType itself in the CSpace, but that doesn't tell me the FunctionImport it's mapped to...
The related xml in the edmx is:
<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>
At runtime I can get a the StorageEntityMappingColle开发者_如何学运维ction but I'm not sure where to go from there:
((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...
According to various sources, pretty much all of the CSSpace is completely internalized and unaccessible to the developer. I saw recommendations that I should go straight for the mapping xml, but I really didn't want to do that...So ultimately I came up with this solution which seems to work well for getting out all of the mappings from an ObjectContext.
Note...this is expensive...so if someone else finds this helpful and takes this approach, they should make sure to cache it.
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;
}
}
精彩评论