Code:
/ Net / Net / 3.5.50727.3053 / DEVDIV / depot / DevDiv / releases / Orcas / SP / ndp / fx / src / DataEntity / System / Data / Map / Update / Internal / FunctionUpdateCommand.cs / 4 / FunctionUpdateCommand.cs
//----------------------------------------------------------------------
//
// Copyright (c) Microsoft Corporation. All rights reserved.
//
//
// @owner [....]
// @backupOwner [....]
//---------------------------------------------------------------------
using System.Data.Common.CommandTrees;
using System.Data.Metadata.Edm;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Data.Common.CommandTrees.Internal;
using System.Data.Common.Utils;
using System.Diagnostics;
using System.Data.Common;
using System.Data.Objects;
using System.Data.EntityClient;
using System.Globalization;
using System.Data.Entity;
using System.Linq;
namespace System.Data.Mapping.Update.Internal
{
///
/// Aggregates information about a modification command delegated to a store function.
///
internal sealed class FunctionUpdateCommand : UpdateCommand
{
#region Constructors
///
/// Initialize a new function command. Initializes the command object.
///
/// Function mapping metadata
/// Translator
/// Primary state entry for this function (additional
/// state entries can be added later, for instance for relationship navigation bindings)
internal FunctionUpdateCommand(StorageFunctionMapping functionMapping, UpdateTranslator translator,
IEntityStateEntry stateEntry)
{
EntityUtil.CheckArgumentNull(functionMapping, "functionMapping");
EntityUtil.CheckArgumentNull(translator, "translator");
EntityUtil.CheckArgumentNull(stateEntry, "stateEntry");
// populate the main state entry for error reporting
m_stateEntries = new List(1);
m_stateEntries.Add(stateEntry);
// create a command
DbCommandDefinition commandDefinition = translator.GenerateCommandDefinition(functionMapping);
m_dbCommand = commandDefinition.CreateCommand();
}
#endregion
#region Fields
private readonly List m_stateEntries;
///
/// Gets the store command wrapped by this command.
///
private readonly DbCommand m_dbCommand;
///
/// Gets pairs for column names and propagator results (so that we can associate reader results with
/// the source records for server generated values).
///
private List> m_resultColumns;
///
/// Gets map from identifiers (key component proxies) to parameters holding the actual
/// key values. Supports propagation of identifier values (fixup for server-gen keys)
///
private List> m_inputIdentifiers;
///
/// Gets map from identifiers (key component proxies) to column names producing the actual
/// key values. Supports propagation of identifier values (fixup for server-gen keys)
///
private Dictionary m_outputIdentifiers;
///
/// Gets a reference to the rows affected output parameter for the stored procedure. May be null.
///
private DbParameter m_rowsAffectedParameter;
#endregion
#region Properties
internal override IEnumerable InputIdentifiers
{
get
{
if (null == m_inputIdentifiers)
{
yield break;
}
else
{
foreach (KeyValuePair inputIdentifier in m_inputIdentifiers)
{
yield return inputIdentifier.Key;
}
}
}
}
internal override IEnumerable OutputIdentifiers
{
get
{
if (null == m_outputIdentifiers)
{
return Enumerable.Empty();
}
return m_outputIdentifiers.Keys;
}
}
internal override UpdateCommandKind Kind
{
get { return UpdateCommandKind.Function; }
}
#endregion
#region Methods
///
/// Gets state entries contributing to this function. Supports error reporting.
///
internal override List GetStateEntries(UpdateTranslator translator)
{
return m_stateEntries;
}
// Adds and register a DbParameter to the current command.
internal void SetParameterValue(PropagatorResult result, StorageFunctionParameterBinding parameterBinding, UpdateTranslator translator)
{
// retrieve DbParameter
DbParameter parameter = this.m_dbCommand.Parameters[parameterBinding.Parameter.Name];
parameter.Value = translator.KeyManager.GetPrincipalValue(result);
// if the parameter corresponds to an identifier (key component), remember this fact in case
// it's important for dependency ordering (e.g., output the identifier before creating it)
long identifier = result.Identifier;
if (PropagatorResult.NullIdentifier != identifier)
{
const int initialSize = 2; // expect on average less than two input identifiers per command
if (null == m_inputIdentifiers)
{
m_inputIdentifiers = new List>(initialSize);
}
foreach (long principal in translator.KeyManager.GetPrincipals(identifier))
{
m_inputIdentifiers.Add(new KeyValuePair(principal, parameter));
}
// if there is a dependent state entry, remember that this command also handles the entry
foreach (IEntityStateEntry stateEntry in translator.KeyManager.GetDependentStateEntries(identifier))
{
m_stateEntries.Add(stateEntry);
}
}
}
// Adds and registers a DbParameter taking the number of rows affected
internal void RegisterRowsAffectedParameter(FunctionParameter rowsAffectedParameter)
{
if (null != rowsAffectedParameter)
{
Debug.Assert(MetadataHelper.GetPrimitiveTypeKind(rowsAffectedParameter.TypeUsage) ==
PrimitiveTypeKind.Int32, "when loading mapping metadata, we check that the parameter is Int32");
Debug.Assert(rowsAffectedParameter.Mode == ParameterMode.Out,
"when loading mapping metadata, we check that the parameter is an out parameter");
m_rowsAffectedParameter = m_dbCommand.Parameters[rowsAffectedParameter.Name];
}
}
// Registers a new state entry as part of the context for this command (for error reporting).
internal void RegisterStateEntry(IEntityStateEntry stateEntry)
{
m_stateEntries.Add(EntityUtil.CheckArgumentNull(stateEntry, "stateEntry"));
}
// Adds a result column binding from a column name (from the result set for the function) to
// a propagator result (which contains the context necessary to back-propagate the result).
// If the result is an identifier, binds the
internal void AddResultColumn(UpdateTranslator translator, String columnName, PropagatorResult result)
{
const int initializeSize = 2; // expect on average less than two result columns per command
if (null == m_resultColumns)
{
m_resultColumns = new List>(initializeSize);
}
m_resultColumns.Add(new KeyValuePair(columnName, result));
long identifier = result.Identifier;
if (PropagatorResult.NullIdentifier != identifier)
{
if (translator.KeyManager.HasPrincipals(identifier))
{
throw EntityUtil.InvalidOperation(System.Data.Entity.Strings.Update_GeneratedDependent(columnName));
}
// register output identifier to enable fix-up and dependency tracking
AddOutputIdentifier(columnName, identifier);
}
}
// Indicate that a column in the command result set (specified by 'columnName') produces the
// value for a key component (specified by 'identifier')
private void AddOutputIdentifier(String columnName, Int64 identifier)
{
const int initialSize = 2; // expect on average less than two identifier output per command
if (null == m_outputIdentifiers)
{
m_outputIdentifiers = new Dictionary(initialSize);
}
m_outputIdentifiers[identifier] = columnName;
}
// efects: Executes the current function command in the given transaction and connection context.
// All server-generated values are added to the generatedValues list. If those values are identifiers, they are
// also added to the identifierValues dictionary, which associates proxy identifiers for keys in the session
// with their actual values, permitting fix-up of identifiers across relationships.
internal override int Execute(UpdateTranslator translator, EntityConnection connection, Dictionary identifierValues,
List> generatedValues)
{
// configure command to use the connection and transaction for this session
m_dbCommand.Transaction = ((null != connection.CurrentTransaction) ? connection.CurrentTransaction.StoreTransaction : null);
m_dbCommand.Connection = connection.StoreConnection;
if (translator.CommandTimeout.HasValue)
{
m_dbCommand.CommandTimeout = translator.CommandTimeout.Value;
}
// set all identifier inputs (to support propagation of identifier values across relationship
// boundaries)
if (null != m_inputIdentifiers)
{
foreach (KeyValuePair inputIdentifier in m_inputIdentifiers)
{
object value;
if (identifierValues.TryGetValue(inputIdentifier.Key, out value))
{
// set the actual value for the identifier if it has been produced by some
// other command
inputIdentifier.Value.Value = value;
}
}
}
// Execute the query
int rowsAffected;
if (null != m_resultColumns)
{
// If there are result columns, read the server gen results
rowsAffected = 0;
using (DbDataReader reader = m_dbCommand.ExecuteReader(CommandBehavior.SequentialAccess))
{
// Retrieve only the first row from the first result set
if (reader.Read())
{
rowsAffected++;
foreach (var resultColumn in m_resultColumns
.Select(r => new KeyValuePair(GetColumnOrdinal(translator, reader, r.Key), r.Value))
.OrderBy(r => r.Key)) // order by column ordinal to avoid breaking SequentialAccess readers
{
int columnOrdinal = resultColumn.Key;
object value = reader.GetValue(columnOrdinal);
// register for back-propagation
PropagatorResult result = resultColumn.Value;
generatedValues.Add(new KeyValuePair(result, value));
// register identifier if it exists
Int64 identifier = result.Identifier;
if (PropagatorResult.NullIdentifier != identifier)
{
identifierValues.Add(identifier, value);
}
}
}
// Consume the current reader (and subsequent result sets) so that any errors
// executing the function can be intercepted
CommandHelper.ConsumeReader(reader);
}
}
else
{
rowsAffected = m_dbCommand.ExecuteNonQuery();
}
// if an explicit rows affected parameter exists, use this value instead
if (null != m_rowsAffectedParameter)
{
// by design, negative row counts indicate failure iff. an explicit rows
// affected parameter is used
if (DBNull.Value.Equals(m_rowsAffectedParameter.Value))
{
rowsAffected = 0;
}
else
{
try
{
rowsAffected = Convert.ToInt32(m_rowsAffectedParameter.Value, CultureInfo.InvariantCulture);
}
catch (Exception e)
{
if (UpdateTranslator.RequiresContext(e))
{
// wrap the exception
throw EntityUtil.Update(System.Data.Entity.Strings.Update_UnableToConvertRowsAffectedParameterToInt32(
m_rowsAffectedParameter.ParameterName, typeof(int).FullName), e, this.GetStateEntries(translator));
}
throw;
}
}
}
return rowsAffected;
}
private int GetColumnOrdinal(UpdateTranslator translator, DbDataReader reader, string columnName)
{
int columnOrdinal;
try
{
columnOrdinal = reader.GetOrdinal(columnName);
}
catch (IndexOutOfRangeException)
{
throw EntityUtil.Update(System.Data.Entity.Strings.Update_MissingResultColumn(columnName), null,
this.GetStateEntries(translator));
}
return columnOrdinal;
}
internal override int CompareToType(UpdateCommand otherCommand)
{
Debug.Assert(!object.ReferenceEquals(this, otherCommand), "caller should ensure other command is different");
FunctionUpdateCommand other = (FunctionUpdateCommand)otherCommand;
// first state entry is the 'main' state entry for the command (see ctor)
IEntityStateEntry thisParent = this.m_stateEntries[0];
IEntityStateEntry otherParent = other.m_stateEntries[0];
// order by state
int result = (int)thisParent.State - (int)otherParent.State;
if (0 != result) { return result; }
// order by entity set
result = StringComparer.Ordinal.Compare(thisParent.EntitySet.Name, otherParent.EntitySet.Name);
if (0 != result) { return result; }
result = StringComparer.Ordinal.Compare(thisParent.EntitySet.EntityContainer.Name, otherParent.EntitySet.EntityContainer.Name);
if (0 != result) { return result; }
// order by key values
int thisInputIdentifierCount = (null == this.m_inputIdentifiers ? 0 : this.m_inputIdentifiers.Count);
int otherInputIdentifierCount = (null == other.m_inputIdentifiers ? 0 : other.m_inputIdentifiers.Count);
result = thisInputIdentifierCount - otherInputIdentifierCount;
if (0 != result) { return result; }
for (int i = 0; i < thisInputIdentifierCount; i++)
{
DbParameter thisParameter = this.m_inputIdentifiers[i].Value;
DbParameter otherParameter = other.m_inputIdentifiers[i].Value;
result = Comparer
Link Menu

This book is available now!
Buy at Amazon US or
Buy at Amazon UK
- UnionExpr.cs
- PerfCounterSection.cs
- WebServiceClientProxyGenerator.cs
- assemblycache.cs
- SpecularMaterial.cs
- DataGridColumnReorderingEventArgs.cs
- MetadataPropertyCollection.cs
- CodeDOMUtility.cs
- PackageRelationshipCollection.cs
- NamespaceMapping.cs
- CaseInsensitiveComparer.cs
- FrameworkReadOnlyPropertyMetadata.cs
- MetadataAssemblyHelper.cs
- ShaperBuffers.cs
- SqlBulkCopy.cs
- columnmapfactory.cs
- ScriptHandlerFactory.cs
- DeviceContext.cs
- TreeNodeBindingCollection.cs
- AutoResizedEvent.cs
- SafeLibraryHandle.cs
- ThreadAttributes.cs
- Typography.cs
- MimeMultiPart.cs
- BufferedGraphicsManager.cs
- DateTimeSerializationSection.cs
- DocumentPageViewAutomationPeer.cs
- Knowncolors.cs
- TransactionManagerProxy.cs
- DoubleAnimationBase.cs
- DataErrorValidationRule.cs
- CompileLiteralTextParser.cs
- MemberMemberBinding.cs
- FormsAuthenticationUser.cs
- Privilege.cs
- InfoCardRSACryptoProvider.cs
- Stack.cs
- ActivityLocationReferenceEnvironment.cs
- SchemaEntity.cs
- DataStreamFromComStream.cs
- MatrixCamera.cs
- Span.cs
- LocalizableResourceBuilder.cs
- ControlEvent.cs
- InputLanguageProfileNotifySink.cs
- SoapTransportImporter.cs
- SByteConverter.cs
- Vector3D.cs
- KeyGesture.cs
- ExportOptions.cs
- CryptoApi.cs
- PromptBuilder.cs
- ActivationArguments.cs
- TranslateTransform.cs
- MD5CryptoServiceProvider.cs
- PackageFilter.cs
- KeyGestureConverter.cs
- CacheModeConverter.cs
- EntityDataSourceConfigureObjectContext.cs
- Point3DAnimationBase.cs
- ErrorTableItemStyle.cs
- TargetInvocationException.cs
- _LazyAsyncResult.cs
- filewebresponse.cs
- TraceHandler.cs
- ResourceReferenceExpression.cs
- ProcessThreadCollection.cs
- LassoSelectionBehavior.cs
- DispatcherSynchronizationContext.cs
- SmiMetaData.cs
- RuleProcessor.cs
- XmlNotation.cs
- ConnectionPointCookie.cs
- IIS7WorkerRequest.cs
- HttpCookie.cs
- TabPageDesigner.cs
- ProfileManager.cs
- DataTableCollection.cs
- FlowDocumentScrollViewer.cs
- SystemIcons.cs
- BStrWrapper.cs
- WebBrowsableAttribute.cs
- X509Logo.cs
- XmlSerializerFactory.cs
- MouseGesture.cs
- HttpHeaderCollection.cs
- CDSCollectionETWBCLProvider.cs
- DesignerForm.cs
- CheckBox.cs
- SimplePropertyEntry.cs
- EntityDataSourceWizardForm.cs
- SetStoryboardSpeedRatio.cs
- XPathPatternBuilder.cs
- TransformConverter.cs
- HwndSource.cs
- KeyConstraint.cs
- ComplexLine.cs
- TextTreeDeleteContentUndoUnit.cs
- SafeLibraryHandle.cs
- HttpResponse.cs