1 //--------------------------------------------------------------------- 2 // <copyright file="SourceInterpreter.cs" company="Microsoft"> 3 // Copyright (c) Microsoft Corporation. All rights reserved. 4 // </copyright> 5 // 6 // @owner Microsoft 7 // @backupOwner Microsoft 8 //--------------------------------------------------------------------- 9 10 using System.Collections.Generic; 11 using System.Collections.ObjectModel; 12 using System.Diagnostics; 13 using System.Data.Objects; 14 using System.Data.Metadata.Edm; 15 namespace System.Data.Mapping.Update.Internal 16 { 17 /// <summary> 18 /// This class determines the state entries contributing to an expression 19 /// propagated through an update mapping view (values in propagated expressions 20 /// remember where they come from) 21 /// </summary> 22 internal class SourceInterpreter 23 { SourceInterpreter(UpdateTranslator translator, EntitySet sourceTable)24 private SourceInterpreter(UpdateTranslator translator, EntitySet sourceTable) 25 { 26 m_stateEntries = new List<IEntityStateEntry>(); 27 m_translator = translator; 28 m_sourceTable = sourceTable; 29 } 30 31 private readonly List<IEntityStateEntry> m_stateEntries; 32 private readonly UpdateTranslator m_translator; 33 private readonly EntitySet m_sourceTable; 34 35 /// <summary> 36 /// Finds all markup associated with the given source. 37 /// </summary> 38 /// <param name="source">Source expression. Must not be null.</param> 39 /// <param name="translator">Translator containing session information.</param> 40 /// <param name="sourceTable">Table from which the exception was thrown (must not be null).</param> 41 /// <returns>Markup.</returns> GetAllStateEntries(PropagatorResult source, UpdateTranslator translator, EntitySet sourceTable)42 internal static ReadOnlyCollection<IEntityStateEntry> GetAllStateEntries(PropagatorResult source, UpdateTranslator translator, 43 EntitySet sourceTable) 44 { 45 Debug.Assert(null != source); 46 Debug.Assert(null != translator); 47 Debug.Assert(null != sourceTable); 48 49 SourceInterpreter interpreter = new SourceInterpreter(translator, sourceTable); 50 interpreter.RetrieveResultMarkup(source); 51 52 return new ReadOnlyCollection<IEntityStateEntry>(interpreter.m_stateEntries); 53 } 54 RetrieveResultMarkup(PropagatorResult source)55 private void RetrieveResultMarkup(PropagatorResult source) 56 { 57 Debug.Assert(null != source); 58 59 if (source.Identifier != PropagatorResult.NullIdentifier) 60 { 61 // state entries travel with identifiers. several state entries may be merged 62 // into a single identifier result via joins in the update mapping view 63 do 64 { 65 if (null != source.StateEntry) 66 { 67 m_stateEntries.Add(source.StateEntry); 68 if (source.Identifier != PropagatorResult.NullIdentifier) 69 { 70 // if this is an identifier, it may also be registered with an "owner". 71 // Return the owner as well if the owner is also mapped to this table. 72 PropagatorResult owner; 73 if (m_translator.KeyManager.TryGetIdentifierOwner(source.Identifier, out owner) && 74 null != owner.StateEntry && 75 ExtentInScope(owner.StateEntry.EntitySet)) 76 { 77 m_stateEntries.Add(owner.StateEntry); 78 } 79 80 // Check if are any referential constraints. If so, the entity key 81 // implies that the dependent relationship instance is also being 82 // handled in this result. 83 foreach (IEntityStateEntry stateEntry in m_translator.KeyManager.GetDependentStateEntries(source.Identifier)) 84 { 85 m_stateEntries.Add(stateEntry); 86 } 87 } 88 } 89 source = source.Next; 90 } 91 while (null != source); 92 } 93 else if (!source.IsSimple && !source.IsNull) 94 { 95 // walk children 96 foreach (PropagatorResult child in source.GetMemberValues()) 97 { 98 RetrieveResultMarkup(child); 99 } 100 } 101 } 102 103 // Determines whether the given table is in scope for the current source: if the source 104 // table does not map to the source table for this interpreter, it is not in scope 105 // for exceptions thrown from this table. ExtentInScope(EntitySetBase extent)106 private bool ExtentInScope(EntitySetBase extent) 107 { 108 if (null == extent) 109 { 110 return false; 111 } 112 // determine if the extent is mapped to this table 113 return m_translator.ViewLoader.GetAffectedTables(extent, m_translator.MetadataWorkspace).Contains(m_sourceTable); 114 } 115 } 116 } 117