536cd135cc
Former-commit-id: 5624ac747d633e885131e8349322922b6a59baaa
200 lines
9.5 KiB
C#
200 lines
9.5 KiB
C#
//---------------------------------------------------------------------
|
|
// <copyright file="CommandHelper.cs" company="Microsoft">
|
|
// Copyright (c) Microsoft Corporation. All rights reserved.
|
|
// </copyright>
|
|
//
|
|
// @owner Microsoft
|
|
// @backupOwner Microsoft
|
|
//---------------------------------------------------------------------
|
|
|
|
namespace System.Data.Common.Utils
|
|
{
|
|
using System.Data.EntityClient;
|
|
using System.Data.Metadata.Edm;
|
|
using System.Data.Spatial;
|
|
using System.Diagnostics;
|
|
|
|
/// <summary>
|
|
/// Contains utility methods for construction of DB commands through generic
|
|
/// provider interfaces.
|
|
/// </summary>
|
|
internal static class CommandHelper
|
|
{
|
|
/// <summary>
|
|
/// Consumes all rows and result sets from the reader. This allows client to retrieve
|
|
/// parameter values and intercept any store exceptions.
|
|
/// </summary>
|
|
/// <param name="reader">reader to consume</param>
|
|
internal static void ConsumeReader(DbDataReader reader)
|
|
{
|
|
if (null != reader && !reader.IsClosed)
|
|
{
|
|
while (reader.NextResult())
|
|
{
|
|
// Note that we only walk through the result sets. We don't need
|
|
// to walk through individual rows (though underlying provider
|
|
// implementation may do so)
|
|
}
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// requires: commandText must not be null
|
|
/// The command text must be in the form Container.FunctionImportName.
|
|
/// </summary>
|
|
internal static void ParseFunctionImportCommandText(string commandText, string defaultContainerName, out string containerName, out string functionImportName)
|
|
{
|
|
Debug.Assert(null != commandText);
|
|
|
|
// Split the string
|
|
string[] nameParts = commandText.Split('.');
|
|
containerName = null;
|
|
functionImportName = null;
|
|
if (2 == nameParts.Length)
|
|
{
|
|
containerName = nameParts[0].Trim();
|
|
functionImportName = nameParts[1].Trim();
|
|
}
|
|
else if (1 == nameParts.Length && null != defaultContainerName)
|
|
{
|
|
containerName = defaultContainerName;
|
|
functionImportName = nameParts[0].Trim();
|
|
}
|
|
if (string.IsNullOrEmpty(containerName) || string.IsNullOrEmpty(functionImportName))
|
|
{
|
|
throw EntityUtil.InvalidOperation(System.Data.Entity.Strings.EntityClient_InvalidStoredProcedureCommandText);
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Given an entity command, returns the associated entity transaction and performs validation
|
|
/// to ensure the transaction is consistent.
|
|
/// </summary>
|
|
/// <param name="entityCommand">Entity command instance. Must not be null.</param>
|
|
/// <returns>Entity transaction</returns>
|
|
internal static EntityTransaction GetEntityTransaction(EntityCommand entityCommand)
|
|
{
|
|
Debug.Assert(null != entityCommand);
|
|
EntityTransaction entityTransaction = (EntityTransaction)entityCommand.Transaction;
|
|
|
|
// Check to make sure that either the command has no transaction associated with it, or it
|
|
// matches the one used by the connection
|
|
if (entityTransaction != null && entityTransaction != entityCommand.Connection.CurrentTransaction)
|
|
{
|
|
throw EntityUtil.InvalidOperation(System.Data.Entity.Strings.EntityClient_InvalidTransactionForCommand);
|
|
}
|
|
// Now we have asserted that EntityCommand either has no transaction or has one that matches the
|
|
// one used in the connection, we can simply use the connection's transaction object
|
|
entityTransaction = entityCommand.Connection.CurrentTransaction;
|
|
return entityTransaction;
|
|
}
|
|
|
|
|
|
/// <summary>
|
|
/// Given an entity command and entity transaction, passes through relevant state to store provider
|
|
/// command.
|
|
/// </summary>
|
|
/// <param name="entityCommand">Entity command. Must not be null.</param>
|
|
/// <param name="entityTransaction">Entity transaction. Must not be null.</param>
|
|
/// <param name="storeProviderCommand">Store provider command that is being setup. Must not be null.</param>
|
|
internal static void SetStoreProviderCommandState(EntityCommand entityCommand, EntityTransaction entityTransaction, DbCommand storeProviderCommand)
|
|
{
|
|
Debug.Assert(null != entityCommand);
|
|
Debug.Assert(null != storeProviderCommand);
|
|
|
|
storeProviderCommand.CommandTimeout = entityCommand.CommandTimeout;
|
|
storeProviderCommand.Connection = ((EntityConnection)entityCommand.Connection).StoreConnection;
|
|
storeProviderCommand.Transaction = (null != entityTransaction) ? entityTransaction.StoreTransaction : null;
|
|
storeProviderCommand.UpdatedRowSource = entityCommand.UpdatedRowSource;
|
|
}
|
|
|
|
|
|
/// <summary>
|
|
/// Given an entity command, store provider command and a connection, sets all output parameter values on the entity command.
|
|
/// The connection is used to determine how to map spatial values.
|
|
/// </summary>
|
|
/// <param name="entityCommand">Entity command on which to set parameter values. Must not be null.</param>
|
|
/// <param name="storeProviderCommand">Store provider command from which to retrieve parameter values. Must not
|
|
/// be null.</param>
|
|
/// <param name="connection">The connection on which the command was run. Must not be null</param>
|
|
internal static void SetEntityParameterValues(EntityCommand entityCommand, DbCommand storeProviderCommand, EntityConnection connection)
|
|
{
|
|
Debug.Assert(null != entityCommand);
|
|
Debug.Assert(null != storeProviderCommand);
|
|
Debug.Assert(null != connection);
|
|
|
|
foreach (DbParameter storeParameter in storeProviderCommand.Parameters)
|
|
{
|
|
ParameterDirection direction = storeParameter.Direction;
|
|
if (0 != (direction & ParameterDirection.Output))
|
|
{
|
|
// if the entity command also defines the parameter, propagate store parameter value
|
|
// to entity parameter
|
|
int parameterOrdinal = entityCommand.Parameters.IndexOf(storeParameter.ParameterName);
|
|
if (0 <= parameterOrdinal)
|
|
{
|
|
EntityParameter entityParameter = entityCommand.Parameters[parameterOrdinal];
|
|
object parameterValue = storeParameter.Value;
|
|
TypeUsage parameterType = entityParameter.GetTypeUsage();
|
|
if (Helper.IsSpatialType(parameterType))
|
|
{
|
|
parameterValue = GetSpatialValueFromProviderValue(parameterValue, (PrimitiveType)parameterType.EdmType, connection);
|
|
}
|
|
entityParameter.Value = parameterValue;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
private static object GetSpatialValueFromProviderValue(object spatialValue, PrimitiveType parameterType, EntityConnection connection)
|
|
{
|
|
DbProviderServices providerServices = DbProviderServices.GetProviderServices(connection.StoreConnection);
|
|
StoreItemCollection storeItemCollection = (StoreItemCollection)connection.GetMetadataWorkspace().GetItemCollection(DataSpace.SSpace);
|
|
DbSpatialServices spatialServices = providerServices.GetSpatialServices(storeItemCollection.StoreProviderManifestToken);
|
|
if (Helper.IsGeographicType(parameterType))
|
|
{
|
|
return spatialServices.GeographyFromProviderValue(spatialValue);
|
|
}
|
|
else
|
|
{
|
|
Debug.Assert(Helper.IsGeometricType(parameterType));
|
|
return spatialServices.GeometryFromProviderValue(spatialValue);
|
|
}
|
|
}
|
|
|
|
// requires: all arguments must be given
|
|
internal static EdmFunction FindFunctionImport(MetadataWorkspace workspace, string containerName, string functionImportName)
|
|
{
|
|
Debug.Assert(null != workspace && null != containerName && null != functionImportName);
|
|
// find entity container
|
|
EntityContainer entityContainer;
|
|
if (!workspace.TryGetEntityContainer(containerName, DataSpace.CSpace, out entityContainer))
|
|
{
|
|
throw EntityUtil.InvalidOperation(System.Data.Entity.Strings.EntityClient_UnableToFindFunctionImportContainer(
|
|
containerName));
|
|
}
|
|
|
|
// find function import
|
|
EdmFunction functionImport = null;
|
|
foreach (EdmFunction candidate in entityContainer.FunctionImports)
|
|
{
|
|
if (candidate.Name == functionImportName)
|
|
{
|
|
functionImport = candidate;
|
|
break;
|
|
}
|
|
}
|
|
if (null == functionImport)
|
|
{
|
|
throw EntityUtil.InvalidOperation(System.Data.Entity.Strings.EntityClient_UnableToFindFunctionImport(
|
|
containerName, functionImportName));
|
|
}
|
|
if (functionImport.IsComposableAttribute)
|
|
{
|
|
throw EntityUtil.InvalidOperation(System.Data.Entity.Strings.EntityClient_FunctionImportMustBeNonComposable(containerName + "." + functionImportName));
|
|
}
|
|
return functionImport;
|
|
}
|
|
}
|
|
}
|