2015-04-07 09:35:12 +01:00
|
|
|
//---------------------------------------------------------------------
|
|
|
|
// <copyright file="SourceInterpreter.cs" company="Microsoft">
|
|
|
|
// Copyright (c) Microsoft Corporation. All rights reserved.
|
|
|
|
// </copyright>
|
|
|
|
//
|
|
|
|
// @owner [....]
|
|
|
|
// @backupOwner [....]
|
|
|
|
//---------------------------------------------------------------------
|
|
|
|
|
|
|
|
using System.Collections.Generic;
|
|
|
|
using System.Collections.ObjectModel;
|
|
|
|
using System.Diagnostics;
|
|
|
|
using System.Data.Objects;
|
|
|
|
using System.Data.Metadata.Edm;
|
|
|
|
namespace System.Data.Mapping.Update.Internal
|
|
|
|
{
|
|
|
|
/// <summary>
|
|
|
|
/// This class determines the state entries contributing to an expression
|
|
|
|
/// propagated through an update mapping view (values in propagated expressions
|
|
|
|
/// remember where they come from)
|
|
|
|
/// </summary>
|
|
|
|
internal class SourceInterpreter
|
|
|
|
{
|
|
|
|
private SourceInterpreter(UpdateTranslator translator, EntitySet sourceTable)
|
|
|
|
{
|
|
|
|
m_stateEntries = new List<IEntityStateEntry>();
|
|
|
|
m_translator = translator;
|
|
|
|
m_sourceTable = sourceTable;
|
|
|
|
}
|
|
|
|
|
|
|
|
private readonly List<IEntityStateEntry> m_stateEntries;
|
|
|
|
private readonly UpdateTranslator m_translator;
|
|
|
|
private readonly EntitySet m_sourceTable;
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
/// Finds all markup associated with the given source.
|
|
|
|
/// </summary>
|
|
|
|
/// <param name="source">Source expression. Must not be null.</param>
|
|
|
|
/// <param name="translator">Translator containing session information.</param>
|
|
|
|
/// <param name="sourceTable">Table from which the exception was thrown (must not be null).</param>
|
|
|
|
/// <returns>Markup.</returns>
|
|
|
|
internal static ReadOnlyCollection<IEntityStateEntry> GetAllStateEntries(PropagatorResult source, UpdateTranslator translator,
|
|
|
|
EntitySet sourceTable)
|
|
|
|
{
|
|
|
|
Debug.Assert(null != source);
|
|
|
|
Debug.Assert(null != translator);
|
|
|
|
Debug.Assert(null != sourceTable);
|
|
|
|
|
|
|
|
SourceInterpreter interpreter = new SourceInterpreter(translator, sourceTable);
|
|
|
|
interpreter.RetrieveResultMarkup(source);
|
|
|
|
|
|
|
|
return new ReadOnlyCollection<IEntityStateEntry>(interpreter.m_stateEntries);
|
|
|
|
}
|
|
|
|
|
|
|
|
private void RetrieveResultMarkup(PropagatorResult source)
|
|
|
|
{
|
|
|
|
Debug.Assert(null != source);
|
|
|
|
|
|
|
|
if (source.Identifier != PropagatorResult.NullIdentifier)
|
|
|
|
{
|
|
|
|
// state entries travel with identifiers. several state entries may be merged
|
|
|
|
// into a single identifier result via joins in the update mapping view
|
|
|
|
do
|
|
|
|
{
|
|
|
|
if (null != source.StateEntry)
|
|
|
|
{
|
|
|
|
m_stateEntries.Add(source.StateEntry);
|
|
|
|
if (source.Identifier != PropagatorResult.NullIdentifier)
|
|
|
|
{
|
|
|
|
// if this is an identifier, it may also be registered with an "owner".
|
|
|
|
// Return the owner as well if the owner is also mapped to this table.
|
|
|
|
PropagatorResult owner;
|
|
|
|
if (m_translator.KeyManager.TryGetIdentifierOwner(source.Identifier, out owner) &&
|
|
|
|
null != owner.StateEntry &&
|
|
|
|
ExtentInScope(owner.StateEntry.EntitySet))
|
|
|
|
{
|
|
|
|
m_stateEntries.Add(owner.StateEntry);
|
|
|
|
}
|
|
|
|
|
|
|
|
// Check if are any referential constraints. If so, the entity key
|
|
|
|
// implies that the dependent relationship instance is also being
|
|
|
|
// handled in this result.
|
|
|
|
foreach (IEntityStateEntry stateEntry in m_translator.KeyManager.GetDependentStateEntries(source.Identifier))
|
|
|
|
{
|
|
|
|
m_stateEntries.Add(stateEntry);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
source = source.Next;
|
|
|
|
}
|
|
|
|
while (null != source);
|
|
|
|
}
|
|
|
|
else if (!source.IsSimple && !source.IsNull)
|
|
|
|
{
|
|
|
|
// walk children
|
|
|
|
foreach (PropagatorResult child in source.GetMemberValues())
|
|
|
|
{
|
|
|
|
RetrieveResultMarkup(child);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Determines whether the given table is in scope for the current source: if the source
|
|
|
|
// table does not map to the source table for this interpreter, it is not in scope
|
|
|
|
// for exceptions thrown from this table.
|
|
|
|
private bool ExtentInScope(EntitySetBase extent)
|
|
|
|
{
|
|
|
|
if (null == extent)
|
|
|
|
{
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
// determine if the extent is mapped to this table
|
|
|
|
return m_translator.ViewLoader.GetAffectedTables(extent, m_translator.MetadataWorkspace).Contains(m_sourceTable);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|