|
//---------------------------------------------------------------------
// <copyright file="MetadataWorkspace.cs" company="Microsoft">
// Copyright (c) Microsoft Corporation. All rights reserved.
// </copyright>
//
// @owner Microsoft
// @backupOwner Microsoft
//---------------------------------------------------------------------
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
}
}
|