1 //---------------------------------------------------------------------
2 // <copyright file="CommandHelper.cs" company="Microsoft">
3 // Copyright (c) Microsoft Corporation. All rights reserved.
7 // @backupOwner Microsoft
8 //---------------------------------------------------------------------
10 namespace System.Data.Common.Utils
12 using System.Data.EntityClient;
13 using System.Data.Metadata.Edm;
14 using System.Data.Spatial;
15 using System.Diagnostics;
18 /// Contains utility methods for construction of DB commands through generic
19 /// provider interfaces.
21 internal static class CommandHelper
24 /// Consumes all rows and result sets from the reader. This allows client to retrieve
25 /// parameter values and intercept any store exceptions.
27 /// <param name="reader">reader to consume</param>
28 internal static void ConsumeReader(DbDataReader reader)
30 if (null != reader && !reader.IsClosed)
32 while (reader.NextResult())
34 // Note that we only walk through the result sets. We don't need
35 // to walk through individual rows (though underlying provider
36 // implementation may do so)
42 /// requires: commandText must not be null
43 /// The command text must be in the form Container.FunctionImportName.
45 internal static void ParseFunctionImportCommandText(string commandText, string defaultContainerName, out string containerName, out string functionImportName)
47 Debug.Assert(null != commandText);
50 string[] nameParts = commandText.Split('.');
52 functionImportName = null;
53 if (2 == nameParts.Length)
55 containerName = nameParts[0].Trim();
56 functionImportName = nameParts[1].Trim();
58 else if (1 == nameParts.Length && null != defaultContainerName)
60 containerName = defaultContainerName;
61 functionImportName = nameParts[0].Trim();
63 if (string.IsNullOrEmpty(containerName) || string.IsNullOrEmpty(functionImportName))
65 throw EntityUtil.InvalidOperation(System.Data.Entity.Strings.EntityClient_InvalidStoredProcedureCommandText);
70 /// Given an entity command, returns the associated entity transaction and performs validation
71 /// to ensure the transaction is consistent.
73 /// <param name="entityCommand">Entity command instance. Must not be null.</param>
74 /// <returns>Entity transaction</returns>
75 internal static EntityTransaction GetEntityTransaction(EntityCommand entityCommand)
77 Debug.Assert(null != entityCommand);
78 EntityTransaction entityTransaction = (EntityTransaction)entityCommand.Transaction;
80 // Check to make sure that either the command has no transaction associated with it, or it
81 // matches the one used by the connection
82 if (entityTransaction != null && entityTransaction != entityCommand.Connection.CurrentTransaction)
84 throw EntityUtil.InvalidOperation(System.Data.Entity.Strings.EntityClient_InvalidTransactionForCommand);
86 // Now we have asserted that EntityCommand either has no transaction or has one that matches the
87 // one used in the connection, we can simply use the connection's transaction object
88 entityTransaction = entityCommand.Connection.CurrentTransaction;
89 return entityTransaction;
94 /// Given an entity command and entity transaction, passes through relevant state to store provider
97 /// <param name="entityCommand">Entity command. Must not be null.</param>
98 /// <param name="entityTransaction">Entity transaction. Must not be null.</param>
99 /// <param name="storeProviderCommand">Store provider command that is being setup. Must not be null.</param>
100 internal static void SetStoreProviderCommandState(EntityCommand entityCommand, EntityTransaction entityTransaction, DbCommand storeProviderCommand)
102 Debug.Assert(null != entityCommand);
103 Debug.Assert(null != storeProviderCommand);
105 storeProviderCommand.CommandTimeout = entityCommand.CommandTimeout;
106 storeProviderCommand.Connection = ((EntityConnection)entityCommand.Connection).StoreConnection;
107 storeProviderCommand.Transaction = (null != entityTransaction) ? entityTransaction.StoreTransaction : null;
108 storeProviderCommand.UpdatedRowSource = entityCommand.UpdatedRowSource;
113 /// Given an entity command, store provider command and a connection, sets all output parameter values on the entity command.
114 /// The connection is used to determine how to map spatial values.
116 /// <param name="entityCommand">Entity command on which to set parameter values. Must not be null.</param>
117 /// <param name="storeProviderCommand">Store provider command from which to retrieve parameter values. Must not
119 /// <param name="connection">The connection on which the command was run. Must not be null</param>
120 internal static void SetEntityParameterValues(EntityCommand entityCommand, DbCommand storeProviderCommand, EntityConnection connection)
122 Debug.Assert(null != entityCommand);
123 Debug.Assert(null != storeProviderCommand);
124 Debug.Assert(null != connection);
126 foreach (DbParameter storeParameter in storeProviderCommand.Parameters)
128 ParameterDirection direction = storeParameter.Direction;
129 if (0 != (direction & ParameterDirection.Output))
131 // if the entity command also defines the parameter, propagate store parameter value
132 // to entity parameter
133 int parameterOrdinal = entityCommand.Parameters.IndexOf(storeParameter.ParameterName);
134 if (0 <= parameterOrdinal)
136 EntityParameter entityParameter = entityCommand.Parameters[parameterOrdinal];
137 object parameterValue = storeParameter.Value;
138 TypeUsage parameterType = entityParameter.GetTypeUsage();
139 if (Helper.IsSpatialType(parameterType))
141 parameterValue = GetSpatialValueFromProviderValue(parameterValue, (PrimitiveType)parameterType.EdmType, connection);
143 entityParameter.Value = parameterValue;
149 private static object GetSpatialValueFromProviderValue(object spatialValue, PrimitiveType parameterType, EntityConnection connection)
151 DbProviderServices providerServices = DbProviderServices.GetProviderServices(connection.StoreConnection);
152 StoreItemCollection storeItemCollection = (StoreItemCollection)connection.GetMetadataWorkspace().GetItemCollection(DataSpace.SSpace);
153 DbSpatialServices spatialServices = providerServices.GetSpatialServices(storeItemCollection.StoreProviderManifestToken);
154 if (Helper.IsGeographicType(parameterType))
156 return spatialServices.GeographyFromProviderValue(spatialValue);
160 Debug.Assert(Helper.IsGeometricType(parameterType));
161 return spatialServices.GeometryFromProviderValue(spatialValue);
165 // requires: all arguments must be given
166 internal static EdmFunction FindFunctionImport(MetadataWorkspace workspace, string containerName, string functionImportName)
168 Debug.Assert(null != workspace && null != containerName && null != functionImportName);
169 // find entity container
170 EntityContainer entityContainer;
171 if (!workspace.TryGetEntityContainer(containerName, DataSpace.CSpace, out entityContainer))
173 throw EntityUtil.InvalidOperation(System.Data.Entity.Strings.EntityClient_UnableToFindFunctionImportContainer(
177 // find function import
178 EdmFunction functionImport = null;
179 foreach (EdmFunction candidate in entityContainer.FunctionImports)
181 if (candidate.Name == functionImportName)
183 functionImport = candidate;
187 if (null == functionImport)
189 throw EntityUtil.InvalidOperation(System.Data.Entity.Strings.EntityClient_UnableToFindFunctionImport(
190 containerName, functionImportName));
192 if (functionImport.IsComposableAttribute)
194 throw EntityUtil.InvalidOperation(System.Data.Entity.Strings.EntityClient_FunctionImportMustBeNonComposable(containerName + "." + functionImportName));
196 return functionImport;