e79aa3c0ed
Former-commit-id: a2155e9bd80020e49e72e86c44da02a8ac0e57a4
620 lines
27 KiB
C#
620 lines
27 KiB
C#
//---------------------------------------------------------------------
|
|
// <copyright file="ObjectItemCollection.cs" company="Microsoft">
|
|
// Copyright (c) Microsoft Corporation. All rights reserved.
|
|
// </copyright>
|
|
//
|
|
// @owner [....]
|
|
// @backupOwner [....]
|
|
//---------------------------------------------------------------------
|
|
|
|
using System.Collections.Generic;
|
|
// Using an alias for this because a lot of names in this namespace conflicts with names in metadata
|
|
using System.Data.Entity;
|
|
using System.Diagnostics;
|
|
using System.Reflection;
|
|
|
|
namespace System.Data.Metadata.Edm
|
|
{
|
|
/// <summary>
|
|
/// Class for representing a collection of items for the object layer.
|
|
/// Most of the implemetation for actual maintainance of the collection is
|
|
/// done by ItemCollection
|
|
/// </summary>
|
|
[CLSCompliant(false)]
|
|
public sealed partial class ObjectItemCollection : ItemCollection
|
|
{
|
|
#region Constructors
|
|
|
|
/// <summary>
|
|
/// The ObjectItemCollection that loads metadata from assemblies
|
|
/// </summary>
|
|
public ObjectItemCollection()
|
|
: base(DataSpace.OSpace)
|
|
{
|
|
foreach (PrimitiveType type in ClrProviderManifest.Instance.GetStoreTypes())
|
|
{
|
|
AddInternal(type);
|
|
_primitiveTypeMaps.Add(type);
|
|
}
|
|
}
|
|
#endregion
|
|
|
|
#region Fields
|
|
|
|
// Cache for primitive type maps for Edm to provider
|
|
private readonly CacheForPrimitiveTypes _primitiveTypeMaps = new CacheForPrimitiveTypes();
|
|
|
|
// Used for tracking the loading of an assembly and its referenced assemblies. Though the value of an entry is bool, the logic represented
|
|
// by an entry is tri-state, the third state represented by a "missing" entry. To summarize:
|
|
// 1. The <value> associated with an <entry> is "true" : Specified and all referenced assemblies have been loaded
|
|
// 2. The <value> associated with an <entry> is "false" : Specified assembly loaded. Its referenced assemblies may not be loaded
|
|
// 3. The <entry> is missing : Specified assembly has not been loaded
|
|
private KnownAssembliesSet _knownAssemblies = new KnownAssembliesSet();
|
|
|
|
// Dictionary which keeps tracks of oc mapping information - the key is the conceptual name of the type
|
|
// and the value is the reference to the ospace type
|
|
private Dictionary<string, EdmType> _ocMapping = new Dictionary<string, EdmType>();
|
|
|
|
private object _loaderCookie;
|
|
private object _loadAssemblyLock = new object();
|
|
|
|
internal object LoadAssemblyLock
|
|
{
|
|
get
|
|
{
|
|
return _loadAssemblyLock;
|
|
}
|
|
}
|
|
|
|
internal static IList<Assembly> ViewGenerationAssemblies
|
|
{
|
|
get
|
|
{
|
|
return AssemblyCache.ViewGenerationAssemblies;
|
|
}
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region Methods
|
|
|
|
|
|
internal static bool IsCompiledViewGenAttributePresent(Assembly assembly)
|
|
{
|
|
return assembly.IsDefined(typeof(System.Data.Mapping.EntityViewGenerationAttribute), false /*inherit*/);
|
|
}
|
|
|
|
/// <summary>
|
|
/// The method loads the O-space metadata for all the referenced assemblies starting from the given assembly
|
|
/// in a recursive way.
|
|
/// The assembly should be from Assembly.GetCallingAssembly via one of our public API's.
|
|
/// </summary>
|
|
/// <param name="assembly">assembly whose dependency list we are going to traverse</param>
|
|
internal void ImplicitLoadAllReferencedAssemblies(Assembly assembly, EdmItemCollection edmItemCollection)
|
|
{
|
|
if (!MetadataAssemblyHelper.ShouldFilterAssembly(assembly))
|
|
{
|
|
bool loadAllReferencedAssemblies = true;
|
|
LoadAssemblyFromCache(this, assembly, loadAllReferencedAssemblies, edmItemCollection, null);
|
|
}
|
|
}
|
|
|
|
internal void ImplicitLoadViewsFromAllReferencedAssemblies(Assembly assembly)
|
|
{
|
|
// we filter implicit loads
|
|
if (MetadataAssemblyHelper.ShouldFilterAssembly(assembly))
|
|
{
|
|
return;
|
|
}
|
|
lock (this)
|
|
{
|
|
CollectIfViewGenAssembly(assembly);
|
|
|
|
foreach (Assembly referenceAssembly in MetadataAssemblyHelper.GetNonSystemReferencedAssemblies(assembly))
|
|
{
|
|
CollectIfViewGenAssembly(referenceAssembly);
|
|
}
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Load metadata from the given assembly
|
|
/// </summary>
|
|
/// <param name="assembly">The assembly from which to load metadata</param>
|
|
/// <exception cref="System.ArgumentNullException">thrown if assembly argument is null</exception>
|
|
public void LoadFromAssembly(Assembly assembly)
|
|
{
|
|
ExplicitLoadFromAssembly(assembly, null, null);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Load metadata from the given assembly
|
|
/// </summary>
|
|
/// <param name="assembly">The assembly from which to load metadata</param>
|
|
/// <exception cref="System.ArgumentNullException">thrown if assembly argument is null</exception>
|
|
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Naming", "CA1704:IdentifiersShouldBeSpelledCorrectly", MessageId = "edm")]
|
|
public void LoadFromAssembly(Assembly assembly, EdmItemCollection edmItemCollection, Action<String> logLoadMessage)
|
|
{
|
|
EntityUtil.CheckArgumentNull(assembly, "assembly");
|
|
EntityUtil.CheckArgumentNull(edmItemCollection, "edmItemCollection");
|
|
EntityUtil.CheckArgumentNull(logLoadMessage, "logLoadMessage");
|
|
|
|
ExplicitLoadFromAssembly(assembly, edmItemCollection, logLoadMessage);
|
|
}
|
|
|
|
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Naming", "CA1704:IdentifiersShouldBeSpelledCorrectly", MessageId = "edm")]
|
|
public void LoadFromAssembly(Assembly assembly, EdmItemCollection edmItemCollection)
|
|
{
|
|
EntityUtil.CheckArgumentNull(assembly, "assembly");
|
|
EntityUtil.CheckArgumentNull(edmItemCollection, "edmItemCollection");
|
|
|
|
ExplicitLoadFromAssembly(assembly, edmItemCollection, null);
|
|
}
|
|
/// <summary>
|
|
/// Explicit loading means that the user specifically asked us to load this assembly.
|
|
/// We won't do any filtering, they "know what they are doing"
|
|
/// </summary>
|
|
internal void ExplicitLoadFromAssembly(Assembly assembly, EdmItemCollection edmItemCollection, Action<String> logLoadMessage)
|
|
{
|
|
LoadAssemblyFromCache(this, assembly, false /*loadAllReferencedAssemblies*/, edmItemCollection, logLoadMessage);
|
|
//Since User called LoadFromAssembly, so we should collect the generated views if present
|
|
//even if the schema attribute is not present
|
|
if (IsCompiledViewGenAttributePresent(assembly) && !ObjectItemAttributeAssemblyLoader.IsSchemaAttributePresent(assembly))
|
|
{
|
|
CollectIfViewGenAssembly(assembly);
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Implicit loading means that we are trying to help the user find the right
|
|
/// assembly, but they didn't explicitly ask for it. Our Implicit rules require that
|
|
/// we filter out assemblies with the Ecma or MicrosoftPublic PublicKeyToken on them
|
|
/// </summary>
|
|
internal void ImplicitLoadFromAssembly(Assembly assembly, EdmItemCollection edmItemCollection)
|
|
{
|
|
if (!MetadataAssemblyHelper.ShouldFilterAssembly(assembly))
|
|
{
|
|
// it meets the Implicit rules Load it
|
|
ExplicitLoadFromAssembly(assembly, edmItemCollection, null);
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Implicit loading means that we are trying to help the user find the right
|
|
/// assembly, but they didn't explicitly ask for it. Our Implicit rules require that
|
|
/// we filter out assemblies with the Ecma or MicrosoftPublic PublicKeyToken on them
|
|
///
|
|
/// Load metadata from the type's assembly.
|
|
/// </summary>
|
|
/// <param name="type">The type's assembly is loaded into the OSpace ItemCollection</param>
|
|
/// <returns>true if the type and all its generic arguments are filtered out (did not attempt to load assembly)</returns>
|
|
internal bool ImplicitLoadAssemblyForType(Type type, EdmItemCollection edmItemCollection)
|
|
{
|
|
bool result;
|
|
|
|
if (!MetadataAssemblyHelper.ShouldFilterAssembly(type.Assembly))
|
|
{
|
|
// InternalLoadFromAssembly will check _knownAssemblies
|
|
result = LoadAssemblyFromCache(this, type.Assembly, false /*loadAllReferencedAssemblies*/, edmItemCollection, null);
|
|
}
|
|
else
|
|
{
|
|
result = false;
|
|
}
|
|
|
|
if (type.IsGenericType)
|
|
{
|
|
// recursively load all generic types
|
|
// interesting code paths are ObjectQuery<Nullable<Int32>>, ObjectQuery<IEnumerable<Product>>
|
|
foreach (Type t in type.GetGenericArguments())
|
|
{
|
|
result |= ImplicitLoadAssemblyForType(t, edmItemCollection);
|
|
}
|
|
}
|
|
return result;
|
|
}
|
|
|
|
/// <summary>
|
|
/// internal static method to get the relationship name
|
|
/// </summary>
|
|
/// <param name="clrType"></param>
|
|
/// <param name="relationshipName"></param>
|
|
/// <returns></returns>
|
|
internal AssociationType GetRelationshipType(Type entityClrType, string relationshipName)
|
|
{
|
|
AssociationType associationType;
|
|
if (TryGetItem<AssociationType>(relationshipName, out associationType))
|
|
{
|
|
return associationType;
|
|
}
|
|
return null;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Loads the OSpace types in the assembly and returns them as a dictionary
|
|
/// </summary>
|
|
/// <param name="assembly">The assembly to load</param>
|
|
/// <returns>A mapping from names to OSpace EdmTypes</returns>
|
|
internal static Dictionary<string, EdmType> LoadTypesExpensiveWay(Assembly assembly)
|
|
{
|
|
Dictionary<string, EdmType> typesInLoading = null;
|
|
|
|
List<EdmItemError> errors;
|
|
KnownAssembliesSet knownAssemblies = new KnownAssembliesSet();
|
|
|
|
AssemblyCache.LoadAssembly(assembly, false /*loadAllReferencedAssemblies*/,
|
|
knownAssemblies, out typesInLoading, out errors);
|
|
|
|
// Check for errors
|
|
if (errors.Count != 0)
|
|
{
|
|
throw EntityUtil.InvalidSchemaEncountered(Helper.CombineErrorMessage(errors));
|
|
}
|
|
|
|
return typesInLoading;
|
|
}
|
|
|
|
/// <summary>
|
|
/// internal static method to get the relationship name
|
|
/// </summary>
|
|
/// <param name="clrType"></param>
|
|
/// <param name="relationshipName"></param>
|
|
/// <returns></returns>
|
|
internal static AssociationType GetRelationshipTypeExpensiveWay(Type entityClrType, string relationshipName)
|
|
{
|
|
Dictionary<string, EdmType> typesInLoading = LoadTypesExpensiveWay(entityClrType.Assembly);
|
|
if (typesInLoading != null)
|
|
{
|
|
EdmType edmType;
|
|
// Look in typesInLoading for relationship type
|
|
if (typesInLoading.TryGetValue(relationshipName, out edmType) && Helper.IsRelationshipType(edmType))
|
|
{
|
|
return (AssociationType)edmType;
|
|
}
|
|
}
|
|
return null;
|
|
}
|
|
|
|
/// <summary>
|
|
/// internal static method to get all the AssociationTypes from an assembly
|
|
/// </summary>
|
|
/// <param name="assembly">The assembly from which to load relationship types</param>
|
|
/// <returns>An enumeration of OSpace AssociationTypes that are present in this assembly</returns>
|
|
internal static IEnumerable<AssociationType> GetAllRelationshipTypesExpensiveWay(Assembly assembly)
|
|
{
|
|
Dictionary<string, EdmType> typesInLoading = LoadTypesExpensiveWay(assembly);
|
|
if (typesInLoading != null)
|
|
{
|
|
// Iterate through the EdmTypes looking for AssociationTypes
|
|
foreach (EdmType edmType in typesInLoading.Values)
|
|
{
|
|
if (Helper.IsAssociationType(edmType))
|
|
{
|
|
yield return (AssociationType)edmType;
|
|
}
|
|
}
|
|
}
|
|
yield break;
|
|
}
|
|
|
|
private static bool LoadAssemblyFromCache(ObjectItemCollection objectItemCollection, Assembly assembly,
|
|
bool loadReferencedAssemblies, EdmItemCollection edmItemCollection, Action<String> logLoadMessage)
|
|
{
|
|
// Check if its loaded in the cache - if the call is for loading referenced assemblies, make sure that all referenced
|
|
// assemblies are also loaded
|
|
KnownAssemblyEntry entry;
|
|
if (objectItemCollection._knownAssemblies.TryGetKnownAssembly(assembly, objectItemCollection._loaderCookie, edmItemCollection, out entry))
|
|
{
|
|
// Proceed if only we need to load the referenced assemblies and they are not loaded
|
|
if (loadReferencedAssemblies == false)
|
|
{
|
|
// don't say we loaded anything, unless we actually did before
|
|
return entry.CacheEntry.TypesInAssembly.Count != 0;
|
|
}
|
|
else if (entry.ReferencedAssembliesAreLoaded == true)
|
|
{
|
|
// this assembly was part of a all hands reference search
|
|
return true;
|
|
}
|
|
}
|
|
|
|
lock (objectItemCollection.LoadAssemblyLock)
|
|
{
|
|
// Check after acquiring the lock, since the known assemblies might have got modified
|
|
// Check if the assembly is already loaded. The reason we need to check if the assembly is already loaded, is that
|
|
if (objectItemCollection._knownAssemblies.TryGetKnownAssembly(assembly, objectItemCollection._loaderCookie, edmItemCollection, out entry))
|
|
{
|
|
// Proceed if only we need to load the referenced assemblies and they are not loaded
|
|
if (loadReferencedAssemblies == false || entry.ReferencedAssembliesAreLoaded == true)
|
|
{
|
|
return true;
|
|
}
|
|
}
|
|
|
|
Dictionary<string, EdmType> typesInLoading;
|
|
List<EdmItemError> errors;
|
|
KnownAssembliesSet knownAssemblies;
|
|
|
|
if (objectItemCollection != null)
|
|
{
|
|
knownAssemblies = new KnownAssembliesSet(objectItemCollection._knownAssemblies);
|
|
}
|
|
else
|
|
{
|
|
knownAssemblies = new KnownAssembliesSet();
|
|
}
|
|
|
|
// Load the assembly from the cache
|
|
AssemblyCache.LoadAssembly(assembly, loadReferencedAssemblies, knownAssemblies, edmItemCollection, logLoadMessage, ref objectItemCollection._loaderCookie, out typesInLoading, out errors);
|
|
|
|
// Throw if we have encountered errors
|
|
if (errors.Count != 0)
|
|
{
|
|
throw EntityUtil.InvalidSchemaEncountered(Helper.CombineErrorMessage(errors));
|
|
}
|
|
|
|
// We can encounter new assemblies, but they may not have any time in them
|
|
if (typesInLoading.Count != 0)
|
|
{
|
|
// No errors, so go ahead and add the types and make them readonly
|
|
// The existence of the loading lock tells us whether we should be thread safe or not, if we need
|
|
// to be thread safe, then we need to use AtomicAddRange. We don't need to actually use the lock
|
|
// because the caller should have done it already
|
|
// Recheck the assemblies added, another list is created just to match up the collection type
|
|
// taken in by AtomicAddRange()
|
|
List<GlobalItem> globalItems = new List<GlobalItem>();
|
|
foreach (EdmType edmType in typesInLoading.Values)
|
|
{
|
|
globalItems.Add(edmType);
|
|
|
|
string cspaceTypeName = "";
|
|
try
|
|
{
|
|
// Also populate the ocmapping information
|
|
if (Helper.IsEntityType(edmType))
|
|
{
|
|
cspaceTypeName = ((ClrEntityType)edmType).CSpaceTypeName;
|
|
objectItemCollection._ocMapping.Add(cspaceTypeName, edmType);
|
|
}
|
|
else if (Helper.IsComplexType(edmType))
|
|
{
|
|
cspaceTypeName = ((ClrComplexType)edmType).CSpaceTypeName;
|
|
objectItemCollection._ocMapping.Add(cspaceTypeName, edmType);
|
|
}
|
|
else if (Helper.IsEnumType(edmType))
|
|
{
|
|
cspaceTypeName = ((ClrEnumType)edmType).CSpaceTypeName;
|
|
objectItemCollection._ocMapping.Add(cspaceTypeName, edmType);
|
|
}
|
|
// for the rest of the types like a relationship type, we do not have oc mapping,
|
|
// so we don't keep that information
|
|
}
|
|
catch (ArgumentException e)
|
|
{
|
|
throw new MappingException(Strings.Mapping_CannotMapCLRTypeMultipleTimes(cspaceTypeName), e);
|
|
}
|
|
}
|
|
|
|
// Create a new ObjectItemCollection and add all the global items to it.
|
|
// Also copy all the existing items from the existing collection
|
|
objectItemCollection.AtomicAddRange(globalItems);
|
|
}
|
|
|
|
|
|
// Update the value of known assemblies
|
|
objectItemCollection._knownAssemblies = knownAssemblies;
|
|
|
|
foreach (Assembly loadedAssembly in knownAssemblies.Assemblies)
|
|
{
|
|
CollectIfViewGenAssembly(loadedAssembly);
|
|
}
|
|
|
|
return typesInLoading.Count != 0;
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Check to see if the assembly has the custom view generation attribute AND
|
|
/// collect the assembly into the local list if it has cutom attribute.
|
|
/// </summary>
|
|
/// <param name="assembly"></param>
|
|
/// <param name="viewGenAssemblies"></param>
|
|
private static void CollectIfViewGenAssembly(Assembly assembly)
|
|
{
|
|
if (assembly.IsDefined(typeof(System.Data.Mapping.EntityViewGenerationAttribute), false /*inherit*/))
|
|
{
|
|
if (!AssemblyCache.ViewGenerationAssemblies.Contains(assembly))
|
|
{
|
|
AssemblyCache.ViewGenerationAssemblies.Add(assembly);
|
|
}
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Get the list of primitive types for the given space
|
|
/// </summary>
|
|
/// <returns></returns>
|
|
public IEnumerable<PrimitiveType> GetPrimitiveTypes()
|
|
{
|
|
return _primitiveTypeMaps.GetTypes();
|
|
}
|
|
|
|
/// <summary>
|
|
/// The method returns the underlying CLR type for the specified OSpace type argument.
|
|
/// If the DataSpace of the parameter is not OSpace, an ArgumentException is thrown.
|
|
/// </summary>
|
|
/// <param name="objectSpaceType">The OSpace type to look up</param>
|
|
/// <returns>The CLR type of the OSpace argument</returns>
|
|
public Type GetClrType(StructuralType objectSpaceType)
|
|
{
|
|
return ObjectItemCollection.GetClrType((EdmType)objectSpaceType);
|
|
}
|
|
|
|
/// <summary>
|
|
/// The method returns the underlying CLR type for the specified OSpace type argument.
|
|
/// If the DataSpace of the parameter is not OSpace, the method returns false and sets
|
|
/// the out parameter to null.
|
|
/// </summary>
|
|
/// <param name="objectSpaceType">The OSpace type to look up</param>
|
|
/// <param name="clrType">The CLR type of the OSpace argument</param>
|
|
/// <returns>true on success, false on failure</returns>
|
|
public bool TryGetClrType(StructuralType objectSpaceType, out Type clrType)
|
|
{
|
|
return ObjectItemCollection.TryGetClrType((EdmType)objectSpaceType, out clrType);
|
|
}
|
|
|
|
/// <summary>
|
|
/// The method returns the underlying CLR type for the specified OSpace type argument.
|
|
/// If the DataSpace of the parameter is not OSpace, an ArgumentException is thrown.
|
|
/// </summary>
|
|
/// <param name="objectSpaceType">The OSpace type to look up</param>
|
|
/// <returns>The CLR type of the OSpace argument</returns>
|
|
public Type GetClrType(EnumType objectSpaceType)
|
|
{
|
|
return ObjectItemCollection.GetClrType((EdmType)objectSpaceType);
|
|
}
|
|
|
|
/// <summary>
|
|
/// The method returns the underlying CLR type for the specified OSpace enum type argument.
|
|
/// If the DataSpace of the parameter is not OSpace, the method returns false and sets
|
|
/// the out parameter to null.
|
|
/// </summary>
|
|
/// <param name="objectSpaceType">The OSpace enum type to look up</param>
|
|
/// <param name="clrType">The CLR enum type of the OSpace argument</param>
|
|
/// <returns>true on success, false on failure</returns>
|
|
public bool TryGetClrType(EnumType objectSpaceType, out Type clrType)
|
|
{
|
|
return ObjectItemCollection.TryGetClrType((EdmType)objectSpaceType, out clrType);
|
|
}
|
|
|
|
/// <summary>
|
|
/// A helper method returning the underlying CLR type for the specified OSpace Enum or Structural type argument.
|
|
/// If the DataSpace of the parameter is not OSpace, an ArgumentException is thrown.
|
|
/// </summary>
|
|
/// <param name="objectSpaceType">The OSpace type to look up</param>
|
|
/// <returns>The CLR type of the OSpace argument</returns>
|
|
private static Type GetClrType(EdmType objectSpaceType)
|
|
{
|
|
Debug.Assert(objectSpaceType == null || objectSpaceType is StructuralType || objectSpaceType is EnumType,
|
|
"Only enum or structural type expected");
|
|
|
|
Type clrType;
|
|
if (!ObjectItemCollection.TryGetClrType(objectSpaceType, out clrType))
|
|
{
|
|
throw EntityUtil.Argument(Strings.FailedToFindClrTypeMapping(objectSpaceType.Identity));
|
|
}
|
|
|
|
return clrType;
|
|
}
|
|
|
|
/// <summary>
|
|
/// A helper method returning the underlying CLR type for the specified OSpace enum or structural type argument.
|
|
/// If the DataSpace of the parameter is not OSpace, the method returns false and sets
|
|
/// the out parameter to null.
|
|
/// </summary>
|
|
/// <param name="objectSpaceType">The OSpace enum type to look up</param>
|
|
/// <param name="clrType">The CLR enum type of the OSpace argument</param>
|
|
/// <returns>true on success, false on failure</returns>
|
|
private static bool TryGetClrType(EdmType objectSpaceType, out Type clrType)
|
|
{
|
|
Debug.Assert(objectSpaceType == null || objectSpaceType is StructuralType || objectSpaceType is EnumType,
|
|
"Only enum or structural type expected");
|
|
|
|
EntityUtil.CheckArgumentNull(objectSpaceType, "objectSpaceType");
|
|
|
|
if (objectSpaceType.DataSpace != DataSpace.OSpace)
|
|
{
|
|
throw EntityUtil.Argument(Strings.ArgumentMustBeOSpaceType, "objectSpaceType");
|
|
}
|
|
|
|
clrType = null;
|
|
|
|
if (Helper.IsEntityType(objectSpaceType) || Helper.IsComplexType(objectSpaceType) || Helper.IsEnumType(objectSpaceType))
|
|
{
|
|
Debug.Assert(objectSpaceType is ClrEntityType || objectSpaceType is ClrComplexType || objectSpaceType is ClrEnumType,
|
|
"Unexpected OSpace object type.");
|
|
|
|
clrType = objectSpaceType.ClrType;
|
|
|
|
Debug.Assert(clrType != null, "ClrType property of ClrEntityType/ClrComplexType/ClrEnumType objects must not be null");
|
|
}
|
|
|
|
return clrType != null;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Given the canonical primitive type, get the mapping primitive type in the given dataspace
|
|
/// </summary>
|
|
/// <param name="modelType">canonical primitive type</param>
|
|
/// <returns>The mapped scalar type</returns>
|
|
internal override PrimitiveType GetMappedPrimitiveType(PrimitiveTypeKind modelType)
|
|
{
|
|
if (Helper.IsGeometricTypeKind(modelType))
|
|
{
|
|
modelType = PrimitiveTypeKind.Geometry;
|
|
}
|
|
else if (Helper.IsGeographicTypeKind(modelType))
|
|
{
|
|
modelType = PrimitiveTypeKind.Geography;
|
|
}
|
|
|
|
PrimitiveType type = null;
|
|
_primitiveTypeMaps.TryGetType(modelType, null, out type);
|
|
return type;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Get the OSpace type given the CSpace typename
|
|
/// </summary>
|
|
/// <param name="cspaceTypeName"></param>
|
|
/// <param name="ignoreCase"></param>
|
|
/// <param name="edmType"></param>
|
|
/// <returns></returns>
|
|
internal bool TryGetOSpaceType(EdmType cspaceType, out EdmType edmType)
|
|
{
|
|
Debug.Assert(DataSpace.CSpace == cspaceType.DataSpace, "DataSpace should be CSpace");
|
|
|
|
// check if there is an entity, complex type or enum type mapping with this name
|
|
if (Helper.IsEntityType(cspaceType) || Helper.IsComplexType(cspaceType) || Helper.IsEnumType(cspaceType))
|
|
{
|
|
return _ocMapping.TryGetValue(cspaceType.Identity, out edmType);
|
|
}
|
|
|
|
return TryGetItem<EdmType>(cspaceType.Identity, out edmType);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Given the ospace type, returns the fullname of the mapped cspace type.
|
|
/// Today, since we allow non-default mapping between entity type and complex type,
|
|
/// this is only possible for entity and complex type.
|
|
/// </summary>
|
|
/// <param name="edmType"></param>
|
|
/// <returns></returns>
|
|
internal static string TryGetMappingCSpaceTypeIdentity(EdmType edmType)
|
|
{
|
|
Debug.Assert(DataSpace.OSpace == edmType.DataSpace, "DataSpace must be OSpace");
|
|
|
|
if (Helper.IsEntityType(edmType))
|
|
{
|
|
return ((ClrEntityType)edmType).CSpaceTypeName;
|
|
}
|
|
else if (Helper.IsComplexType(edmType))
|
|
{
|
|
return ((ClrComplexType)edmType).CSpaceTypeName;
|
|
}
|
|
else if (Helper.IsEnumType(edmType))
|
|
{
|
|
return ((ClrEnumType)edmType).CSpaceTypeName;
|
|
}
|
|
|
|
return edmType.Identity;
|
|
}
|
|
|
|
public override System.Collections.ObjectModel.ReadOnlyCollection<T> GetItems<T>()
|
|
{
|
|
return base.InternalGetItems(typeof(T)) as System.Collections.ObjectModel.ReadOnlyCollection<T>;
|
|
}
|
|
#endregion
|
|
}
|
|
}
|