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
- NodeFunctions.cs
- PenLineJoinValidation.cs
- ImageListImage.cs
- Tool.cs
- TemplateDefinition.cs
- WebPartHelpVerb.cs
- SendingRequestEventArgs.cs
- ConfigurationSettings.cs
- TableRow.cs
- filewebresponse.cs
- WebPartZoneDesigner.cs
- XmlMessageFormatter.cs
- ToolboxItemCollection.cs
- SqlRowUpdatingEvent.cs
- EventSourceCreationData.cs
- CultureInfo.cs
- RelativeSource.cs
- MultiViewDesigner.cs
- HtmlPanelAdapter.cs
- XmlAnyAttributeAttribute.cs
- initElementDictionary.cs
- ColorBlend.cs
- QueryContinueDragEvent.cs
- GridLengthConverter.cs
- HeaderUtility.cs
- PeerName.cs
- DoubleCollectionConverter.cs
- NativeMethods.cs
- LinqDataSourceSelectEventArgs.cs
- Model3DCollection.cs
- GeneralTransform3D.cs
- HelpKeywordAttribute.cs
- AssemblyAttributesGoHere.cs
- CollectionViewSource.cs
- WebScriptEnablingElement.cs
- Rule.cs
- ExpressionBinding.cs
- ObjectDesignerDataSourceView.cs
- HwndHostAutomationPeer.cs
- MemberRelationshipService.cs
- TypeDescriptionProviderAttribute.cs
- ValuePattern.cs
- WebPartConnection.cs
- BindingElement.cs
- DataMemberConverter.cs
- Html32TextWriter.cs
- brushes.cs
- StylusOverProperty.cs
- ClientUrlResolverWrapper.cs
- NamedPipeTransportBindingElement.cs
- DynamicRenderer.cs
- MouseActionConverter.cs
- XmlLoader.cs
- ScrollChrome.cs
- ContentWrapperAttribute.cs
- WindowsScrollBarBits.cs
- SqlXmlStorage.cs
- HttpRuntime.cs
- ButtonBase.cs
- RealizationDrawingContextWalker.cs
- PageCatalogPart.cs
- xmlformatgeneratorstatics.cs
- HwndProxyElementProvider.cs
- DrawListViewSubItemEventArgs.cs
- PropertySegmentSerializationProvider.cs
- ValidationException.cs
- AssemblyAttributes.cs
- TerminatingOperationBehavior.cs
- SqlMetaData.cs
- ButtonFlatAdapter.cs
- ComponentDispatcherThread.cs
- DataViewManager.cs
- MatrixUtil.cs
- StylusPointPropertyId.cs
- TextFormattingConverter.cs
- XmlSchemaValidationException.cs
- ByteStorage.cs
- IriParsingElement.cs
- SearchExpression.cs
- DbDataAdapter.cs
- CurrentChangingEventArgs.cs
- DecimalAnimationUsingKeyFrames.cs
- RedistVersionInfo.cs
- SchemaElement.cs
- UpdateException.cs
- FormsIdentity.cs
- DataGridToolTip.cs
- XsltContext.cs
- DataRelationCollection.cs
- NavigationHelper.cs
- FlowDocumentReaderAutomationPeer.cs
- Claim.cs
- StringBuilder.cs
- PropertyChangedEventArgs.cs
- TimeSpanParse.cs
- AxisAngleRotation3D.cs
- GlyphRun.cs
- WebBrowsableAttribute.cs
- ClientUtils.cs
- ToolboxComponentsCreatedEventArgs.cs