|
//---------------------------------------------------------------------
// <copyright file="StoreItemCollection.cs" company="Microsoft">
// Copyright (c) Microsoft Corporation. All rights reserved.
// </copyright>
//
// @owner Microsoft
// @backupOwner Microsoft
//---------------------------------------------------------------------
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;
/// <summary>
/// Class for representing a collection of items in Store space.
/// </summary>
[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<EdmFunction, EdmFunction> _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<EdmFunction, EdmFunction>(ConvertFunctionSignatureToCType, null);
LoadProviderManifest(_providerManifest, true /*checkForSystemNamespace*/);
}
/// <summary>
/// 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
/// </summary>
/// <param name="xmlReaders">xmlReaders where the CDM schemas are loaded</param>
/// <param name="filePaths">the paths where the files can be found that match the xml readers collection</param>
/// <param name="errors">An out parameter to return the collection of errors encountered while loading</param>
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] // referenced by System.Data.Entity.Design.dll
internal StoreItemCollection(IEnumerable<XmlReader> xmlReaders,
System.Collections.ObjectModel.ReadOnlyCollection<string> filePaths,
out IList<EdmSchemaError> 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);
}
/// <summary>
/// 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
/// </summary>
/// <param name="xmlReaders">xmlReaders where the CDM schemas are loaded</param>
/// <param name="filePaths">the paths where the files can be found that match the xml readers collection</param>
internal StoreItemCollection(IEnumerable<XmlReader> xmlReaders,
IEnumerable<string> 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);
}
/// <summary>
/// Public constructor that loads the metadata files from the specified xmlReaders.
/// Throws when encounter errors.
/// </summary>
/// <param name="xmlReaders">xmlReaders where the CDM schemas are loaded</param>
public StoreItemCollection(IEnumerable<XmlReader> 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);
}
/// <summary>
/// Constructs the new instance of StoreItemCollection
/// with the list of CDM files provided.
/// </summary>
/// <param name="filePaths">paths where the CDM schemas are loaded</param>
/// <exception cref="ArgumentException"> Thrown if path name is not valid</exception>
/// <exception cref="System.ArgumentNullException">thrown if paths argument is null</exception>
/// <exception cref="System.Data.MetadataException">For errors related to invalid schemas.</exception>
[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<string> 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<XmlReader> readers = null;
try
{
composite = MetadataArtifactLoader.CreateCompositeFromFilePaths(enumerableFilePaths, XmlConstants.SSpaceSchemaExtension);
readers = composite.CreateReaders(DataSpace.SSpace);
IEnumerable<XmlReader> 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<EdmSchemaError> Init(IEnumerable<XmlReader> xmlReaders,
IEnumerable<string> filePaths, bool throwOnError,
out DbProviderManifest providerManifest,
out DbProviderFactory providerFactory,
out string providerManifestToken,
out Memoizer<EdmFunction, EdmFunction> cachedCTypeFunction)
{
EntityUtil.CheckArgumentNull(xmlReaders, "xmlReaders");
// 'filePaths' can be null
cachedCTypeFunction = new Memoizer<EdmFunction, EdmFunction>(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<EdmSchemaError> 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
/// <summary>
/// Returns the query cache manager
/// </summary>
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;
}
}
/// <summary>
/// Version of this StoreItemCollection represents.
/// </summary>
public Double StoreSchemaVersion
{
get
{
return _schemaVersion;
}
internal set
{
_schemaVersion = value;
}
}
#endregion
#region Methods
/// <summary>
/// Get the list of primitive types for the given space
/// </summary>
/// <returns></returns>
public System.Collections.ObjectModel.ReadOnlyCollection<PrimitiveType> GetPrimitiveTypes()
{
return _primitiveTypeMaps.GetTypes();
}
/// <summary>
/// Given the canonical primitive type, get the mapping primitive type in the given dataspace
/// </summary>
/// <param name="primitiveTypeKind">canonical primitive type</param>
/// <returns>The mapped scalar type</returns>
internal override PrimitiveType GetMappedPrimitiveType(PrimitiveTypeKind primitiveTypeKind)
{
PrimitiveType type = null;
_primitiveTypeMaps.TryGetType(primitiveTypeKind, null, out type);
return type;
}
/// <summary>
/// checks if the schemaKey refers to the provider manifest schema key
/// and if true, loads the provider manifest
/// </summary>
/// <param name="connection">The connection where the store manifest is loaded from</param>
/// <param name="checkForSystemNamespace">Check for System namespace</param>
/// <returns>The provider manifest object that was loaded</returns>
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
/// <summary>
/// Get all the overloads of the function with the given name, this method is used for internal perspective
/// </summary>
/// <param name="functionName">The full name of the function</param>
/// <param name="ignoreCase">true for case-insensitive lookup</param>
/// <returns>A collection of all the functions with the given name in the given data space</returns>
/// <exception cref="System.ArgumentNullException">Thrown if functionaName argument passed in is null</exception>
internal System.Collections.ObjectModel.ReadOnlyCollection<EdmFunction> GetCTypeFunctions(string functionName, bool ignoreCase)
{
System.Collections.ObjectModel.ReadOnlyCollection<EdmFunction> 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<EdmFunction> ConvertToCTypeFunctions(
System.Collections.ObjectModel.ReadOnlyCollection<EdmFunction> functionOverloads)
{
List<EdmFunction> cTypeFunctions = new List<EdmFunction>();
foreach (var sTypeFunction in functionOverloads)
{
cTypeFunctions.Add(ConvertToCTypeFunction(sTypeFunction));
}
return cTypeFunctions.AsReadOnly();
}
internal EdmFunction ConvertToCTypeFunction(EdmFunction sTypeFunction)
{
return this._cachedCTypeFunction.Evaluate(sTypeFunction);
}
/// <summary>
/// Convert the S type function parameters and returnType to C types.
/// </summary>
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<FunctionParameter> parameters = new List<FunctionParameter>();
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
}//----
|