FunctionMappingTranslator.cs source code in C# .NET

Source code for the .NET framework in C#

                        

Code:

/ 4.0 / 4.0 / untmp / DEVDIV_TFS / Dev10 / Releases / RTMRel / ndp / fx / src / DataEntity / System / Data / Map / Update / Internal / FunctionMappingTranslator.cs / 1305376 / FunctionMappingTranslator.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.Linq; 
using System.Data.Entity;
namespace System.Data.Mapping.Update.Internal
{
    ///  
    /// Function mapping translators are defined per extent (entity set
    /// or association set) and manage the creation of function commands. 
    ///  
    internal abstract class FunctionMappingTranslator
    { 
        /// 
        /// Requires: this translator must be registered to handle the entity set
        /// for the given state entry.
        /// 
        /// Translates the given state entry to a command.
        ///  
        /// Parent update translator (global state for the workload) 
        /// State entry to translate. Must belong to the
        /// entity/association set handled by this translator 
        /// Command corresponding to the given state entry
        internal abstract FunctionUpdateCommand Translate(
            UpdateTranslator translator,
            ExtractedStateEntry stateEntry); 

        ///  
        /// Initialize a translator for the given entity set mapping. 
        /// 
        /// Entity set mapping. 
        /// Translator.
        internal static FunctionMappingTranslator CreateEntitySetFunctionMappingTranslator(
            StorageEntitySetMapping setMapping)
        { 
            return new EntitySetFunctionMappingTranslator(setMapping);
        } 
 
        /// 
        /// Initialize a translator for the given association set mapping. 
        /// 
        /// Association set mapping.
        /// Translator.
        internal static FunctionMappingTranslator CreateAssociationSetFunctionMappingTranslator( 
            StorageAssociationSetMapping setMapping)
        { 
            return new AssociationSetFunctionMappingTranslator(setMapping); 
        }
 
        private sealed class EntitySetFunctionMappingTranslator : FunctionMappingTranslator
        {
            private readonly Dictionary m_typeMappings;
 
            internal EntitySetFunctionMappingTranslator(StorageEntitySetMapping setMapping)
            { 
                Debug.Assert(null != setMapping && null != setMapping.FunctionMappings && 
                    0 < setMapping.FunctionMappings.Count, "set mapping must exist and must specify function mappings");
                m_typeMappings = new Dictionary(); 
                foreach (StorageEntityTypeFunctionMapping typeMapping in setMapping.FunctionMappings)
                {
                    m_typeMappings.Add(typeMapping.EntityType, typeMapping);
                } 
            }
 
            internal override FunctionUpdateCommand Translate( 
                UpdateTranslator translator,
                ExtractedStateEntry stateEntry) 
            {
                var mapping = GetFunctionMapping(stateEntry);
                StorageEntityTypeFunctionMapping typeMapping = mapping.Item1;
                StorageFunctionMapping functionMapping = mapping.Item2; 
                EntityKey entityKey = stateEntry.Source.EntityKey;
 
                var stateEntries = new HashSet { stateEntry.Source }; 

                // gather all referenced association ends 
                var collocatedEntries =
                    // find all related entries corresponding to collocated association types
                    from end in functionMapping.CollocatedAssociationSetEnds
                    join candidateEntry in translator.GetRelationships(entityKey) 
                    on end.CorrespondingAssociationEndMember.DeclaringType equals candidateEntry.EntitySet.ElementType
                    select Tuple.Create(end.CorrespondingAssociationEndMember, candidateEntry); 
 
                var currentReferenceEnds = new Dictionary();
                var originalReferenceEnds = new Dictionary(); 

                foreach (var candidate in collocatedEntries)
                {
                    ProcessReferenceCandidate(entityKey, stateEntries, currentReferenceEnds, originalReferenceEnds, candidate.Item1, candidate.Item2); 
                }
 
                // create function object 
                FunctionUpdateCommand command = new FunctionUpdateCommand(functionMapping, translator, stateEntries.ToList().AsReadOnly(), stateEntry);
 
                // bind all function parameters
                BindFunctionParameters(translator, stateEntry, functionMapping, command, currentReferenceEnds, originalReferenceEnds);

                // interpret all result bindings 
                if (null != functionMapping.ResultBindings)
                { 
                    foreach (StorageFunctionResultBinding resultBinding in functionMapping.ResultBindings) 
                    {
                        PropagatorResult result = stateEntry.Current.GetMemberValue(resultBinding.Property); 
                        command.AddResultColumn(translator, resultBinding.ColumnName, result);
                    }
                }
 
                return command;
            } 
 
            private static void ProcessReferenceCandidate(
                EntityKey source, 
                HashSet stateEntries,
                Dictionary currentReferenceEnd,
                Dictionary originalReferenceEnd,
                AssociationEndMember endMember, 
                IEntityStateEntry candidateEntry)
            { 
                Func getEntityKey = (record, ordinal) => (EntityKey)record[ordinal]; 
                Action> findMatch = (record, registerTarget) =>
                { 
                    // find the end corresponding to the 'to' end
                    int toOrdinal = record.GetOrdinal(endMember.Name);
                    Debug.Assert(-1 != toOrdinal, "to end of relationship doesn't exist in record");
 
                    // the 'from' end must be the other end
                    int fromOrdinal = 0 == toOrdinal ? 1 : 0; 
 
                    if (getEntityKey(record, fromOrdinal) == source)
                    { 
                        stateEntries.Add(candidateEntry);
                        registerTarget(candidateEntry);
                    }
                }; 

                switch (candidateEntry.State) 
                { 
                    case EntityState.Unchanged:
                        findMatch( 
                            candidateEntry.CurrentValues,
                            (target) =>
                            {
                                currentReferenceEnd.Add(endMember, target); 
                                originalReferenceEnd.Add(endMember, target);
                            }); 
                        break; 
                    case EntityState.Added:
                        findMatch( 
                            candidateEntry.CurrentValues,
                            (target) => currentReferenceEnd.Add(endMember, target));
                        break;
                    case EntityState.Deleted: 
                        findMatch(
                            candidateEntry.OriginalValues, 
                            (target) => originalReferenceEnd.Add(endMember, target)); 
                        break;
                    default: 
                        break;
                }
            }
 
            private Tuple GetFunctionMapping(ExtractedStateEntry stateEntry)
            { 
                // choose mapping based on type and operation 
                StorageFunctionMapping functionMapping;
                EntityType entityType; 
                if (null != stateEntry.Current)
                {
                    entityType = (EntityType)stateEntry.Current.StructuralType;
                } 
                else
                { 
                    entityType = (EntityType)stateEntry.Original.StructuralType; 
                }
                StorageEntityTypeFunctionMapping typeMapping = m_typeMappings[entityType]; 
                switch (stateEntry.State)
                {
                    case EntityState.Added:
                        functionMapping = typeMapping.InsertFunctionMapping; 
                        EntityUtil.ValidateNecessaryFunctionMapping(functionMapping, "Insert", stateEntry.Source, "EntityType", entityType.Name);
                        break; 
                    case EntityState.Deleted: 
                        functionMapping = typeMapping.DeleteFunctionMapping;
                        EntityUtil.ValidateNecessaryFunctionMapping(functionMapping, "Delete", stateEntry.Source, "EntityType", entityType.Name); 
                        break;
                    case EntityState.Unchanged:
                    case EntityState.Modified:
                        functionMapping = typeMapping.UpdateFunctionMapping; 
                        EntityUtil.ValidateNecessaryFunctionMapping(functionMapping, "Update", stateEntry.Source, "EntityType", entityType.Name);
                        break; 
                    default: 
                        functionMapping = null;
                        Debug.Fail("unexpected state"); 
                        break;
                }
                return Tuple.Create(typeMapping, functionMapping);
            } 

            // Walks through all parameter bindings in the function mapping and binds the parameters to the 
            // requested properties of the given state entry. 
            private void BindFunctionParameters(UpdateTranslator translator, ExtractedStateEntry stateEntry, StorageFunctionMapping functionMapping, FunctionUpdateCommand command, Dictionary currentReferenceEnds, Dictionary originalReferenceEnds)
            { 
                // bind all parameters
                foreach (StorageFunctionParameterBinding parameterBinding in functionMapping.ParameterBindings)
                {
                    PropagatorResult result; 

                    // extract value 
                    if (null != parameterBinding.MemberPath.AssociationSetEnd) 
                    {
                        // find the relationship entry corresponding to the navigation 
                        AssociationEndMember endMember = parameterBinding.MemberPath.AssociationSetEnd.CorrespondingAssociationEndMember;
                        IEntityStateEntry relationshipEntry;
                        bool hasTarget = parameterBinding.IsCurrent
                            ? currentReferenceEnds.TryGetValue(endMember, out relationshipEntry) 
                            : originalReferenceEnds.TryGetValue(endMember, out relationshipEntry);
                        if (!hasTarget) 
                        { 
                            if (endMember.RelationshipMultiplicity == RelationshipMultiplicity.One)
                            { 
                                string entitySetName = stateEntry.Source.EntitySet.Name;
                                string associationSetName = parameterBinding.MemberPath.AssociationSetEnd.ParentAssociationSet.Name;
                                throw EntityUtil.Update(Strings.Update_MissingRequiredRelationshipValue(entitySetName, associationSetName),
                                    null, 
                                    command.GetStateEntries(translator));
                            } 
                            else 
                            {
                                result = PropagatorResult.CreateSimpleValue(PropagatorFlags.NoFlags, null); 
                            }
                        }
                        else
                        { 
                            // get the actual value
                            PropagatorResult relationshipResult = parameterBinding.IsCurrent ? 
                                translator.RecordConverter.ConvertCurrentValuesToPropagatorResult(relationshipEntry, ModifiedPropertiesBehavior.AllModified) : 
                                translator.RecordConverter.ConvertOriginalValuesToPropagatorResult(relationshipEntry, ModifiedPropertiesBehavior.AllModified);
                            PropagatorResult endResult = relationshipResult.GetMemberValue(endMember); 
                            EdmProperty keyProperty = (EdmProperty)parameterBinding.MemberPath.Members[0];
                            result = endResult.GetMemberValue(keyProperty);
                        }
                    } 
                    else
                    { 
                        // walk through the member path to find the appropriate propagator results 
                        result = parameterBinding.IsCurrent ? stateEntry.Current : stateEntry.Original;
                        for (int i = parameterBinding.MemberPath.Members.Count; i > 0;) 
                        {
                            --i;
                            EdmMember member = parameterBinding.MemberPath.Members[i];
                            result = result.GetMemberValue(member); 
                        }
                    } 
 
                    // create DbParameter
                    command.SetParameterValue(result, parameterBinding, translator); 
                }
                // Add rows affected parameter
                command.RegisterRowsAffectedParameter(functionMapping.RowsAffectedParameter);
            } 
        }
 
        private sealed class AssociationSetFunctionMappingTranslator : FunctionMappingTranslator 
        {
            // If this value is null, it indicates that the association set is 
            // only implicitly mapped as part of an entity set
            private readonly StorageAssociationSetFunctionMapping m_mapping;

            internal AssociationSetFunctionMappingTranslator(StorageAssociationSetMapping setMapping) 
            {
                if (null != setMapping) 
                { 
                    m_mapping = setMapping.FunctionMapping;
                } 
            }

            internal override FunctionUpdateCommand Translate(
                UpdateTranslator translator, 
                ExtractedStateEntry stateEntry)
            { 
                if (null == m_mapping) { return null; } 

                bool isInsert = EntityState.Added == stateEntry.State; 

                EntityUtil.ValidateNecessaryFunctionMapping(
                    isInsert ? m_mapping.InsertFunctionMapping : m_mapping.DeleteFunctionMapping,
                    isInsert ? "Insert" : "Delete", 
                    stateEntry.Source, "AssociationSet", m_mapping.AssociationSet.Name);
 
                // initialize a new command 
                StorageFunctionMapping functionMapping = isInsert ? m_mapping.InsertFunctionMapping : m_mapping.DeleteFunctionMapping;
                FunctionUpdateCommand command = new FunctionUpdateCommand(functionMapping, translator, new [] { stateEntry.Source }.ToList().AsReadOnly(), stateEntry); 

                // extract the relationship values from the state entry
                PropagatorResult recordResult;
                if (isInsert) 
                {
                    recordResult = stateEntry.Current; 
                } 
                else
                { 
                    recordResult = stateEntry.Original;
                }

                // bind parameters 
                foreach (StorageFunctionParameterBinding parameterBinding in functionMapping.ParameterBindings)
                { 
                    // extract the relationship information 
                    Debug.Assert(2 == parameterBinding.MemberPath.Members.Count, "relationship parameter binding member " +
                        "path should include the relationship end and key property only"); 

                    EdmProperty keyProperty = (EdmProperty)parameterBinding.MemberPath.Members[0];
                    AssociationEndMember endMember = (AssociationEndMember)parameterBinding.MemberPath.Members[1];
 
                    // get the end member
                    PropagatorResult endResult = recordResult.GetMemberValue(endMember); 
                    PropagatorResult keyResult = endResult.GetMemberValue(keyProperty); 

                    command.SetParameterValue(keyResult, parameterBinding, translator); 
                }
                // add rows affected output parameter
                command.RegisterRowsAffectedParameter(functionMapping.RowsAffectedParameter);
 
                return command;
            } 
        } 
    }
} 

// File provided for Reference Use Only by Microsoft Corporation (c) 2007.


                        

Link Menu

Network programming in C#, Network Programming in VB.NET, Network Programming in .NET
This book is available now!
Buy at Amazon US or
Buy at Amazon UK