1 //---------------------------------------------------------------------
2 // <copyright file="MetadataWorkspace.cs" company="Microsoft">
3 // Copyright (c) Microsoft Corporation. All rights reserved.
7 // @backupOwner Microsoft
8 //---------------------------------------------------------------------
10 namespace System.Data.Metadata.Edm
13 using System.Collections.Generic;
14 using System.Collections.ObjectModel;
16 using System.Data.Common.CommandTrees;
17 using eSQL = System.Data.Common.EntitySql;
18 using System.Data.Common.Utils;
19 using System.Data.Entity;
20 using System.Data.Mapping;
21 using System.Data.Mapping.Update.Internal;
22 using System.Data.Mapping.ViewGeneration;
23 using System.Diagnostics;
24 using System.Globalization;
26 using System.Reflection;
27 using System.Runtime.Versioning;
31 /// Runtime Metadata Workspace
33 public sealed class MetadataWorkspace
37 /// Constructs the new instance of runtime metadata workspace
39 public MetadataWorkspace()
44 /// Create MetadataWorkspace that is populated with ItemCollections for all the spaces that the metadata artifacts provided.
45 /// All res:// paths will be resolved only from the assemblies returned from the enumerable assembliesToConsider.
47 /// <param name="paths">The paths where the metadata artifacts located</param>
48 /// <param name="assembliesToConsider">User specified assemblies to consider</param>
49 /// <exception cref="ArgumentNullException"></exception>
50 /// <exception cref="ArgumentException">Throw when assembliesToConsider is empty or contains null, or cannot find the corresponding assembly in it</exception>
51 /// <exception cref="MetadataException"></exception>
52 [ResourceExposure(ResourceScope.Machine)] //Exposes the file path names which are a Machine resource
53 [ResourceConsumption(ResourceScope.Machine)] //For MetadataWorkspace.CreateMetadataWorkspaceWithResolver method call but we do not create the file paths in this method
54 public MetadataWorkspace(IEnumerable<string> paths, IEnumerable<Assembly> assembliesToConsider)
56 // we are intentionally not checking to see if the paths enumerable is empty
57 EntityUtil.CheckArgumentNull(paths, "paths");
58 EntityUtil.CheckArgumentContainsNull(ref paths, "paths");
60 EntityUtil.CheckArgumentNull(assembliesToConsider, "assembliesToConsider");
61 EntityUtil.CheckArgumentContainsNull(ref assembliesToConsider, "assembliesToConsider");
63 Func<AssemblyName, Assembly> resolveReference = (AssemblyName referenceName)=>
65 foreach(Assembly assembly in assembliesToConsider)
67 if (AssemblyName.ReferenceMatchesDefinition(referenceName, new AssemblyName(assembly.FullName)))
72 throw EntityUtil.Argument(Strings.AssemblyMissingFromAssembliesToConsider(referenceName.FullName), "assembliesToConsider");
76 CreateMetadataWorkspaceWithResolver(paths, () => assembliesToConsider, resolveReference);
79 [ResourceExposure(ResourceScope.Machine)] //Exposes the file path names which are a Machine resource
80 [ResourceConsumption(ResourceScope.Machine)] //For MetadataArtifactLoader.CreateCompositeFromFilePaths method call but We do not create the file paths in this method
81 private void CreateMetadataWorkspaceWithResolver(IEnumerable<string> paths, Func<IEnumerable<Assembly>> wildcardAssemblies, Func<AssemblyName, Assembly> resolveReference)
83 MetadataArtifactLoader composite = MetadataArtifactLoader.CreateCompositeFromFilePaths(paths.ToArray(), "", new CustomAssemblyResolver(wildcardAssemblies, resolveReference));
85 // only create the ItemCollection that has corresponding artifacts
86 DataSpace dataSpace = DataSpace.CSpace;
87 using (DisposableCollectionWrapper<XmlReader> cSpaceReaders = new DisposableCollectionWrapper<XmlReader>(composite.CreateReaders(dataSpace)))
89 if (cSpaceReaders.Any())
91 this._itemsCSpace = new EdmItemCollection(cSpaceReaders, composite.GetPaths(dataSpace));
95 dataSpace = DataSpace.SSpace;
96 using (DisposableCollectionWrapper<XmlReader> sSpaceReaders = new DisposableCollectionWrapper<XmlReader>(composite.CreateReaders(dataSpace)))
98 if (sSpaceReaders.Any())
100 this._itemsSSpace = new StoreItemCollection(sSpaceReaders, composite.GetPaths(dataSpace));
104 dataSpace = DataSpace.CSSpace;
105 using (DisposableCollectionWrapper<XmlReader> csSpaceReaders = new DisposableCollectionWrapper<XmlReader>(composite.CreateReaders(dataSpace)))
107 if (csSpaceReaders.Any() && null != this._itemsCSpace && null != this._itemsSSpace)
109 this._itemsCSSpace = new StorageMappingItemCollection(this._itemsCSpace, this._itemsSSpace, csSpaceReaders, composite.GetPaths(dataSpace));
116 private EdmItemCollection _itemsCSpace;
117 private StoreItemCollection _itemsSSpace;
118 private ObjectItemCollection _itemsOSpace;
119 private StorageMappingItemCollection _itemsCSSpace;
120 private DefaultObjectMappingItemCollection _itemsOCSpace;
122 private List<object> _cacheTokens;
123 private bool _foundAssemblyWithAttribute = false;
124 private double _schemaVersion = XmlConstants.UndefinedVersion;
125 private Guid _metadataWorkspaceId = Guid.Empty;
128 #region public static Fields
129 [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Naming", "CA1704:IdentifiersShouldBeSpelledCorrectly", MessageId = "Edm")]
130 private static IEnumerable<double> SupportedEdmVersions
134 yield return XmlConstants.UndefinedVersion;
135 yield return XmlConstants.EdmVersionForV1;
136 yield return XmlConstants.EdmVersionForV2;
137 Debug.Assert(XmlConstants.SchemaVersionLatest == XmlConstants.EdmVersionForV3, "Did you add a new version?");
138 yield return XmlConstants.EdmVersionForV3;
141 //The Max EDM version thats going to be supported by the runtime.
142 [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Naming", "CA1704:IdentifiersShouldBeSpelledCorrectly", MessageId = "Edm")]
143 public static readonly double MaximumEdmVersionSupported = SupportedEdmVersions.Last();
148 /// Create an <see cref="eSQL.EntitySqlParser"/> configured to use the <see cref="DataSpace.CSpace"/> data space.
150 public eSQL.EntitySqlParser CreateEntitySqlParser()
152 return new eSQL.EntitySqlParser(new ModelPerspective(this));
156 /// Creates a new <see cref="DbQueryCommandTree"/> bound to this metadata workspace based on the specified query expression.
158 /// <param name="query">A <see cref="DbExpression"/> that defines the query</param>
159 /// <returns>A new <see cref="DbQueryCommandTree"/> with the specified expression as it's <see cref="DbQueryCommandTree.Query"/> property</returns>
160 /// <exception cref="ArgumentNullException">If <paramref name="query"/> is null</exception>
161 /// <exception cref="ArgumentException">If <paramref name="query"/> contains metadata that cannot be resolved in this metadata workspace</exception>
162 /// <exception cref="ArgumentException">If <paramref name="query"/> is not structurally valid because it contains unresolvable variable references</exception>
163 public DbQueryCommandTree CreateQueryCommandTree(DbExpression query)
165 return new DbQueryCommandTree(this, DataSpace.CSpace, query);
169 /// Get item collection for the space. The ItemCollection is in read only mode as it is
170 /// part of the workspace.
172 /// <param name="dataSpace">The dataspace for the item colelction that should be returned</param>
173 /// <returns>The item collection for the given space</returns>
174 /// <exception cref="System.ArgumentNullException">if space argument is null</exception>
175 /// <exception cref="System.InvalidOperationException">If ItemCollection has not been registered for the space passed in</exception>
176 [CLSCompliant(false)]
177 public ItemCollection GetItemCollection(DataSpace dataSpace)
179 ItemCollection collection = GetItemCollection(dataSpace, true);
184 /// Register the item collection for the space associated with it.
185 /// This should be done only once for a space.
186 /// If a space already has a registered ItemCollection InvalidOperation exception is thrown
188 /// <param name="collection">The out parameter collection that needs to be filled up</param>
189 /// <returns></returns>
190 /// <exception cref="System.ArgumentNullException">if collection argument is null</exception>
191 /// <exception cref="System.InvalidOperationException">If there is an ItemCollection that has already been registered for collection's space passed in</exception>
192 [CLSCompliant(false)]
193 public void RegisterItemCollection(ItemCollection collection)
195 EntityUtil.CheckArgumentNull(collection, "collection");
197 ItemCollection existing;
201 switch (collection.DataSpace)
203 case DataSpace.CSpace:
204 if (null == (existing = _itemsCSpace)) {
205 EdmItemCollection edmCollection = (EdmItemCollection)collection;
206 if (!MetadataWorkspace.SupportedEdmVersions.Contains(edmCollection.EdmVersion))
209 throw EntityUtil.InvalidOperation(
210 System.Data.Entity.Strings.EdmVersionNotSupportedByRuntime(
211 edmCollection.EdmVersion,
212 Helper.GetCommaDelimitedString(
214 .Where(e => e != XmlConstants.UndefinedVersion)
215 .Select(e => e.ToString(CultureInfo.InvariantCulture)))));
218 CheckAndSetItemCollectionVersionInWorkSpace(collection);
220 _itemsCSpace = edmCollection;
223 case DataSpace.SSpace:
224 if (null == (existing = _itemsSSpace))
226 CheckAndSetItemCollectionVersionInWorkSpace(collection);
227 _itemsSSpace = (StoreItemCollection)collection;
230 case DataSpace.OSpace:
231 if (null == (existing = _itemsOSpace)) {
232 _itemsOSpace = (ObjectItemCollection)collection;
235 case DataSpace.CSSpace:
236 if (null == (existing = _itemsCSSpace)) {
237 CheckAndSetItemCollectionVersionInWorkSpace(collection);
238 _itemsCSSpace = (StorageMappingItemCollection)collection;
242 Debug.Assert(collection.DataSpace == DataSpace.OCSpace, "Invalid DataSpace Enum value: " + collection.DataSpace);
244 if (null == (existing = _itemsOCSpace)) {
245 _itemsOCSpace = (DefaultObjectMappingItemCollection)collection;
250 catch (InvalidCastException)
252 throw EntityUtil.InvalidCollectionForMapping(collection.DataSpace);
254 if (null != existing)
256 throw EntityUtil.ItemCollectionAlreadyRegistered(collection.DataSpace);
258 // Need to make sure that if the storage mapping Item collection was created with the
259 // same instances of item collection that are registered for CSpace and SSpace
260 if (collection.DataSpace == DataSpace.CSpace)
262 if (_itemsCSSpace != null && !object.ReferenceEquals(_itemsCSSpace.EdmItemCollection, collection))
264 throw EntityUtil.InvalidCollectionSpecified(collection.DataSpace);
268 if (collection.DataSpace == DataSpace.SSpace)
270 if (_itemsCSSpace != null && !object.ReferenceEquals(_itemsCSSpace.StoreItemCollection, collection))
272 throw EntityUtil.InvalidCollectionSpecified(collection.DataSpace);
276 if (collection.DataSpace == DataSpace.CSSpace)
278 if (_itemsCSpace != null && !object.ReferenceEquals(_itemsCSSpace.EdmItemCollection, _itemsCSpace))
280 throw EntityUtil.InvalidCollectionSpecified(collection.DataSpace);
283 if (_itemsSSpace != null && !object.ReferenceEquals(_itemsCSSpace.StoreItemCollection, _itemsSSpace))
285 throw EntityUtil.InvalidCollectionSpecified(collection.DataSpace);
293 /// <param name="itemCollectionToRegister"></param>
294 private void CheckAndSetItemCollectionVersionInWorkSpace(ItemCollection itemCollectionToRegister)
296 double versionToRegister = XmlConstants.UndefinedVersion;
297 string itemCollectionType = null;
298 switch (itemCollectionToRegister.DataSpace)
300 case DataSpace.CSpace:
301 versionToRegister = ((EdmItemCollection)itemCollectionToRegister).EdmVersion;
302 itemCollectionType = "EdmItemCollection";
304 case DataSpace.SSpace:
305 versionToRegister = ((StoreItemCollection)itemCollectionToRegister).StoreSchemaVersion;
306 itemCollectionType = "StoreItemCollection";
308 case DataSpace.CSSpace:
309 versionToRegister = ((StorageMappingItemCollection)itemCollectionToRegister).MappingVersion;
310 itemCollectionType = "StorageMappingItemCollection";
313 // we don't care about other spaces so keep the _versionToRegister to Undefined
317 if (versionToRegister != this._schemaVersion &&
318 versionToRegister != XmlConstants.UndefinedVersion &&
319 this._schemaVersion != XmlConstants.UndefinedVersion)
321 Debug.Assert(itemCollectionType != null);
322 throw EntityUtil.DifferentSchemaVersionInCollection(itemCollectionType, versionToRegister, this._schemaVersion);
326 this._schemaVersion = versionToRegister;
330 /// Add a token for this MetadataWorkspace just so this metadata workspace holds a reference to it, this
331 /// is for metadata caching to make the workspace marking a particular cache entry is still in used
333 /// <param name="token"></param>
334 internal void AddMetadataEntryToken(object token)
336 if (_cacheTokens == null)
338 _cacheTokens = new List<object>();
341 _cacheTokens.Add(token);
345 /// Load metadata from the given assembly
347 /// <param name="assembly">The assembly from which to load metadata</param>
348 /// <exception cref="System.ArgumentNullException">thrown if assembly argument is null</exception>
349 public void LoadFromAssembly(Assembly assembly)
351 LoadFromAssembly(assembly, null);
355 /// Load metadata from the given assembly
357 /// <param name="assembly">The assembly from which to load metadata</param>
358 /// <param name="logLoadMessage">The delegate for logging the load messages</param>
359 /// <exception cref="System.ArgumentNullException">thrown if assembly argument is null</exception>
360 public void LoadFromAssembly(Assembly assembly, Action<string> logLoadMessage)
362 EntityUtil.CheckArgumentNull(assembly, "assembly");
363 ObjectItemCollection collection = (ObjectItemCollection)GetItemCollection(DataSpace.OSpace);
364 ExplicitLoadFromAssembly(assembly, collection, logLoadMessage);
367 private void ExplicitLoadFromAssembly(Assembly assembly, ObjectItemCollection collection, Action<string> logLoadMessage)
369 ItemCollection itemCollection;
370 if (!TryGetItemCollection(DataSpace.CSpace, out itemCollection))
372 itemCollection = null;
375 collection.ExplicitLoadFromAssembly(assembly, (EdmItemCollection)itemCollection, logLoadMessage);
378 private void ImplicitLoadFromAssembly(Assembly assembly, ObjectItemCollection collection)
380 if (!MetadataAssemblyHelper.ShouldFilterAssembly(assembly))
382 ExplicitLoadFromAssembly(assembly, collection, null);
387 /// Implicit loading means that we are trying to help the user find the right
388 /// assembly, but they didn't explicitly ask for it. Our Implicit rules require that
389 /// we filter out assemblies with the Ecma or MicrosoftPublic PublicKeyToken on them
391 /// Load metadata from the type's assembly into the OSpace ItemCollection.
392 /// If type comes from known source, has Ecma or Microsoft PublicKeyToken then the type's assembly is not
393 /// loaded, but the callingAssembly and its referenced assemblies are loaded.
395 /// <param name="type">The type's assembly is loaded into the OSpace ItemCollection</param>
396 /// <param name="callingAssembly">The assembly and its referenced assemblies to load when type is insuffiecent</param>
397 internal void ImplicitLoadAssemblyForType(Type type, Assembly callingAssembly)
399 // this exists separately from LoadFromAssembly so that we can handle generics, like IEnumerable<Product>
400 Debug.Assert(null != type, "null type");
401 ItemCollection collection;
402 if (TryGetItemCollection(DataSpace.OSpace, out collection))
403 { // if OSpace is not loaded - don't register
404 ObjectItemCollection objItemCollection = (ObjectItemCollection)collection;
405 ItemCollection edmItemCollection;
406 TryGetItemCollection(DataSpace.CSpace, out edmItemCollection);
407 if (!objItemCollection.ImplicitLoadAssemblyForType(type, (EdmItemCollection)edmItemCollection) && (null != callingAssembly))
409 // only load from callingAssembly if all types were filtered
410 // then loaded referenced assemblies of calling assembly
412 // attempt automatic discovery of user types
413 // interesting code paths are ObjectQuery<object>, ObjectQuery<DbDataRecord>, ObjectQuery<IExtendedDataRecord>
414 // other interesting code paths are ObjectQuery<Nullable<Int32>>, ObjectQuery<IEnumerable<object>>
415 // when assemblies is mscorlib, System.Data or System.Data.Entity
417 // If the schema attribute is presented on the assembly or any referenced assemblies, then it is a V1 scenario that we should
418 // strictly follow the Get all referenced assemblies rules.
419 // If the attribute is not presented on the assembly, then we won't load the referenced ----sembly
420 // for this callingAssembly
421 if (ObjectItemAttributeAssemblyLoader.IsSchemaAttributePresent(callingAssembly) ||
422 (_foundAssemblyWithAttribute ||
423 MetadataAssemblyHelper.GetNonSystemReferencedAssemblies(callingAssembly).Any(a => ObjectItemAttributeAssemblyLoader.IsSchemaAttributePresent(a))))
425 // cache the knowledge that we found an attribute
426 // because it can be expesive to figure out
427 _foundAssemblyWithAttribute = true;
428 objItemCollection.ImplicitLoadAllReferencedAssemblies(callingAssembly, (EdmItemCollection)edmItemCollection);
432 this.ImplicitLoadFromAssembly(callingAssembly, objItemCollection);
439 /// If OSpace is not loaded for the specified EntityType
440 /// the load metadata from the callingAssembly and its referenced assemblies.
442 /// <param name="type">The CSPace type to verify its OSpace counterpart is loaded</param>
443 /// <param name="callingAssembly">The assembly and its referenced assemblies to load when type is insuffiecent</param>
444 internal void ImplicitLoadFromEntityType(EntityType type, Assembly callingAssembly)
446 // used by ObjectContext.*GetObjectByKey when the clr type is not available
447 // so we check the OCMap to find the clr type else attempt to autoload the OSpace from callingAssembly
448 Debug.Assert(null != type, "null type");
450 if (!TryGetMap(type, DataSpace.OCSpace, out map))
451 { // an OCMap is not exist, attempt to load OSpace to retry
452 ImplicitLoadAssemblyForType(typeof(System.Data.Objects.DataClasses.IEntityWithKey), callingAssembly);
454 // We do a check here to see if the type was actually found in the attempted load.
455 ObjectItemCollection ospaceCollection = GetItemCollection(DataSpace.OSpace) as ObjectItemCollection;
457 if (ospaceCollection == null || !ospaceCollection.TryGetOSpaceType(type, out ospaceType))
459 throw new InvalidOperationException(System.Data.Entity.Strings.Mapping_Object_InvalidType(type.Identity));
465 /// Search for an item with the given identity in the given space.
466 /// For example, The identity for EdmType is Namespace.Name.
468 /// <typeparam name="T"></typeparam>
469 /// <param name="identity"></param>
470 /// <param name="dataSpace"></param>
471 /// <returns></returns>
472 /// <exception cref="System.ArgumentNullException">if space argument is null</exception>
473 /// <exception cref="System.InvalidOperationException">If ItemCollection has not been registered for the space passed in</exception>
474 /// <exception cref="System.ArgumentNullException">if identity argument passed in is null</exception>
475 /// <exception cref="System.ArgumentException">If the ItemCollection for this space does not have an item with the given identity</exception>
476 /// <exception cref="System.ArgumentException">Thrown if the space is not a valid space. Valid space is either C, O, CS or OCSpace</exception>
477 public T GetItem<T>(string identity, DataSpace dataSpace) where T:GlobalItem
479 ItemCollection collection = GetItemCollection(dataSpace, true);
480 return collection.GetItem<T>(identity, false /*ignoreCase*/);
484 /// Search for an item with the given identity in the given space.
486 /// <typeparam name="T"></typeparam>
487 /// <param name="identity"></param>
488 /// <param name="space"></param>
489 /// <param name="item"></param>
490 /// <returns></returns>
491 /// <exception cref="System.ArgumentNullException">if identity or space argument is null</exception>
492 public bool TryGetItem<T>(string identity, DataSpace space, out T item ) where T:GlobalItem
495 ItemCollection collection = GetItemCollection(space, false);
496 return (null != collection) && collection.TryGetItem<T>(identity, false /*ignoreCase*/, out item);
500 /// Search for an item with the given identity in the given space.
501 /// For example, The identity for EdmType is Namespace.Name.
503 /// <typeparam name="T"></typeparam>
504 /// <param name="identity"></param>
505 /// <param name="ignoreCase"></param>
506 /// <param name="dataSpace"></param>
507 /// <returns></returns>
508 /// <exception cref="System.ArgumentNullException">if space argument is null</exception>
509 /// <exception cref="System.InvalidOperationException">If ItemCollection has not been registered for the space passed in</exception>
510 /// <exception cref="System.ArgumentNullException">if identity argument passed in is null</exception>
511 /// <exception cref="System.ArgumentException">If the ItemCollection for this space does not have an item with the given identity</exception>
512 /// <exception cref="System.ArgumentException">Thrown if the space is not a valid space. Valid space is either C, O, CS or OCSpace</exception>
513 public T GetItem<T>(string identity, bool ignoreCase, DataSpace dataSpace) where T : GlobalItem
515 ItemCollection collection = GetItemCollection(dataSpace, true);
516 return collection.GetItem<T>(identity, ignoreCase);
520 /// Search for an item with the given identity in the given space.
522 /// <typeparam name="T"></typeparam>
523 /// <param name="ignoreCase"></param>
524 /// <param name="identity"></param>
525 /// <param name="dataSpace"></param>
526 /// <param name="item"></param>
527 /// <returns></returns>
528 /// <exception cref="System.ArgumentNullException">if identity or space argument is null</exception>
529 public bool TryGetItem<T>(string identity, bool ignoreCase, DataSpace dataSpace, out T item) where T : GlobalItem
532 ItemCollection collection = GetItemCollection(dataSpace, false);
533 return (null != collection) && collection.TryGetItem<T>(identity, ignoreCase, out item);
537 /// Returns ReadOnlyCollection of the Items of the given type
538 /// in the workspace.
540 /// <typeparam name="T"></typeparam>
541 /// <param name="dataSpace"></param>
542 /// <returns></returns>
543 /// <exception cref="System.ArgumentNullException">if space argument is null</exception>
544 /// <exception cref="System.InvalidOperationException">If ItemCollection has not been registered for the space passed in</exception>
545 /// <exception cref="System.ArgumentException">Thrown if the space is not a valid space. Valid space is either C, O, CS or OCSpace</exception>
546 public ReadOnlyCollection<T> GetItems<T>(DataSpace dataSpace) where T : GlobalItem
548 ItemCollection collection = GetItemCollection(dataSpace, true);
549 return collection.GetItems<T>();
553 /// Search for a type metadata with the specified name and namespace name in the given space.
555 /// <param name="name">name of the type</param>
556 /// <param name="namespaceName">namespace of the type</param>
557 /// <param name="dataSpace">Dataspace to search the type for</param>
558 /// <returns>Returns null if no match found.</returns>
559 /// <exception cref="System.ArgumentNullException">if space argument is null</exception>
560 /// <exception cref="System.InvalidOperationException">If ItemCollection has not been registered for the space passed in</exception>
561 /// <exception cref="System.ArgumentNullException">if name or namespaceName arguments passed in are null</exception>
562 /// <exception cref="System.ArgumentException">If the ItemCollection for this space does not have a type with the given name and namespaceName</exception>
563 /// <exception cref="System.ArgumentException">Thrown if the space is not a valid space. Valid space is either C, O, CS or OCSpace</exception>
564 public EdmType GetType(string name, string namespaceName, DataSpace dataSpace)
566 ItemCollection collection = GetItemCollection(dataSpace, true);
567 return collection.GetType(name, namespaceName, false /*ignoreCase*/);
571 /// Search for a type metadata with the specified name and namespace name in the given space.
573 /// <param name="name">name of the type</param>
574 /// <param name="namespaceName">namespace of the type</param>
575 /// <param name="dataSpace">Dataspace to search the type for</param>
576 /// <param name="type">The type that needs to be filled with the return value</param>
577 /// <returns>Returns false if no match found.</returns>
578 /// <exception cref="System.ArgumentNullException">if name, namespaceName or space argument is null</exception>
579 public bool TryGetType(string name, string namespaceName, DataSpace dataSpace, out EdmType type)
582 ItemCollection collection = GetItemCollection(dataSpace, false);
583 return (null != collection) && collection.TryGetType(name, namespaceName, false /*ignoreCase*/, out type);
589 /// Search for a type metadata with the specified name and namespace name in the given space.
591 /// <param name="name">name of the type</param>
592 /// <param name="namespaceName">namespace of the type</param>
593 /// <param name="ignoreCase"></param>
594 /// <param name="dataSpace">Dataspace to search the type for</param>
595 /// <returns>Returns null if no match found.</returns>
596 /// <exception cref="System.ArgumentNullException">if space argument is null</exception>
597 /// <exception cref="System.InvalidOperationException">If ItemCollection has not been registered for the space passed in</exception>
598 /// <exception cref="System.ArgumentNullException">if name or namespaceName arguments passed in are null</exception>
599 /// <exception cref="System.ArgumentException">If the ItemCollection for this space does not have a type with the given name and namespaceName</exception>
600 /// <exception cref="System.ArgumentException">Thrown if the space is not a valid space. Valid space is either C, O, CS or OCSpace</exception>
601 public EdmType GetType(string name, string namespaceName, bool ignoreCase, DataSpace dataSpace)
603 ItemCollection collection = GetItemCollection(dataSpace, true);
604 return collection.GetType(name, namespaceName, ignoreCase);
608 /// Search for a type metadata with the specified name and namespace name in the given space.
610 /// <param name="name">name of the type</param>
611 /// <param name="namespaceName">namespace of the type</param>
612 /// <param name="dataSpace">Dataspace to search the type for</param>
613 /// <param name="ignoreCase"></param>
614 /// <param name="type">The type that needs to be filled with the return value</param>
615 /// <returns>Returns null if no match found.</returns>
616 /// <exception cref="System.ArgumentNullException">if name, namespaceName or space argument is null</exception>
617 public bool TryGetType(string name, string namespaceName, bool ignoreCase,
618 DataSpace dataSpace, out EdmType type)
621 ItemCollection collection = GetItemCollection(dataSpace, false);
622 return (null != collection) && collection.TryGetType(name, namespaceName, ignoreCase, out type);
627 /// Get an entity container based upon the strong name of the container
628 /// If no entity container is found, returns null, else returns the first one/// </summary>
629 /// <param name="name">name of the entity container</param>
630 /// <param name="dataSpace"></param>
631 /// <returns>The EntityContainer</returns>
632 /// <exception cref="System.ArgumentNullException">if space argument is null</exception>
633 /// <exception cref="System.InvalidOperationException">If ItemCollection has not been registered for the space passed in</exception>
634 /// <exception cref="System.ArgumentNullException">if name argument passed in is null</exception>
635 /// <exception cref="System.ArgumentException">If the ItemCollection for this space does not have a EntityContainer with the given name</exception>
636 /// <exception cref="System.ArgumentException">Thrown if the space is not a valid space. Valid space is either C, O, CS or OCSpace</exception>
637 public EntityContainer GetEntityContainer(string name, DataSpace dataSpace)
639 ItemCollection collection = GetItemCollection(dataSpace, true);
640 return collection.GetEntityContainer(name);
644 /// Get an entity container based upon the strong name of the container
645 /// If no entity container is found, returns null, else returns the first one/// </summary>
646 /// <param name="name">name of the entity container</param>
647 /// <param name="dataSpace"></param>
648 /// <param name="entityContainer"></param>
649 /// <exception cref="System.ArgumentNullException">if either space or name arguments is null</exception>
650 public bool TryGetEntityContainer(string name, DataSpace dataSpace, out EntityContainer entityContainer)
652 entityContainer = null;
653 // null check exists in call stack, but throws for "identity" not "name"
654 EntityUtil.GenericCheckArgumentNull(name, "name");
655 ItemCollection collection = GetItemCollection(dataSpace, false);
656 return (null != collection) && collection.TryGetEntityContainer(name, out entityContainer);
660 /// Get an entity container based upon the strong name of the container
661 /// If no entity container is found, returns null, else returns the first one/// </summary>
662 /// <param name="name">name of the entity container</param>
663 /// <param name="ignoreCase">true for case-insensitive lookup</param>
664 /// <param name="dataSpace"></param>
665 /// <returns>The EntityContainer</returns>
666 /// <exception cref="System.ArgumentNullException">if space argument is null</exception>
667 /// <exception cref="System.InvalidOperationException">If ItemCollection has not been registered for the space passed in</exception>
668 /// <exception cref="System.ArgumentNullException">if name argument passed in is null</exception>
669 /// <exception cref="System.ArgumentException">If the ItemCollection for this space does not have a EntityContainer with the given name</exception>
670 /// <exception cref="System.ArgumentException">Thrown if the space is not a valid space. Valid space is either C, O, CS or OCSpace</exception>
671 public EntityContainer GetEntityContainer(string name, bool ignoreCase, DataSpace dataSpace)
673 ItemCollection collection = GetItemCollection(dataSpace, true);
674 return collection.GetEntityContainer(name, ignoreCase);
678 /// Get an entity container based upon the strong name of the container
679 /// If no entity container is found, returns null, else returns the first one/// </summary>
680 /// <param name="name">name of the entity container</param>
681 /// <param name="ignoreCase">true for case-insensitive lookup</param>
682 /// <param name="dataSpace"></param>
683 /// <param name="entityContainer"></param>
684 /// <exception cref="System.ArgumentNullException">if name or space argument is null</exception>
685 public bool TryGetEntityContainer(string name, bool ignoreCase,
686 DataSpace dataSpace, out EntityContainer entityContainer)
688 entityContainer = null;
689 // null check exists in call stack, but throws for "identity" not "name"
690 EntityUtil.GenericCheckArgumentNull(name, "name");
691 ItemCollection collection = GetItemCollection(dataSpace, false);
692 return (null != collection) && collection.TryGetEntityContainer(name, ignoreCase, out entityContainer);
696 /// Get all the overloads of the function with the given name
698 /// <param name="name">name of the function</param>
699 /// <param name="namespaceName">namespace of the function</param>
700 /// <param name="dataSpace">The dataspace for which we need to get the function for</param>
701 /// <returns>A collection of all the functions with the given name in the given data space</returns>
702 /// <exception cref="System.ArgumentNullException">if space argument is null</exception>
703 /// <exception cref="System.ArgumentNullException">if name or namespaceName argument is null</exception>
704 /// <exception cref="System.InvalidOperationException">If ItemCollection has not been registered for the space passed in</exception>
705 /// <exception cref="System.ArgumentNullException">if functionName argument passed in is null</exception>
706 /// <exception cref="System.ArgumentException">If the ItemCollection for this space does not have a EdmFunction with the given functionName</exception>
707 /// <exception cref="System.ArgumentException">If the name or namespaceName is empty</exception>
708 /// <exception cref="System.ArgumentException">Thrown if the space is not a valid space. Valid space is either C, O, CS or OCSpace</exception>
709 public ReadOnlyCollection<EdmFunction> GetFunctions(string name, string namespaceName, DataSpace dataSpace)
711 return GetFunctions(name, namespaceName, dataSpace, false /*ignoreCase*/);
715 /// Get all the overloads of the function with the given name
717 /// <param name="name">name of the function</param>
718 /// <param name="namespaceName">namespace of the function</param>
719 /// <param name="dataSpace">The dataspace for which we need to get the function for</param>
720 /// <param name="ignoreCase">true for case-insensitive lookup</param>
721 /// <returns>A collection of all the functions with the given name in the given data space</returns>
722 /// <exception cref="System.ArgumentNullException">if space argument is null</exception>
723 /// <exception cref="System.ArgumentNullException">if name or namespaceName argument is null</exception>
724 /// <exception cref="System.InvalidOperationException">If ItemCollection has not been registered for the space passed in</exception>
725 /// <exception cref="System.ArgumentNullException">if functionName argument passed in is null</exception>
726 /// <exception cref="System.ArgumentException">If the ItemCollection for this space does not have a EdmFunction with the given functionName</exception>
727 /// <exception cref="System.ArgumentException">If the name or namespaceName is empty</exception>
728 /// <exception cref="System.ArgumentException">Thrown if the space is not a valid space. Valid space is either C, O, CS or OCSpace</exception>
729 public ReadOnlyCollection<EdmFunction> GetFunctions(string name,
730 string namespaceName,
734 EntityUtil.CheckStringArgument(name, "name");
735 EntityUtil.CheckStringArgument(namespaceName, "namespaceName");
736 ItemCollection collection = GetItemCollection(dataSpace, true);
738 // Get the function with this full name, which is namespace name plus name
739 return collection.GetFunctions(namespaceName + "." + name, ignoreCase);
743 /// Gets the function as specified by the function key.
744 /// All parameters are assumed to be <see cref="ParameterMode.In"/>.
746 /// <param name="name">name of the function</param>
747 /// <param name="namespaceName">namespace of the function</param>
748 /// <param name="parameterTypes">types of the parameters</param>
749 /// <param name="ignoreCase">true for case-insensitive lookup</param>
750 /// <param name="dataSpace"></param>
751 /// <param name="function">The function that needs to be returned</param>
752 /// <returns> The function as specified in the function key or null</returns>
753 /// <exception cref="System.ArgumentNullException">if name, namespaceName, parameterTypes or space argument is null</exception>
754 internal bool TryGetFunction(string name,
755 string namespaceName,
756 TypeUsage[] parameterTypes,
759 out EdmFunction function)
762 EntityUtil.GenericCheckArgumentNull(name, "name");
763 EntityUtil.GenericCheckArgumentNull(namespaceName, "namespaceName");
764 ItemCollection collection = GetItemCollection(dataSpace, false);
766 // Get the function with this full name, which is namespace name plus name
767 return (null != collection) && collection.TryGetFunction(namespaceName + "." + name, parameterTypes, ignoreCase, out function);
771 /// Get the list of primitive types for the given space
773 /// <param name="dataSpace">dataspace for which you need the list of primitive types</param>
774 /// <returns></returns>
775 /// <exception cref="System.ArgumentNullException">if space argument is null</exception>
776 /// <exception cref="System.InvalidOperationException">If ItemCollection has not been registered for the space passed in</exception>
777 /// <exception cref="System.ArgumentException">Thrown if the space is not a valid space. Valid space is either C, O, CS or OCSpace</exception>
778 public ReadOnlyCollection<PrimitiveType> GetPrimitiveTypes(DataSpace dataSpace)
780 ItemCollection collection = GetItemCollection(dataSpace, true);
781 return collection.GetItems<PrimitiveType>();
785 /// Get all the items in the data space
787 /// <param name="dataSpace">dataspace for which you need the list of items</param>
788 /// <returns></returns>
789 /// <exception cref="System.ArgumentNullException">if space argument is null</exception>
790 /// <exception cref="System.InvalidOperationException">If ItemCollection has not been registered for the space passed in</exception>
791 /// <exception cref="System.ArgumentException">Thrown if the space is not a valid space. Valid space is either C, O, CS or OCSpace</exception>
792 public ReadOnlyCollection<GlobalItem> GetItems(DataSpace dataSpace)
794 ItemCollection collection = GetItemCollection(dataSpace, true);
795 return collection.GetItems<GlobalItem>();
799 /// Given the canonical primitive type, get the mapping primitive type in the given dataspace
801 /// <param name="primitiveTypeKind">primitive type kind</param>
802 /// <param name="dataSpace">dataspace in which one needs to the mapping primitive types</param>
803 /// <returns>The mapped scalar type</returns>
804 /// <exception cref="System.ArgumentNullException">if space argument is null</exception>
805 /// <exception cref="System.InvalidOperationException">If ItemCollection has not been registered for the space passed in</exception>
806 /// <exception cref="System.ArgumentException">Thrown if the space is not a valid space. Valid space is either C, O, CS or OCSpace</exception>
807 internal PrimitiveType GetMappedPrimitiveType(PrimitiveTypeKind primitiveTypeKind, DataSpace dataSpace)
809 ItemCollection collection = GetItemCollection(dataSpace, true);
810 return collection.GetMappedPrimitiveType(primitiveTypeKind);
814 /// Search for a Mapping metadata with the specified type key.
816 /// <param name="typeIdentity">type</param>
817 /// <param name="typeSpace">The dataspace that the type for which map needs to be returned belongs to</param>
818 /// <param name="ignoreCase">true for case-insensitive lookup</param>
819 /// <param name="mappingSpace">space for which you want to get the mapped type</param>
820 /// <param name="map"></param>
821 /// <returns>Returns false if no match found.</returns>
822 internal bool TryGetMap(string typeIdentity, DataSpace typeSpace, bool ignoreCase, DataSpace mappingSpace, out Map map)
825 ItemCollection collection = GetItemCollection(mappingSpace, false);
826 return (null != collection) && ((MappingItemCollection)collection).TryGetMap(typeIdentity, typeSpace, ignoreCase, out map);
830 /// Search for a Mapping metadata with the specified type key.
832 /// <param name="identity">typeIdentity of the type</param>
833 /// <param name="typeSpace">The dataspace that the type for which map needs to be returned belongs to</param>
834 /// <param name="dataSpace">space for which you want to get the mapped type</param>
835 /// <exception cref="ArgumentException"> Thrown if mapping space is not valid</exception>
836 internal Map GetMap(string identity, DataSpace typeSpace, DataSpace dataSpace)
838 ItemCollection collection = GetItemCollection(dataSpace, true);
839 return ((MappingItemCollection)collection).GetMap(identity, typeSpace);
843 /// Search for a Mapping metadata with the specified type key.
845 /// <param name="item"></param>
846 /// <param name="dataSpace">space for which you want to get the mapped type</param>
847 /// <exception cref="ArgumentException"> Thrown if mapping space is not valid</exception>
848 internal Map GetMap(GlobalItem item, DataSpace dataSpace)
850 ItemCollection collection = GetItemCollection(dataSpace, true);
851 return ((MappingItemCollection)collection).GetMap(item);
855 /// Search for a Mapping metadata with the specified type key.
857 /// <param name="item"></param>
858 /// <param name="dataSpace">space for which you want to get the mapped type</param>
859 /// <param name="map"></param>
860 /// <returns>Returns false if no match found.</returns>
861 internal bool TryGetMap(GlobalItem item, DataSpace dataSpace, out Map map)
864 ItemCollection collection = GetItemCollection(dataSpace, false);
865 return (null != collection) && ((MappingItemCollection)collection).TryGetMap(item, out map);
868 private ItemCollection RegisterDefaultObjectMappingItemCollection()
870 EdmItemCollection edm = _itemsCSpace as EdmItemCollection;
871 ObjectItemCollection obj = _itemsOSpace as ObjectItemCollection;
872 if ((null != edm) && (null != obj))
874 RegisterItemCollection(new DefaultObjectMappingItemCollection(edm, obj));
876 return _itemsOCSpace;
880 /// Get item collection for the space, if registered. If returned, the ItemCollection is in read only mode as it is
881 /// part of the workspace.
883 /// <param name="dataSpace">The dataspace for the item collection that should be returned</param>
884 /// <param name="collection">The collection registered for the specified dataspace, if any</param>
885 /// <returns><c>true</c> if an item collection is currently registered for the specified space; otherwise <c>false</c>.</returns>
886 /// <exception cref="System.ArgumentNullException">if space argument is null</exception>
887 [CLSCompliant(false)]
888 public bool TryGetItemCollection(DataSpace dataSpace, out ItemCollection collection)
890 collection = GetItemCollection(dataSpace, false);
891 return (null != collection);
895 /// Checks if the space is valid and whether the collection is registered for the given space, and if both are valid,
896 /// then returns the itemcollection for the given space
898 /// <param name="dataSpace"></param>
899 /// <param name="required">if true, will throw</param>
900 /// <exception cref="ArgumentException">Thrown if required and mapping space is not valid or registered</exception>
901 internal ItemCollection GetItemCollection(DataSpace dataSpace, bool required)
903 ItemCollection collection;
906 case DataSpace.CSpace:
907 collection = _itemsCSpace;
909 case DataSpace.OSpace:
910 collection = _itemsOSpace;
912 case DataSpace.OCSpace:
913 collection = _itemsOCSpace ?? RegisterDefaultObjectMappingItemCollection();
915 case DataSpace.CSSpace:
916 collection = _itemsCSSpace;
918 case DataSpace.SSpace:
919 collection = _itemsSSpace;
923 Debug.Fail("Invalid DataSpace Enum value: " + dataSpace);
928 if (required && (null == collection)) {
929 throw EntityUtil.NoCollectionForSpace(dataSpace);
935 /// The method returns the OSpace structural type mapped to the specified Edm Space Type.
936 /// If the DataSpace of the argument is not CSpace, or the mapped OSpace type
937 /// cannot be determined, an ArgumentException is thrown.
939 /// <param name="edmSpaceType">The CSpace type to look up</param>
940 /// <returns>The OSpace type mapped to the supplied argument</returns>
941 [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Naming", "CA1704:IdentifiersShouldBeSpelledCorrectly", MessageId = "edm")]
942 public StructuralType GetObjectSpaceType(StructuralType edmSpaceType)
944 return GetObjectSpaceType<StructuralType>(edmSpaceType);
948 /// This method returns the OSpace structural type mapped to the specified Edm Space Type.
949 /// If the DataSpace of the argument is not CSpace, or if the mapped OSpace type
950 /// cannot be determined, the method returns false and sets the out parameter
953 /// <param name="edmSpaceType">The CSpace type to look up</param>
954 /// <param name="objectSpaceType">The OSpace type mapped to the supplied argument</param>
955 /// <returns>true on success, false on failure</returns>
956 [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1011:ConsiderPassingBaseTypesAsParameters"), System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Naming", "CA1704:IdentifiersShouldBeSpelledCorrectly", MessageId = "edm")]
957 public bool TryGetObjectSpaceType(StructuralType edmSpaceType, out StructuralType objectSpaceType)
959 return TryGetObjectSpaceType<StructuralType>(edmSpaceType, out objectSpaceType);
963 /// The method returns the OSpace enum type mapped to the specified Edm Space Type.
964 /// If the DataSpace of the argument is not CSpace, or the mapped OSpace type
965 /// cannot be determined, an ArgumentException is thrown.
967 /// <param name="edmSpaceType">The CSpace type to look up</param>
968 /// <returns>The OSpace type mapped to the supplied argument</returns>
969 [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Naming", "CA1704:IdentifiersShouldBeSpelledCorrectly", MessageId = "edm")]
970 public EnumType GetObjectSpaceType(EnumType edmSpaceType)
972 return GetObjectSpaceType<EnumType>(edmSpaceType);
976 /// This method returns the OSpace enum type mapped to the specified Edm Space Type.
977 /// If the DataSpace of the argument is not CSpace, or if the mapped OSpace type
978 /// cannot be determined, the method returns false and sets the out parameter
981 /// <param name="edmSpaceType">The CSpace type to look up</param>
982 /// <param name="objectSpaceType">The OSpace type mapped to the supplied argument</param>
983 /// <returns>true on success, false on failure</returns>
984 [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1011:ConsiderPassingBaseTypesAsParameters"), System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Naming", "CA1704:IdentifiersShouldBeSpelledCorrectly", MessageId = "edm")]
985 public bool TryGetObjectSpaceType(EnumType edmSpaceType, out EnumType objectSpaceType)
987 return TryGetObjectSpaceType<EnumType>(edmSpaceType, out objectSpaceType);
991 /// Helper method returning the OSpace enum type mapped to the specified Edm Space Type.
992 /// If the DataSpace of the argument is not CSpace, or the mapped OSpace type
993 /// cannot be determined, an ArgumentException is thrown.
995 /// <param name="edmSpaceType">The CSpace type to look up</param>
996 /// <returns>The OSpace type mapped to the supplied argument</returns>
997 /// <typeparam name="T">Must be StructuralType or EnumType.</typeparam>
998 private T GetObjectSpaceType<T>(T edmSpaceType)
1002 edmSpaceType == null || edmSpaceType is StructuralType || edmSpaceType is EnumType,
1003 "Only structural or enum type expected");
1006 if (!this.TryGetObjectSpaceType(edmSpaceType, out objectSpaceType))
1008 throw EntityUtil.Argument(Strings.FailedToFindOSpaceTypeMapping(edmSpaceType.Identity));
1011 return objectSpaceType;
1015 /// Helper method returning the OSpace structural or enum type mapped to the specified Edm Space Type.
1016 /// If the DataSpace of the argument is not CSpace, or if the mapped OSpace type
1017 /// cannot be determined, the method returns false and sets the out parameter
1020 /// <param name="edmSpaceType">The CSpace type to look up</param>
1021 /// <param name="objectSpaceType">The OSpace type mapped to the supplied argument</param>
1022 /// <returns>true on success, false on failure</returns>
1023 /// <typeparam name="T">Must be StructuralType or EnumType.</typeparam>
1024 private bool TryGetObjectSpaceType<T>(T edmSpaceType, out T objectSpaceType)
1028 edmSpaceType == null || edmSpaceType is StructuralType || edmSpaceType is EnumType,
1029 "Only structural or enum type expected");
1031 EntityUtil.CheckArgumentNull(edmSpaceType, "edmSpaceType");
1033 if (edmSpaceType.DataSpace != DataSpace.CSpace)
1035 throw EntityUtil.Argument(Strings.ArgumentMustBeCSpaceType, "edmSpaceType");
1038 objectSpaceType = null;
1041 if (this.TryGetMap(edmSpaceType, DataSpace.OCSpace, out map))
1043 ObjectTypeMapping ocMap = map as ObjectTypeMapping;
1046 objectSpaceType = (T)ocMap.ClrType;
1050 return objectSpaceType != null;
1054 /// This method returns the Edm Space structural type mapped to the OSpace Type parameter. If the
1055 /// DataSpace of the supplied type is not OSpace, or the mapped Edm Space type cannot
1056 /// be determined, an ArgumentException is thrown.
1058 /// <param name="objectSpaceType">The OSpace type to look up</param>
1059 /// <returns>The CSpace type mapped to the OSpace parameter</returns>
1060 [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Naming", "CA1704:IdentifiersShouldBeSpelledCorrectly", MessageId = "Edm")]
1061 public StructuralType GetEdmSpaceType(StructuralType objectSpaceType)
1063 return GetEdmSpaceType<StructuralType>(objectSpaceType);
1067 /// This method returns the Edm Space structural type mapped to the OSpace Type parameter. If the
1068 /// DataSpace of the supplied type is not OSpace, or the mapped Edm Space type cannot
1069 /// be determined, the method returns false and sets the out parameter to null.
1071 /// <param name="objectSpaceType">The OSpace type to look up</param>
1072 /// <param name="edmSpaceType">The mapped CSpace type</param>
1073 /// <returns>true on success, false on failure</returns>
1074 [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Naming", "CA1704:IdentifiersShouldBeSpelledCorrectly", MessageId = "edm"), System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Naming", "CA1704:IdentifiersShouldBeSpelledCorrectly", MessageId = "Edm")]
1075 public bool TryGetEdmSpaceType(StructuralType objectSpaceType, out StructuralType edmSpaceType)
1077 return TryGetEdmSpaceType<StructuralType>(objectSpaceType, out edmSpaceType);
1081 /// This method returns the Edm Space enum type mapped to the OSpace Type parameter. If the
1082 /// DataSpace of the supplied type is not OSpace, or the mapped Edm Space type cannot
1083 /// be determined, an ArgumentException is thrown.
1085 /// <param name="objectSpaceType">The OSpace type to look up</param>
1086 /// <returns>The CSpace type mapped to the OSpace parameter</returns>
1087 [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Naming", "CA1704:IdentifiersShouldBeSpelledCorrectly", MessageId = "Edm")]
1088 public EnumType GetEdmSpaceType(EnumType objectSpaceType)
1090 return GetEdmSpaceType<EnumType>(objectSpaceType);
1094 /// This method returns the Edm Space enum type mapped to the OSpace Type parameter. If the
1095 /// DataSpace of the supplied type is not OSpace, or the mapped Edm Space type cannot
1096 /// be determined, the method returns false and sets the out parameter to null.
1098 /// <param name="objectSpaceType">The OSpace type to look up</param>
1099 /// <param name="edmSpaceType">The mapped CSpace type</param>
1100 /// <returns>true on success, false on failure</returns>
1101 [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Naming", "CA1704:IdentifiersShouldBeSpelledCorrectly", MessageId = "edm"), System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Naming", "CA1704:IdentifiersShouldBeSpelledCorrectly", MessageId = "Edm")]
1102 public bool TryGetEdmSpaceType(EnumType objectSpaceType, out EnumType edmSpaceType)
1104 return TryGetEdmSpaceType<EnumType>(objectSpaceType, out edmSpaceType);
1108 /// Helper method returning the Edm Space structural or enum type mapped to the OSpace Type parameter. If the
1109 /// DataSpace of the supplied type is not OSpace, or the mapped Edm Space type cannot
1110 /// be determined, an ArgumentException is thrown.
1112 /// <param name="objectSpaceType">The OSpace type to look up</param>
1113 /// <returns>The CSpace type mapped to the OSpace parameter</returns>
1114 /// <typeparam name="T">Must be StructuralType or EnumType</typeparam>
1115 private T GetEdmSpaceType<T>(T objectSpaceType)
1119 objectSpaceType == null || objectSpaceType is StructuralType || objectSpaceType is EnumType,
1120 "Only structural or enum type expected");
1123 if (!this.TryGetEdmSpaceType(objectSpaceType, out edmSpaceType))
1125 throw EntityUtil.Argument(Strings.FailedToFindCSpaceTypeMapping(objectSpaceType.Identity));
1128 return edmSpaceType;
1132 /// Helper method returning the Edm Space structural or enum type mapped to the OSpace Type parameter. If the
1133 /// DataSpace of the supplied type is not OSpace, or the mapped Edm Space type cannot
1134 /// be determined, the method returns false and sets the out parameter to null.
1136 /// <param name="objectSpaceType">The OSpace type to look up</param>
1137 /// <param name="edmSpaceType">The mapped CSpace type</param>
1138 /// <returns>true on success, false on failure</returns>
1139 /// <typeparam name="T">Must be StructuralType or EnumType</typeparam>
1140 private bool TryGetEdmSpaceType<T>(T objectSpaceType, out T edmSpaceType)
1144 objectSpaceType == null || objectSpaceType is StructuralType || objectSpaceType is EnumType,
1145 "Only structural or enum type expected");
1147 EntityUtil.CheckArgumentNull(objectSpaceType, "objectSpaceType");
1149 if (objectSpaceType.DataSpace != DataSpace.OSpace)
1151 throw EntityUtil.Argument(Strings.ArgumentMustBeOSpaceType, "objectSpaceType");
1154 edmSpaceType = null;
1157 if (this.TryGetMap(objectSpaceType, DataSpace.OCSpace, out map))
1159 ObjectTypeMapping ocMap = map as ObjectTypeMapping;
1162 edmSpaceType = (T)ocMap.EdmType;
1166 return edmSpaceType != null;
1170 ///// Returns the update or query view for an Extent as a
1171 ///// command tree. For a given Extent, MetadataWorkspace will
1172 ///// have either a Query view or an Update view but not both.
1174 ///// <param name="extent"></param>
1175 ///// <returns></returns>
1176 internal DbQueryCommandTree GetCqtView(EntitySetBase extent)
1178 return GetGeneratedView(extent).GetCommandTree();
1182 /// Returns generated update or query view for the given extent.
1184 internal GeneratedView GetGeneratedView(EntitySetBase extent)
1186 ItemCollection collection = GetItemCollection(DataSpace.CSSpace, true);
1187 return ((StorageMappingItemCollection)collection).GetGeneratedView(extent, this);
1191 /// Returns a TypeOf/TypeOfOnly Query for a given Extent and Type as a command tree.
1193 /// <param name="extent"></param>
1194 /// <returns></returns>
1195 internal bool TryGetGeneratedViewOfType(EntitySetBase extent, EntityTypeBase type, bool includeSubtypes, out GeneratedView generatedView)
1197 ItemCollection collection = GetItemCollection(DataSpace.CSSpace, true);
1198 return ((StorageMappingItemCollection)collection).TryGetGeneratedViewOfType(this, extent, type, includeSubtypes, out generatedView);
1202 /// Returns generated function definition for the given function.
1203 /// Guarantees type match of declaration and generated parameters.
1204 /// Guarantees return type match.
1205 /// Throws internal error for functions without definition.
1206 /// Passes thru exception occured during definition generation.
1208 internal DbLambda GetGeneratedFunctionDefinition(EdmFunction function)
1210 ItemCollection collection = GetItemCollection(DataSpace.CSpace, true);
1211 return ((EdmItemCollection)collection).GetGeneratedFunctionDefinition(function);
1215 /// Determines if a target function exists for the given function import.
1217 /// <param name="functionImport">Function import (function declared in a model entity container)</param>
1218 /// <param name="targetFunctionMapping">Function target mapping (function to which the import is mapped in the target store)</param>
1219 /// <returns>true if a mapped target function exists; false otherwise</returns>
1220 internal bool TryGetFunctionImportMapping(EdmFunction functionImport, out FunctionImportMapping targetFunctionMapping)
1222 Debug.Assert(null != functionImport);
1223 ReadOnlyCollection<StorageEntityContainerMapping> entityContainerMaps = this.GetItems<StorageEntityContainerMapping>(DataSpace.CSSpace);
1224 foreach (StorageEntityContainerMapping containerMapping in entityContainerMaps)
1226 if (containerMapping.TryGetFunctionImportMapping(functionImport, out targetFunctionMapping))
1231 targetFunctionMapping = null;
1236 /// Returns the view loader associated with this workspace,
1237 /// creating a loader if non exists. The loader includes
1238 /// context information used by the update pipeline when
1239 /// processing changes to C-space extents.
1241 /// <returns></returns>
1242 internal ViewLoader GetUpdateViewLoader()
1244 if (_itemsCSSpace != null)
1246 return _itemsCSSpace.GetUpdateViewLoader();
1253 /// Takes in a Edm space type usage and converts into an
1254 /// equivalent O space type usage
1256 /// <param name="edmSpaceTypeUsage"></param>
1257 /// <returns></returns>
1258 internal TypeUsage GetOSpaceTypeUsage(TypeUsage edmSpaceTypeUsage)
1260 EntityUtil.CheckArgumentNull(edmSpaceTypeUsage, "edmSpaceTypeUsage");
1261 Debug.Assert(edmSpaceTypeUsage.EdmType != null, "The TypeUsage object does not have an EDMType.");
1263 EdmType clrType = null;
1264 if (Helper.IsPrimitiveType(edmSpaceTypeUsage.EdmType))
1266 ItemCollection collection = GetItemCollection(DataSpace.OSpace, true);
1267 clrType = collection.GetMappedPrimitiveType(((PrimitiveType)edmSpaceTypeUsage.EdmType).PrimitiveTypeKind);
1271 // Check and throw if the OC space doesn't exist
1272 ItemCollection collection = GetItemCollection(DataSpace.OCSpace, true);
1275 Map map = ((DefaultObjectMappingItemCollection)collection).GetMap(edmSpaceTypeUsage.EdmType);
1276 clrType = ((ObjectTypeMapping)map).ClrType;
1279 Debug.Assert(!Helper.IsPrimitiveType(clrType) ||
1280 object.ReferenceEquals(ClrProviderManifest.Instance.GetFacetDescriptions(clrType),
1281 EdmProviderManifest.Instance.GetFacetDescriptions(clrType.BaseType)),
1282 "these are no longer equal so we can't just use the same set of facets for the new type usage");
1284 // Transfer the facet values
1285 TypeUsage result = TypeUsage.Create(clrType, edmSpaceTypeUsage.Facets);
1291 /// Returns true if the item collection for the given space has already been registered else returns false
1293 /// <param name="dataSpace"></param>
1294 /// <returns></returns>
1295 internal bool IsItemCollectionAlreadyRegistered(DataSpace dataSpace)
1297 ItemCollection itemCollection;
1298 return TryGetItemCollection(dataSpace, out itemCollection);
1302 /// Requires: C, S and CS are registered in this and other
1303 /// Determines whether C, S and CS are equivalent. Useful in determining whether a DbCommandTree
1304 /// is usable within a particular entity connection.
1306 /// <param name="other">Other workspace.</param>
1307 /// <returns>true is C, S and CS collections are equivalent</returns>
1308 internal bool IsMetadataWorkspaceCSCompatible(MetadataWorkspace other)
1310 Debug.Assert(this.IsItemCollectionAlreadyRegistered(DataSpace.CSSpace) &&
1311 other.IsItemCollectionAlreadyRegistered(DataSpace.CSSpace),
1312 "requires: C, S and CS are registered in this and other");
1314 bool result = this._itemsCSSpace.MetadataEquals(other._itemsCSSpace);
1316 Debug.Assert(!result ||
1317 (this._itemsCSpace.MetadataEquals(other._itemsCSpace) && this._itemsSSpace.MetadataEquals(other._itemsSSpace)),
1318 "constraint: this.CS == other.CS --> this.S == other.S && this.C == other.C");
1324 /// Clear all the metadata cache entries
1326 public static void ClearCache()
1328 MetadataCache.Clear();
1329 ObjectItemCollection.ViewGenerationAssemblies.Clear();
1330 using (LockedAssemblyCache cache = AssemblyCache.AquireLockedAssemblyCache())
1337 /// Creates a new Metadata workspace sharing the (currently defined) item collections
1338 /// and tokens for caching purposes.
1340 /// <returns></returns>
1341 internal MetadataWorkspace ShallowCopy()
1343 MetadataWorkspace copy = (MetadataWorkspace)MemberwiseClone();
1344 if (null != copy._cacheTokens) {
1345 copy._cacheTokens = new List<Object>(copy._cacheTokens);
1351 /// Returns the canonical Model TypeUsage for a given PrimitiveTypeKind
1353 /// <param name="primitiveTypeKind">PrimitiveTypeKind for which a canonical TypeUsage is expected</param>
1354 /// <returns>a canonical model TypeUsage</returns>
1355 internal TypeUsage GetCanonicalModelTypeUsage(PrimitiveTypeKind primitiveTypeKind)
1357 return EdmProviderManifest.Instance.GetCanonicalModelTypeUsage(primitiveTypeKind);
1361 /// Returns the Model PrimitiveType for a given primitiveTypeKind
1363 /// <param name="primitiveTypeKind">a PrimitiveTypeKind for which a Model PrimitiveType is expected</param>
1364 /// <returns>Model PrimitiveType</returns>
1365 internal PrimitiveType GetModelPrimitiveType(PrimitiveTypeKind primitiveTypeKind)
1367 return EdmProviderManifest.Instance.GetPrimitiveType(primitiveTypeKind);
1370 // GetRequiredOriginalValueMembers and GetRelevantMembersForUpdate return list of "interesting" members for the given EntitySet/EntityType
1371 // Interesting Members are a subset of the following:
1373 // 1. Members with C-Side conditions (complex types can not have C-side condition at present)
1374 // 2. Members participating in association end
1375 // 3. Members with ConcurrencyMode 'Fixed'
1376 // 3.1 Complex Members with any child member having Concurrency mode Fixed
1377 // 4. Members included in Update ModificationFunction with Version='Original' (Original = Not Current)
1378 // 4.1 Complex Members in ModificationFunction if any sub-member is interesting
1379 // 5. Members included in Update ModificationFunction (mutually exclusive with 4 - required for partial update scenarios)
1381 // 7. All complex members - partial update scenarios only
1383 /// Returns members of a given EntitySet/EntityType for which original values are necessary for determining which tables to modify.
1385 /// <param name="entitySet">An EntitySet belonging to the C-Space</param>
1386 /// <param name="entityType">An EntityType that participates in the given EntitySet</param>
1387 /// <returns>Edm Members for which original Value is required</returns>
1389 /// This method returns the following groups of members: 0, 1, 2, 3, 3.1, 4, 4.1. (see group descriptions above).
1390 /// This method is marked as obsolete since it does not support partial update scenarios as it does not return
1391 /// members from group 5 and changing it to return these members would be a breaking change.
1393 [Obsolete("Use MetadataWorkspace.GetRelevantMembersForUpdate(EntitySetBase, EntityTypeBase, bool) instead")]
1394 public IEnumerable<EdmMember> GetRequiredOriginalValueMembers(EntitySetBase entitySet, EntityTypeBase entityType)
1396 return GetInterestingMembers(entitySet, entityType, StorageMappingItemCollection.InterestingMembersKind.RequiredOriginalValueMembers);
1400 /// Returns members of a given EntitySet/EntityType for which original values are needed when modifying an entity.
1402 /// <param name="entitySet">An EntitySet belonging to the C-Space</param>
1403 /// <param name="entityType">An EntityType that participates in the given EntitySet</param>
1404 /// <param name="partialUpdateSupported">Whether entities may be updated partially.</param>
1405 /// <returns>Edm Members for which original Value is required</returns>
1407 /// This method returns the following groups of members:
1408 /// - if <paramref name="partialUpdateSupported"/> is <c>false</c>: 1, 2, 3, 3.1, 4, 4.1, 6 (see group descriptions above)
1409 /// - if <paramref name="partialUpdateSupported"/> is <c>true</c>: 1, 2, 3, 3.1, 5, 6, 7 (see group descriptions above)
1410 /// See DevDiv bugs #124460 and #272992 for more details.
1412 public ReadOnlyCollection<EdmMember> GetRelevantMembersForUpdate(EntitySetBase entitySet, EntityTypeBase entityType, bool partialUpdateSupported)
1414 return GetInterestingMembers(
1417 partialUpdateSupported ?
1418 StorageMappingItemCollection.InterestingMembersKind.PartialUpdate :
1419 StorageMappingItemCollection.InterestingMembersKind.FullUpdate);
1423 /// Return members for <see cref="GetRequiredOriginalValueMembers"/> and <see cref="GetRelevantMembersForUpdate"/> methods.
1425 /// <param name="entitySet">An EntitySet belonging to the C-Space</param>
1426 /// <param name="entityType">An EntityType that participates in the given EntitySet</param>
1427 /// <param name="interestingMembersKind">Scenario the members should be returned for.</param>
1428 /// <returns>ReadOnlyCollection of interesting members for the requested scenario (<paramref name="interestingMembersKind"/>).</returns>
1429 private ReadOnlyCollection<EdmMember> GetInterestingMembers(EntitySetBase entitySet, EntityTypeBase entityType, StorageMappingItemCollection.InterestingMembersKind interestingMembersKind)
1431 EntityUtil.CheckArgumentNull<EntitySetBase>(entitySet, "entitySet");
1432 EntityUtil.CheckArgumentNull<EntityTypeBase>(entityType, "entityType");
1434 Debug.Assert(entitySet.EntityContainer != null);
1436 //Check that EntitySet is from CSpace
1437 if (entitySet.EntityContainer.DataSpace != DataSpace.CSpace)
1439 AssociationSet associationSet = entitySet as AssociationSet;
1440 if (associationSet != null)
1442 throw EntityUtil.AssociationSetNotInCSpace(entitySet.Name);
1446 throw EntityUtil.EntitySetNotInCSpace(entitySet.Name);
1450 //Check that entityType belongs to entitySet
1451 if (!entitySet.ElementType.IsAssignableFrom(entityType))
1453 AssociationSet associationSet = entitySet as AssociationSet;
1454 if (associationSet != null)
1456 throw EntityUtil.TypeNotInAssociationSet(entitySet.Name, entitySet.ElementType.FullName, entityType.FullName);
1460 throw EntityUtil.TypeNotInEntitySet(entitySet.Name, entitySet.ElementType.FullName, entityType.FullName);
1464 var mappingCollection = (StorageMappingItemCollection)GetItemCollection(DataSpace.CSSpace, true);
1465 return mappingCollection.GetInterestingMembers(entitySet, entityType, interestingMembersKind);
1472 /// Returns the QueryCacheManager hosted by this metadata workspace instance
1474 internal System.Data.Common.QueryCache.QueryCacheManager GetQueryCacheManager()
1476 Debug.Assert(null != _itemsSSpace, "_itemsSSpace must not be null");
1477 return _itemsSSpace.QueryCacheManager;
1480 internal Guid MetadataWorkspaceId
1484 if (Guid.Equals(Guid.Empty, _metadataWorkspaceId))
1486 _metadataWorkspaceId = Guid.NewGuid();
1488 return _metadataWorkspaceId;