You've already forked linux-packaging-mono
							
							
		
			
				
	
	
		
			908 lines
		
	
	
		
			49 KiB
		
	
	
	
		
			C#
		
	
	
	
	
	
			
		
		
	
	
			908 lines
		
	
	
		
			49 KiB
		
	
	
	
		
			C#
		
	
	
	
	
	
| //---------------------------------------------------------------------
 | |
| // <copyright file="StorageMappingItemCollection.cs" company="Microsoft">
 | |
| //      Copyright (c) Microsoft Corporation.  All rights reserved.
 | |
| // </copyright>
 | |
| //
 | |
| // @owner       Microsoft
 | |
| // @backupOwner Microsoft
 | |
| //---------------------------------------------------------------------
 | |
| 
 | |
| using System.Collections.Concurrent;
 | |
| using System.Collections.Generic;
 | |
| using System.Collections.ObjectModel;
 | |
| using System.Data.Common.Utils;
 | |
| using System.Data.Entity;
 | |
| using System.Data.Mapping.Update.Internal;
 | |
| using System.Data.Mapping.ViewGeneration;
 | |
| using System.Data.Metadata.Edm;
 | |
| using System.Diagnostics;
 | |
| using System.Linq;
 | |
| using System.Runtime.Versioning;
 | |
| using System.Xml;
 | |
| using som = System.Data.EntityModel.SchemaObjectModel;
 | |
| 
 | |
| namespace System.Data.Mapping
 | |
| {
 | |
|     using OfTypeQVCacheKey = Pair<EntitySetBase, Pair<EntityTypeBase, bool>>;
 | |
| 
 | |
|     /// <summary>
 | |
|     /// Class for representing a collection of items in Storage Mapping( CS Mapping) space.
 | |
|     /// </summary>
 | |
|     [CLSCompliant(false)]
 | |
|     public partial class StorageMappingItemCollection : MappingItemCollection
 | |
|     {
 | |
|         #region Fields
 | |
|         //EdmItemCollection that is associated with the MSL Loader.
 | |
|         private EdmItemCollection m_edmCollection;
 | |
| 
 | |
|         //StoreItemCollection that is associated with the MSL Loader.
 | |
|         private StoreItemCollection m_storeItemCollection;
 | |
|         private ViewDictionary m_viewDictionary;
 | |
|         private double m_mappingVersion = XmlConstants.UndefinedVersion;
 | |
| 
 | |
|         private MetadataWorkspace m_workspace;
 | |
| 
 | |
|         // In this version, we won't allow same types in CSpace to map to different types in store. If the same type
 | |
|         // need to be reused, the store type must be the same. To keep track of this, we need to keep track of the member 
 | |
|         // mapping across maps to make sure they are mapped to the same store side.
 | |
|         // The first TypeUsage in the KeyValuePair stores the store equivalent type for the cspace member type and the second
 | |
|         // one store the actual store type to which the member is mapped to.
 | |
|         // For e.g. If the CSpace member of type Edm.Int32 maps to a sspace member of type SqlServer.bigint, then the KeyValuePair
 | |
|         // for the cspace member will contain SqlServer.int (store equivalent for Edm.Int32) and SqlServer.bigint (Actual store type
 | |
|         // to which the member was mapped to)
 | |
|         private Dictionary<EdmMember, KeyValuePair<TypeUsage, TypeUsage>> m_memberMappings = new Dictionary<EdmMember, KeyValuePair<TypeUsage, TypeUsage>>();
 | |
|         private ViewLoader _viewLoader;
 | |
| 
 | |
|         internal enum InterestingMembersKind
 | |
|         { 
 | |
|             RequiredOriginalValueMembers,   // legacy - used by the obsolete GetRequiredOriginalValueMembers
 | |
|             FullUpdate,                     // Interesting members in case of full update scenario
 | |
|             PartialUpdate                   // Interesting members in case of partial update scenario
 | |
|         };
 | |
| 
 | |
|         private ConcurrentDictionary<Tuple<EntitySetBase, EntityTypeBase, InterestingMembersKind>, ReadOnlyCollection<EdmMember>> _cachedInterestingMembers =
 | |
|             new ConcurrentDictionary<Tuple<EntitySetBase, EntityTypeBase, InterestingMembersKind>, ReadOnlyCollection<EdmMember>>();
 | |
| 
 | |
|         #endregion
 | |
| 
 | |
|         #region Constructors
 | |
|         /// <summary>
 | |
|         /// constructor that takes in a list of folder or files or a mix of both and
 | |
|         /// creates metadata for mapping in all the files.
 | |
|         /// </summary>
 | |
|         /// <param name="edmCollection"></param>
 | |
|         /// <param name="storeCollection"></param>
 | |
|         /// <param name="filePaths"></param>
 | |
|         [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
 | |
|         [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA2214:DoNotCallOverridableMethodsInConstructors"), System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Naming", "CA1704:IdentifiersShouldBeSpelledCorrectly", MessageId = "edm")]
 | |
|         public StorageMappingItemCollection(EdmItemCollection edmCollection, StoreItemCollection storeCollection,
 | |
|             params string[] filePaths)
 | |
|             : base(DataSpace.CSSpace)
 | |
|         {
 | |
|             EntityUtil.CheckArgumentNull(edmCollection, "edmCollection");
 | |
|             EntityUtil.CheckArgumentNull(storeCollection, "storeCollection");
 | |
|             EntityUtil.CheckArgumentNull(filePaths, "filePaths");
 | |
| 
 | |
|             this.m_edmCollection = edmCollection;
 | |
|             this.m_storeItemCollection = storeCollection;
 | |
| 
 | |
|             // Wrap the file paths in instances of the MetadataArtifactLoader class, which provides
 | |
|             // an abstraction and a uniform interface over a diverse set of metadata artifacts.
 | |
|             //
 | |
|             MetadataArtifactLoader composite = null;
 | |
|             List<XmlReader> readers = null;
 | |
|             try
 | |
|             {
 | |
|                 composite = MetadataArtifactLoader.CreateCompositeFromFilePaths(filePaths, XmlConstants.CSSpaceSchemaExtension);
 | |
|                 readers = composite.CreateReaders(DataSpace.CSSpace);
 | |
| 
 | |
|                 this.Init(edmCollection, storeCollection, readers,
 | |
|                           composite.GetPaths(DataSpace.CSSpace), true /*throwOnError*/);
 | |
|             }
 | |
|             finally
 | |
|             {
 | |
|                 if (readers != null)
 | |
|                 {
 | |
|                     Helper.DisposeXmlReaders(readers);
 | |
|                 }
 | |
|             }
 | |
|         }
 | |
| 
 | |
|         /// <summary>
 | |
|         /// constructor that takes in a list of XmlReaders and creates metadata for mapping 
 | |
|         /// in all the files.  
 | |
|         /// </summary>
 | |
|         /// <param name="edmCollection">The edm metadata collection that this mapping is to use</param>
 | |
|         /// <param name="storeCollection">The store metadata collection that this mapping is to use</param>
 | |
|         /// <param name="xmlReaders">The XmlReaders to load mapping from</param>
 | |
|         [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA2214:DoNotCallOverridableMethodsInConstructors"), System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Naming", "CA1704:IdentifiersShouldBeSpelledCorrectly", MessageId = "edm")]
 | |
|         public StorageMappingItemCollection(EdmItemCollection edmCollection,
 | |
|                                             StoreItemCollection storeCollection,
 | |
|                                             IEnumerable<XmlReader> xmlReaders)
 | |
|             : base(DataSpace.CSSpace)
 | |
|         {
 | |
|             EntityUtil.CheckArgumentNull(xmlReaders, "xmlReaders");
 | |
| 
 | |
|             MetadataArtifactLoader composite = MetadataArtifactLoader.CreateCompositeFromXmlReaders(xmlReaders);
 | |
| 
 | |
|             this.Init(edmCollection,
 | |
|                       storeCollection,
 | |
|                       composite.GetReaders(),   // filter out duplicates
 | |
|                       composite.GetPaths(),
 | |
|                       true /* throwOnError*/);
 | |
| 
 | |
|         }
 | |
| 
 | |
|         /// <summary>
 | |
|         /// constructor that takes in a list of XmlReaders and creates metadata for mapping 
 | |
|         /// in all the files.  
 | |
|         /// </summary>
 | |
|         /// <param name="edmCollection">The edm metadata collection that this mapping is to use</param>
 | |
|         /// <param name="storeCollection">The store metadata collection that this mapping is to use</param>
 | |
|         /// <param name="filePaths">Mapping URIs</param>
 | |
|         /// <param name="xmlReaders">The XmlReaders to load mapping from</param>
 | |
|         /// <param name="errors">a list of errors for each file loaded</param>
 | |
|         // referenced by System.Data.Entity.Design.dll
 | |
|         [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")]
 | |
|         [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA2214:DoNotCallOverridableMethodsInConstructors")]
 | |
|         internal StorageMappingItemCollection(EdmItemCollection edmCollection,
 | |
|                                               StoreItemCollection storeCollection,
 | |
|                                               IEnumerable<XmlReader> xmlReaders,
 | |
|                                               List<string> filePaths,
 | |
|                                               out IList<EdmSchemaError> errors)
 | |
|             : base(DataSpace.CSSpace)
 | |
|         {
 | |
|             // we will check the parameters for this internal ctor becuase
 | |
|             // it is pretty much publicly exposed through the MetadataItemCollectionFactory
 | |
|             // in System.Data.Entity.Design
 | |
|             EntityUtil.CheckArgumentNull(xmlReaders, "xmlReaders");
 | |
|             EntityUtil.CheckArgumentContainsNull(ref xmlReaders, "xmlReaders");
 | |
|             // filePaths is allowed to be null
 | |
| 
 | |
|             errors = this.Init(edmCollection, storeCollection, xmlReaders, filePaths, false /*throwOnError*/);
 | |
|         }
 | |
| 
 | |
|         /// <summary>
 | |
|         /// constructor that takes in a list of XmlReaders and creates metadata for mapping 
 | |
|         /// in all the files.  
 | |
|         /// </summary>
 | |
|         /// <param name="edmCollection">The edm metadata collection that this mapping is to use</param>
 | |
|         /// <param name="storeCollection">The store metadata collection that this mapping is to use</param>
 | |
|         /// <param name="filePaths">Mapping URIs</param>
 | |
|         /// <param name="xmlReaders">The XmlReaders to load mapping from</param>
 | |
|         [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA2214:DoNotCallOverridableMethodsInConstructors")]
 | |
|         internal StorageMappingItemCollection(EdmItemCollection edmCollection,
 | |
|                                               StoreItemCollection storeCollection,
 | |
|                                               IEnumerable<XmlReader> xmlReaders,
 | |
|                                               List<string> filePaths)
 | |
|             : base(DataSpace.CSSpace)
 | |
|         {
 | |
|             this.Init(edmCollection, storeCollection, xmlReaders, filePaths, true /*throwOnError*/);
 | |
|         }
 | |
| 
 | |
|         /// <summary>
 | |
|         /// Initializer that takes in a list of XmlReaders and creates metadata for mapping 
 | |
|         /// in all the files.  
 | |
|         /// </summary>
 | |
|         /// <param name="edmCollection">The edm metadata collection that this mapping is to use</param>
 | |
|         /// <param name="storeCollection">The store metadata collection that this mapping is to use</param>
 | |
|         /// <param name="filePaths">Mapping URIs</param>
 | |
|         /// <param name="xmlReaders">The XmlReaders to load mapping from</param>
 | |
|         /// <param name="errors">a list of errors for each file loaded</param>
 | |
|         private IList<EdmSchemaError> Init(EdmItemCollection edmCollection,
 | |
|                           StoreItemCollection storeCollection,
 | |
|                           IEnumerable<XmlReader> xmlReaders,
 | |
|                           List<string> filePaths,
 | |
|                           bool throwOnError)
 | |
|         {
 | |
|             EntityUtil.CheckArgumentNull(xmlReaders, "xmlReaders");
 | |
|             EntityUtil.CheckArgumentNull(edmCollection, "edmCollection");
 | |
|             EntityUtil.CheckArgumentNull(storeCollection, "storeCollection");
 | |
| 
 | |
|             this.m_edmCollection = edmCollection;
 | |
|             this.m_storeItemCollection = storeCollection;
 | |
|             
 | |
|             Dictionary<EntitySetBase, GeneratedView> userDefinedQueryViewsDict;
 | |
|             Dictionary<OfTypeQVCacheKey, GeneratedView> userDefinedQueryViewsOfTypeDict;
 | |
|             
 | |
|             this.m_viewDictionary = new ViewDictionary(this, out userDefinedQueryViewsDict, out userDefinedQueryViewsOfTypeDict);
 | |
| 
 | |
|             List<EdmSchemaError> errors = new List<EdmSchemaError>();
 | |
|             
 | |
|             if(this.m_edmCollection.EdmVersion != XmlConstants.UndefinedVersion &&
 | |
|                 this.m_storeItemCollection.StoreSchemaVersion != XmlConstants.UndefinedVersion &&
 | |
|                 this.m_edmCollection.EdmVersion != this.m_storeItemCollection.StoreSchemaVersion)
 | |
|             {
 | |
|                 errors.Add(
 | |
|                     new EdmSchemaError(
 | |
|                         Strings.Mapping_DifferentEdmStoreVersion, 
 | |
|                         (int)StorageMappingErrorCode.MappingDifferentEdmStoreVersion, EdmSchemaErrorSeverity.Error));
 | |
|             }
 | |
|             else
 | |
|             {
 | |
|                 double expectedVersion = this.m_edmCollection.EdmVersion != XmlConstants.UndefinedVersion
 | |
|                     ? this.m_edmCollection.EdmVersion
 | |
|                     : this.m_storeItemCollection.StoreSchemaVersion;
 | |
|                 errors.AddRange(LoadItems(xmlReaders, filePaths, userDefinedQueryViewsDict, userDefinedQueryViewsOfTypeDict, expectedVersion));
 | |
|             }
 | |
| 
 | |
|             Debug.Assert(errors != null);
 | |
| 
 | |
|             if (errors.Count > 0 && throwOnError)
 | |
|             {
 | |
|                 if (!System.Data.Common.Utils.MetadataHelper.CheckIfAllErrorsAreWarnings(errors))
 | |
|                 {
 | |
|                     // NOTE: not using Strings.InvalidSchemaEncountered because it will truncate the errors list.
 | |
|                     throw new MappingException(
 | |
|                     String.Format(System.Globalization.CultureInfo.CurrentCulture,
 | |
|                                     EntityRes.GetString(EntityRes.InvalidSchemaEncountered),
 | |
|                                     Helper.CombineErrorMessage(errors)));
 | |
|                 }
 | |
|             }
 | |
| 
 | |
|             return errors;
 | |
|         }
 | |
| 
 | |
|         #endregion Constructors
 | |
| 
 | |
|         internal MetadataWorkspace Workspace
 | |
|         {
 | |
|             get
 | |
|             {
 | |
|                 if (m_workspace == null)
 | |
|                 {
 | |
|                     m_workspace = new MetadataWorkspace();
 | |
|                     m_workspace.RegisterItemCollection(m_edmCollection);
 | |
|                     m_workspace.RegisterItemCollection(m_storeItemCollection);
 | |
|                     m_workspace.RegisterItemCollection(this);
 | |
|                 }
 | |
|                 return m_workspace;
 | |
|             }
 | |
|         }
 | |
| 
 | |
|         /// <summary>
 | |
|         /// Return the EdmItemCollection associated with the Mapping Collection
 | |
|         /// </summary>
 | |
|         internal EdmItemCollection EdmItemCollection
 | |
|         {
 | |
|             get
 | |
|             {
 | |
|                 return this.m_edmCollection;
 | |
|             }
 | |
|         }
 | |
| 
 | |
|         /// <summary>
 | |
|         /// Version of this StorageMappingItemCollection represents.
 | |
|         /// </summary>
 | |
|         public double MappingVersion
 | |
|         {
 | |
|             get
 | |
|             {
 | |
|                 return this.m_mappingVersion;
 | |
|             }
 | |
|         }
 | |
| 
 | |
|         /// <summary>
 | |
|         /// Return the StoreItemCollection associated with the Mapping Collection
 | |
|         /// </summary>
 | |
|         internal StoreItemCollection StoreItemCollection
 | |
|         {
 | |
|             get
 | |
|             {
 | |
|                 return this.m_storeItemCollection;
 | |
|             }
 | |
|         }
 | |
| 
 | |
|         /// <summary>
 | |
|         /// Search for a Mapping metadata with the specified type key.
 | |
|         /// </summary>
 | |
|         /// <param name="identity">identity of the 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>
 | |
|         /// <exception cref="ArgumentException"> Thrown if mapping space is not valid</exception>
 | |
|         internal override Map GetMap(string identity, DataSpace typeSpace, bool ignoreCase)
 | |
|         {
 | |
|             EntityUtil.CheckArgumentNull(identity, "identity");
 | |
|             if (typeSpace != DataSpace.CSpace)
 | |
|             {
 | |
|                 throw EntityUtil.InvalidOperation(System.Data.Entity.Strings.Mapping_Storage_InvalidSpace(typeSpace));
 | |
|             }
 | |
|             return GetItem<Map>(identity, ignoreCase);
 | |
|         }
 | |
| 
 | |
|         /// <summary>
 | |
|         /// Search for a Mapping metadata with the specified type key.
 | |
|         /// </summary>
 | |
|         /// <param name="identity">identity of the 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="map"></param>
 | |
|         /// <returns>Returns false if no match found.</returns>
 | |
|         internal override bool TryGetMap(string identity, DataSpace typeSpace, bool ignoreCase, out Map map)
 | |
|         {
 | |
|             if (typeSpace != DataSpace.CSpace)
 | |
|             {
 | |
|                 throw EntityUtil.InvalidOperation(System.Data.Entity.Strings.Mapping_Storage_InvalidSpace(typeSpace));
 | |
|             }
 | |
|             return TryGetItem<Map>(identity, ignoreCase, out map);
 | |
|         }
 | |
| 
 | |
|         /// <summary>
 | |
|         /// Search for a Mapping metadata with the specified type key.
 | |
|         /// </summary>
 | |
|         /// <param name="identity">identity of the type</param>
 | |
|         /// <param name="typeSpace">The dataspace that the type for which map needs to be returned belongs to</param>
 | |
|         /// <exception cref="ArgumentException"> Thrown if mapping space is not valid</exception>
 | |
|         internal override Map GetMap(string identity, DataSpace typeSpace)
 | |
|         {
 | |
|             return this.GetMap(identity, typeSpace, false /*ignoreCase*/);
 | |
|         }
 | |
| 
 | |
|         /// <summary>
 | |
|         /// Search for a Mapping metadata with the specified type key.
 | |
|         /// </summary>
 | |
|         /// <param name="identity">identity of the type</param>
 | |
|         /// <param name="typeSpace">The dataspace that the type for which map needs to be returned belongs to</param>
 | |
|         /// <param name="map"></param>
 | |
|         /// <returns>Returns false if no match found.</returns>
 | |
|         internal override bool TryGetMap(string identity, DataSpace typeSpace, out Map map)
 | |
|         {
 | |
|             return this.TryGetMap(identity, typeSpace, false /*ignoreCase*/, out map);
 | |
|         }
 | |
| 
 | |
|         /// <summary>
 | |
|         /// Search for a Mapping metadata with the specified type key.
 | |
|         /// </summary>
 | |
|         /// <param name="item"></param>
 | |
|         internal override Map GetMap(GlobalItem item)
 | |
|         {
 | |
|             EntityUtil.CheckArgumentNull(item, "item");
 | |
|             DataSpace typeSpace = item.DataSpace;
 | |
|             if (typeSpace != DataSpace.CSpace)
 | |
|             {
 | |
|                 throw EntityUtil.InvalidOperation(System.Data.Entity.Strings.Mapping_Storage_InvalidSpace(typeSpace));
 | |
|             }
 | |
|             return this.GetMap(item.Identity, typeSpace);
 | |
|         }
 | |
| 
 | |
|         /// <summary>
 | |
|         /// Search for a Mapping metadata with the specified type key.
 | |
|         /// </summary>
 | |
|         /// <param name="item"></param>
 | |
|         /// <param name="map"></param>
 | |
|         /// <returns>Returns false if no match found.</returns>
 | |
|         internal override bool TryGetMap(GlobalItem item, out Map map)
 | |
|         {
 | |
|             if (item == null)
 | |
|             {
 | |
|                 map = null;
 | |
|                 return false;
 | |
|             }
 | |
|             DataSpace typeSpace = item.DataSpace;
 | |
|             if (typeSpace != DataSpace.CSpace)
 | |
|             {
 | |
|                 map = null;
 | |
|                 return false;
 | |
|             }
 | |
|             return this.TryGetMap(item.Identity, typeSpace, out map);
 | |
|         }
 | |
| 
 | |
|         /// <summary>
 | |
|         /// This method
 | |
|         ///     - generates views from the mapping elements in the collection;
 | |
|         ///     - does not process user defined views - these are processed during mapping collection loading;
 | |
|         ///     - does not cache generated views in the mapping collection.
 | |
|         /// The main purpose is design-time view validation and generation.
 | |
|         /// </summary>
 | |
|         [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] // referenced by System.Data.Entity.Design.dll
 | |
|         internal Dictionary<EntitySetBase, string> GenerateEntitySetViews(out IList<EdmSchemaError> errors)
 | |
|         {
 | |
|             Dictionary<EntitySetBase, string> esqlViews = new Dictionary<EntitySetBase, string>();
 | |
|             errors = new List<EdmSchemaError>();
 | |
|             foreach (var mapping in GetItems<Map>())
 | |
|             {
 | |
|                 var entityContainerMapping = mapping as StorageEntityContainerMapping;
 | |
|                 if (entityContainerMapping != null)
 | |
|                 {
 | |
|                     // If there are no entity set maps, don't call the view generation process.
 | |
|                     if (!entityContainerMapping.HasViews)
 | |
|                     {
 | |
|                         return esqlViews;
 | |
|                     }
 | |
| 
 | |
|                     // If entityContainerMapping contains only query views, then add a warning to the errors and continue to next mapping.
 | |
|                     if (!entityContainerMapping.HasMappingFragments())
 | |
|                     {
 | |
|                         Debug.Assert(2088 == (int)StorageMappingErrorCode.MappingAllQueryViewAtCompileTime, "Please change the ERRORCODE_MAPPINGALLQUERYVIEWATCOMPILETIME value as well");
 | |
|                         errors.Add(new EdmSchemaError(
 | |
|                             Strings.Mapping_AllQueryViewAtCompileTime(entityContainerMapping.Identity),
 | |
|                             (int)StorageMappingErrorCode.MappingAllQueryViewAtCompileTime,
 | |
|                             EdmSchemaErrorSeverity.Warning));
 | |
|                     }
 | |
|                     else
 | |
|                     {
 | |
|                         ViewGenResults viewGenResults = ViewgenGatekeeper.GenerateViewsFromMapping(entityContainerMapping, new ConfigViewGenerator() { GenerateEsql = true });
 | |
|                         if (viewGenResults.HasErrors)
 | |
|                         {
 | |
|                             ((List<EdmSchemaError>)errors).AddRange(viewGenResults.Errors);
 | |
|                         }
 | |
|                         KeyToListMap<EntitySetBase, GeneratedView> extentMappingViews = viewGenResults.Views;
 | |
|                         foreach (KeyValuePair<EntitySetBase, List<GeneratedView>> extentViewPair in extentMappingViews.KeyValuePairs)
 | |
|                         {
 | |
|                             List<GeneratedView> generatedViews = extentViewPair.Value;
 | |
|                             // Multiple Views are returned for an extent but the first view
 | |
|                             // is the only one that we will use for now. In the future,
 | |
|                             // we might start using the other views which are per type within an extent.
 | |
|                             esqlViews.Add(extentViewPair.Key, generatedViews[0].eSQL);
 | |
|                         }
 | |
|                     }
 | |
|                 }
 | |
|             }
 | |
|             return esqlViews;
 | |
|         }
 | |
| 
 | |
|         #region Get interesting members
 | |
| 
 | |
|         /// <summary>
 | |
|         /// Return members for MetdataWorkspace.GetRequiredOriginalValueMembers() and MetdataWorkspace.GetRelevantMembersForUpdate() methods.
 | |
|         /// </summary>
 | |
|         /// <param name="entitySet">An EntitySet belonging to the C-Space. Must not be null.</param>
 | |
|         /// <param name="entityType">An EntityType that participates in the given EntitySet. Must not be null.</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>        
 | |
|         internal ReadOnlyCollection<EdmMember> GetInterestingMembers(EntitySetBase entitySet, EntityTypeBase entityType, InterestingMembersKind interestingMembersKind)
 | |
|         {
 | |
|             Debug.Assert(entitySet != null, "entitySet != null");
 | |
|             Debug.Assert(entityType != null, "entityType != null");
 | |
| 
 | |
|             var key = new Tuple<EntitySetBase, EntityTypeBase, InterestingMembersKind>(entitySet, entityType, interestingMembersKind);
 | |
|             return _cachedInterestingMembers.GetOrAdd(key,  FindInterestingMembers(entitySet, entityType, interestingMembersKind));
 | |
|         }
 | |
| 
 | |
|         /// <summary>
 | |
|         /// Finds interesting members for MetdataWorkspace.GetRequiredOriginalValueMembers() and MetdataWorkspace.GetRelevantMembersForUpdate() methods
 | |
|         /// for the given <paramref name="entitySet"/> and <paramref name="entityType"/>.
 | |
|         /// </summary>
 | |
|         /// <param name="entitySet">An EntitySet belonging to the C-Space. Must not be null.</param>
 | |
|         /// <param name="entityType">An EntityType that participates in the given EntitySet. Must not be null.</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> FindInterestingMembers(EntitySetBase entitySet, EntityTypeBase entityType, InterestingMembersKind interestingMembersKind)
 | |
|         {
 | |
|             Debug.Assert(entitySet != null, "entitySet != null");
 | |
|             Debug.Assert(entityType != null, "entityType != null");
 | |
| 
 | |
|             var interestingMembers = new List<EdmMember>();
 | |
| 
 | |
|             foreach (var storageTypeMapping in MappingMetadataHelper.GetMappingsForEntitySetAndSuperTypes(this, entitySet.EntityContainer, entitySet, entityType))
 | |
|             {
 | |
|                 StorageAssociationTypeMapping associationTypeMapping = storageTypeMapping as StorageAssociationTypeMapping;
 | |
|                 if (associationTypeMapping != null)
 | |
|                 {
 | |
|                     FindInterestingAssociationMappingMembers(associationTypeMapping, interestingMembers);
 | |
|                 }
 | |
|                 else
 | |
|                 {
 | |
|                     Debug.Assert(storageTypeMapping is StorageEntityTypeMapping, "StorageEntityTypeMapping expected.");
 | |
| 
 | |
|                     FindInterestingEntityMappingMembers((StorageEntityTypeMapping)storageTypeMapping, interestingMembersKind, interestingMembers);
 | |
|                 }
 | |
|             }
 | |
| 
 | |
|             // For backwards compatibility we don't return foreign keys from the obsolete MetadataWorkspace.GetRequiredOriginalValueMembers() method
 | |
|             if (interestingMembersKind != InterestingMembersKind.RequiredOriginalValueMembers)
 | |
|             {
 | |
|                 FindForeignKeyProperties(entitySet, entityType, interestingMembers);
 | |
|             }
 | |
| 
 | |
|             foreach (var functionMappings in MappingMetadataHelper
 | |
|                                                 .GetModificationFunctionMappingsForEntitySetAndType(this, entitySet.EntityContainer, entitySet, entityType)
 | |
|                                                 .Where(functionMappings => functionMappings.UpdateFunctionMapping != null))
 | |
|             {
 | |
|                 FindInterestingFunctionMappingMembers(functionMappings, interestingMembersKind, ref interestingMembers);
 | |
|             }
 | |
| 
 | |
|             Debug.Assert(interestingMembers != null, "interestingMembers must never be null.");
 | |
| 
 | |
|             return new ReadOnlyCollection<EdmMember>(interestingMembers.Distinct().ToList());
 | |
|         }
 | |
| 
 | |
|         /// <summary>
 | |
|         /// Finds members participating in the assocciation and adds them to the <paramref name="interestingMembers"/>.
 | |
|         /// </summary>
 | |
|         /// <param name="associationTypeMapping">Association type mapping. Must not be null.</param>
 | |
|         /// <param name="interestingMembers">The list the interesting members (if any) will be added to. Must not be null.</param>
 | |
|         private static void FindInterestingAssociationMappingMembers(StorageAssociationTypeMapping associationTypeMapping, List<EdmMember> interestingMembers)
 | |
|         {
 | |
|             Debug.Assert(associationTypeMapping != null, "entityTypeMapping != null");
 | |
|             Debug.Assert(interestingMembers != null, "interestingMembers != null");
 | |
| 
 | |
|             //(2) Ends participating in association are "interesting"
 | |
|             interestingMembers.AddRange(
 | |
|                 associationTypeMapping
 | |
|                 .MappingFragments
 | |
|                 .SelectMany(m => m.AllProperties)
 | |
|                 .OfType<StorageEndPropertyMapping>()
 | |
|                 .Select(epm => epm.EndMember));
 | |
|         }
 | |
| 
 | |
|         /// <summary>
 | |
|         /// Finds interesting entity properties - primary keys (if requested), properties (including complex properties and nested properties)
 | |
|         /// with concurrency mode set to fixed and C-Side condition members and adds them to the <paramref name="interestingMembers"/>.
 | |
|         /// </summary>
 | |
|         /// <param name="entityTypeMapping">Entity type mapping. Must not be null.</param>
 | |
|         /// <param name="interestingMembersKind">Scenario the members should be returned for.</param>
 | |
|         /// <param name="interestingMembers">The list the interesting members (if any) will be added to. Must not be null.</param>
 | |
|         private static void FindInterestingEntityMappingMembers(StorageEntityTypeMapping entityTypeMapping, InterestingMembersKind interestingMembersKind, List<EdmMember> interestingMembers)
 | |
|         {
 | |
|             Debug.Assert(entityTypeMapping != null, "entityTypeMapping != null");
 | |
|             Debug.Assert(interestingMembers != null, "interestingMembers != null");
 | |
| 
 | |
|             foreach (var propertyMapping in entityTypeMapping.MappingFragments.SelectMany(mf => mf.AllProperties))
 | |
|             {
 | |
|                 StorageScalarPropertyMapping scalarPropMapping = propertyMapping as StorageScalarPropertyMapping;
 | |
|                 StorageComplexPropertyMapping complexPropMapping = propertyMapping as StorageComplexPropertyMapping;
 | |
|                 StorageConditionPropertyMapping conditionMapping = propertyMapping as StorageConditionPropertyMapping;
 | |
| 
 | |
|                 Debug.Assert(!(propertyMapping is StorageEndPropertyMapping), "association mapping properties should be handled elsewhere.");
 | |
| 
 | |
|                 Debug.Assert(scalarPropMapping != null ||
 | |
|                              complexPropMapping != null ||
 | |
|                              conditionMapping != null, "Unimplemented property mapping");
 | |
| 
 | |
|                 //scalar property
 | |
|                 if (scalarPropMapping != null && scalarPropMapping.EdmProperty != null)
 | |
|                 {
 | |
|                     // (0) if a member is part of the key it is interesting
 | |
|                     if (MetadataHelper.IsPartOfEntityTypeKey(scalarPropMapping.EdmProperty))
 | |
|                     {
 | |
|                         // For backwards compatibility we do return primary keys from the obsolete MetadataWorkspace.GetRequiredOriginalValueMembers() method
 | |
|                         if (interestingMembersKind == InterestingMembersKind.RequiredOriginalValueMembers)
 | |
|                         {
 | |
|                             interestingMembers.Add(scalarPropMapping.EdmProperty);
 | |
|                         }
 | |
|                     }
 | |
|                     //(3) if a scalar property has Fixed concurrency mode then it is "interesting"
 | |
|                     else if (MetadataHelper.GetConcurrencyMode(scalarPropMapping.EdmProperty) == ConcurrencyMode.Fixed)
 | |
|                     {
 | |
|                         interestingMembers.Add(scalarPropMapping.EdmProperty);
 | |
|                     }
 | |
|                 }
 | |
|                 else if (complexPropMapping != null)
 | |
|                 {
 | |
|                     // (7) All complex members - partial update scenarios only
 | |
|                     // (3.1) The complex property or its one of its children has fixed concurrency mode
 | |
|                     if (interestingMembersKind == InterestingMembersKind.PartialUpdate ||
 | |
|                         MetadataHelper.GetConcurrencyMode(complexPropMapping.EdmProperty) == ConcurrencyMode.Fixed || HasFixedConcurrencyModeInAnyChildProperty(complexPropMapping))
 | |
|                     {
 | |
|                         interestingMembers.Add(complexPropMapping.EdmProperty);
 | |
|                     }
 | |
|                 }
 | |
|                 else if (conditionMapping != null)
 | |
|                 {
 | |
|                     //(1) C-Side condition members are 'interesting'
 | |
|                     if (conditionMapping.EdmProperty != null)
 | |
|                     {
 | |
|                         interestingMembers.Add(conditionMapping.EdmProperty);
 | |
|                     }
 | |
|                 }
 | |
|             }
 | |
|         }
 | |
| 
 | |
|         /// <summary>
 | |
|         /// Recurses down the complex property to find whether any of the nseted properties has concurrency mode set to "Fixed"
 | |
|         /// </summary>
 | |
|         /// <param name="complexMapping">Complex property mapping. Must not be null.</param>
 | |
|         /// <returns><c>true</c> if any of the descendant properties has concurrency mode set to "Fixed". Otherwise <c>false</c>.</returns>
 | |
|         private static bool HasFixedConcurrencyModeInAnyChildProperty(StorageComplexPropertyMapping complexMapping)
 | |
|         {
 | |
|             Debug.Assert(complexMapping != null, "complexMapping != null");
 | |
| 
 | |
|             foreach (StoragePropertyMapping propertyMapping in complexMapping.TypeMappings.SelectMany(m => m.AllProperties))
 | |
|             {
 | |
|                 StorageScalarPropertyMapping childScalarPropertyMapping = propertyMapping as StorageScalarPropertyMapping;
 | |
|                 StorageComplexPropertyMapping childComplexPropertyMapping = propertyMapping as StorageComplexPropertyMapping;
 | |
| 
 | |
|                 Debug.Assert(childScalarPropertyMapping != null ||
 | |
|                              childComplexPropertyMapping != null, "Unimplemented property mapping for complex property");
 | |
| 
 | |
|                 //scalar property and has Fixed CC mode
 | |
|                 if (childScalarPropertyMapping != null && MetadataHelper.GetConcurrencyMode(childScalarPropertyMapping.EdmProperty) == ConcurrencyMode.Fixed)
 | |
|                 {
 | |
|                     return true;
 | |
|                 }
 | |
|                 // Complex Prop and sub-properties or itself has fixed CC mode
 | |
|                 else if (childComplexPropertyMapping != null &&
 | |
|                     (MetadataHelper.GetConcurrencyMode(childComplexPropertyMapping.EdmProperty) == ConcurrencyMode.Fixed
 | |
|                         || HasFixedConcurrencyModeInAnyChildProperty(childComplexPropertyMapping)))
 | |
|                 {
 | |
|                     return true;
 | |
|                 }
 | |
|             }
 | |
| 
 | |
|             return false;
 | |
|         }
 | |
| 
 | |
|         /// <summary>
 | |
|         /// Finds foreign key properties and adds them to the <paramref name="interestingMembers"/>.
 | |
|         /// </summary>
 | |
|         /// <param name="entitySetBase">Entity set <paramref name="entityType"/> relates to. Must not be null.</param>
 | |
|         /// <param name="entityType">Entity type for which to find foreign key properties. Must not be null.</param>
 | |
|         /// <param name="interestingMembers">The list the interesting members (if any) will be added to. Must not be null.</param>
 | |
|         private void FindForeignKeyProperties(EntitySetBase entitySetBase, EntityTypeBase entityType, List<EdmMember> interestingMembers)
 | |
|         {
 | |
|             var entitySet = entitySetBase as EntitySet;
 | |
|             if (entitySet != null && entitySet.HasForeignKeyRelationships)
 | |
|             {
 | |
|                 // (6) Foreign keys
 | |
|                 // select all foreign key properties defined on the entityType and all its ancestors
 | |
|                 interestingMembers.AddRange(
 | |
|                         MetadataHelper.GetTypeAndParentTypesOf(entityType, this.m_edmCollection, true)
 | |
|                         .SelectMany(e => ((EntityType)e).Properties)
 | |
|                         .Where(p => entitySet.ForeignKeyDependents.SelectMany(fk => fk.Item2.ToProperties).Contains(p)));
 | |
|             }
 | |
|         }
 | |
|         
 | |
|         /// <summary>
 | |
|         /// Finds interesting members for modification functions mapped to stored procedures and adds them to the <paramref name="interestingMembers"/>.
 | |
|         /// </summary>
 | |
|         /// <param name="functionMappings">Modification function mapping. Must not be null.</param>
 | |
|         /// <param name="interestingMembersKind">Update scenario the members will be used in (in general - partial update vs. full update).</param>
 | |
|         /// <param name="interestingMembers"></param>
 | |
|         private static void FindInterestingFunctionMappingMembers(StorageEntityTypeModificationFunctionMapping functionMappings, InterestingMembersKind interestingMembersKind, ref List<EdmMember> interestingMembers)
 | |
|         {
 | |
|             Debug.Assert(functionMappings != null && functionMappings.UpdateFunctionMapping != null, "Expected function mapping fragment with non-null update function mapping");
 | |
|             Debug.Assert(interestingMembers != null, "interestingMembers != null");
 | |
| 
 | |
|             // for partial update scenarios (e.g. EntityDataSourceControl) all members are interesting otherwise the data may be corrupt. 
 | |
|             // See bugs #272992 and #124460 in DevDiv database for more details. For full update scenarios and the obsolete 
 | |
|             // MetadataWorkspace.GetRequiredOriginalValueMembers() metod we return only members with Version set to "Original".
 | |
|             if (interestingMembersKind == InterestingMembersKind.PartialUpdate)
 | |
|             {
 | |
|                 // (5) Members included in Update ModificationFunction
 | |
|                 interestingMembers.AddRange(functionMappings.UpdateFunctionMapping.ParameterBindings.Select(p => p.MemberPath.Members.Last()));
 | |
|             }
 | |
|             else
 | |
|             {
 | |
|                 //(4) Members in update ModificationFunction with Version="Original" are "interesting"
 | |
|                 // This also works when you have complex-types (4.1)
 | |
| 
 | |
|                 Debug.Assert(
 | |
|                     interestingMembersKind == InterestingMembersKind.FullUpdate || interestingMembersKind == InterestingMembersKind.RequiredOriginalValueMembers,
 | |
|                     "Unexpected kind of interesting members - if you changed the InterestingMembersKind enum type update this code accordingly");
 | |
| 
 | |
|                 foreach (var parameterBinding in functionMappings.UpdateFunctionMapping.ParameterBindings.Where(p => !p.IsCurrent))
 | |
|                 {
 | |
|                     //Last is the root element (with respect to the Entity)
 | |
|                     //For example,  Entity1={
 | |
|                     //                  S1, 
 | |
|                     //                  C1{S2, 
 | |
|                     //                     C2{ S3, S4 } 
 | |
|                     //                     }, 
 | |
|                     //                  S5}
 | |
|                     // if S4 matches (i.e. C1.C2.S4), then it returns C1
 | |
|                     //because internally the list is [S4][C2][C1]
 | |
|                     interestingMembers.Add(parameterBinding.MemberPath.Members.Last());
 | |
|                 }
 | |
|             }
 | |
|         }
 | |
| 
 | |
|         #endregion
 | |
| 
 | |
|         /// <summary>
 | |
|         /// Calls the view dictionary to load the view, see detailed comments in the view dictionary class.
 | |
|         /// </summary>
 | |
|         internal GeneratedView GetGeneratedView(EntitySetBase extent, MetadataWorkspace workspace)
 | |
|         {
 | |
|             return this.m_viewDictionary.GetGeneratedView(extent, workspace, this);
 | |
|         }
 | |
| 
 | |
|         // Add to the cache. If it is already present, then throw an exception
 | |
|         private void AddInternal(Map storageMap)
 | |
|         {
 | |
|             storageMap.DataSpace = DataSpace.CSSpace;
 | |
|             try
 | |
|             {
 | |
|                 base.AddInternal(storageMap);
 | |
|             }
 | |
|             catch (ArgumentException e)
 | |
|             {
 | |
|                 throw new MappingException(System.Data.Entity.Strings.Mapping_Duplicate_Type(storageMap.EdmItem.Identity), e);
 | |
|             }
 | |
|         }
 | |
| 
 | |
|         // Contains whether the given StorageEntityContainerName
 | |
|         internal bool ContainsStorageEntityContainer(string storageEntityContainerName)
 | |
|         {
 | |
|             ReadOnlyCollection<StorageEntityContainerMapping> entityContainerMaps =
 | |
|                 this.GetItems<StorageEntityContainerMapping>();
 | |
|             return entityContainerMaps.Any(map => map.StorageEntityContainer.Name.Equals(storageEntityContainerName, StringComparison.Ordinal));
 | |
|         }
 | |
| 
 | |
| 
 | |
|         /// <summary>
 | |
|         /// This helper method loads items based on contents of in-memory XmlReader instances.
 | |
|         /// Assumption: This method is called only from the constructor because m_extentMappingViews is not thread safe.
 | |
|         /// </summary>
 | |
|         /// <param name="xmlReaders">A list of XmlReader instances</param>
 | |
|         /// <param name="mappingSchemaUris">A list of URIs</param>
 | |
|         /// <returns>A list of schema errors</returns>
 | |
|         private List<EdmSchemaError> LoadItems(IEnumerable<XmlReader> xmlReaders,
 | |
|                                                List<string> mappingSchemaUris,
 | |
|                                                Dictionary<EntitySetBase, GeneratedView> userDefinedQueryViewsDict,
 | |
|                                                Dictionary<OfTypeQVCacheKey, GeneratedView> userDefinedQueryViewsOfTypeDict,
 | |
|                                                double expectedVersion)
 | |
|         {
 | |
|             Debug.Assert(m_memberMappings.Count == 0, "Assumption: This method is called only once, and from the constructor because m_extentMappingViews is not thread safe.");
 | |
| 
 | |
|             List<EdmSchemaError> errors = new List<EdmSchemaError>();
 | |
| 
 | |
|             int index = -1;
 | |
|             foreach (XmlReader xmlReader in xmlReaders)
 | |
|             {
 | |
|                 index++;
 | |
|                 string location = null;
 | |
|                 if (mappingSchemaUris == null)
 | |
|                 {
 | |
|                     som.SchemaManager.TryGetBaseUri(xmlReader, out location);
 | |
|                 }
 | |
|                 else
 | |
|                 {
 | |
|                     location = mappingSchemaUris[index];
 | |
|                 }
 | |
| 
 | |
|                 StorageMappingItemLoader mapLoader = new StorageMappingItemLoader(
 | |
|                                                             xmlReader,
 | |
|                                                             this,
 | |
|                                                             location,  // ASSUMPTION: location is only used for generating error-messages
 | |
|                                                             m_memberMappings);
 | |
|                 errors.AddRange(mapLoader.ParsingErrors);
 | |
| 
 | |
|                 CheckIsSameVersion(expectedVersion, mapLoader.MappingVersion, errors);
 | |
| 
 | |
|                 // Process container mapping.
 | |
|                 StorageEntityContainerMapping containerMapping = mapLoader.ContainerMapping;
 | |
|                 if (mapLoader.HasQueryViews && containerMapping != null)
 | |
|                 {
 | |
|                     // Compile the query views so that we can report the errors in the user specified views.
 | |
|                     CompileUserDefinedQueryViews(containerMapping, userDefinedQueryViewsDict, userDefinedQueryViewsOfTypeDict, errors);
 | |
|                 }
 | |
|                 // Add container mapping if there are no errors and entity container mapping is not already present.
 | |
|                 if (MetadataHelper.CheckIfAllErrorsAreWarnings(errors) && !this.Contains(containerMapping))
 | |
|                 {
 | |
|                     AddInternal(containerMapping);
 | |
|                 }
 | |
|             }
 | |
| 
 | |
|             CheckForDuplicateItems(EdmItemCollection, StoreItemCollection, errors);
 | |
| 
 | |
|             return errors;
 | |
|         }
 | |
| 
 | |
|         /// <summary>
 | |
|         /// This method compiles all the user defined query views in the <paramref name="entityContainerMapping"/>.
 | |
|         /// </summary>
 | |
|         private static void CompileUserDefinedQueryViews(StorageEntityContainerMapping entityContainerMapping,
 | |
|                                                          Dictionary<EntitySetBase, GeneratedView> userDefinedQueryViewsDict,
 | |
|                                                          Dictionary<OfTypeQVCacheKey, GeneratedView> userDefinedQueryViewsOfTypeDict,
 | |
|                                                          IList<EdmSchemaError> errors)
 | |
|         {
 | |
|             ConfigViewGenerator config = new ConfigViewGenerator();
 | |
|             foreach (StorageSetMapping setMapping in entityContainerMapping.AllSetMaps)
 | |
|             {
 | |
|                 if (setMapping.QueryView != null)
 | |
|                 {
 | |
|                     GeneratedView generatedView;
 | |
|                     if (!userDefinedQueryViewsDict.TryGetValue(setMapping.Set, out generatedView))
 | |
|                     {
 | |
|                         // Parse the view so that we will get back any errors in the view.
 | |
|                         if (GeneratedView.TryParseUserSpecifiedView(setMapping,
 | |
|                                                                     setMapping.Set.ElementType,
 | |
|                                                                     setMapping.QueryView,
 | |
|                                                                     true, // includeSubtypes
 | |
|                                                                     entityContainerMapping.StorageMappingItemCollection,
 | |
|                                                                     config,
 | |
|                                                                     /*out*/ errors,
 | |
|                                                                     out generatedView))
 | |
|                         {
 | |
|                             // Add first QueryView
 | |
|                             userDefinedQueryViewsDict.Add(setMapping.Set, generatedView);
 | |
|                         }
 | |
| 
 | |
|                         // Add all type-specific QueryViews
 | |
|                         foreach (OfTypeQVCacheKey key in setMapping.GetTypeSpecificQVKeys())
 | |
|                         {
 | |
|                             Debug.Assert(key.First.Equals(setMapping.Set));
 | |
| 
 | |
|                             if (GeneratedView.TryParseUserSpecifiedView(setMapping,
 | |
|                                                                         key.Second.First, // type
 | |
|                                                                         setMapping.GetTypeSpecificQueryView(key),
 | |
|                                                                         key.Second.Second, // includeSubtypes
 | |
|                                                                         entityContainerMapping.StorageMappingItemCollection,
 | |
|                                                                         config,
 | |
|                                                                         /*out*/ errors,
 | |
|                                                                         out generatedView))
 | |
|                             {
 | |
|                                 userDefinedQueryViewsOfTypeDict.Add(key, generatedView);
 | |
|                             }
 | |
|                         }
 | |
|                     }
 | |
|                 }
 | |
|             }
 | |
|         }
 | |
| 
 | |
|         private void CheckIsSameVersion(double expectedVersion, double currentLoaderVersion, IList<EdmSchemaError> errors)
 | |
|         {
 | |
|             if (m_mappingVersion == XmlConstants.UndefinedVersion)
 | |
|             {
 | |
|                 m_mappingVersion = currentLoaderVersion;
 | |
|             }
 | |
|             if (expectedVersion != XmlConstants.UndefinedVersion && currentLoaderVersion != XmlConstants.UndefinedVersion && currentLoaderVersion != expectedVersion)
 | |
|             {
 | |
|                 // Check that the mapping version is the same as the storage and model version
 | |
|                 errors.Add(
 | |
|                     new EdmSchemaError(
 | |
|                         Strings.Mapping_DifferentMappingEdmStoreVersion,
 | |
|                         (int)StorageMappingErrorCode.MappingDifferentMappingEdmStoreVersion, EdmSchemaErrorSeverity.Error));
 | |
|             }
 | |
|             if (currentLoaderVersion != m_mappingVersion && currentLoaderVersion != XmlConstants.UndefinedVersion)
 | |
|             {
 | |
|                 // Check that the mapping versions are all consistent with each other
 | |
|                 errors.Add(
 | |
|                    new EdmSchemaError(
 | |
|                        Strings.CannotLoadDifferentVersionOfSchemaInTheSameItemCollection,
 | |
|                        (int)StorageMappingErrorCode.CannotLoadDifferentVersionOfSchemaInTheSameItemCollection,
 | |
|                        EdmSchemaErrorSeverity.Error));
 | |
|             }
 | |
|         }
 | |
| 
 | |
|         /// <summary>
 | |
|         /// Return the update view loader
 | |
|         /// </summary>
 | |
|         /// <returns></returns>
 | |
|         internal ViewLoader GetUpdateViewLoader()
 | |
|         {
 | |
|             if (_viewLoader == null)
 | |
|             {
 | |
|                 _viewLoader = new ViewLoader(this);
 | |
|             }
 | |
| 
 | |
|             return _viewLoader;
 | |
|         }
 | |
| 
 | |
|         /// <summary>
 | |
|         /// this method will be called in metadatworkspace, the signature is the same as the one in ViewDictionary
 | |
|         /// </summary>
 | |
|         /// <param name="workspace"></param>
 | |
|         /// <param name="entity"></param>
 | |
|         /// <param name="type"></param>
 | |
|         /// <param name="includeSubtypes"></param>
 | |
|         /// <param name="generatedView"></param>
 | |
|         /// <returns></returns>
 | |
|         internal bool TryGetGeneratedViewOfType(MetadataWorkspace workspace, EntitySetBase entity, EntityTypeBase type, bool includeSubtypes, out GeneratedView generatedView)
 | |
|         {
 | |
|             return this.m_viewDictionary.TryGetGeneratedViewOfType(workspace, entity, type, includeSubtypes, out generatedView);
 | |
|         }
 | |
| 
 | |
|         // Check for duplicate items (items with same name) in edm item collection and store item collection. Mapping is the only logical place to do this. 
 | |
|         // The only other place is workspace, but that is at the time of registering item collections (only when the second one gets registered) and we 
 | |
|         // will have to throw exceptions at that time. If we do this check in mapping, we might throw error in a more consistent way (by adding it to error
 | |
|         // collection). Also if someone is just creating item collection, and not registering it with workspace (tools), doing it in mapping makes more sense
 | |
|         private static void CheckForDuplicateItems(EdmItemCollection edmItemCollection, StoreItemCollection storeItemCollection, List<EdmSchemaError> errorCollection)
 | |
|         {
 | |
|             Debug.Assert(edmItemCollection != null && storeItemCollection != null && errorCollection != null, "The parameters must not be null in CheckForDuplicateItems");
 | |
| 
 | |
|             foreach (GlobalItem item in edmItemCollection)
 | |
|             {
 | |
|                 if (storeItemCollection.Contains(item.Identity))
 | |
|                 {
 | |
|                     errorCollection.Add(new EdmSchemaError(Strings.Mapping_ItemWithSameNameExistsBothInCSpaceAndSSpace(item.Identity),
 | |
|                                         (int)StorageMappingErrorCode.ItemWithSameNameExistsBothInCSpaceAndSSpace, EdmSchemaErrorSeverity.Error));
 | |
|                 }
 | |
|             }
 | |
|         }
 | |
|     }//---- ItemCollection
 | |
| 
 | |
| }//---- 
 |