2016-08-03 10:59:49 +00:00
//---------------------------------------------------------------------
// <copyright file="MetadataWorkspace.cs" company="Microsoft">
// Copyright (c) Microsoft Corporation. All rights reserved.
// </copyright>
//
2017-08-21 15:34:15 +00:00
// @owner Microsoft
// @backupOwner Microsoft
2016-08-03 10:59:49 +00:00
//---------------------------------------------------------------------
namespace System.Data.Metadata.Edm
{
using System ;
using System.Collections.Generic ;
using System.Collections.ObjectModel ;
using System.Data ;
using System.Data.Common.CommandTrees ;
using eSQL = System . Data . Common . EntitySql ;
using System.Data.Common.Utils ;
using System.Data.Entity ;
using System.Data.Mapping ;
using System.Data.Mapping.Update.Internal ;
using System.Data.Mapping.ViewGeneration ;
using System.Diagnostics ;
using System.Globalization ;
using System.Linq ;
using System.Reflection ;
using System.Runtime.Versioning ;
using System.Xml ;
/// <summary>
/// Runtime Metadata Workspace
/// </summary>
public sealed class MetadataWorkspace
{
#region Constructors
/// <summary>
/// Constructs the new instance of runtime metadata workspace
/// </summary>
public MetadataWorkspace ( )
{
}
/// <summary>
/// Create MetadataWorkspace that is populated with ItemCollections for all the spaces that the metadata artifacts provided.
/// All res:// paths will be resolved only from the assemblies returned from the enumerable assembliesToConsider.
/// </summary>
/// <param name="paths">The paths where the metadata artifacts located</param>
/// <param name="assembliesToConsider">User specified assemblies to consider</param>
/// <exception cref="ArgumentNullException"></exception>
/// <exception cref="ArgumentException">Throw when assembliesToConsider is empty or contains null, or cannot find the corresponding assembly in it</exception>
/// <exception cref="MetadataException"></exception>
[ResourceExposure(ResourceScope.Machine)] //Exposes the file path names which are a Machine resource
[ResourceConsumption(ResourceScope.Machine)] //For MetadataWorkspace.CreateMetadataWorkspaceWithResolver method call but we do not create the file paths in this method
public MetadataWorkspace ( IEnumerable < string > paths , IEnumerable < Assembly > assembliesToConsider )
{
// we are intentionally not checking to see if the paths enumerable is empty
EntityUtil . CheckArgumentNull ( paths , "paths" ) ;
EntityUtil . CheckArgumentContainsNull ( ref paths , "paths" ) ;
EntityUtil . CheckArgumentNull ( assembliesToConsider , "assembliesToConsider" ) ;
EntityUtil . CheckArgumentContainsNull ( ref assembliesToConsider , "assembliesToConsider" ) ;
Func < AssemblyName , Assembly > resolveReference = ( AssemblyName referenceName ) = >
{
foreach ( Assembly assembly in assembliesToConsider )
{
if ( AssemblyName . ReferenceMatchesDefinition ( referenceName , new AssemblyName ( assembly . FullName ) ) )
{
return assembly ;
}
}
throw EntityUtil . Argument ( Strings . AssemblyMissingFromAssembliesToConsider ( referenceName . FullName ) , "assembliesToConsider" ) ;
} ;
CreateMetadataWorkspaceWithResolver ( paths , ( ) = > assembliesToConsider , resolveReference ) ;
}
[ResourceExposure(ResourceScope.Machine)] //Exposes the file path names which are a Machine resource
[ResourceConsumption(ResourceScope.Machine)] //For MetadataArtifactLoader.CreateCompositeFromFilePaths method call but We do not create the file paths in this method
private void CreateMetadataWorkspaceWithResolver ( IEnumerable < string > paths , Func < IEnumerable < Assembly > > wildcardAssemblies , Func < AssemblyName , Assembly > resolveReference )
{
MetadataArtifactLoader composite = MetadataArtifactLoader . CreateCompositeFromFilePaths ( paths . ToArray ( ) , "" , new CustomAssemblyResolver ( wildcardAssemblies , resolveReference ) ) ;
// only create the ItemCollection that has corresponding artifacts
DataSpace dataSpace = DataSpace . CSpace ;
using ( DisposableCollectionWrapper < XmlReader > cSpaceReaders = new DisposableCollectionWrapper < XmlReader > ( composite . CreateReaders ( dataSpace ) ) )
{
if ( cSpaceReaders . Any ( ) )
{
this . _itemsCSpace = new EdmItemCollection ( cSpaceReaders , composite . GetPaths ( dataSpace ) ) ;
}
}
dataSpace = DataSpace . SSpace ;
using ( DisposableCollectionWrapper < XmlReader > sSpaceReaders = new DisposableCollectionWrapper < XmlReader > ( composite . CreateReaders ( dataSpace ) ) )
{
if ( sSpaceReaders . Any ( ) )
{
this . _itemsSSpace = new StoreItemCollection ( sSpaceReaders , composite . GetPaths ( dataSpace ) ) ;
}
}
dataSpace = DataSpace . CSSpace ;
using ( DisposableCollectionWrapper < XmlReader > csSpaceReaders = new DisposableCollectionWrapper < XmlReader > ( composite . CreateReaders ( dataSpace ) ) )
{
if ( csSpaceReaders . Any ( ) & & null ! = this . _itemsCSpace & & null ! = this . _itemsSSpace )
{
this . _itemsCSSpace = new StorageMappingItemCollection ( this . _itemsCSpace , this . _itemsSSpace , csSpaceReaders , composite . GetPaths ( dataSpace ) ) ;
}
}
}
#endregion
#region Fields
private EdmItemCollection _itemsCSpace ;
private StoreItemCollection _itemsSSpace ;
private ObjectItemCollection _itemsOSpace ;
private StorageMappingItemCollection _itemsCSSpace ;
private DefaultObjectMappingItemCollection _itemsOCSpace ;
private List < object > _cacheTokens ;
private bool _foundAssemblyWithAttribute = false ;
private double _schemaVersion = XmlConstants . UndefinedVersion ;
private Guid _metadataWorkspaceId = Guid . Empty ;
#endregion
#region public static Fields
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Naming", "CA1704:IdentifiersShouldBeSpelledCorrectly", MessageId = "Edm")]
private static IEnumerable < double > SupportedEdmVersions
{
get
{
yield return XmlConstants . UndefinedVersion ;
yield return XmlConstants . EdmVersionForV1 ;
yield return XmlConstants . EdmVersionForV2 ;
Debug . Assert ( XmlConstants . SchemaVersionLatest = = XmlConstants . EdmVersionForV3 , "Did you add a new version?" ) ;
yield return XmlConstants . EdmVersionForV3 ;
}
}
//The Max EDM version thats going to be supported by the runtime.
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Naming", "CA1704:IdentifiersShouldBeSpelledCorrectly", MessageId = "Edm")]
public static readonly double MaximumEdmVersionSupported = SupportedEdmVersions . Last ( ) ;
#endregion
#region Methods
/// <summary>
/// Create an <see cref="eSQL.EntitySqlParser"/> configured to use the <see cref="DataSpace.CSpace"/> data space.
/// </summary>
public eSQL . EntitySqlParser CreateEntitySqlParser ( )
{
return new eSQL . EntitySqlParser ( new ModelPerspective ( this ) ) ;
}
/// <summary>
/// Creates a new <see cref="DbQueryCommandTree"/> bound to this metadata workspace based on the specified query expression.
/// </summary>
/// <param name="query">A <see cref="DbExpression"/> that defines the query</param>
/// <returns>A new <see cref="DbQueryCommandTree"/> with the specified expression as it's <see cref="DbQueryCommandTree.Query"/> property</returns>
/// <exception cref="ArgumentNullException">If <paramref name="query"/> is null</exception>
/// <exception cref="ArgumentException">If <paramref name="query"/> contains metadata that cannot be resolved in this metadata workspace</exception>
/// <exception cref="ArgumentException">If <paramref name="query"/> is not structurally valid because it contains unresolvable variable references</exception>
public DbQueryCommandTree CreateQueryCommandTree ( DbExpression query )
{
return new DbQueryCommandTree ( this , DataSpace . CSpace , query ) ;
}
/// <summary>
/// Get item collection for the space. The ItemCollection is in read only mode as it is
/// part of the workspace.
/// </summary>
/// <param name="dataSpace">The dataspace for the item colelction that should be returned</param>
/// <returns>The item collection for the given space</returns>
/// <exception cref="System.ArgumentNullException">if space argument is null</exception>
/// <exception cref="System.InvalidOperationException">If ItemCollection has not been registered for the space passed in</exception>
[CLSCompliant(false)]
public ItemCollection GetItemCollection ( DataSpace dataSpace )
{
ItemCollection collection = GetItemCollection ( dataSpace , true ) ;
return collection ;
}
/// <summary>
/// Register the item collection for the space associated with it.
/// This should be done only once for a space.
/// If a space already has a registered ItemCollection InvalidOperation exception is thrown
/// </summary>
/// <param name="collection">The out parameter collection that needs to be filled up</param>
/// <returns></returns>
/// <exception cref="System.ArgumentNullException">if collection argument is null</exception>
/// <exception cref="System.InvalidOperationException">If there is an ItemCollection that has already been registered for collection's space passed in</exception>
[CLSCompliant(false)]
public void RegisterItemCollection ( ItemCollection collection )
{
EntityUtil . CheckArgumentNull ( collection , "collection" ) ;
ItemCollection existing ;
try
{
switch ( collection . DataSpace )
{
case DataSpace . CSpace :
if ( null = = ( existing = _itemsCSpace ) ) {
EdmItemCollection edmCollection = ( EdmItemCollection ) collection ;
if ( ! MetadataWorkspace . SupportedEdmVersions . Contains ( edmCollection . EdmVersion ) )
{
throw EntityUtil . InvalidOperation (
System . Data . Entity . Strings . EdmVersionNotSupportedByRuntime (
edmCollection . EdmVersion ,
Helper . GetCommaDelimitedString (
SupportedEdmVersions
. Where ( e = > e ! = XmlConstants . UndefinedVersion )
. Select ( e = > e . ToString ( CultureInfo . InvariantCulture ) ) ) ) ) ;
}
CheckAndSetItemCollectionVersionInWorkSpace ( collection ) ;
_itemsCSpace = edmCollection ;
}
break ;
case DataSpace . SSpace :
if ( null = = ( existing = _itemsSSpace ) )
{
CheckAndSetItemCollectionVersionInWorkSpace ( collection ) ;
_itemsSSpace = ( StoreItemCollection ) collection ;
}
break ;
case DataSpace . OSpace :
if ( null = = ( existing = _itemsOSpace ) ) {
_itemsOSpace = ( ObjectItemCollection ) collection ;
}
break ;
case DataSpace . CSSpace :
if ( null = = ( existing = _itemsCSSpace ) ) {
CheckAndSetItemCollectionVersionInWorkSpace ( collection ) ;
_itemsCSSpace = ( StorageMappingItemCollection ) collection ;
}
break ;
default :
Debug . Assert ( collection . DataSpace = = DataSpace . OCSpace , "Invalid DataSpace Enum value: " + collection . DataSpace ) ;
if ( null = = ( existing = _itemsOCSpace ) ) {
_itemsOCSpace = ( DefaultObjectMappingItemCollection ) collection ;
}
break ;
}
}
catch ( InvalidCastException )
{
throw EntityUtil . InvalidCollectionForMapping ( collection . DataSpace ) ;
}
if ( null ! = existing )
{
throw EntityUtil . ItemCollectionAlreadyRegistered ( collection . DataSpace ) ;
}
// Need to make sure that if the storage mapping Item collection was created with the
// same instances of item collection that are registered for CSpace and SSpace
if ( collection . DataSpace = = DataSpace . CSpace )
{
if ( _itemsCSSpace ! = null & & ! object . ReferenceEquals ( _itemsCSSpace . EdmItemCollection , collection ) )
{
throw EntityUtil . InvalidCollectionSpecified ( collection . DataSpace ) ;
}
}
if ( collection . DataSpace = = DataSpace . SSpace )
{
if ( _itemsCSSpace ! = null & & ! object . ReferenceEquals ( _itemsCSSpace . StoreItemCollection , collection ) )
{
throw EntityUtil . InvalidCollectionSpecified ( collection . DataSpace ) ;
}
}
if ( collection . DataSpace = = DataSpace . CSSpace )
{
if ( _itemsCSpace ! = null & & ! object . ReferenceEquals ( _itemsCSSpace . EdmItemCollection , _itemsCSpace ) )
{
throw EntityUtil . InvalidCollectionSpecified ( collection . DataSpace ) ;
}
if ( _itemsSSpace ! = null & & ! object . ReferenceEquals ( _itemsCSSpace . StoreItemCollection , _itemsSSpace ) )
{
throw EntityUtil . InvalidCollectionSpecified ( collection . DataSpace ) ;
}
}
}
/// <summary>
///
/// </summary>
/// <param name="itemCollectionToRegister"></param>
private void CheckAndSetItemCollectionVersionInWorkSpace ( ItemCollection itemCollectionToRegister )
{
double versionToRegister = XmlConstants . UndefinedVersion ;
string itemCollectionType = null ;
switch ( itemCollectionToRegister . DataSpace )
{
case DataSpace . CSpace :
versionToRegister = ( ( EdmItemCollection ) itemCollectionToRegister ) . EdmVersion ;
itemCollectionType = "EdmItemCollection" ;
break ;
case DataSpace . SSpace :
versionToRegister = ( ( StoreItemCollection ) itemCollectionToRegister ) . StoreSchemaVersion ;
itemCollectionType = "StoreItemCollection" ;
break ;
case DataSpace . CSSpace :
versionToRegister = ( ( StorageMappingItemCollection ) itemCollectionToRegister ) . MappingVersion ;
itemCollectionType = "StorageMappingItemCollection" ;
break ;
default :
// we don't care about other spaces so keep the _versionToRegister to Undefined
break ;
}
if ( versionToRegister ! = this . _schemaVersion & &
versionToRegister ! = XmlConstants . UndefinedVersion & &
this . _schemaVersion ! = XmlConstants . UndefinedVersion )
{
Debug . Assert ( itemCollectionType ! = null ) ;
throw EntityUtil . DifferentSchemaVersionInCollection ( itemCollectionType , versionToRegister , this . _schemaVersion ) ;
}
else
{
this . _schemaVersion = versionToRegister ;
}
}
/// <summary>
/// Add a token for this MetadataWorkspace just so this metadata workspace holds a reference to it, this
/// is for metadata caching to make the workspace marking a particular cache entry is still in used
/// </summary>
/// <param name="token"></param>
internal void AddMetadataEntryToken ( object token )
{
if ( _cacheTokens = = null )
{
_cacheTokens = new List < object > ( ) ;
}
_cacheTokens . Add ( token ) ;
}
/// <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 )
{
LoadFromAssembly ( assembly , null ) ;
}
/// <summary>
/// Load metadata from the given assembly
/// </summary>
/// <param name="assembly">The assembly from which to load metadata</param>
/// <param name="logLoadMessage">The delegate for logging the load messages</param>
/// <exception cref="System.ArgumentNullException">thrown if assembly argument is null</exception>
public void LoadFromAssembly ( Assembly assembly , Action < string > logLoadMessage )
{
EntityUtil . CheckArgumentNull ( assembly , "assembly" ) ;
ObjectItemCollection collection = ( ObjectItemCollection ) GetItemCollection ( DataSpace . OSpace ) ;
ExplicitLoadFromAssembly ( assembly , collection , logLoadMessage ) ;
}
private void ExplicitLoadFromAssembly ( Assembly assembly , ObjectItemCollection collection , Action < string > logLoadMessage )
{
ItemCollection itemCollection ;
if ( ! TryGetItemCollection ( DataSpace . CSpace , out itemCollection ) )
{
itemCollection = null ;
}
collection . ExplicitLoadFromAssembly ( assembly , ( EdmItemCollection ) itemCollection , logLoadMessage ) ;
}
private void ImplicitLoadFromAssembly ( Assembly assembly , ObjectItemCollection collection )
{
if ( ! MetadataAssemblyHelper . ShouldFilterAssembly ( assembly ) )
{
ExplicitLoadFromAssembly ( assembly , collection , 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 into the OSpace ItemCollection.
/// If type comes from known source, has Ecma or Microsoft PublicKeyToken then the type's assembly is not
/// loaded, but the callingAssembly and its referenced assemblies are loaded.
/// </summary>
/// <param name="type">The type's assembly is loaded into the OSpace ItemCollection</param>
/// <param name="callingAssembly">The assembly and its referenced assemblies to load when type is insuffiecent</param>
internal void ImplicitLoadAssemblyForType ( Type type , Assembly callingAssembly )
{
// this exists separately from LoadFromAssembly so that we can handle generics, like IEnumerable<Product>
Debug . Assert ( null ! = type , "null type" ) ;
ItemCollection collection ;
if ( TryGetItemCollection ( DataSpace . OSpace , out collection ) )
{ // if OSpace is not loaded - don't register
ObjectItemCollection objItemCollection = ( ObjectItemCollection ) collection ;
ItemCollection edmItemCollection ;
TryGetItemCollection ( DataSpace . CSpace , out edmItemCollection ) ;
if ( ! objItemCollection . ImplicitLoadAssemblyForType ( type , ( EdmItemCollection ) edmItemCollection ) & & ( null ! = callingAssembly ) )
{
// only load from callingAssembly if all types were filtered
// then loaded referenced assemblies of calling assembly
// attempt automatic discovery of user types
// interesting code paths are ObjectQuery<object>, ObjectQuery<DbDataRecord>, ObjectQuery<IExtendedDataRecord>
// other interesting code paths are ObjectQuery<Nullable<Int32>>, ObjectQuery<IEnumerable<object>>
// when assemblies is mscorlib, System.Data or System.Data.Entity
// If the schema attribute is presented on the assembly or any referenced assemblies, then it is a V1 scenario that we should
// strictly follow the Get all referenced assemblies rules.
// If the attribute is not presented on the assembly, then we won't load the referenced ----sembly
// for this callingAssembly
if ( ObjectItemAttributeAssemblyLoader . IsSchemaAttributePresent ( callingAssembly ) | |
( _foundAssemblyWithAttribute | |
MetadataAssemblyHelper . GetNonSystemReferencedAssemblies ( callingAssembly ) . Any ( a = > ObjectItemAttributeAssemblyLoader . IsSchemaAttributePresent ( a ) ) ) )
{
// cache the knowledge that we found an attribute
// because it can be expesive to figure out
_foundAssemblyWithAttribute = true ;
objItemCollection . ImplicitLoadAllReferencedAssemblies ( callingAssembly , ( EdmItemCollection ) edmItemCollection ) ;
}
else
{
this . ImplicitLoadFromAssembly ( callingAssembly , objItemCollection ) ;
}
}
}
}
/// <summary>
/// If OSpace is not loaded for the specified EntityType
/// the load metadata from the callingAssembly and its referenced assemblies.
/// </summary>
/// <param name="type">The CSPace type to verify its OSpace counterpart is loaded</param>
/// <param name="callingAssembly">The assembly and its referenced assemblies to load when type is insuffiecent</param>
internal void ImplicitLoadFromEntityType ( EntityType type , Assembly callingAssembly )
{
// used by ObjectContext.*GetObjectByKey when the clr type is not available
// so we check the OCMap to find the clr type else attempt to autoload the OSpace from callingAssembly
Debug . Assert ( null ! = type , "null type" ) ;
Map map ;
if ( ! TryGetMap ( type , DataSpace . OCSpace , out map ) )
{ // an OCMap is not exist, attempt to load OSpace to retry
ImplicitLoadAssemblyForType ( typeof ( System . Data . Objects . DataClasses . IEntityWithKey ) , callingAssembly ) ;
// We do a check here to see if the type was actually found in the attempted load.
ObjectItemCollection ospaceCollection = GetItemCollection ( DataSpace . OSpace ) as ObjectItemCollection ;
EdmType ospaceType ;
if ( ospaceCollection = = null | | ! ospaceCollection . TryGetOSpaceType ( type , out ospaceType ) )
{
throw new InvalidOperationException ( System . Data . Entity . Strings . Mapping_Object_InvalidType ( type . Identity ) ) ;
}
}
}
/// <summary>
/// Search for an item with the given identity in the given space.
/// For example, The identity for EdmType is Namespace.Name.
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="identity"></param>
/// <param name="dataSpace"></param>
/// <returns></returns>
/// <exception cref="System.ArgumentNullException">if space argument is null</exception>
/// <exception cref="System.InvalidOperationException">If ItemCollection has not been registered for the space passed in</exception>
/// <exception cref="System.ArgumentNullException">if identity argument passed in is null</exception>
/// <exception cref="System.ArgumentException">If the ItemCollection for this space does not have an item with the given identity</exception>
/// <exception cref="System.ArgumentException">Thrown if the space is not a valid space. Valid space is either C, O, CS or OCSpace</exception>
public T GetItem < T > ( string identity , DataSpace dataSpace ) where T : GlobalItem
{
ItemCollection collection = GetItemCollection ( dataSpace , true ) ;
return collection . GetItem < T > ( identity , false /*ignoreCase*/ ) ;
}
/// <summary>
/// Search for an item with the given identity in the given space.
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="identity"></param>
/// <param name="space"></param>
/// <param name="item"></param>
/// <returns></returns>
/// <exception cref="System.ArgumentNullException">if identity or space argument is null</exception>
public bool TryGetItem < T > ( string identity , DataSpace space , out T item ) where T : GlobalItem
{
item = null ;
ItemCollection collection = GetItemCollection ( space , false ) ;
return ( null ! = collection ) & & collection . TryGetItem < T > ( identity , false /*ignoreCase*/ , out item ) ;
}
/// <summary>
/// Search for an item with the given identity in the given space.
/// For example, The identity for EdmType is Namespace.Name.
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="identity"></param>
/// <param name="ignoreCase"></param>
/// <param name="dataSpace"></param>
/// <returns></returns>
/// <exception cref="System.ArgumentNullException">if space argument is null</exception>
/// <exception cref="System.InvalidOperationException">If ItemCollection has not been registered for the space passed in</exception>
/// <exception cref="System.ArgumentNullException">if identity argument passed in is null</exception>
/// <exception cref="System.ArgumentException">If the ItemCollection for this space does not have an item with the given identity</exception>
/// <exception cref="System.ArgumentException">Thrown if the space is not a valid space. Valid space is either C, O, CS or OCSpace</exception>
public T GetItem < T > ( string identity , bool ignoreCase , DataSpace dataSpace ) where T : GlobalItem
{
ItemCollection collection = GetItemCollection ( dataSpace , true ) ;
return collection . GetItem < T > ( identity , ignoreCase ) ;
}
/// <summary>
/// Search for an item with the given identity in the given space.
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="ignoreCase"></param>
/// <param name="identity"></param>
/// <param name="dataSpace"></param>
/// <param name="item"></param>
/// <returns></returns>
/// <exception cref="System.ArgumentNullException">if identity or space argument is null</exception>
public bool TryGetItem < T > ( string identity , bool ignoreCase , DataSpace dataSpace , out T item ) where T : GlobalItem
{
item = null ;
ItemCollection collection = GetItemCollection ( dataSpace , false ) ;
return ( null ! = collection ) & & collection . TryGetItem < T > ( identity , ignoreCase , out item ) ;
}
/// <summary>
/// Returns ReadOnlyCollection of the Items of the given type
/// in the workspace.
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="dataSpace"></param>
/// <returns></returns>
/// <exception cref="System.ArgumentNullException">if space argument is null</exception>
/// <exception cref="System.InvalidOperationException">If ItemCollection has not been registered for the space passed in</exception>
/// <exception cref="System.ArgumentException">Thrown if the space is not a valid space. Valid space is either C, O, CS or OCSpace</exception>
public ReadOnlyCollection < T > GetItems < T > ( DataSpace dataSpace ) where T : GlobalItem
{
ItemCollection collection = GetItemCollection ( dataSpace , true ) ;
return collection . GetItems < T > ( ) ;
}
/// <summary>
/// Search for a type metadata with the specified name and namespace name in the given space.
/// </summary>
/// <param name="name">name of the type</param>
/// <param name="namespaceName">namespace of the type</param>
/// <param name="dataSpace">Dataspace to search the type for</param>
/// <returns>Returns null if no match found.</returns>
/// <exception cref="System.ArgumentNullException">if space argument is null</exception>
/// <exception cref="System.InvalidOperationException">If ItemCollection has not been registered for the space passed in</exception>
/// <exception cref="System.ArgumentNullException">if name or namespaceName arguments passed in are null</exception>
/// <exception cref="System.ArgumentException">If the ItemCollection for this space does not have a type with the given name and namespaceName</exception>
/// <exception cref="System.ArgumentException">Thrown if the space is not a valid space. Valid space is either C, O, CS or OCSpace</exception>
public EdmType GetType ( string name , string namespaceName , DataSpace dataSpace )
{
ItemCollection collection = GetItemCollection ( dataSpace , true ) ;
return collection . GetType ( name , namespaceName , false /*ignoreCase*/ ) ;
}
/// <summary>
/// Search for a type metadata with the specified name and namespace name in the given space.
/// </summary>
/// <param name="name">name of the type</param>
/// <param name="namespaceName">namespace of the type</param>
/// <param name="dataSpace">Dataspace to search the type for</param>
/// <param name="type">The type that needs to be filled with the return value</param>
/// <returns>Returns false if no match found.</returns>
/// <exception cref="System.ArgumentNullException">if name, namespaceName or space argument is null</exception>
public bool TryGetType ( string name , string namespaceName , DataSpace dataSpace , out EdmType type )
{
type = null ;
ItemCollection collection = GetItemCollection ( dataSpace , false ) ;
return ( null ! = collection ) & & collection . TryGetType ( name , namespaceName , false /*ignoreCase*/ , out type ) ;
}
/// <summary>
/// Search for a type metadata with the specified name and namespace name in the given space.
/// </summary>
/// <param name="name">name of the type</param>
/// <param name="namespaceName">namespace of the type</param>
/// <param name="ignoreCase"></param>
/// <param name="dataSpace">Dataspace to search the type for</param>
/// <returns>Returns null if no match found.</returns>
/// <exception cref="System.ArgumentNullException">if space argument is null</exception>
/// <exception cref="System.InvalidOperationException">If ItemCollection has not been registered for the space passed in</exception>
/// <exception cref="System.ArgumentNullException">if name or namespaceName arguments passed in are null</exception>
/// <exception cref="System.ArgumentException">If the ItemCollection for this space does not have a type with the given name and namespaceName</exception>
/// <exception cref="System.ArgumentException">Thrown if the space is not a valid space. Valid space is either C, O, CS or OCSpace</exception>
public EdmType GetType ( string name , string namespaceName , bool ignoreCase , DataSpace dataSpace )
{
ItemCollection collection = GetItemCollection ( dataSpace , true ) ;
return collection . GetType ( name , namespaceName , ignoreCase ) ;
}
/// <summary>
/// Search for a type metadata with the specified name and namespace name in the given space.
/// </summary>
/// <param name="name">name of the type</param>
/// <param name="namespaceName">namespace of the type</param>
/// <param name="dataSpace">Dataspace to search the type for</param>
/// <param name="ignoreCase"></param>
/// <param name="type">The type that needs to be filled with the return value</param>
/// <returns>Returns null if no match found.</returns>
/// <exception cref="System.ArgumentNullException">if name, namespaceName or space argument is null</exception>
public bool TryGetType ( string name , string namespaceName , bool ignoreCase ,
DataSpace dataSpace , out EdmType type )
{
type = null ;
ItemCollection collection = GetItemCollection ( dataSpace , false ) ;
return ( null ! = collection ) & & collection . TryGetType ( name , namespaceName , ignoreCase , out type ) ;
}
/// <summary>
/// Get an entity container based upon the strong name of the container
/// If no entity container is found, returns null, else returns the first one/// </summary>
/// <param name="name">name of the entity container</param>
/// <param name="dataSpace"></param>
/// <returns>The EntityContainer</returns>
/// <exception cref="System.ArgumentNullException">if space argument is null</exception>
/// <exception cref="System.InvalidOperationException">If ItemCollection has not been registered for the space passed in</exception>
/// <exception cref="System.ArgumentNullException">if name argument passed in is null</exception>
/// <exception cref="System.ArgumentException">If the ItemCollection for this space does not have a EntityContainer with the given name</exception>
/// <exception cref="System.ArgumentException">Thrown if the space is not a valid space. Valid space is either C, O, CS or OCSpace</exception>
public EntityContainer GetEntityContainer ( string name , DataSpace dataSpace )
{
ItemCollection collection = GetItemCollection ( dataSpace , true ) ;
return collection . GetEntityContainer ( name ) ;
}
/// <summary>
/// Get an entity container based upon the strong name of the container
/// If no entity container is found, returns null, else returns the first one/// </summary>
/// <param name="name">name of the entity container</param>
/// <param name="dataSpace"></param>
/// <param name="entityContainer"></param>
/// <exception cref="System.ArgumentNullException">if either space or name arguments is null</exception>
public bool TryGetEntityContainer ( string name , DataSpace dataSpace , out EntityContainer entityContainer )
{
entityContainer = null ;
// null check exists in call stack, but throws for "identity" not "name"
EntityUtil . GenericCheckArgumentNull ( name , "name" ) ;
ItemCollection collection = GetItemCollection ( dataSpace , false ) ;
return ( null ! = collection ) & & collection . TryGetEntityContainer ( name , out entityContainer ) ;
}
/// <summary>
/// Get an entity container based upon the strong name of the container
/// If no entity container is found, returns null, else returns the first one/// </summary>
/// <param name="name">name of the entity container</param>
/// <param name="ignoreCase">true for case-insensitive lookup</param>
/// <param name="dataSpace"></param>
/// <returns>The EntityContainer</returns>
/// <exception cref="System.ArgumentNullException">if space argument is null</exception>
/// <exception cref="System.InvalidOperationException">If ItemCollection has not been registered for the space passed in</exception>
/// <exception cref="System.ArgumentNullException">if name argument passed in is null</exception>
/// <exception cref="System.ArgumentException">If the ItemCollection for this space does not have a EntityContainer with the given name</exception>
/// <exception cref="System.ArgumentException">Thrown if the space is not a valid space. Valid space is either C, O, CS or OCSpace</exception>
public EntityContainer GetEntityContainer ( string name , bool ignoreCase , DataSpace dataSpace )
{
ItemCollection collection = GetItemCollection ( dataSpace , true ) ;
return collection . GetEntityContainer ( name , ignoreCase ) ;
}
/// <summary>
/// Get an entity container based upon the strong name of the container
/// If no entity container is found, returns null, else returns the first one/// </summary>
/// <param name="name">name of the entity container</param>
/// <param name="ignoreCase">true for case-insensitive lookup</param>
/// <param name="dataSpace"></param>
/// <param name="entityContainer"></param>
/// <exception cref="System.ArgumentNullException">if name or space argument is null</exception>
public bool TryGetEntityContainer ( string name , bool ignoreCase ,
DataSpace dataSpace , out EntityContainer entityContainer )
{
entityContainer = null ;
// null check exists in call stack, but throws for "identity" not "name"
EntityUtil . GenericCheckArgumentNull ( name , "name" ) ;
ItemCollection collection = GetItemCollection ( dataSpace , false ) ;
return ( null ! = collection ) & & collection . TryGetEntityContainer ( name , ignoreCase , out entityContainer ) ;
}
/// <summary>
/// Get all the overloads of the function with the given name
/// </summary>
/// <param name="name">name of the function</param>
/// <param name="namespaceName">namespace of the function</param>
/// <param name="dataSpace">The dataspace for which we need to get the function for</param>
/// <returns>A collection of all the functions with the given name in the given data space</returns>
/// <exception cref="System.ArgumentNullException">if space argument is null</exception>
/// <exception cref="System.ArgumentNullException">if name or namespaceName argument is null</exception>
/// <exception cref="System.InvalidOperationException">If ItemCollection has not been registered for the space passed in</exception>
/// <exception cref="System.ArgumentNullException">if functionName argument passed in is null</exception>
/// <exception cref="System.ArgumentException">If the ItemCollection for this space does not have a EdmFunction with the given functionName</exception>
/// <exception cref="System.ArgumentException">If the name or namespaceName is empty</exception>
/// <exception cref="System.ArgumentException">Thrown if the space is not a valid space. Valid space is either C, O, CS or OCSpace</exception>
public ReadOnlyCollection < EdmFunction > GetFunctions ( string name , string namespaceName , DataSpace dataSpace )
{
return GetFunctions ( name , namespaceName , dataSpace , false /*ignoreCase*/ ) ;
}
/// <summary>
/// Get all the overloads of the function with the given name
/// </summary>
/// <param name="name">name of the function</param>
/// <param name="namespaceName">namespace of the function</param>
/// <param name="dataSpace">The dataspace for which we need to get the function for</param>
/// <param name="ignoreCase">true for case-insensitive lookup</param>
/// <returns>A collection of all the functions with the given name in the given data space</returns>
/// <exception cref="System.ArgumentNullException">if space argument is null</exception>
/// <exception cref="System.ArgumentNullException">if name or namespaceName argument is null</exception>
/// <exception cref="System.InvalidOperationException">If ItemCollection has not been registered for the space passed in</exception>
/// <exception cref="System.ArgumentNullException">if functionName argument passed in is null</exception>
/// <exception cref="System.ArgumentException">If the ItemCollection for this space does not have a EdmFunction with the given functionName</exception>
/// <exception cref="System.ArgumentException">If the name or namespaceName is empty</exception>
/// <exception cref="System.ArgumentException">Thrown if the space is not a valid space. Valid space is either C, O, CS or OCSpace</exception>
public ReadOnlyCollection < EdmFunction > GetFunctions ( string name ,
string namespaceName ,
DataSpace dataSpace ,
bool ignoreCase )
{
EntityUtil . CheckStringArgument ( name , "name" ) ;
EntityUtil . CheckStringArgument ( namespaceName , "namespaceName" ) ;
ItemCollection collection = GetItemCollection ( dataSpace , true ) ;
// Get the function with this full name, which is namespace name plus name
return collection . GetFunctions ( namespaceName + "." + name , ignoreCase ) ;
}
/// <summary>
/// Gets the function as specified by the function key.
/// All parameters are assumed to be <see cref="ParameterMode.In"/>.
/// </summary>
/// <param name="name">name of the function</param>
/// <param name="namespaceName">namespace of the function</param>
/// <param name="parameterTypes">types of the parameters</param>
/// <param name="ignoreCase">true for case-insensitive lookup</param>
/// <param name="dataSpace"></param>
/// <param name="function">The function that needs to be returned</param>
/// <returns> The function as specified in the function key or null</returns>
/// <exception cref="System.ArgumentNullException">if name, namespaceName, parameterTypes or space argument is null</exception>
internal bool TryGetFunction ( string name ,
string namespaceName ,
TypeUsage [ ] parameterTypes ,
bool ignoreCase ,
DataSpace dataSpace ,
out EdmFunction function )
{
function = null ;
EntityUtil . GenericCheckArgumentNull ( name , "name" ) ;
EntityUtil . GenericCheckArgumentNull ( namespaceName , "namespaceName" ) ;
ItemCollection collection = GetItemCollection ( dataSpace , false ) ;
// Get the function with this full name, which is namespace name plus name
return ( null ! = collection ) & & collection . TryGetFunction ( namespaceName + "." + name , parameterTypes , ignoreCase , out function ) ;
}
/// <summary>
/// Get the list of primitive types for the given space
/// </summary>
/// <param name="dataSpace">dataspace for which you need the list of primitive types</param>
/// <returns></returns>
/// <exception cref="System.ArgumentNullException">if space argument is null</exception>
/// <exception cref="System.InvalidOperationException">If ItemCollection has not been registered for the space passed in</exception>
/// <exception cref="System.ArgumentException">Thrown if the space is not a valid space. Valid space is either C, O, CS or OCSpace</exception>
public ReadOnlyCollection < PrimitiveType > GetPrimitiveTypes ( DataSpace dataSpace )
{
ItemCollection collection = GetItemCollection ( dataSpace , true ) ;
return collection . GetItems < PrimitiveType > ( ) ;
}
/// <summary>
/// Get all the items in the data space
/// </summary>
/// <param name="dataSpace">dataspace for which you need the list of items</param>
/// <returns></returns>
/// <exception cref="System.ArgumentNullException">if space argument is null</exception>
/// <exception cref="System.InvalidOperationException">If ItemCollection has not been registered for the space passed in</exception>
/// <exception cref="System.ArgumentException">Thrown if the space is not a valid space. Valid space is either C, O, CS or OCSpace</exception>
public ReadOnlyCollection < GlobalItem > GetItems ( DataSpace dataSpace )
{
ItemCollection collection = GetItemCollection ( dataSpace , true ) ;
return collection . GetItems < GlobalItem > ( ) ;
}
/// <summary>
/// Given the canonical primitive type, get the mapping primitive type in the given dataspace
/// </summary>
/// <param name="primitiveTypeKind">primitive type kind</param>
/// <param name="dataSpace">dataspace in which one needs to the mapping primitive types</param>
/// <returns>The mapped scalar type</returns>
/// <exception cref="System.ArgumentNullException">if space argument is null</exception>
/// <exception cref="System.InvalidOperationException">If ItemCollection has not been registered for the space passed in</exception>
/// <exception cref="System.ArgumentException">Thrown if the space is not a valid space. Valid space is either C, O, CS or OCSpace</exception>
internal PrimitiveType GetMappedPrimitiveType ( PrimitiveTypeKind primitiveTypeKind , DataSpace dataSpace )
{
ItemCollection collection = GetItemCollection ( dataSpace , true ) ;
return collection . GetMappedPrimitiveType ( primitiveTypeKind ) ;
}
/// <summary>
/// Search for a Mapping metadata with the specified type key.
/// </summary>
/// <param name="typeIdentity">type</param>
/// <param name="typeSpace">The dataspace that the type for which map needs to be returned belongs to</param>
/// <param name="ignoreCase">true for case-insensitive lookup</param>
/// <param name="mappingSpace">space for which you want to get the mapped type</param>
/// <param name="map"></param>
/// <returns>Returns false if no match found.</returns>
internal bool TryGetMap ( string typeIdentity , DataSpace typeSpace , bool ignoreCase , DataSpace mappingSpace , out Map map )
{
map = null ;
ItemCollection collection = GetItemCollection ( mappingSpace , false ) ;
return ( null ! = collection ) & & ( ( MappingItemCollection ) collection ) . TryGetMap ( typeIdentity , typeSpace , ignoreCase , out map ) ;
}
/// <summary>
/// Search for a Mapping metadata with the specified type key.
/// </summary>
/// <param name="identity">typeIdentity of the type</param>
/// <param name="typeSpace">The dataspace that the type for which map needs to be returned belongs to</param>
/// <param name="dataSpace">space for which you want to get the mapped type</param>
/// <exception cref="ArgumentException"> Thrown if mapping space is not valid</exception>
internal Map GetMap ( string identity , DataSpace typeSpace , DataSpace dataSpace )
{
ItemCollection collection = GetItemCollection ( dataSpace , true ) ;
return ( ( MappingItemCollection ) collection ) . GetMap ( identity , typeSpace ) ;
}
/// <summary>
/// Search for a Mapping metadata with the specified type key.
/// </summary>
/// <param name="item"></param>
/// <param name="dataSpace">space for which you want to get the mapped type</param>
/// <exception cref="ArgumentException"> Thrown if mapping space is not valid</exception>
internal Map GetMap ( GlobalItem item , DataSpace dataSpace )
{
ItemCollection collection = GetItemCollection ( dataSpace , true ) ;
return ( ( MappingItemCollection ) collection ) . GetMap ( item ) ;
}
/// <summary>
/// Search for a Mapping metadata with the specified type key.
/// </summary>
/// <param name="item"></param>
/// <param name="dataSpace">space for which you want to get the mapped type</param>
/// <param name="map"></param>
/// <returns>Returns false if no match found.</returns>
internal bool TryGetMap ( GlobalItem item , DataSpace dataSpace , out Map map )
{
map = null ;
ItemCollection collection = GetItemCollection ( dataSpace , false ) ;
return ( null ! = collection ) & & ( ( MappingItemCollection ) collection ) . TryGetMap ( item , out map ) ;
}
private ItemCollection RegisterDefaultObjectMappingItemCollection ( )
{
EdmItemCollection edm = _itemsCSpace as EdmItemCollection ;
ObjectItemCollection obj = _itemsOSpace as ObjectItemCollection ;
if ( ( null ! = edm ) & & ( null ! = obj ) )
{
RegisterItemCollection ( new DefaultObjectMappingItemCollection ( edm , obj ) ) ;
}
return _itemsOCSpace ;
}
/// <summary>
/// Get item collection for the space, if registered. If returned, the ItemCollection is in read only mode as it is
/// part of the workspace.
/// </summary>
/// <param name="dataSpace">The dataspace for the item collection that should be returned</param>
/// <param name="collection">The collection registered for the specified dataspace, if any</param>
/// <returns><c>true</c> if an item collection is currently registered for the specified space; otherwise <c>false</c>.</returns>
/// <exception cref="System.ArgumentNullException">if space argument is null</exception>
[CLSCompliant(false)]
public bool TryGetItemCollection ( DataSpace dataSpace , out ItemCollection collection )
{
collection = GetItemCollection ( dataSpace , false ) ;
return ( null ! = collection ) ;
}
/// <summary>
/// Checks if the space is valid and whether the collection is registered for the given space, and if both are valid,
/// then returns the itemcollection for the given space
/// </summary>
/// <param name="dataSpace"></param>
/// <param name="required">if true, will throw</param>
/// <exception cref="ArgumentException">Thrown if required and mapping space is not valid or registered</exception>
internal ItemCollection GetItemCollection ( DataSpace dataSpace , bool required )
{
ItemCollection collection ;
switch ( dataSpace )
{
case DataSpace . CSpace :
collection = _itemsCSpace ;
break ;
case DataSpace . OSpace :
collection = _itemsOSpace ;
break ;
case DataSpace . OCSpace :
collection = _itemsOCSpace ? ? RegisterDefaultObjectMappingItemCollection ( ) ;
break ;
case DataSpace . CSSpace :
collection = _itemsCSSpace ;
break ;
case DataSpace . SSpace :
collection = _itemsSSpace ;
break ;
default :
if ( required ) {
Debug . Fail ( "Invalid DataSpace Enum value: " + dataSpace ) ;
}
collection = null ;
break ;
}
if ( required & & ( null = = collection ) ) {
throw EntityUtil . NoCollectionForSpace ( dataSpace ) ;
}
return collection ;
}
/// <summary>
/// The method returns the OSpace structural type mapped to the specified Edm Space Type.
/// If the DataSpace of the argument is not CSpace, or the mapped OSpace type
/// cannot be determined, an ArgumentException is thrown.
/// </summary>
/// <param name="edmSpaceType">The CSpace type to look up</param>
/// <returns>The OSpace type mapped to the supplied argument</returns>
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Naming", "CA1704:IdentifiersShouldBeSpelledCorrectly", MessageId = "edm")]
public StructuralType GetObjectSpaceType ( StructuralType edmSpaceType )
{
return GetObjectSpaceType < StructuralType > ( edmSpaceType ) ;
}
/// <summary>
/// This method returns the OSpace structural type mapped to the specified Edm Space Type.
/// If the DataSpace of the argument is not CSpace, or if the mapped OSpace type
/// cannot be determined, the method returns false and sets the out parameter
/// to null.
/// </summary>
/// <param name="edmSpaceType">The CSpace type to look up</param>
/// <param name="objectSpaceType">The OSpace type mapped to the supplied argument</param>
/// <returns>true on success, false on failure</returns>
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1011:ConsiderPassingBaseTypesAsParameters"), System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Naming", "CA1704:IdentifiersShouldBeSpelledCorrectly", MessageId = "edm")]
public bool TryGetObjectSpaceType ( StructuralType edmSpaceType , out StructuralType objectSpaceType )
{
return TryGetObjectSpaceType < StructuralType > ( edmSpaceType , out objectSpaceType ) ;
}
/// <summary>
/// The method returns the OSpace enum type mapped to the specified Edm Space Type.
/// If the DataSpace of the argument is not CSpace, or the mapped OSpace type
/// cannot be determined, an ArgumentException is thrown.
/// </summary>
/// <param name="edmSpaceType">The CSpace type to look up</param>
/// <returns>The OSpace type mapped to the supplied argument</returns>
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Naming", "CA1704:IdentifiersShouldBeSpelledCorrectly", MessageId = "edm")]
public EnumType GetObjectSpaceType ( EnumType edmSpaceType )
{
return GetObjectSpaceType < EnumType > ( edmSpaceType ) ;
}
/// <summary>
/// This method returns the OSpace enum type mapped to the specified Edm Space Type.
/// If the DataSpace of the argument is not CSpace, or if the mapped OSpace type
/// cannot be determined, the method returns false and sets the out parameter
/// to null.
/// </summary>
/// <param name="edmSpaceType">The CSpace type to look up</param>
/// <param name="objectSpaceType">The OSpace type mapped to the supplied argument</param>
/// <returns>true on success, false on failure</returns>
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1011:ConsiderPassingBaseTypesAsParameters"), System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Naming", "CA1704:IdentifiersShouldBeSpelledCorrectly", MessageId = "edm")]
public bool TryGetObjectSpaceType ( EnumType edmSpaceType , out EnumType objectSpaceType )
{
return TryGetObjectSpaceType < EnumType > ( edmSpaceType , out objectSpaceType ) ;
}
/// <summary>
/// Helper method returning the OSpace enum type mapped to the specified Edm Space Type.
/// If the DataSpace of the argument is not CSpace, or the mapped OSpace type
/// cannot be determined, an ArgumentException is thrown.
/// </summary>
/// <param name="edmSpaceType">The CSpace type to look up</param>
/// <returns>The OSpace type mapped to the supplied argument</returns>
/// <typeparam name="T">Must be StructuralType or EnumType.</typeparam>
private T GetObjectSpaceType < T > ( T edmSpaceType )
where T : EdmType
{
Debug . Assert (
edmSpaceType = = null | | edmSpaceType is StructuralType | | edmSpaceType is EnumType ,
"Only structural or enum type expected" ) ;
T objectSpaceType ;
if ( ! this . TryGetObjectSpaceType ( edmSpaceType , out objectSpaceType ) )
{
throw EntityUtil . Argument ( Strings . FailedToFindOSpaceTypeMapping ( edmSpaceType . Identity ) ) ;
}
return objectSpaceType ;
}
/// <summary>
/// Helper method returning the OSpace structural or enum type mapped to the specified Edm Space Type.
/// If the DataSpace of the argument is not CSpace, or if the mapped OSpace type
/// cannot be determined, the method returns false and sets the out parameter
/// to null.
/// </summary>
/// <param name="edmSpaceType">The CSpace type to look up</param>
/// <param name="objectSpaceType">The OSpace type mapped to the supplied argument</param>
/// <returns>true on success, false on failure</returns>
/// <typeparam name="T">Must be StructuralType or EnumType.</typeparam>
private bool TryGetObjectSpaceType < T > ( T edmSpaceType , out T objectSpaceType )
where T : EdmType
{
Debug . Assert (
edmSpaceType = = null | | edmSpaceType is StructuralType | | edmSpaceType is EnumType ,
"Only structural or enum type expected" ) ;
EntityUtil . CheckArgumentNull ( edmSpaceType , "edmSpaceType" ) ;
if ( edmSpaceType . DataSpace ! = DataSpace . CSpace )
{
throw EntityUtil . Argument ( Strings . ArgumentMustBeCSpaceType , "edmSpaceType" ) ;
}
objectSpaceType = null ;
Map map ;
if ( this . TryGetMap ( edmSpaceType , DataSpace . OCSpace , out map ) )
{
ObjectTypeMapping ocMap = map as ObjectTypeMapping ;
if ( ocMap ! = null )
{
objectSpaceType = ( T ) ocMap . ClrType ;
}
}
return objectSpaceType ! = null ;
}
/// <summary>
/// This method returns the Edm Space structural type mapped to the OSpace Type parameter. If the
/// DataSpace of the supplied type is not OSpace, or the mapped Edm Space type cannot
/// be determined, an ArgumentException is thrown.
/// </summary>
/// <param name="objectSpaceType">The OSpace type to look up</param>
/// <returns>The CSpace type mapped to the OSpace parameter</returns>
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Naming", "CA1704:IdentifiersShouldBeSpelledCorrectly", MessageId = "Edm")]
public StructuralType GetEdmSpaceType ( StructuralType objectSpaceType )
{
return GetEdmSpaceType < StructuralType > ( objectSpaceType ) ;
}
/// <summary>
/// This method returns the Edm Space structural type mapped to the OSpace Type parameter. If the
/// DataSpace of the supplied type is not OSpace, or the mapped Edm Space type cannot
/// be determined, the method returns false and sets the out parameter to null.
/// </summary>
/// <param name="objectSpaceType">The OSpace type to look up</param>
/// <param name="edmSpaceType">The mapped CSpace type</param>
/// <returns>true on success, false on failure</returns>
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Naming", "CA1704:IdentifiersShouldBeSpelledCorrectly", MessageId = "edm"), System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Naming", "CA1704:IdentifiersShouldBeSpelledCorrectly", MessageId = "Edm")]
public bool TryGetEdmSpaceType ( StructuralType objectSpaceType , out StructuralType edmSpaceType )
{
return TryGetEdmSpaceType < StructuralType > ( objectSpaceType , out edmSpaceType ) ;
}
/// <summary>
/// This method returns the Edm Space enum type mapped to the OSpace Type parameter. If the
/// DataSpace of the supplied type is not OSpace, or the mapped Edm Space type cannot
/// be determined, an ArgumentException is thrown.
/// </summary>
/// <param name="objectSpaceType">The OSpace type to look up</param>
/// <returns>The CSpace type mapped to the OSpace parameter</returns>
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Naming", "CA1704:IdentifiersShouldBeSpelledCorrectly", MessageId = "Edm")]
public EnumType GetEdmSpaceType ( EnumType objectSpaceType )
{
return GetEdmSpaceType < EnumType > ( objectSpaceType ) ;
}
/// <summary>
/// This method returns the Edm Space enum type mapped to the OSpace Type parameter. If the
/// DataSpace of the supplied type is not OSpace, or the mapped Edm Space type cannot
/// be determined, the method returns false and sets the out parameter to null.
/// </summary>
/// <param name="objectSpaceType">The OSpace type to look up</param>
/// <param name="edmSpaceType">The mapped CSpace type</param>
/// <returns>true on success, false on failure</returns>
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Naming", "CA1704:IdentifiersShouldBeSpelledCorrectly", MessageId = "edm"), System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Naming", "CA1704:IdentifiersShouldBeSpelledCorrectly", MessageId = "Edm")]
public bool TryGetEdmSpaceType ( EnumType objectSpaceType , out EnumType edmSpaceType )
{
return TryGetEdmSpaceType < EnumType > ( objectSpaceType , out edmSpaceType ) ;
}
/// <summary>
/// Helper method returning the Edm Space structural or enum type mapped to the OSpace Type parameter. If the
/// DataSpace of the supplied type is not OSpace, or the mapped Edm Space type cannot
/// be determined, an ArgumentException is thrown.
/// </summary>
/// <param name="objectSpaceType">The OSpace type to look up</param>
/// <returns>The CSpace type mapped to the OSpace parameter</returns>
/// <typeparam name="T">Must be StructuralType or EnumType</typeparam>
private T GetEdmSpaceType < T > ( T objectSpaceType )
where T : EdmType
{
Debug . Assert (
objectSpaceType = = null | | objectSpaceType is StructuralType | | objectSpaceType is EnumType ,
"Only structural or enum type expected" ) ;
T edmSpaceType ;
if ( ! this . TryGetEdmSpaceType ( objectSpaceType , out edmSpaceType ) )
{
throw EntityUtil . Argument ( Strings . FailedToFindCSpaceTypeMapping ( objectSpaceType . Identity ) ) ;
}
return edmSpaceType ;
}
/// <summary>
/// Helper method returning the Edm Space structural or enum type mapped to the OSpace Type parameter. If the
/// DataSpace of the supplied type is not OSpace, or the mapped Edm Space type cannot
/// be determined, the method returns false and sets the out parameter to null.
/// </summary>
/// <param name="objectSpaceType">The OSpace type to look up</param>
/// <param name="edmSpaceType">The mapped CSpace type</param>
/// <returns>true on success, false on failure</returns>
/// <typeparam name="T">Must be StructuralType or EnumType</typeparam>
private bool TryGetEdmSpaceType < T > ( T objectSpaceType , out T edmSpaceType )
where T : EdmType
{
Debug . Assert (
objectSpaceType = = null | | objectSpaceType is StructuralType | | objectSpaceType is EnumType ,
"Only structural or enum type expected" ) ;
EntityUtil . CheckArgumentNull ( objectSpaceType , "objectSpaceType" ) ;
if ( objectSpaceType . DataSpace ! = DataSpace . OSpace )
{
throw EntityUtil . Argument ( Strings . ArgumentMustBeOSpaceType , "objectSpaceType" ) ;
}
edmSpaceType = null ;
Map map ;
if ( this . TryGetMap ( objectSpaceType , DataSpace . OCSpace , out map ) )
{
ObjectTypeMapping ocMap = map as ObjectTypeMapping ;
if ( ocMap ! = null )
{
edmSpaceType = ( T ) ocMap . EdmType ;
}
}
return edmSpaceType ! = null ;
}
///// <summary>
///// Returns the update or query view for an Extent as a
///// command tree. For a given Extent, MetadataWorkspace will
///// have either a Query view or an Update view but not both.
///// </summary>
///// <param name="extent"></param>
///// <returns></returns>
internal DbQueryCommandTree GetCqtView ( EntitySetBase extent )
{
return GetGeneratedView ( extent ) . GetCommandTree ( ) ;
}
/// <summary>
/// Returns generated update or query view for the given extent.
/// </summary>
internal GeneratedView GetGeneratedView ( EntitySetBase extent )
{
ItemCollection collection = GetItemCollection ( DataSpace . CSSpace , true ) ;
return ( ( StorageMappingItemCollection ) collection ) . GetGeneratedView ( extent , this ) ;
}
/// <summary>
/// Returns a TypeOf/TypeOfOnly Query for a given Extent and Type as a command tree.
/// </summary>
/// <param name="extent"></param>
/// <returns></returns>
internal bool TryGetGeneratedViewOfType ( EntitySetBase extent , EntityTypeBase type , bool includeSubtypes , out GeneratedView generatedView )
{
ItemCollection collection = GetItemCollection ( DataSpace . CSSpace , true ) ;
return ( ( StorageMappingItemCollection ) collection ) . TryGetGeneratedViewOfType ( this , extent , type , includeSubtypes , out generatedView ) ;
}
/// <summary>
/// Returns generated function definition for the given function.
/// Guarantees type match of declaration and generated parameters.
/// Guarantees return type match.
/// Throws internal error for functions without definition.
/// Passes thru exception occured during definition generation.
/// </summary>
internal DbLambda GetGeneratedFunctionDefinition ( EdmFunction function )
{
ItemCollection collection = GetItemCollection ( DataSpace . CSpace , true ) ;
return ( ( EdmItemCollection ) collection ) . GetGeneratedFunctionDefinition ( function ) ;
}
/// <summary>
/// Determines if a target function exists for the given function import.
/// </summary>
/// <param name="functionImport">Function import (function declared in a model entity container)</param>
/// <param name="targetFunctionMapping">Function target mapping (function to which the import is mapped in the target store)</param>
/// <returns>true if a mapped target function exists; false otherwise</returns>
internal bool TryGetFunctionImportMapping ( EdmFunction functionImport , out FunctionImportMapping targetFunctionMapping )
{
Debug . Assert ( null ! = functionImport ) ;
ReadOnlyCollection < StorageEntityContainerMapping > entityContainerMaps = this . GetItems < StorageEntityContainerMapping > ( DataSpace . CSSpace ) ;
foreach ( StorageEntityContainerMapping containerMapping in entityContainerMaps )
{
if ( containerMapping . TryGetFunctionImportMapping ( functionImport , out targetFunctionMapping ) )
{
return true ;
}
}
targetFunctionMapping = null ;
return false ;
}
/// <summary>
/// Returns the view loader associated with this workspace,
/// creating a loader if non exists. The loader includes
/// context information used by the update pipeline when
/// processing changes to C-space extents.
/// </summary>
/// <returns></returns>
internal ViewLoader GetUpdateViewLoader ( )
{
if ( _itemsCSSpace ! = null )
{
return _itemsCSSpace . GetUpdateViewLoader ( ) ;
}
return null ;
}
/// <summary>
/// Takes in a Edm space type usage and converts into an
/// equivalent O space type usage
/// </summary>
/// <param name="edmSpaceTypeUsage"></param>
/// <returns></returns>
internal TypeUsage GetOSpaceTypeUsage ( TypeUsage edmSpaceTypeUsage )
{
EntityUtil . CheckArgumentNull ( edmSpaceTypeUsage , "edmSpaceTypeUsage" ) ;
Debug . Assert ( edmSpaceTypeUsage . EdmType ! = null , "The TypeUsage object does not have an EDMType." ) ;
EdmType clrType = null ;
if ( Helper . IsPrimitiveType ( edmSpaceTypeUsage . EdmType ) )
{
ItemCollection collection = GetItemCollection ( DataSpace . OSpace , true ) ;
clrType = collection . GetMappedPrimitiveType ( ( ( PrimitiveType ) edmSpaceTypeUsage . EdmType ) . PrimitiveTypeKind ) ;
}
else
{
// Check and throw if the OC space doesn't exist
ItemCollection collection = GetItemCollection ( DataSpace . OCSpace , true ) ;
// Get the OC map
Map map = ( ( DefaultObjectMappingItemCollection ) collection ) . GetMap ( edmSpaceTypeUsage . EdmType ) ;
clrType = ( ( ObjectTypeMapping ) map ) . ClrType ;
}
Debug . Assert ( ! Helper . IsPrimitiveType ( clrType ) | |
object . ReferenceEquals ( ClrProviderManifest . Instance . GetFacetDescriptions ( clrType ) ,
EdmProviderManifest . Instance . GetFacetDescriptions ( clrType . BaseType ) ) ,
"these are no longer equal so we can't just use the same set of facets for the new type usage" ) ;
// Transfer the facet values
TypeUsage result = TypeUsage . Create ( clrType , edmSpaceTypeUsage . Facets ) ;
return result ;
}
/// <summary>
/// Returns true if the item collection for the given space has already been registered else returns false
/// </summary>
/// <param name="dataSpace"></param>
/// <returns></returns>
internal bool IsItemCollectionAlreadyRegistered ( DataSpace dataSpace )
{
ItemCollection itemCollection ;
return TryGetItemCollection ( dataSpace , out itemCollection ) ;
}
/// <summary>
/// Requires: C, S and CS are registered in this and other
/// Determines whether C, S and CS are equivalent. Useful in determining whether a DbCommandTree
/// is usable within a particular entity connection.
/// </summary>
/// <param name="other">Other workspace.</param>
/// <returns>true is C, S and CS collections are equivalent</returns>
internal bool IsMetadataWorkspaceCSCompatible ( MetadataWorkspace other )
{
Debug . Assert ( this . IsItemCollectionAlreadyRegistered ( DataSpace . CSSpace ) & &
other . IsItemCollectionAlreadyRegistered ( DataSpace . CSSpace ) ,
"requires: C, S and CS are registered in this and other" ) ;
bool result = this . _itemsCSSpace . MetadataEquals ( other . _itemsCSSpace ) ;
Debug . Assert ( ! result | |
( this . _itemsCSpace . MetadataEquals ( other . _itemsCSpace ) & & this . _itemsSSpace . MetadataEquals ( other . _itemsSSpace ) ) ,
"constraint: this.CS == other.CS --> this.S == other.S && this.C == other.C" ) ;
return result ;
}
/// <summary>
/// Clear all the metadata cache entries
/// </summary>
public static void ClearCache ( )
{
MetadataCache . Clear ( ) ;
ObjectItemCollection . ViewGenerationAssemblies . Clear ( ) ;
using ( LockedAssemblyCache cache = AssemblyCache . AquireLockedAssemblyCache ( ) )
{
cache . Clear ( ) ;
}
}
/// <summary>
/// Creates a new Metadata workspace sharing the (currently defined) item collections
/// and tokens for caching purposes.
/// </summary>
/// <returns></returns>
internal MetadataWorkspace ShallowCopy ( )
{
MetadataWorkspace copy = ( MetadataWorkspace ) MemberwiseClone ( ) ;
if ( null ! = copy . _cacheTokens ) {
copy . _cacheTokens = new List < Object > ( copy . _cacheTokens ) ;
}
return copy ;
}
/// <summary>
/// Returns the canonical Model TypeUsage for a given PrimitiveTypeKind
/// </summary>
/// <param name="primitiveTypeKind">PrimitiveTypeKind for which a canonical TypeUsage is expected</param>
/// <returns>a canonical model TypeUsage</returns>
internal TypeUsage GetCanonicalModelTypeUsage ( PrimitiveTypeKind primitiveTypeKind )
{
return EdmProviderManifest . Instance . GetCanonicalModelTypeUsage ( primitiveTypeKind ) ;
}
/// <summary>
/// Returns the Model PrimitiveType for a given primitiveTypeKind
/// </summary>
/// <param name="primitiveTypeKind">a PrimitiveTypeKind for which a Model PrimitiveType is expected</param>
/// <returns>Model PrimitiveType</returns>
internal PrimitiveType GetModelPrimitiveType ( PrimitiveTypeKind primitiveTypeKind )
{
return EdmProviderManifest . Instance . GetPrimitiveType ( primitiveTypeKind ) ;
}
// GetRequiredOriginalValueMembers and GetRelevantMembersForUpdate return list of "interesting" members for the given EntitySet/EntityType
// Interesting Members are a subset of the following:
// 0. Key members
// 1. Members with C-Side conditions (complex types can not have C-side condition at present)
// 2. Members participating in association end
// 3. Members with ConcurrencyMode 'Fixed'
// 3.1 Complex Members with any child member having Concurrency mode Fixed
// 4. Members included in Update ModificationFunction with Version='Original' (Original = Not Current)
// 4.1 Complex Members in ModificationFunction if any sub-member is interesting
// 5. Members included in Update ModificationFunction (mutually exclusive with 4 - required for partial update scenarios)
// 6. Foreign keys
// 7. All complex members - partial update scenarios only
/// <summary>
/// Returns members of a given EntitySet/EntityType for which original values are necessary for determining which tables to modify.
/// </summary>
/// <param name="entitySet">An EntitySet belonging to the C-Space</param>
/// <param name="entityType">An EntityType that participates in the given EntitySet</param>
/// <returns>Edm Members for which original Value is required</returns>
/// <remarks>
/// This method returns the following groups of members: 0, 1, 2, 3, 3.1, 4, 4.1. (see group descriptions above).
/// This method is marked as obsolete since it does not support partial update scenarios as it does not return
/// members from group 5 and changing it to return these members would be a breaking change.
/// </remarks>
[Obsolete("Use MetadataWorkspace.GetRelevantMembersForUpdate(EntitySetBase, EntityTypeBase, bool) instead")]
public IEnumerable < EdmMember > GetRequiredOriginalValueMembers ( EntitySetBase entitySet , EntityTypeBase entityType )
{
return GetInterestingMembers ( entitySet , entityType , StorageMappingItemCollection . InterestingMembersKind . RequiredOriginalValueMembers ) ;
}
/// <summary>
/// Returns members of a given EntitySet/EntityType for which original values are needed when modifying an entity.
/// </summary>
/// <param name="entitySet">An EntitySet belonging to the C-Space</param>
/// <param name="entityType">An EntityType that participates in the given EntitySet</param>
/// <param name="partialUpdateSupported">Whether entities may be updated partially.</param>
/// <returns>Edm Members for which original Value is required</returns>
/// <remarks>
/// This method returns the following groups of members:
/// - if <paramref name="partialUpdateSupported"/> is <c>false</c>: 1, 2, 3, 3.1, 4, 4.1, 6 (see group descriptions above)
/// - if <paramref name="partialUpdateSupported"/> is <c>true</c>: 1, 2, 3, 3.1, 5, 6, 7 (see group descriptions above)
/// See DevDiv bugs #124460 and #272992 for more details.
/// </remarks>
public ReadOnlyCollection < EdmMember > GetRelevantMembersForUpdate ( EntitySetBase entitySet , EntityTypeBase entityType , bool partialUpdateSupported )
{
return GetInterestingMembers (
entitySet ,
entityType ,
partialUpdateSupported ?
StorageMappingItemCollection . InterestingMembersKind . PartialUpdate :
StorageMappingItemCollection . InterestingMembersKind . FullUpdate ) ;
}
/// <summary>
/// Return members for <see cref="GetRequiredOriginalValueMembers"/> and <see cref="GetRelevantMembersForUpdate"/> methods.
/// </summary>
/// <param name="entitySet">An EntitySet belonging to the C-Space</param>
/// <param name="entityType">An EntityType that participates in the given EntitySet</param>
/// <param name="interestingMembersKind">Scenario the members should be returned for.</param>
/// <returns>ReadOnlyCollection of interesting members for the requested scenario (<paramref name="interestingMembersKind"/>).</returns>
private ReadOnlyCollection < EdmMember > GetInterestingMembers ( EntitySetBase entitySet , EntityTypeBase entityType , StorageMappingItemCollection . InterestingMembersKind interestingMembersKind )
{
EntityUtil . CheckArgumentNull < EntitySetBase > ( entitySet , "entitySet" ) ;
EntityUtil . CheckArgumentNull < EntityTypeBase > ( entityType , "entityType" ) ;
Debug . Assert ( entitySet . EntityContainer ! = null ) ;
//Check that EntitySet is from CSpace
if ( entitySet . EntityContainer . DataSpace ! = DataSpace . CSpace )
{
AssociationSet associationSet = entitySet as AssociationSet ;
if ( associationSet ! = null )
{
throw EntityUtil . AssociationSetNotInCSpace ( entitySet . Name ) ;
}
else
{
throw EntityUtil . EntitySetNotInCSpace ( entitySet . Name ) ;
}
}
//Check that entityType belongs to entitySet
if ( ! entitySet . ElementType . IsAssignableFrom ( entityType ) )
{
AssociationSet associationSet = entitySet as AssociationSet ;
if ( associationSet ! = null )
{
throw EntityUtil . TypeNotInAssociationSet ( entitySet . Name , entitySet . ElementType . FullName , entityType . FullName ) ;
}
else
{
throw EntityUtil . TypeNotInEntitySet ( entitySet . Name , entitySet . ElementType . FullName , entityType . FullName ) ;
}
}
var mappingCollection = ( StorageMappingItemCollection ) GetItemCollection ( DataSpace . CSSpace , true ) ;
return mappingCollection . GetInterestingMembers ( entitySet , entityType , interestingMembersKind ) ;
}
#endregion
#region Properties
/// <summary>
/// Returns the QueryCacheManager hosted by this metadata workspace instance
/// </summary>
internal System . Data . Common . QueryCache . QueryCacheManager GetQueryCacheManager ( )
{
Debug . Assert ( null ! = _itemsSSpace , "_itemsSSpace must not be null" ) ;
return _itemsSSpace . QueryCacheManager ;
}
internal Guid MetadataWorkspaceId
{
get
{
if ( Guid . Equals ( Guid . Empty , _metadataWorkspaceId ) )
{
_metadataWorkspaceId = Guid . NewGuid ( ) ;
}
return _metadataWorkspaceId ;
}
}
#endregion
}
}