Code:
/ Dotnetfx_Vista_SP2 / Dotnetfx_Vista_SP2 / 8.0.50727.4016 / DEVDIV / depot / DevDiv / releases / Orcas / QFE / ndp / fx / src / DataEntity / System / Data / EntityClient / EntityCommandDefinition.cs / 2 / EntityCommandDefinition.cs
//------------------------------------------------------------------------------ //// Copyright (c) Microsoft Corporation. All rights reserved. // // // @owner [....], [....] //----------------------------------------------------------------------------- namespace System.Data.EntityClient { using System.Collections.Generic; using System.Collections.ObjectModel; using System.Data.Common; using System.Data.Common.CommandTrees; using System.Data.Query.InternalTrees; using System.Data.Metadata.Edm; using System.Data.Query.ResultAssembly; using System.Data.Query.PlanCompiler; using System.Diagnostics; using System.Data.Common.Utils; using System.Text; using System.Data.Mapping; ////// An aggregate Command Definition used by the EntityClient layers. This is an aggregator /// object that represent information from multiple underlying provider commands. /// sealed internal class EntityCommandDefinition : DbCommandDefinition { #region internal state ////// Bid Counter object /// private static int _objectTypeCount; ////// The object Id of this instance, for BID tracing. /// internal readonly int ObjectID = System.Threading.Interlocked.Increment(ref _objectTypeCount); ////// nested store command definitions /// private readonly List_mappedCommandDefinitions; /// /// generates column map for the store result reader /// private readonly IColumnMapGenerator _columnMapGenerator; ////// list of the parameters that the resulting command should have /// private readonly System.Collections.ObjectModel.ReadOnlyCollection_parameters; /// /// Set of entity sets exposed in the command. /// private readonly Set_entitySets; #endregion #region constructors /// /// don't let this be constructed publicly; /// ///Cannot prepare the command definition for execution; consult the InnerException for more information. ///The ADO.NET Data Provider you are using does not support CommandTrees. internal EntityCommandDefinition(DbProviderFactory storeProviderFactory, DbCommandTree commandTree) { EntityUtil.CheckArgumentNull(storeProviderFactory, "storeProviderFactory"); EntityUtil.CheckArgumentNull(commandTree, "commandTree"); EntityBid.Trace("%d# Constructing. commandTree=%d#\n", ObjectID, commandTree.ObjectId); DbProviderServices storeProviderServices = DbProviderServices.GetProviderServices(storeProviderFactory); try { if (DbCommandTreeKind.Query == commandTree.CommandTreeKind) { // Next compile the plan for the command tree List mappedCommandList = new List (); ColumnMap columnMap; int columnCount; PlanCompiler.Compile(commandTree, out mappedCommandList, out columnMap, out columnCount, out _entitySets); _columnMapGenerator = new ConstantColumnMapGenerator(columnMap, columnCount); // Note: we presume that the first item in the ProviderCommandInfo is the root node; Debug.Assert(mappedCommandList.Count > 0, "empty providerCommandInfo collection and no exception?"); // this shouldn't ever happen. // Then, generate the store commands from the resulting command tree(s) _mappedCommandDefinitions = new List (mappedCommandList.Count); foreach (ProviderCommandInfo providerCommandInfo in mappedCommandList) { DbCommandDefinition providerCommandDefinition = storeProviderServices.CreateCommandDefinition(providerCommandInfo.CommandTree); if (null == providerCommandDefinition) { throw EntityUtil.ProviderIncompatible(System.Data.Entity.Strings.ProviderReturnedNullForCreateCommandDefinition); } _mappedCommandDefinitions.Add(providerCommandDefinition); } } else { Debug.Assert(DbCommandTreeKind.Function == commandTree.CommandTreeKind, "only query and function command trees are supported"); DbFunctionCommandTree entityCommandTree = (DbFunctionCommandTree)commandTree; // Retrieve mapping and metadata information for the function import. FunctionImportMapping mapping = GetTargetFunctionMapping(entityCommandTree); TypeUsage storeResultType = DetermineStoreResultType(entityCommandTree.MetadataWorkspace, mapping, out _columnMapGenerator); // Construct store command tree usage. DbFunctionCommandTree providerCommandTree = new DbFunctionCommandTree(entityCommandTree.MetadataWorkspace, DataSpace.SSpace, mapping.TargetFunction, storeResultType); // Copy over parameters (this happens through a more indirect route in the plan compiler, but // it happens nonetheless) foreach (KeyValuePair parameter in entityCommandTree.Parameters) { providerCommandTree.AddParameter(parameter.Key, parameter.Value); } DbCommandDefinition storeCommandDefinition = storeProviderServices.CreateCommandDefinition(providerCommandTree); _mappedCommandDefinitions = new List (1) { storeCommandDefinition }; if (null != mapping.FunctionImport.EntitySet) { _entitySets = new Set (); _entitySets.Add(mapping.FunctionImport.EntitySet); _entitySets.MakeReadOnly(); } } // Finally, build a list of the parameters that the resulting command should have; List parameterList = new List (); foreach (KeyValuePair queryParameter in commandTree.Parameters) { EntityParameter parameter = CreateEntityParameterFromQueryParameter(queryParameter); parameterList.Add(parameter); } _parameters = new System.Collections.ObjectModel.ReadOnlyCollection (parameterList); } catch (Exception e) { // we should not be wrapping all exceptions if (EntityUtil.IsCatchableExceptionType(e)) { // we don't wan't folks to have to know all the various types of exceptions that can // occur, so we just rethrow a CommandDefinitionException and make whatever we caught // the inner exception of it. throw EntityUtil.CommandCompilation(System.Data.Entity.Strings.EntityClient_CommandDefinitionPreparationFailed, e); } throw; } } /// /// Determines the store type for a function import. /// private TypeUsage DetermineStoreResultType(MetadataWorkspace workspace, FunctionImportMapping mapping, out IColumnMapGenerator columnMapGenerator) { // Determine column maps and infer result types for the mapped function. There are three varieties: // 1. Collection(Entity) // 2. Collection(PrimitiveType) // 3. No result type TypeUsage storeResultType; { EntityType baseEntityType; EdmFunction functionImport = mapping.FunctionImport; // 1. Collection(Entity) if (MetadataHelper.TryGetFunctionImportReturnEntityType(functionImport, out baseEntityType)) { EntitySet entitySet = functionImport.EntitySet; Debug.Assert(null != entitySet, "FunctionImport requires entity set if the return type is EntityType"); columnMapGenerator = new FunctionColumnMapGenerator(mapping, entitySet, baseEntityType); // We don't actually know the return type for the stored procedure, but we can infer // one based on the mapping (i.e.: a column for every property of the mapped types // and for all discriminator columns) storeResultType = mapping.GetExpectedTargetResultType(workspace); } // 2. Collection(PrimitiveType) else if (functionImport.ReturnParameter != null && functionImport.ReturnParameter.TypeUsage != null) { // Get components of metadata description storeResultType = functionImport.ReturnParameter.TypeUsage; Debug.Assert(storeResultType.EdmType.BuiltInTypeKind == BuiltInTypeKind.CollectionType, "FunctionImport currently supports only collection result type"); TypeUsage elementType = ((CollectionType)storeResultType.EdmType).TypeUsage; Debug.Assert(elementType.EdmType.BuiltInTypeKind == BuiltInTypeKind.PrimitiveType, "FunctionImport supports only Collection(Entity) and Collection(Primitive)"); // Build collection column map where the first column of the store result is assumed // to contain the primitive type values. ScalarColumnMap scalarColumnMap = new ScalarColumnMap(elementType, string.Empty, 0, 0); SimpleCollectionColumnMap collectionColumnMap = new SimpleCollectionColumnMap(storeResultType, string.Empty, scalarColumnMap, null, null, null); columnMapGenerator = new ConstantColumnMapGenerator(collectionColumnMap, 1); } // 3. No result type else { storeResultType = null; columnMapGenerator = new ConstantColumnMapGenerator(null, 0); } } return storeResultType; } ////// Retrieves mapping for the given C-Space functionCommandTree /// private static FunctionImportMapping GetTargetFunctionMapping(DbFunctionCommandTree functionCommandTree) { Debug.Assert(functionCommandTree.DataSpace == DataSpace.CSpace, "map from CSpace->SSpace function"); Debug.Assert(null != functionCommandTree, "null functionCommandTree"); // find mapped store function FunctionImportMapping targetFunctionMapping; if (!functionCommandTree.MetadataWorkspace.TryGetFunctionImportMapping(functionCommandTree.EdmFunction, out targetFunctionMapping)) { throw EntityUtil.InvalidOperation(System.Data.Entity.Strings.EntityClient_UnmappedFunctionImport); } return targetFunctionMapping; } #endregion #region public API ////// Create a DbCommand object from the definition, that can be executed /// ///public override DbCommand CreateCommand() { EntityBid.Trace(" %d#\n", ObjectID); return new EntityCommand(this); } #endregion #region internal methods /// /// Get a list of commands to be executed by the provider /// [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] internal IEnumerableMappedCommands { get { // Build up the list of command texts, if we haven't done so yet List mappedCommandTexts = new List (); foreach (DbCommandDefinition commandDefinition in _mappedCommandDefinitions) { DbCommand mappedCommand = commandDefinition.CreateCommand(); mappedCommandTexts.Add(mappedCommand.CommandText); } return mappedCommandTexts; } } /// /// Creates ColumnMap for result assembly using the given reader. /// internal ColumnMap CreateColumnMap(DbDataReader storeDataReader) { return _columnMapGenerator.CreateColumnMap(storeDataReader); } ////// Property to expose the known parameters for the query, so the Command objects /// constructor can poplulate it's parameter collection from. /// internal IEnumerableParameters { get { return _parameters; } } /// /// Set of entity sets exposed in the command. /// internal SetEntitySets { get { return _entitySets; } } /// /// Constructs a EntityParameter from a CQT parameter. /// /// ///private static EntityParameter CreateEntityParameterFromQueryParameter(KeyValuePair queryParameter) { // We really can't have a parameter here that isn't a scalar type... Debug.Assert(TypeSemantics.IsPrimitiveType(queryParameter.Value), "Non-PrimitiveType used as query parameter type"); EntityParameter result = new EntityParameter(); result.ParameterName = queryParameter.Key; DbCommandDefinition.PopulateParameterFromTypeUsage(result, queryParameter.Value, false /* isOutParam */ ); return result; } /// /// Internal execute method -- copies command information from the map command /// to the command objects, executes them, and builds the result assembly /// components needed to return the data reader /// /// /// ////// behavior must specify CommandBehavior.SequentialAccess ///input parameters in the entityCommand.Parameters collection must have non-null values. internal DbDataReader Execute(EntityCommand entityCommand, CommandBehavior behavior) { IntPtr hscp; EntityBid.ScopeEnter(out hscp, "%d#\n", ObjectID); try { if (CommandBehavior.SequentialAccess != (behavior & CommandBehavior.SequentialAccess)) { throw EntityUtil.MustUseSequentialAccess(); } DbDataReader storeDataReader = ExecuteStoreCommands(entityCommand, behavior); DbDataReader result = null; // If we actually executed something, then go ahead and construct a bridge // data reader for it. if (null != storeDataReader) { try { ColumnMap columnMap = _columnMapGenerator.CreateColumnMap(storeDataReader); if (null == columnMap) { // For a query with no result type (and therefore no column map), consume the reader. // When the user requests Metadata for this reader, we return nothing. CommandHelper.ConsumeReader(storeDataReader); result = storeDataReader; } else { result = BridgeDataReader.Create(storeDataReader, _columnMapGenerator.CreateColumnMap(storeDataReader), entityCommand.Connection.GetMetadataWorkspace()); } } catch { // dispose of store reader if there is an error creating the BridgeDataReader storeDataReader.Dispose(); throw; } } return result; } finally { EntityBid.ScopeLeave(ref hscp); } } /// /// Execute the store commands, and return IteratorSources for each one /// /// /// internal DbDataReader ExecuteStoreCommands(EntityCommand entityCommand, CommandBehavior behavior) { // SQLPT #120007433 is the work item to implement MARS support, which we // need to do here, but since the PlanCompiler doesn't // have it yet, neither do we... if (1 != _mappedCommandDefinitions.Count) { throw EntityUtil.NotSupported("MARS"); } EntityTransaction entityTransaction = CommandHelper.GetEntityTransaction(entityCommand); DbCommandDefinition definition = _mappedCommandDefinitions[0]; DbCommand storeProviderCommand = definition.CreateCommand(); CommandHelper.SetStoreProviderCommandState(entityCommand, entityTransaction, storeProviderCommand); // Copy over the values from the map command to the store command; we // assume that they were not renamed by either the plan compiler or SQL // Generation. // // Note that this pretty much presumes that named parameters are supported // by the store provider, but it might work if we don't reorder/reuse // parameters. // // Note also that the store provider may choose to add parameters to thier // command object for some things; we'll only copy over the values for // parameters that we find in the EntityCommands parameters collection, so // we won't damage anything the store provider did. bool hasOutputParameters = false; if (storeProviderCommand.Parameters != null) // SQLBUDT 519066 { foreach (DbParameter storeParameter in storeProviderCommand.Parameters) { // I could just use the string indexer, but then if I didn't find it the // consumer would get some ParameterNotFound exeception message and that // wouldn't be very meaningful. Instead, I use the IndexOf method and // if I don't find it, it's not a big deal (The store provider must // have added it). int parameterOrdinal = entityCommand.Parameters.IndexOf(storeParameter.ParameterName); if (-1 != parameterOrdinal) { EntityParameter entityParameter = entityCommand.Parameters[parameterOrdinal]; SyncParameterProperties(entityParameter, storeParameter); if (storeParameter.Direction != ParameterDirection.Input) { hasOutputParameters = true; } } } } // If the EntityCommand has output parameters, we must synchronize parameter values when // the reader is closed. Tell the EntityCommand about the store command so that it knows // where to pull those values from. if (hasOutputParameters) { entityCommand.SetStoreProviderCommand(storeProviderCommand); } DbDataReader reader = null; try { reader = storeProviderCommand.ExecuteReader(behavior & ~CommandBehavior.SequentialAccess); } catch (Exception e) { // we should not be wrapping all exceptions if (EntityUtil.IsCatchableExceptionType(e)) { // we don't wan't folks to have to know all the various types of exceptions that can // occur, so we just rethrow a CommandDefinitionException and make whatever we caught // the inner exception of it. throw EntityUtil.CommandExecution(System.Data.Entity.Strings.EntityClient_CommandDefinitionExecutionFailed, e); } throw; } return reader; } ////// Updates storeParameter size, precision and scale properties from user provided parameter properties. /// /// /// private static void SyncParameterProperties(EntityParameter entityParameter, DbParameter storeParameter) { IDbDataParameter dbDataParameter = (IDbDataParameter)storeParameter; // DBType is not currently syncable; it's part of the cache key anyway; this is because we can't guarantee // that the store provider will honor it -- (SqlClient doesn't...) //if (entityParameter.IsDbTypeSpecified) //{ // storeParameter.DbType = entityParameter.DbType; //} if (entityParameter.IsDirectionSpecified) { storeParameter.Direction = entityParameter.Direction; } if (entityParameter.IsIsNullableSpecified) { storeParameter.IsNullable = entityParameter.IsNullable; } if (entityParameter.IsSizeSpecified) { storeParameter.Size = entityParameter.Size; } if (entityParameter.IsPrecisionSpecified) { dbDataParameter.Precision = entityParameter.Precision; } if (entityParameter.IsScaleSpecified) { dbDataParameter.Scale = entityParameter.Scale; } storeParameter.Value = entityParameter.Value; } ////// Return the string used by EntityCommand and ObjectQuery ///ToTraceString"/> /// internal string ToTraceString() { if (_mappedCommandDefinitions != null) { if (_mappedCommandDefinitions.Count == 1) { // Gosh it sure would be nice if I could just get the inner commandText, but // that would require more public surface area on DbCommandDefinition, or // me to know about the inner object... return _mappedCommandDefinitions[0].CreateCommand().CommandText; } else { StringBuilder sb = new StringBuilder(); foreach (DbCommandDefinition commandDefinition in _mappedCommandDefinitions) { DbCommand mappedCommand = commandDefinition.CreateCommand(); sb.Append(mappedCommand.CommandText); } return sb.ToString(); } } return string.Empty; } #endregion #region nested types /// /// Generates a column map given a data reader. /// private interface IColumnMapGenerator { ////// Given a data reader, returns column map. /// /// Data reader. ///Column map. ColumnMap CreateColumnMap(DbDataReader reader); } ////// IColumnMapGenerator wrapping a constant instance of a column map (invariant with respect /// to the given DbDataReader) /// private sealed class ConstantColumnMapGenerator : IColumnMapGenerator { private readonly ColumnMap _columnMap; private readonly int _fieldsRequired; internal ConstantColumnMapGenerator(ColumnMap columnMap, int fieldsRequired) { _columnMap = columnMap; _fieldsRequired = fieldsRequired; } ColumnMap IColumnMapGenerator.CreateColumnMap(DbDataReader reader) { if (null != reader && reader.FieldCount < _fieldsRequired) { throw EntityUtil.CommandExecution(System.Data.Entity.Strings.EntityClient_TooFewColumns); } return _columnMap; } } ////// Generates column maps for a function mapping. /// private sealed class FunctionColumnMapGenerator : IColumnMapGenerator { private readonly FunctionImportMapping _mapping; private readonly EntitySet _entitySet; private readonly EntityType _baseEntityType; internal FunctionColumnMapGenerator(FunctionImportMapping mapping, EntitySet entitySet, EntityType baseEntityType) { _mapping = mapping; _entitySet = entitySet; _baseEntityType = baseEntityType; } ColumnMap IColumnMapGenerator.CreateColumnMap(DbDataReader reader) { return ColumnMapFactory.CreateFunctionImportEntityColumnMap(reader, _mapping, _entitySet, _baseEntityType); } } #endregion } } // File provided for Reference Use Only by Microsoft Corporation (c) 2007. //------------------------------------------------------------------------------ //// Copyright (c) Microsoft Corporation. All rights reserved. // // // @owner [....], [....] //----------------------------------------------------------------------------- namespace System.Data.EntityClient { using System.Collections.Generic; using System.Collections.ObjectModel; using System.Data.Common; using System.Data.Common.CommandTrees; using System.Data.Query.InternalTrees; using System.Data.Metadata.Edm; using System.Data.Query.ResultAssembly; using System.Data.Query.PlanCompiler; using System.Diagnostics; using System.Data.Common.Utils; using System.Text; using System.Data.Mapping; ////// An aggregate Command Definition used by the EntityClient layers. This is an aggregator /// object that represent information from multiple underlying provider commands. /// sealed internal class EntityCommandDefinition : DbCommandDefinition { #region internal state ////// Bid Counter object /// private static int _objectTypeCount; ////// The object Id of this instance, for BID tracing. /// internal readonly int ObjectID = System.Threading.Interlocked.Increment(ref _objectTypeCount); ////// nested store command definitions /// private readonly List_mappedCommandDefinitions; /// /// generates column map for the store result reader /// private readonly IColumnMapGenerator _columnMapGenerator; ////// list of the parameters that the resulting command should have /// private readonly System.Collections.ObjectModel.ReadOnlyCollection_parameters; /// /// Set of entity sets exposed in the command. /// private readonly Set_entitySets; #endregion #region constructors /// /// don't let this be constructed publicly; /// ///Cannot prepare the command definition for execution; consult the InnerException for more information. ///The ADO.NET Data Provider you are using does not support CommandTrees. internal EntityCommandDefinition(DbProviderFactory storeProviderFactory, DbCommandTree commandTree) { EntityUtil.CheckArgumentNull(storeProviderFactory, "storeProviderFactory"); EntityUtil.CheckArgumentNull(commandTree, "commandTree"); EntityBid.Trace("%d# Constructing. commandTree=%d#\n", ObjectID, commandTree.ObjectId); DbProviderServices storeProviderServices = DbProviderServices.GetProviderServices(storeProviderFactory); try { if (DbCommandTreeKind.Query == commandTree.CommandTreeKind) { // Next compile the plan for the command tree List mappedCommandList = new List (); ColumnMap columnMap; int columnCount; PlanCompiler.Compile(commandTree, out mappedCommandList, out columnMap, out columnCount, out _entitySets); _columnMapGenerator = new ConstantColumnMapGenerator(columnMap, columnCount); // Note: we presume that the first item in the ProviderCommandInfo is the root node; Debug.Assert(mappedCommandList.Count > 0, "empty providerCommandInfo collection and no exception?"); // this shouldn't ever happen. // Then, generate the store commands from the resulting command tree(s) _mappedCommandDefinitions = new List (mappedCommandList.Count); foreach (ProviderCommandInfo providerCommandInfo in mappedCommandList) { DbCommandDefinition providerCommandDefinition = storeProviderServices.CreateCommandDefinition(providerCommandInfo.CommandTree); if (null == providerCommandDefinition) { throw EntityUtil.ProviderIncompatible(System.Data.Entity.Strings.ProviderReturnedNullForCreateCommandDefinition); } _mappedCommandDefinitions.Add(providerCommandDefinition); } } else { Debug.Assert(DbCommandTreeKind.Function == commandTree.CommandTreeKind, "only query and function command trees are supported"); DbFunctionCommandTree entityCommandTree = (DbFunctionCommandTree)commandTree; // Retrieve mapping and metadata information for the function import. FunctionImportMapping mapping = GetTargetFunctionMapping(entityCommandTree); TypeUsage storeResultType = DetermineStoreResultType(entityCommandTree.MetadataWorkspace, mapping, out _columnMapGenerator); // Construct store command tree usage. DbFunctionCommandTree providerCommandTree = new DbFunctionCommandTree(entityCommandTree.MetadataWorkspace, DataSpace.SSpace, mapping.TargetFunction, storeResultType); // Copy over parameters (this happens through a more indirect route in the plan compiler, but // it happens nonetheless) foreach (KeyValuePair parameter in entityCommandTree.Parameters) { providerCommandTree.AddParameter(parameter.Key, parameter.Value); } DbCommandDefinition storeCommandDefinition = storeProviderServices.CreateCommandDefinition(providerCommandTree); _mappedCommandDefinitions = new List (1) { storeCommandDefinition }; if (null != mapping.FunctionImport.EntitySet) { _entitySets = new Set (); _entitySets.Add(mapping.FunctionImport.EntitySet); _entitySets.MakeReadOnly(); } } // Finally, build a list of the parameters that the resulting command should have; List parameterList = new List (); foreach (KeyValuePair queryParameter in commandTree.Parameters) { EntityParameter parameter = CreateEntityParameterFromQueryParameter(queryParameter); parameterList.Add(parameter); } _parameters = new System.Collections.ObjectModel.ReadOnlyCollection (parameterList); } catch (Exception e) { // we should not be wrapping all exceptions if (EntityUtil.IsCatchableExceptionType(e)) { // we don't wan't folks to have to know all the various types of exceptions that can // occur, so we just rethrow a CommandDefinitionException and make whatever we caught // the inner exception of it. throw EntityUtil.CommandCompilation(System.Data.Entity.Strings.EntityClient_CommandDefinitionPreparationFailed, e); } throw; } } /// /// Determines the store type for a function import. /// private TypeUsage DetermineStoreResultType(MetadataWorkspace workspace, FunctionImportMapping mapping, out IColumnMapGenerator columnMapGenerator) { // Determine column maps and infer result types for the mapped function. There are three varieties: // 1. Collection(Entity) // 2. Collection(PrimitiveType) // 3. No result type TypeUsage storeResultType; { EntityType baseEntityType; EdmFunction functionImport = mapping.FunctionImport; // 1. Collection(Entity) if (MetadataHelper.TryGetFunctionImportReturnEntityType(functionImport, out baseEntityType)) { EntitySet entitySet = functionImport.EntitySet; Debug.Assert(null != entitySet, "FunctionImport requires entity set if the return type is EntityType"); columnMapGenerator = new FunctionColumnMapGenerator(mapping, entitySet, baseEntityType); // We don't actually know the return type for the stored procedure, but we can infer // one based on the mapping (i.e.: a column for every property of the mapped types // and for all discriminator columns) storeResultType = mapping.GetExpectedTargetResultType(workspace); } // 2. Collection(PrimitiveType) else if (functionImport.ReturnParameter != null && functionImport.ReturnParameter.TypeUsage != null) { // Get components of metadata description storeResultType = functionImport.ReturnParameter.TypeUsage; Debug.Assert(storeResultType.EdmType.BuiltInTypeKind == BuiltInTypeKind.CollectionType, "FunctionImport currently supports only collection result type"); TypeUsage elementType = ((CollectionType)storeResultType.EdmType).TypeUsage; Debug.Assert(elementType.EdmType.BuiltInTypeKind == BuiltInTypeKind.PrimitiveType, "FunctionImport supports only Collection(Entity) and Collection(Primitive)"); // Build collection column map where the first column of the store result is assumed // to contain the primitive type values. ScalarColumnMap scalarColumnMap = new ScalarColumnMap(elementType, string.Empty, 0, 0); SimpleCollectionColumnMap collectionColumnMap = new SimpleCollectionColumnMap(storeResultType, string.Empty, scalarColumnMap, null, null, null); columnMapGenerator = new ConstantColumnMapGenerator(collectionColumnMap, 1); } // 3. No result type else { storeResultType = null; columnMapGenerator = new ConstantColumnMapGenerator(null, 0); } } return storeResultType; } ////// Retrieves mapping for the given C-Space functionCommandTree /// private static FunctionImportMapping GetTargetFunctionMapping(DbFunctionCommandTree functionCommandTree) { Debug.Assert(functionCommandTree.DataSpace == DataSpace.CSpace, "map from CSpace->SSpace function"); Debug.Assert(null != functionCommandTree, "null functionCommandTree"); // find mapped store function FunctionImportMapping targetFunctionMapping; if (!functionCommandTree.MetadataWorkspace.TryGetFunctionImportMapping(functionCommandTree.EdmFunction, out targetFunctionMapping)) { throw EntityUtil.InvalidOperation(System.Data.Entity.Strings.EntityClient_UnmappedFunctionImport); } return targetFunctionMapping; } #endregion #region public API ////// Create a DbCommand object from the definition, that can be executed /// ///public override DbCommand CreateCommand() { EntityBid.Trace(" %d#\n", ObjectID); return new EntityCommand(this); } #endregion #region internal methods /// /// Get a list of commands to be executed by the provider /// [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] internal IEnumerableMappedCommands { get { // Build up the list of command texts, if we haven't done so yet List mappedCommandTexts = new List (); foreach (DbCommandDefinition commandDefinition in _mappedCommandDefinitions) { DbCommand mappedCommand = commandDefinition.CreateCommand(); mappedCommandTexts.Add(mappedCommand.CommandText); } return mappedCommandTexts; } } /// /// Creates ColumnMap for result assembly using the given reader. /// internal ColumnMap CreateColumnMap(DbDataReader storeDataReader) { return _columnMapGenerator.CreateColumnMap(storeDataReader); } ////// Property to expose the known parameters for the query, so the Command objects /// constructor can poplulate it's parameter collection from. /// internal IEnumerableParameters { get { return _parameters; } } /// /// Set of entity sets exposed in the command. /// internal SetEntitySets { get { return _entitySets; } } /// /// Constructs a EntityParameter from a CQT parameter. /// /// ///private static EntityParameter CreateEntityParameterFromQueryParameter(KeyValuePair queryParameter) { // We really can't have a parameter here that isn't a scalar type... Debug.Assert(TypeSemantics.IsPrimitiveType(queryParameter.Value), "Non-PrimitiveType used as query parameter type"); EntityParameter result = new EntityParameter(); result.ParameterName = queryParameter.Key; DbCommandDefinition.PopulateParameterFromTypeUsage(result, queryParameter.Value, false /* isOutParam */ ); return result; } /// /// Internal execute method -- copies command information from the map command /// to the command objects, executes them, and builds the result assembly /// components needed to return the data reader /// /// /// ////// behavior must specify CommandBehavior.SequentialAccess ///input parameters in the entityCommand.Parameters collection must have non-null values. internal DbDataReader Execute(EntityCommand entityCommand, CommandBehavior behavior) { IntPtr hscp; EntityBid.ScopeEnter(out hscp, "%d#\n", ObjectID); try { if (CommandBehavior.SequentialAccess != (behavior & CommandBehavior.SequentialAccess)) { throw EntityUtil.MustUseSequentialAccess(); } DbDataReader storeDataReader = ExecuteStoreCommands(entityCommand, behavior); DbDataReader result = null; // If we actually executed something, then go ahead and construct a bridge // data reader for it. if (null != storeDataReader) { try { ColumnMap columnMap = _columnMapGenerator.CreateColumnMap(storeDataReader); if (null == columnMap) { // For a query with no result type (and therefore no column map), consume the reader. // When the user requests Metadata for this reader, we return nothing. CommandHelper.ConsumeReader(storeDataReader); result = storeDataReader; } else { result = BridgeDataReader.Create(storeDataReader, _columnMapGenerator.CreateColumnMap(storeDataReader), entityCommand.Connection.GetMetadataWorkspace()); } } catch { // dispose of store reader if there is an error creating the BridgeDataReader storeDataReader.Dispose(); throw; } } return result; } finally { EntityBid.ScopeLeave(ref hscp); } } /// /// Execute the store commands, and return IteratorSources for each one /// /// /// internal DbDataReader ExecuteStoreCommands(EntityCommand entityCommand, CommandBehavior behavior) { // SQLPT #120007433 is the work item to implement MARS support, which we // need to do here, but since the PlanCompiler doesn't // have it yet, neither do we... if (1 != _mappedCommandDefinitions.Count) { throw EntityUtil.NotSupported("MARS"); } EntityTransaction entityTransaction = CommandHelper.GetEntityTransaction(entityCommand); DbCommandDefinition definition = _mappedCommandDefinitions[0]; DbCommand storeProviderCommand = definition.CreateCommand(); CommandHelper.SetStoreProviderCommandState(entityCommand, entityTransaction, storeProviderCommand); // Copy over the values from the map command to the store command; we // assume that they were not renamed by either the plan compiler or SQL // Generation. // // Note that this pretty much presumes that named parameters are supported // by the store provider, but it might work if we don't reorder/reuse // parameters. // // Note also that the store provider may choose to add parameters to thier // command object for some things; we'll only copy over the values for // parameters that we find in the EntityCommands parameters collection, so // we won't damage anything the store provider did. bool hasOutputParameters = false; if (storeProviderCommand.Parameters != null) // SQLBUDT 519066 { foreach (DbParameter storeParameter in storeProviderCommand.Parameters) { // I could just use the string indexer, but then if I didn't find it the // consumer would get some ParameterNotFound exeception message and that // wouldn't be very meaningful. Instead, I use the IndexOf method and // if I don't find it, it's not a big deal (The store provider must // have added it). int parameterOrdinal = entityCommand.Parameters.IndexOf(storeParameter.ParameterName); if (-1 != parameterOrdinal) { EntityParameter entityParameter = entityCommand.Parameters[parameterOrdinal]; SyncParameterProperties(entityParameter, storeParameter); if (storeParameter.Direction != ParameterDirection.Input) { hasOutputParameters = true; } } } } // If the EntityCommand has output parameters, we must synchronize parameter values when // the reader is closed. Tell the EntityCommand about the store command so that it knows // where to pull those values from. if (hasOutputParameters) { entityCommand.SetStoreProviderCommand(storeProviderCommand); } DbDataReader reader = null; try { reader = storeProviderCommand.ExecuteReader(behavior & ~CommandBehavior.SequentialAccess); } catch (Exception e) { // we should not be wrapping all exceptions if (EntityUtil.IsCatchableExceptionType(e)) { // we don't wan't folks to have to know all the various types of exceptions that can // occur, so we just rethrow a CommandDefinitionException and make whatever we caught // the inner exception of it. throw EntityUtil.CommandExecution(System.Data.Entity.Strings.EntityClient_CommandDefinitionExecutionFailed, e); } throw; } return reader; } ////// Updates storeParameter size, precision and scale properties from user provided parameter properties. /// /// /// private static void SyncParameterProperties(EntityParameter entityParameter, DbParameter storeParameter) { IDbDataParameter dbDataParameter = (IDbDataParameter)storeParameter; // DBType is not currently syncable; it's part of the cache key anyway; this is because we can't guarantee // that the store provider will honor it -- (SqlClient doesn't...) //if (entityParameter.IsDbTypeSpecified) //{ // storeParameter.DbType = entityParameter.DbType; //} if (entityParameter.IsDirectionSpecified) { storeParameter.Direction = entityParameter.Direction; } if (entityParameter.IsIsNullableSpecified) { storeParameter.IsNullable = entityParameter.IsNullable; } if (entityParameter.IsSizeSpecified) { storeParameter.Size = entityParameter.Size; } if (entityParameter.IsPrecisionSpecified) { dbDataParameter.Precision = entityParameter.Precision; } if (entityParameter.IsScaleSpecified) { dbDataParameter.Scale = entityParameter.Scale; } storeParameter.Value = entityParameter.Value; } ////// Return the string used by EntityCommand and ObjectQuery ///ToTraceString"/> /// internal string ToTraceString() { if (_mappedCommandDefinitions != null) { if (_mappedCommandDefinitions.Count == 1) { // Gosh it sure would be nice if I could just get the inner commandText, but // that would require more public surface area on DbCommandDefinition, or // me to know about the inner object... return _mappedCommandDefinitions[0].CreateCommand().CommandText; } else { StringBuilder sb = new StringBuilder(); foreach (DbCommandDefinition commandDefinition in _mappedCommandDefinitions) { DbCommand mappedCommand = commandDefinition.CreateCommand(); sb.Append(mappedCommand.CommandText); } return sb.ToString(); } } return string.Empty; } #endregion #region nested types /// /// Generates a column map given a data reader. /// private interface IColumnMapGenerator { ////// Given a data reader, returns column map. /// /// Data reader. ///Column map. ColumnMap CreateColumnMap(DbDataReader reader); } ////// IColumnMapGenerator wrapping a constant instance of a column map (invariant with respect /// to the given DbDataReader) /// private sealed class ConstantColumnMapGenerator : IColumnMapGenerator { private readonly ColumnMap _columnMap; private readonly int _fieldsRequired; internal ConstantColumnMapGenerator(ColumnMap columnMap, int fieldsRequired) { _columnMap = columnMap; _fieldsRequired = fieldsRequired; } ColumnMap IColumnMapGenerator.CreateColumnMap(DbDataReader reader) { if (null != reader && reader.FieldCount < _fieldsRequired) { throw EntityUtil.CommandExecution(System.Data.Entity.Strings.EntityClient_TooFewColumns); } return _columnMap; } } ////// Generates column maps for a function mapping. /// private sealed class FunctionColumnMapGenerator : IColumnMapGenerator { private readonly FunctionImportMapping _mapping; private readonly EntitySet _entitySet; private readonly EntityType _baseEntityType; internal FunctionColumnMapGenerator(FunctionImportMapping mapping, EntitySet entitySet, EntityType baseEntityType) { _mapping = mapping; _entitySet = entitySet; _baseEntityType = baseEntityType; } ColumnMap IColumnMapGenerator.CreateColumnMap(DbDataReader reader) { return ColumnMapFactory.CreateFunctionImportEntityColumnMap(reader, _mapping, _entitySet, _baseEntityType); } } #endregion } } // File provided for Reference Use Only by Microsoft Corporation (c) 2007.
Link Menu
This book is available now!
Buy at Amazon US or
Buy at Amazon UK
- MsmqIntegrationReceiveParameters.cs
- ZipIORawDataFileBlock.cs
- FunctionMappingTranslator.cs
- DataSpaceManager.cs
- _DomainName.cs
- ProfileSection.cs
- mediaeventshelper.cs
- RbTree.cs
- UnsafeNativeMethods.cs
- Renderer.cs
- ConditionalBranch.cs
- Function.cs
- EntityDataSourceValidationException.cs
- RtfFormatStack.cs
- Renderer.cs
- EncryptedData.cs
- AsyncOperation.cs
- CellNormalizer.cs
- DataGridViewLinkColumn.cs
- InfoCardSymmetricAlgorithm.cs
- WebPartDeleteVerb.cs
- Signature.cs
- Tracer.cs
- ErrorTableItemStyle.cs
- FrameworkElementFactoryMarkupObject.cs
- LogWriteRestartAreaAsyncResult.cs
- WindowsSlider.cs
- LogConverter.cs
- WindowsBrush.cs
- ForceCopyBuildProvider.cs
- JobInputBins.cs
- QilCloneVisitor.cs
- LoadedOrUnloadedOperation.cs
- HwndHost.cs
- LinearGradientBrush.cs
- SQLBytesStorage.cs
- EventLogPermissionAttribute.cs
- SelfIssuedAuthProofToken.cs
- QueryOptionExpression.cs
- OLEDB_Enum.cs
- Expressions.cs
- TreeNodeMouseHoverEvent.cs
- XmlSerializationWriter.cs
- SrgsSemanticInterpretationTag.cs
- MaterialGroup.cs
- ClientFactory.cs
- ZipIOModeEnforcingStream.cs
- loginstatus.cs
- CodeComment.cs
- PageParser.cs
- ComponentRenameEvent.cs
- InputScopeManager.cs
- IERequestCache.cs
- RelationshipType.cs
- RepeaterCommandEventArgs.cs
- ProcessModelSection.cs
- TimelineGroup.cs
- Vars.cs
- DataGridCell.cs
- ChtmlLinkAdapter.cs
- MdiWindowListItemConverter.cs
- DataGridViewRowCollection.cs
- WebControl.cs
- TextElementEditingBehaviorAttribute.cs
- GenericXmlSecurityToken.cs
- BamlLocalizationDictionary.cs
- RequestDescription.cs
- SerializationInfo.cs
- Speller.cs
- CodeVariableDeclarationStatement.cs
- PrefixHandle.cs
- Interlocked.cs
- InputScopeNameConverter.cs
- XmlSchemaSequence.cs
- StickyNoteContentControl.cs
- DataGridViewRowHeaderCell.cs
- _NetworkingPerfCounters.cs
- InkPresenter.cs
- FunctionParameter.cs
- TableRow.cs
- InkCanvas.cs
- RepeaterItemEventArgs.cs
- AvTraceFormat.cs
- DataGridDefaultColumnWidthTypeConverter.cs
- Compensate.cs
- ActivationServices.cs
- PageBuildProvider.cs
- ListViewContainer.cs
- HiddenField.cs
- DateTimeHelper.cs
- Comparer.cs
- SoapAttributes.cs
- InstanceLockLostException.cs
- DataGridItem.cs
- SendingRequestEventArgs.cs
- SelectingProviderEventArgs.cs
- XmlSchemaElement.cs
- WebPartManagerDesigner.cs
- CustomSignedXml.cs
- UrlPropertyAttribute.cs