internal EntityCommandDefinition( DbProviderFactory storeProviderFactory, DbCommandTree commandTree, BridgeDataReaderFactory bridgeDataReaderFactory = null) { //Contract.Requires(storeProviderFactory != null); //Contract.Requires(commandTree != null); _bridgeDataReaderFactory = bridgeDataReaderFactory ?? new BridgeDataReaderFactory(); var storeProviderServices = storeProviderFactory.GetProviderServices(); try { if (DbCommandTreeKind.Query == commandTree.CommandTreeKind) { // Next compile the plan for the command tree var mappedCommandList = new List<ProviderCommandInfo>(); ColumnMap columnMap; int columnCount; PlanCompiler.Compile(commandTree, out mappedCommandList, out columnMap, out columnCount, out _entitySets); _columnMapGenerators = new IColumnMapGenerator[] { 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<DbCommandDefinition>(mappedCommandList.Count); foreach (var providerCommandInfo in mappedCommandList) { var providerCommandDefinition = storeProviderServices.CreateCommandDefinition(providerCommandInfo.CommandTree); if (null == providerCommandDefinition) { throw new ProviderIncompatibleException(Strings.ProviderReturnedNullForCreateCommandDefinition); } _mappedCommandDefinitions.Add(providerCommandDefinition); } } else { Contract.Assert( DbCommandTreeKind.Function == commandTree.CommandTreeKind, "only query and function command trees are supported"); var entityCommandTree = (DbFunctionCommandTree)commandTree; // Retrieve mapping and metadata information for the function import. var mapping = GetTargetFunctionMapping(entityCommandTree); IList<FunctionParameter> returnParameters = entityCommandTree.EdmFunction.ReturnParameters; var resultSetCount = returnParameters.Count > 1 ? returnParameters.Count : 1; _columnMapGenerators = new IColumnMapGenerator[resultSetCount]; var storeResultType = DetermineStoreResultType(mapping, 0, out _columnMapGenerators[0]); for (var i = 1; i < resultSetCount; i++) { DetermineStoreResultType(mapping, i, out _columnMapGenerators[i]); } // Copy over parameters (this happens through a more indirect route in the plan compiler, but // it happens nonetheless) var providerParameters = new List<KeyValuePair<string, TypeUsage>>(); foreach (var parameter in entityCommandTree.Parameters) { providerParameters.Add(parameter); } // Construct store command tree usage. var providerCommandTree = new DbFunctionCommandTree( entityCommandTree.MetadataWorkspace, DataSpace.SSpace, mapping.TargetFunction, storeResultType, providerParameters); var storeCommandDefinition = storeProviderServices.CreateCommandDefinition(providerCommandTree); _mappedCommandDefinitions = new List<DbCommandDefinition>(1) { storeCommandDefinition }; var firstResultEntitySet = mapping.FunctionImport.EntitySets.FirstOrDefault(); if (firstResultEntitySet != null) { _entitySets = new Set<EntitySet>(); _entitySets.Add(mapping.FunctionImport.EntitySets.FirstOrDefault()); _entitySets.MakeReadOnly(); } } // Finally, build a list of the parameters that the resulting command should have; var parameterList = new List<EntityParameter>(); foreach (var queryParameter in commandTree.Parameters) { var parameter = CreateEntityParameterFromQueryParameter(queryParameter); parameterList.Add(parameter); } _parameters = new ReadOnlyCollection<EntityParameter>(parameterList); } catch (EntityCommandCompilationException) { // No need to re-wrap EntityCommandCompilationException throw; } catch (Exception e) { // we should not be wrapping all exceptions if (e.IsCatchableExceptionType()) { // 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 new EntityCommandCompilationException(Strings.EntityClient_CommandDefinitionPreparationFailed, e); } throw; } }
/// <summary> /// Constructor for testing/mocking purposes. /// </summary> protected EntityCommandDefinition(BridgeDataReaderFactory factory = null, List<DbCommandDefinition> mappedCommandDefinitions = null) { _bridgeDataReaderFactory = factory ?? new BridgeDataReaderFactory(); _mappedCommandDefinitions = mappedCommandDefinitions; }