Code:
/ 4.0 / 4.0 / untmp / DEVDIV_TFS / Dev10 / Releases / RTMRel / ndp / fx / src / DataEntity / System / Data / Map / Update / Internal / ViewLoader.cs / 1305376 / ViewLoader.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.Threading;
namespace System.Data.Mapping.Update.Internal
{
///
/// Retrieves update mapping views and dependency information for update mapping views. Acts as a wrapper around
/// the metadata workspace (and allows direct definition of update mapping views for test purposes).
///
internal class ViewLoader
{
#region Constructors
///
/// Constructor specifying a metadata workspace to use for mapping views.
///
internal ViewLoader(StorageMappingItemCollection mappingCollection)
{
Debug.Assert(null != mappingCollection, "mapping collection required");
m_mappingCollection = mappingCollection;
}
#endregion
#region Fields
private readonly StorageMappingItemCollection m_mappingCollection;
private readonly Dictionary m_associationSetMetadata = new Dictionary();
private readonly Dictionary> m_affectedTables = new Dictionary>();
private readonly Set m_serverGenProperties = new Set();
private readonly Set m_isNullConditionProperties = new Set();
private readonly Dictionary m_functionMappingTranslators = new Dictionary(
EqualityComparer.Default);
private readonly ReaderWriterLockSlim m_readerWriterLock = new ReaderWriterLockSlim();
#endregion
#region Methods
///
/// For a given extent, returns the function mapping translator.
///
/// Association set or entity set for which to retrieve a translator
/// Function translator or null if none exists for this extent
internal FunctionMappingTranslator GetFunctionMappingTranslator(EntitySetBase extent, MetadataWorkspace workspace)
{
return SyncGetValue(extent, workspace, m_functionMappingTranslators, extent);
}
///
/// Returns store tables affected by modifications to a particular C-layer extent. Although this
/// information can be inferred from the update view, we want to avoid compiling or loading
/// views when not required. This information can be directly determined from mapping metadata.
///
/// C-layer extent.
/// Affected store tables.
internal Set GetAffectedTables(EntitySetBase extent, MetadataWorkspace workspace)
{
return SyncGetValue(extent, workspace, m_affectedTables, extent);
}
///
/// Gets information relevant to the processing of an AssociationSet in the update pipeline.
/// Caches information on first retrieval.
///
internal AssociationSetMetadata GetAssociationSetMetadata(AssociationSet associationSet, MetadataWorkspace workspace)
{
return SyncGetValue(associationSet, workspace, m_associationSetMetadata, associationSet);
}
///
/// Determines whether the given member maps to a server-generated column in the store.
/// Requires: InitializeExtentInformation has been called for the extent being persisted.
///
/// Entity set containing member.
/// Member to lookup
/// Whether the member is server generated in some context
internal bool IsServerGen(EntitySetBase entitySetBase, MetadataWorkspace workspace, EdmMember member)
{
return SyncContains(entitySetBase, workspace, m_serverGenProperties, member);
}
///
/// Determines whether the given member maps to a column participating in an isnull
/// condition. Useful to determine if a nullability constraint violation is going to
/// cause roundtripping problems (e.g. if type is based on nullability of a 'non-nullable'
/// property of a derived entity type)
///
internal bool IsNullConditionMember(EntitySetBase entitySetBase, MetadataWorkspace workspace, EdmMember member)
{
return SyncContains(entitySetBase, workspace, m_isNullConditionProperties, member);
}
///
/// Utility method reading value from dictionary within read lock.
///
private T_Value SyncGetValue(EntitySetBase entitySetBase, MetadataWorkspace workspace, Dictionary dictionary, T_Key key)
{
return SyncInitializeEntitySet(entitySetBase, workspace, k => dictionary[k], key);
}
///
/// Utility method checking for membership of element in set within read lock.
///
private bool SyncContains(EntitySetBase entitySetBase, MetadataWorkspace workspace, Set set, T_Element element)
{
return SyncInitializeEntitySet(entitySetBase, workspace, set.Contains, element);
}
///
/// Initializes all information relevant to the entity set.
///
/// Association set or entity set to load.
/// Function to evaluate to produce a result.
private TResult SyncInitializeEntitySet(EntitySetBase entitySetBase, MetadataWorkspace workspace, Func evaluate, TArg arg)
{
m_readerWriterLock.EnterReadLock();
try
{
// check if we've already done the work for this entity set
if (m_affectedTables.ContainsKey(entitySetBase))
{
return evaluate(arg);
}
}
finally
{
m_readerWriterLock.ExitReadLock();
}
// acquire a write lock
m_readerWriterLock.EnterWriteLock();
try
{
// see if we've since done the work for this entity set
if (m_affectedTables.ContainsKey(entitySetBase))
{
return evaluate(arg);
}
InitializeEntitySet(entitySetBase, workspace);
return evaluate(arg);
}
finally
{
m_readerWriterLock.ExitWriteLock();
}
}
private void InitializeEntitySet(EntitySetBase entitySetBase, MetadataWorkspace workspace)
{
// make sure views have been generated for this sub-graph (trigger generation of the sub-graph
// by retrieving a view for one of its components; not actually using the view here)
m_mappingCollection.GetGeneratedView(entitySetBase, workspace);
Set affectedTables = new Set();
StorageEntityContainerMapping mapping = (StorageEntityContainerMapping)m_mappingCollection.GetMap(entitySetBase.EntityContainer);
if (null != mapping)
{
Set isNullConditionColumns = new Set();
// find extent in the container mapping
StorageSetMapping setMapping;
if (entitySetBase.BuiltInTypeKind == BuiltInTypeKind.EntitySet)
{
setMapping = mapping.GetEntitySetMapping(entitySetBase.Name);
// Check for members that have result bindings in a function mapping. If a
// function returns the member values, it indicates they are server-generated
m_serverGenProperties.Unite(GetMembersWithResultBinding((StorageEntitySetMapping)setMapping));
}
else if (entitySetBase.BuiltInTypeKind == BuiltInTypeKind.AssociationSet)
{
setMapping = mapping.GetRelationshipSetMapping(entitySetBase.Name);
}
else
{
Debug.Fail("unexpected extent type " + entitySetBase.BuiltInTypeKind);
throw EntityUtil.NotSupported();
}
// gather interesting tables, columns and properties from mapping fragments
foreach (StorageMappingFragment mappingFragment in GetMappingFragments(setMapping))
{
affectedTables.Add(mappingFragment.TableSet);
// get all property mappings to figure out if anything is server generated
m_serverGenProperties.AddRange(FindServerGenMembers(mappingFragment));
// get all columns participating in is null conditions
isNullConditionColumns.AddRange(FindIsNullConditionColumns(mappingFragment));
}
if (0 < isNullConditionColumns.Count)
{
// gather is null condition properties based on is null condition columns
foreach (StorageMappingFragment mappingFragment in GetMappingFragments(setMapping))
{
m_isNullConditionProperties.AddRange(FindPropertiesMappedToColumns(isNullConditionColumns, mappingFragment));
}
}
}
m_affectedTables.Add(entitySetBase, affectedTables.MakeReadOnly());
InitializeFunctionMappingTranslators(entitySetBase, mapping);
// for association sets, initialize AssociationSetMetadata if no function has claimed ownership
// of the association yet
if (entitySetBase.BuiltInTypeKind == BuiltInTypeKind.AssociationSet)
{
AssociationSet associationSet = (AssociationSet)entitySetBase;
if (!m_associationSetMetadata.ContainsKey(associationSet))
{
m_associationSetMetadata.Add(associationSet, new AssociationSetMetadata(
m_affectedTables[associationSet], associationSet, workspace));
}
}
}
///
/// Yields all members appearing in function mapping result bindings.
///
/// Set mapping to examine
/// All result bindings
private IEnumerable GetMembersWithResultBinding(StorageEntitySetMapping entitySetMapping)
{
foreach (StorageEntityTypeFunctionMapping typeFunctionMapping in entitySetMapping.FunctionMappings)
{
// look at all result bindings for insert and update commands
if (null != typeFunctionMapping.InsertFunctionMapping && null != typeFunctionMapping.InsertFunctionMapping.ResultBindings)
{
foreach (StorageFunctionResultBinding binding in typeFunctionMapping.InsertFunctionMapping.ResultBindings)
{
yield return binding.Property;
}
}
if (null != typeFunctionMapping.UpdateFunctionMapping && null != typeFunctionMapping.UpdateFunctionMapping.ResultBindings)
{
foreach (StorageFunctionResultBinding binding in typeFunctionMapping.UpdateFunctionMapping.ResultBindings)
{
yield return binding.Property;
}
}
}
}
// Loads and registers any function mapping translators for the given extent (and related container)
private void InitializeFunctionMappingTranslators(EntitySetBase entitySetBase, StorageEntityContainerMapping mapping)
{
KeyToListMap requiredEnds = new KeyToListMap(
EqualityComparer.Default);
// see if function mapping metadata needs to be processed
if (!m_functionMappingTranslators.ContainsKey(entitySetBase))
{
// load all function mapping data from the current entity container
foreach (StorageEntitySetMapping entitySetMapping in mapping.EntitySetMaps)
{
if (0 < entitySetMapping.FunctionMappings.Count)
{
// register the function mapping
m_functionMappingTranslators.Add(entitySetMapping.Set, FunctionMappingTranslator.CreateEntitySetFunctionMappingTranslator(entitySetMapping));
// register "null" function translators for all implicitly mapped association sets
foreach (AssociationSetEnd end in entitySetMapping.ImplicitlyMappedAssociationSetEnds)
{
AssociationSet associationSet = end.ParentAssociationSet;
if (!m_functionMappingTranslators.ContainsKey(associationSet))
{
m_functionMappingTranslators.Add(associationSet, FunctionMappingTranslator.CreateAssociationSetFunctionMappingTranslator(null));
}
// Remember that the current entity set is required for all updates to the collocated
// relationship set. This entity set's end is opposite the target end for the mapping.
AssociationSetEnd oppositeEnd = MetadataHelper.GetOppositeEnd(end);
requiredEnds.Add(associationSet, oppositeEnd.CorrespondingAssociationEndMember);
}
}
else
{
// register null translator (so that we never attempt to process this extent again)
m_functionMappingTranslators.Add(entitySetMapping.Set, null);
}
}
foreach (StorageAssociationSetMapping associationSetMapping in mapping.RelationshipSetMaps)
{
if (null != associationSetMapping.FunctionMapping)
{
AssociationSet set = (AssociationSet)associationSetMapping.Set;
// use indexer rather than Add since the association set may already have an implicit function
// mapping -- this explicit function mapping takes precedence in such cases
m_functionMappingTranslators.Add(set,
FunctionMappingTranslator.CreateAssociationSetFunctionMappingTranslator(associationSetMapping));
// remember that we've seen a function mapping for this association set, which overrides
// any other behaviors for determining required/optional ends
requiredEnds.AddRange(set, Enumerable.Empty());
}
else
{
if (!m_functionMappingTranslators.ContainsKey(associationSetMapping.Set))
{
// register null translator (so that we never attempt to process this extent again)
m_functionMappingTranslators.Add(associationSetMapping.Set, null);
}
}
}
}
// register association metadata for all association sets encountered
foreach (AssociationSet associationSet in requiredEnds.Keys)
{
m_associationSetMetadata.Add(associationSet, new AssociationSetMetadata(
requiredEnds.EnumerateValues(associationSet)));
}
}
///
/// Gets all model properties mapped to server generated columns.
///
private static IEnumerable FindServerGenMembers(StorageMappingFragment mappingFragment)
{
foreach (var scalarPropertyMapping in FlattenPropertyMappings(mappingFragment.AllProperties)
.OfType())
{
if (StoreGeneratedPattern.None != MetadataHelper.GetStoreGeneratedPattern(scalarPropertyMapping.ColumnProperty))
{
yield return scalarPropertyMapping.EdmProperty;
}
}
}
///
/// Gets all store columns participating in is null conditions.
///
private static IEnumerable FindIsNullConditionColumns(StorageMappingFragment mappingFragment)
{
foreach (var conditionPropertyMapping in FlattenPropertyMappings(mappingFragment.AllProperties)
.OfType())
{
if (conditionPropertyMapping.ColumnProperty != null &&
conditionPropertyMapping.IsNull.HasValue)
{
yield return conditionPropertyMapping.ColumnProperty;
}
}
}
///
/// Gets all model properties mapped to given columns.
///
private static IEnumerable FindPropertiesMappedToColumns(Set columns, StorageMappingFragment mappingFragment)
{
foreach (var scalarPropertyMapping in FlattenPropertyMappings(mappingFragment.AllProperties)
.OfType())
{
if (columns.Contains(scalarPropertyMapping.ColumnProperty))
{
yield return scalarPropertyMapping.EdmProperty;
}
}
}
///
/// Enumerates all mapping fragments in given set mapping.
///
private static IEnumerable GetMappingFragments(StorageSetMapping setMapping)
{
// get all type mappings for the extent
foreach (StorageTypeMapping typeMapping in setMapping.TypeMappings)
{
// get all table mapping fragments for the type
foreach (StorageMappingFragment mappingFragment in typeMapping.MappingFragments)
{
yield return mappingFragment;
}
}
}
///
/// Returns all bottom-level mappings (e.g. conditions and scalar property mappings but not complex property mappings
/// whose components are returned)
///
private static IEnumerable FlattenPropertyMappings(System.Collections.ObjectModel.ReadOnlyCollection propertyMappings)
{
foreach (StoragePropertyMapping propertyMapping in propertyMappings)
{
StorageComplexPropertyMapping complexPropertyMapping = propertyMapping as StorageComplexPropertyMapping;
if (null != complexPropertyMapping)
{
foreach (StorageComplexTypeMapping complexTypeMapping in complexPropertyMapping.TypeMappings)
{
// recursively call self with nested type
foreach (StoragePropertyMapping nestedPropertyMapping in FlattenPropertyMappings(complexTypeMapping.AllProperties))
{
yield return nestedPropertyMapping;
}
}
}
else
{
yield return propertyMapping;
}
}
}
#endregion
}
}
// File provided for Reference Use Only by Microsoft Corporation (c) 2007.
Link Menu

This book is available now!
Buy at Amazon US or
Buy at Amazon UK
- CmsInterop.cs
- HtmlInputImage.cs
- BufferCache.cs
- ConsoleEntryPoint.cs
- Point3DCollectionConverter.cs
- FixedPageAutomationPeer.cs
- OdbcCommand.cs
- ClientRuntimeConfig.cs
- COM2ExtendedBrowsingHandler.cs
- ValidationEventArgs.cs
- DataRowCollection.cs
- EnumerableValidator.cs
- PropertyTabChangedEvent.cs
- SessionPageStatePersister.cs
- StringExpressionSet.cs
- SiteOfOriginContainer.cs
- ProcessHost.cs
- Registration.cs
- EditCommandColumn.cs
- AspNetCompatibilityRequirementsMode.cs
- TraceLog.cs
- MenuAutomationPeer.cs
- ReadWriteObjectLock.cs
- DataGridViewRowCancelEventArgs.cs
- DayRenderEvent.cs
- WebScriptClientGenerator.cs
- XmlSequenceWriter.cs
- OpenFileDialog.cs
- ReferenceEqualityComparer.cs
- EncryptedPackage.cs
- ButtonRenderer.cs
- HttpResponseInternalBase.cs
- TrackBarRenderer.cs
- FastPropertyAccessor.cs
- FrugalMap.cs
- NamespaceCollection.cs
- X509UI.cs
- DashStyles.cs
- ScrollBarAutomationPeer.cs
- User.cs
- TextBox.cs
- BaseTransportHeaders.cs
- SynchronizedRandom.cs
- ColorTranslator.cs
- KeysConverter.cs
- TaskFormBase.cs
- QilNode.cs
- XamlSerializationHelper.cs
- XmlWriter.cs
- PlatformCulture.cs
- RotateTransform.cs
- UdpDiscoveryMessageFilter.cs
- XamlDesignerSerializationManager.cs
- httpstaticobjectscollection.cs
- EmptyQuery.cs
- Token.cs
- ObjectConverter.cs
- Baml2006ReaderFrame.cs
- FromReply.cs
- DataColumnPropertyDescriptor.cs
- TypeUsageBuilder.cs
- WebConfigurationHostFileChange.cs
- TextEditorTyping.cs
- ELinqQueryState.cs
- CheckBoxField.cs
- EntityType.cs
- StateItem.cs
- TextTreeTextElementNode.cs
- DataGridViewTextBoxColumn.cs
- MultiBindingExpression.cs
- SafeNativeMethodsCLR.cs
- OleDbCommand.cs
- RotateTransform3D.cs
- SelectionItemProviderWrapper.cs
- ContentPlaceHolder.cs
- AsyncStreamReader.cs
- ToolStripArrowRenderEventArgs.cs
- SettingsProperty.cs
- InvalidOperationException.cs
- EqualityComparer.cs
- SchemaTypeEmitter.cs
- XsltArgumentList.cs
- EntityKeyElement.cs
- WebPartMovingEventArgs.cs
- ToolBar.cs
- OdbcStatementHandle.cs
- ScriptingProfileServiceSection.cs
- GridViewSortEventArgs.cs
- ToolStripItemCollection.cs
- UnmanagedHandle.cs
- XmlElement.cs
- MetaChildrenColumn.cs
- NullableDecimalMinMaxAggregationOperator.cs
- SmtpFailedRecipientsException.cs
- ShaperBuffers.cs
- Matrix3DConverter.cs
- ContextDataSource.cs
- NestedContainer.cs
- CharUnicodeInfo.cs
- TextRangeEditLists.cs