//--------------------------------------------------------------------- // // Copyright (c) Microsoft Corporation. All rights reserved. // // // @owner [....] // @backupOwner [....] //--------------------------------------------------------------------- namespace System.Data.Metadata.Edm { using System.Collections.Generic; using System.Data.Common; using System.Data.Common.Utils; using System.Data.Entity; using System.Diagnostics; using System.Linq; using System.Runtime.Versioning; using System.Xml; /// /// Class for representing a collection of items in Store space. /// [CLSCompliant(false)] public sealed partial class StoreItemCollection : ItemCollection { #region Fields double _schemaVersion = XmlConstants.UndefinedVersion; // Cache for primitive type maps for Edm to provider private readonly CacheForPrimitiveTypes _primitiveTypeMaps = new CacheForPrimitiveTypes(); private readonly Memoizer _cachedCTypeFunction; private readonly DbProviderManifest _providerManifest; private readonly string _providerManifestToken; private readonly DbProviderFactory _providerFactory; // Storing the query cache manager in the store item collection since all queries are currently bound to the // store. So storing it in StoreItemCollection makes sense. Also, since query cache requires version and other // stuff of the provider, we can assume that the connection is always open and we have the store metadata. // Also we can use the same cache manager both for Entity Client and Object Query, since query cache has // no reference to any metadata in OSpace. Also we assume that ObjectMaterializer loads the assembly // before it tries to do object materialization, since we might not have loaded an assembly in another workspace // where this store item collection is getting reused private readonly System.Data.Common.QueryCache.QueryCacheManager _queryCacheManager = System.Data.Common.QueryCache.QueryCacheManager.Create(); #endregion #region Constructors // used by EntityStoreSchemaGenerator to start with an empty (primitive types only) StoreItemCollection and // add types discovered from the database internal StoreItemCollection(DbProviderFactory factory, DbProviderManifest manifest, string providerManifestToken) : base(DataSpace.SSpace) { Debug.Assert(factory != null, "factory is null"); Debug.Assert(manifest != null, "manifest is null"); _providerFactory = factory; _providerManifest = manifest; _providerManifestToken = providerManifestToken; _cachedCTypeFunction = new Memoizer(ConvertFunctionSignatureToCType, null); LoadProviderManifest(_providerManifest, true /*checkForSystemNamespace*/); } /// /// constructor that loads the metadata files from the specified xmlReaders, and returns the list of errors /// encountered during load as the out parameter errors. /// /// Publicly available from System.Data.Entity.Desgin.dll /// /// xmlReaders where the CDM schemas are loaded /// the paths where the files can be found that match the xml readers collection /// An out parameter to return the collection of errors encountered while loading [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] // referenced by System.Data.Entity.Design.dll internal StoreItemCollection(IEnumerable xmlReaders, System.Collections.ObjectModel.ReadOnlyCollection filePaths, out IList errors) : base(DataSpace.SSpace) { // 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"); EntityUtil.CheckArgumentEmpty(ref xmlReaders, Strings.StoreItemCollectionMustHaveOneArtifact, "xmlReader"); // filePaths is allowed to be null errors = this.Init(xmlReaders, filePaths, false, out _providerManifest, out _providerFactory, out _providerManifestToken, out _cachedCTypeFunction); } /// /// constructor that loads the metadata files from the specified xmlReaders, and returns the list of errors /// encountered during load as the out parameter errors. /// /// Publicly available from System.Data.Entity.Desgin.dll /// /// xmlReaders where the CDM schemas are loaded /// the paths where the files can be found that match the xml readers collection internal StoreItemCollection(IEnumerable xmlReaders, IEnumerable filePaths) : base(DataSpace.SSpace) { EntityUtil.CheckArgumentNull(filePaths, "filePaths"); EntityUtil.CheckArgumentEmpty(ref xmlReaders, Strings.StoreItemCollectionMustHaveOneArtifact, "xmlReader"); this.Init(xmlReaders, filePaths, true, out _providerManifest, out _providerFactory, out _providerManifestToken, out _cachedCTypeFunction); } /// /// Public constructor that loads the metadata files from the specified xmlReaders. /// Throws when encounter errors. /// /// xmlReaders where the CDM schemas are loaded public StoreItemCollection(IEnumerable xmlReaders) : base(DataSpace.SSpace) { EntityUtil.CheckArgumentNull(xmlReaders, "xmlReaders"); EntityUtil.CheckArgumentEmpty(ref xmlReaders, Strings.StoreItemCollectionMustHaveOneArtifact, "xmlReader"); MetadataArtifactLoader composite = MetadataArtifactLoader.CreateCompositeFromXmlReaders(xmlReaders); this.Init(composite.GetReaders(), composite.GetPaths(), true, out _providerManifest, out _providerFactory, out _providerManifestToken, out _cachedCTypeFunction); } /// /// Constructs the new instance of StoreItemCollection /// with the list of CDM files provided. /// /// paths where the CDM schemas are loaded /// Thrown if path name is not valid /// thrown if paths argument is null /// For errors related to invalid schemas. [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 public StoreItemCollection(params string[] filePaths) : base(DataSpace.SSpace) { EntityUtil.CheckArgumentNull(filePaths, "filePaths"); IEnumerable enumerableFilePaths = filePaths; EntityUtil.CheckArgumentEmpty(ref enumerableFilePaths, Strings.StoreItemCollectionMustHaveOneArtifact, "filePaths"); // 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 readers = null; try { composite = MetadataArtifactLoader.CreateCompositeFromFilePaths(enumerableFilePaths, XmlConstants.SSpaceSchemaExtension); readers = composite.CreateReaders(DataSpace.SSpace); IEnumerable ieReaders = readers.AsEnumerable(); EntityUtil.CheckArgumentEmpty(ref ieReaders, Strings.StoreItemCollectionMustHaveOneArtifact, "filePaths"); this.Init(readers, composite.GetPaths(DataSpace.SSpace), true, out _providerManifest, out _providerFactory, out _providerManifestToken, out _cachedCTypeFunction); } finally { if (readers != null) { Helper.DisposeXmlReaders(readers); } } } private IList Init(IEnumerable xmlReaders, IEnumerable filePaths, bool throwOnError, out DbProviderManifest providerManifest, out DbProviderFactory providerFactory, out string providerManifestToken, out Memoizer cachedCTypeFunction) { EntityUtil.CheckArgumentNull(xmlReaders, "xmlReaders"); // 'filePaths' can be null cachedCTypeFunction = new Memoizer(ConvertFunctionSignatureToCType, null); Loader loader = new Loader(xmlReaders, filePaths, throwOnError); providerFactory = loader.ProviderFactory; providerManifest = loader.ProviderManifest; providerManifestToken = loader.ProviderManifestToken; // load the items into the colleciton if (!loader.HasNonWarningErrors) { LoadProviderManifest(loader.ProviderManifest, true /* check for system namespace */); List errorList = EdmItemCollection.LoadItems(_providerManifest, loader.Schemas, this); foreach (var error in errorList) { loader.Errors.Add(error); } if (throwOnError && errorList.Count != 0) loader.ThrowOnNonWarningErrors(); } return loader.Errors; } #endregion #region Properties /// /// Returns the query cache manager /// internal System.Data.Common.QueryCache.QueryCacheManager QueryCacheManager { get { return _queryCacheManager; } } internal DbProviderFactory StoreProviderFactory { get { return _providerFactory; } } internal DbProviderManifest StoreProviderManifest { get { return _providerManifest; } } internal string StoreProviderManifestToken { get { return _providerManifestToken; } } /// /// Version of this StoreItemCollection represents. /// public Double StoreSchemaVersion { get { return _schemaVersion; } internal set { _schemaVersion = value; } } #endregion #region Methods /// /// Get the list of primitive types for the given space /// /// public System.Collections.ObjectModel.ReadOnlyCollection GetPrimitiveTypes() { return _primitiveTypeMaps.GetTypes(); } /// /// Given the canonical primitive type, get the mapping primitive type in the given dataspace /// /// canonical primitive type /// The mapped scalar type internal override PrimitiveType GetMappedPrimitiveType(PrimitiveTypeKind primitiveTypeKind) { PrimitiveType type = null; _primitiveTypeMaps.TryGetType(primitiveTypeKind, null, out type); return type; } /// /// checks if the schemaKey refers to the provider manifest schema key /// and if true, loads the provider manifest /// /// The connection where the store manifest is loaded from /// Check for System namespace /// The provider manifest object that was loaded private void LoadProviderManifest(DbProviderManifest storeManifest, bool checkForSystemNamespace) { foreach (PrimitiveType primitiveType in storeManifest.GetStoreTypes()) { //Add it to the collection and the primitive type maps this.AddInternal(primitiveType); _primitiveTypeMaps.Add(primitiveType); } foreach (EdmFunction function in storeManifest.GetStoreFunctions()) { AddInternal(function); } } #endregion /// /// Get all the overloads of the function with the given name, this method is used for internal perspective /// /// The full name of the function /// true for case-insensitive lookup /// A collection of all the functions with the given name in the given data space /// Thrown if functionaName argument passed in is null internal System.Collections.ObjectModel.ReadOnlyCollection GetCTypeFunctions(string functionName, bool ignoreCase) { System.Collections.ObjectModel.ReadOnlyCollection functionOverloads; if (this.FunctionLookUpTable.TryGetValue(functionName, out functionOverloads)) { functionOverloads = ConvertToCTypeFunctions(functionOverloads); if (ignoreCase) { return functionOverloads; } return GetCaseSensitiveFunctions(functionOverloads, functionName); } return Helper.EmptyEdmFunctionReadOnlyCollection; } private System.Collections.ObjectModel.ReadOnlyCollection ConvertToCTypeFunctions( System.Collections.ObjectModel.ReadOnlyCollection functionOverloads) { List cTypeFunctions = new List(); foreach (var sTypeFunction in functionOverloads) { cTypeFunctions.Add(ConvertToCTypeFunction(sTypeFunction)); } return cTypeFunctions.AsReadOnly(); } internal EdmFunction ConvertToCTypeFunction(EdmFunction sTypeFunction) { return this._cachedCTypeFunction.Evaluate(sTypeFunction); } /// /// Convert the S type function parameters and returnType to C types. /// private EdmFunction ConvertFunctionSignatureToCType(EdmFunction sTypeFunction) { Debug.Assert(sTypeFunction.DataSpace == Edm.DataSpace.SSpace, "sTypeFunction.DataSpace == Edm.DataSpace.SSpace"); if (sTypeFunction.IsFromProviderManifest) { return sTypeFunction; } FunctionParameter returnParameter = null; if (sTypeFunction.ReturnParameter != null) { TypeUsage edmTypeUsageReturnParameter = MetadataHelper.ConvertStoreTypeUsageToEdmTypeUsage(sTypeFunction.ReturnParameter.TypeUsage); returnParameter = new FunctionParameter( sTypeFunction.ReturnParameter.Name, edmTypeUsageReturnParameter, sTypeFunction.ReturnParameter.GetParameterMode()); } List parameters = new List(); if (sTypeFunction.Parameters.Count > 0) { foreach (var parameter in sTypeFunction.Parameters) { TypeUsage edmTypeUsage = MetadataHelper.ConvertStoreTypeUsageToEdmTypeUsage(parameter.TypeUsage); FunctionParameter edmTypeParameter = new FunctionParameter(parameter.Name, edmTypeUsage, parameter.GetParameterMode()); parameters.Add(edmTypeParameter); } } FunctionParameter[] returnParameters = returnParameter == null ? new FunctionParameter[0] : new FunctionParameter[] { returnParameter }; EdmFunction edmFunction = new EdmFunction(sTypeFunction.Name, sTypeFunction.NamespaceName, DataSpace.CSpace, new EdmFunctionPayload { Schema = sTypeFunction.Schema, StoreFunctionName = sTypeFunction.StoreFunctionNameAttribute, CommandText = sTypeFunction.CommandTextAttribute, IsAggregate = sTypeFunction.AggregateAttribute, IsBuiltIn = sTypeFunction.BuiltInAttribute, IsNiladic = sTypeFunction.NiladicFunctionAttribute, IsComposable = sTypeFunction.IsComposableAttribute, IsFromProviderManifest = sTypeFunction.IsFromProviderManifest, IsCachedStoreFunction = true, IsFunctionImport = sTypeFunction.IsFunctionImport, ReturnParameters = returnParameters, Parameters = parameters.ToArray(), ParameterTypeSemantics = sTypeFunction.ParameterTypeSemanticsAttribute, }); edmFunction.SetReadOnly(); return edmFunction; } }//---- ItemCollection }//----