536cd135cc
Former-commit-id: 5624ac747d633e885131e8349322922b6a59baaa
836 lines
27 KiB
C#
836 lines
27 KiB
C#
//---------------------------------------------------------------------
|
|
// <copyright file="MetadataMappingHasherVisitor.cs" company="Microsoft">
|
|
// Copyright (c) Microsoft Corporation. All rights reserved.
|
|
// </copyright>
|
|
|
|
// @owner Microsoft
|
|
// @backupOwner Microsoft
|
|
//---------------------------------------------------------------------
|
|
|
|
using System;
|
|
using System.Collections.Generic;
|
|
using System.Linq;
|
|
using System.Text;
|
|
using System.Data.Metadata.Edm;
|
|
using System.Data.Common;
|
|
using System.Data.Common.Utils;
|
|
using System.Data.Mapping;
|
|
using System.Diagnostics;
|
|
using System.Globalization;
|
|
|
|
|
|
namespace System.Data.Mapping
|
|
{
|
|
internal partial class MetadataMappingHasherVisitor : BaseMetadataMappingVisitor
|
|
{
|
|
private CompressingHashBuilder m_hashSourceBuilder;
|
|
private Dictionary<Object, int> m_itemsAlreadySeen = new Dictionary<Object, int>();
|
|
private int m_instanceNumber = 0;
|
|
private EdmItemCollection m_EdmItemCollection;
|
|
private double m_EdmVersion;
|
|
private double m_MappingVersion;
|
|
|
|
private MetadataMappingHasherVisitor(double mappingVersion)
|
|
{
|
|
m_MappingVersion = mappingVersion;
|
|
this.m_hashSourceBuilder = new CompressingHashBuilder(MetadataHelper.CreateMetadataHashAlgorithm(m_MappingVersion));
|
|
}
|
|
|
|
#region visitor method
|
|
protected override void Visit(StorageEntityContainerMapping storageEntityContainerMapping)
|
|
{
|
|
Debug.Assert(storageEntityContainerMapping != null, "storageEntityContainerMapping cannot be null!");
|
|
|
|
// at the entry point of visitor, we setup the versions
|
|
Debug.Assert(m_MappingVersion == storageEntityContainerMapping.StorageMappingItemCollection.MappingVersion, "the original version and the mapping collection version are not the same");
|
|
this.m_MappingVersion = storageEntityContainerMapping.StorageMappingItemCollection.MappingVersion;
|
|
this.m_EdmVersion = storageEntityContainerMapping.StorageMappingItemCollection.EdmItemCollection.EdmVersion;
|
|
|
|
this.m_EdmItemCollection = storageEntityContainerMapping.StorageMappingItemCollection.EdmItemCollection;
|
|
|
|
int index;
|
|
if (!this.AddObjectToSeenListAndHashBuilder(storageEntityContainerMapping, out index))
|
|
{
|
|
// if this has been add to the seen list, then just
|
|
return;
|
|
}
|
|
if (this.m_itemsAlreadySeen.Count > 1)
|
|
{
|
|
|
|
// this means user try another visit over SECM, this is allowed but all the previous visit all lost due to clean
|
|
// user can visit different SECM objects by using the same visitor to load the SECM object
|
|
this.Clean();
|
|
Visit(storageEntityContainerMapping);
|
|
return;
|
|
}
|
|
|
|
this.AddObjectStartDumpToHashBuilder(storageEntityContainerMapping, index);
|
|
|
|
#region Inner data visit
|
|
|
|
this.AddObjectContentToHashBuilder(storageEntityContainerMapping.Identity);
|
|
|
|
this.AddV2ObjectContentToHashBuilder(storageEntityContainerMapping.GenerateUpdateViews, this.m_MappingVersion);
|
|
|
|
base.Visit(storageEntityContainerMapping);
|
|
|
|
#endregion
|
|
|
|
this.AddObjectEndDumpToHashBuilder();
|
|
}
|
|
|
|
protected override void Visit(EntityContainer entityContainer)
|
|
{
|
|
int index;
|
|
if (!this.AddObjectToSeenListAndHashBuilder(entityContainer, out index))
|
|
{
|
|
return;
|
|
}
|
|
|
|
this.AddObjectStartDumpToHashBuilder(entityContainer, index);
|
|
|
|
#region Inner data visit
|
|
|
|
this.AddObjectContentToHashBuilder(entityContainer.Identity);
|
|
// Name is covered by Identity
|
|
|
|
base.Visit(entityContainer);
|
|
|
|
#endregion
|
|
|
|
this.AddObjectEndDumpToHashBuilder();
|
|
}
|
|
|
|
protected override void Visit(StorageSetMapping storageSetMapping)
|
|
{
|
|
int index;
|
|
if (!this.AddObjectToSeenListAndHashBuilder(storageSetMapping, out index))
|
|
{
|
|
return;
|
|
}
|
|
|
|
this.AddObjectStartDumpToHashBuilder(storageSetMapping, index);
|
|
|
|
#region Inner data visit
|
|
base.Visit(storageSetMapping);
|
|
#endregion
|
|
|
|
this.AddObjectEndDumpToHashBuilder();
|
|
}
|
|
|
|
protected override void Visit(StorageTypeMapping storageTypeMapping)
|
|
{
|
|
int index;
|
|
if (!this.AddObjectToSeenListAndHashBuilder(storageTypeMapping, out index))
|
|
{
|
|
return;
|
|
}
|
|
|
|
this.AddObjectStartDumpToHashBuilder(storageTypeMapping, index);
|
|
|
|
#region Inner data visit
|
|
|
|
base.Visit(storageTypeMapping);
|
|
|
|
#endregion
|
|
|
|
this.AddObjectEndDumpToHashBuilder();
|
|
}
|
|
|
|
protected override void Visit(StorageMappingFragment storageMappingFragment)
|
|
{
|
|
int index;
|
|
if (!this.AddObjectToSeenListAndHashBuilder(storageMappingFragment, out index))
|
|
{
|
|
return;
|
|
}
|
|
|
|
this.AddObjectStartDumpToHashBuilder(storageMappingFragment, index);
|
|
|
|
#region Inner data visit
|
|
|
|
this.AddV2ObjectContentToHashBuilder(storageMappingFragment.IsSQueryDistinct, this.m_MappingVersion);
|
|
|
|
base.Visit(storageMappingFragment);
|
|
|
|
#endregion
|
|
|
|
this.AddObjectEndDumpToHashBuilder();
|
|
}
|
|
|
|
protected override void Visit(StoragePropertyMapping storagePropertyMapping)
|
|
{
|
|
base.Visit(storagePropertyMapping);
|
|
}
|
|
|
|
protected override void Visit(StorageComplexPropertyMapping storageComplexPropertyMapping)
|
|
{
|
|
int index;
|
|
if (!this.AddObjectToSeenListAndHashBuilder(storageComplexPropertyMapping, out index))
|
|
{
|
|
return;
|
|
}
|
|
|
|
this.AddObjectStartDumpToHashBuilder(storageComplexPropertyMapping, index);
|
|
|
|
#region Inner data visit
|
|
|
|
base.Visit(storageComplexPropertyMapping);
|
|
|
|
#endregion
|
|
|
|
this.AddObjectEndDumpToHashBuilder();
|
|
}
|
|
protected override void Visit(StorageComplexTypeMapping storageComplexTypeMapping)
|
|
{
|
|
int index;
|
|
if (!this.AddObjectToSeenListAndHashBuilder(storageComplexTypeMapping, out index))
|
|
{
|
|
return;
|
|
}
|
|
|
|
this.AddObjectStartDumpToHashBuilder(storageComplexTypeMapping, index);
|
|
|
|
#region Inner data visit
|
|
|
|
base.Visit(storageComplexTypeMapping);
|
|
|
|
#endregion
|
|
|
|
this.AddObjectEndDumpToHashBuilder();
|
|
}
|
|
|
|
protected override void Visit(StorageConditionPropertyMapping storageConditionPropertyMapping)
|
|
{
|
|
int index;
|
|
if (!this.AddObjectToSeenListAndHashBuilder(storageConditionPropertyMapping, out index))
|
|
{
|
|
return;
|
|
}
|
|
|
|
this.AddObjectStartDumpToHashBuilder(storageConditionPropertyMapping, index);
|
|
|
|
#region Inner data visit
|
|
this.AddObjectContentToHashBuilder(storageConditionPropertyMapping.IsNull);
|
|
this.AddObjectContentToHashBuilder(storageConditionPropertyMapping.Value);
|
|
|
|
base.Visit(storageConditionPropertyMapping);
|
|
|
|
#endregion
|
|
|
|
this.AddObjectEndDumpToHashBuilder();
|
|
}
|
|
|
|
protected override void Visit(StorageScalarPropertyMapping storageScalarPropertyMapping)
|
|
{
|
|
int index;
|
|
if (!this.AddObjectToSeenListAndHashBuilder(storageScalarPropertyMapping, out index))
|
|
{
|
|
return;
|
|
}
|
|
|
|
this.AddObjectStartDumpToHashBuilder(storageScalarPropertyMapping, index);
|
|
|
|
#region Inner data visit
|
|
|
|
base.Visit(storageScalarPropertyMapping);
|
|
|
|
#endregion
|
|
|
|
this.AddObjectEndDumpToHashBuilder();
|
|
}
|
|
|
|
protected override void Visit(EntitySetBase entitySetBase)
|
|
{
|
|
base.Visit(entitySetBase);
|
|
}
|
|
|
|
protected override void Visit(EntitySet entitySet)
|
|
{
|
|
int index;
|
|
if (!this.AddObjectToSeenListAndHashBuilder(entitySet, out index))
|
|
{
|
|
return;
|
|
}
|
|
#region Inner data visit
|
|
|
|
this.AddObjectStartDumpToHashBuilder(entitySet, index);
|
|
this.AddObjectContentToHashBuilder(entitySet.Name);
|
|
this.AddObjectContentToHashBuilder(entitySet.Schema);
|
|
this.AddObjectContentToHashBuilder(entitySet.Table);
|
|
|
|
base.Visit(entitySet);
|
|
|
|
foreach (var entityType in MetadataHelper.GetTypeAndSubtypesOf(entitySet.ElementType, this.m_EdmItemCollection, false).Where(type => type != entitySet.ElementType))
|
|
{
|
|
this.Visit(entityType);
|
|
}
|
|
|
|
#endregion
|
|
|
|
this.AddObjectEndDumpToHashBuilder();
|
|
}
|
|
|
|
protected override void Visit(AssociationSet associationSet)
|
|
{
|
|
int index;
|
|
if (!this.AddObjectToSeenListAndHashBuilder(associationSet, out index))
|
|
{
|
|
return;
|
|
}
|
|
|
|
this.AddObjectStartDumpToHashBuilder(associationSet, index);
|
|
|
|
#region Inner data visit
|
|
this.AddObjectContentToHashBuilder(associationSet.CachedProviderSql);
|
|
// Name is coverd by Identity
|
|
this.AddObjectContentToHashBuilder(associationSet.Identity);
|
|
this.AddObjectContentToHashBuilder(associationSet.Schema);
|
|
this.AddObjectContentToHashBuilder(associationSet.Table);
|
|
|
|
base.Visit(associationSet);
|
|
|
|
#endregion
|
|
|
|
this.AddObjectEndDumpToHashBuilder();
|
|
}
|
|
|
|
protected override void Visit(EntityType entityType)
|
|
{
|
|
int index;
|
|
if (!this.AddObjectToSeenListAndHashBuilder(entityType, out index))
|
|
{
|
|
return;
|
|
}
|
|
|
|
this.AddObjectStartDumpToHashBuilder(entityType, index);
|
|
|
|
#region Inner data visit
|
|
this.AddObjectContentToHashBuilder(entityType.Abstract);
|
|
this.AddObjectContentToHashBuilder(entityType.Identity);
|
|
// FullName, Namespace and Name are all covered by Identity
|
|
|
|
base.Visit(entityType);
|
|
|
|
#endregion
|
|
|
|
this.AddObjectEndDumpToHashBuilder();
|
|
}
|
|
|
|
protected override void Visit(AssociationSetEnd associationSetEnd)
|
|
{
|
|
int index;
|
|
if (!this.AddObjectToSeenListAndHashBuilder(associationSetEnd, out index))
|
|
{
|
|
return;
|
|
}
|
|
|
|
this.AddObjectStartDumpToHashBuilder(associationSetEnd, index);
|
|
|
|
#region Inner data visit
|
|
this.AddObjectContentToHashBuilder(associationSetEnd.Identity);
|
|
// Name is covered by Identity
|
|
|
|
base.Visit(associationSetEnd);
|
|
|
|
#endregion
|
|
|
|
this.AddObjectEndDumpToHashBuilder();
|
|
}
|
|
|
|
protected override void Visit(AssociationType associationType)
|
|
{
|
|
int index;
|
|
if (!this.AddObjectToSeenListAndHashBuilder(associationType, out index))
|
|
{
|
|
return;
|
|
}
|
|
|
|
this.AddObjectStartDumpToHashBuilder(associationType, index);
|
|
|
|
#region Inner data visit
|
|
this.AddObjectContentToHashBuilder(associationType.Abstract);
|
|
this.AddObjectContentToHashBuilder(associationType.Identity);
|
|
// FullName, Namespace, and Name are all covered by Identity
|
|
|
|
base.Visit(associationType);
|
|
|
|
#endregion
|
|
|
|
this.AddObjectEndDumpToHashBuilder();
|
|
}
|
|
|
|
protected override void Visit(EdmProperty edmProperty)
|
|
{
|
|
int index;
|
|
if (!this.AddObjectToSeenListAndHashBuilder(edmProperty, out index))
|
|
{
|
|
return;
|
|
}
|
|
|
|
this.AddObjectStartDumpToHashBuilder(edmProperty, index);
|
|
|
|
#region Inner data visit
|
|
// since the delaring type is fixed and referenced to the upper type,
|
|
// there is no need to hash this
|
|
//this.AddObjectContentToHashBuilder(edmProperty.DeclaringType);
|
|
this.AddObjectContentToHashBuilder(edmProperty.DefaultValue);
|
|
this.AddObjectContentToHashBuilder(edmProperty.Identity);
|
|
// Name is covered by Identity
|
|
this.AddObjectContentToHashBuilder(edmProperty.IsStoreGeneratedComputed);
|
|
this.AddObjectContentToHashBuilder(edmProperty.IsStoreGeneratedIdentity);
|
|
this.AddObjectContentToHashBuilder(edmProperty.Nullable);
|
|
|
|
base.Visit(edmProperty);
|
|
|
|
#endregion
|
|
|
|
this.AddObjectEndDumpToHashBuilder();
|
|
}
|
|
|
|
protected override void Visit(NavigationProperty navigationProperty)
|
|
{
|
|
// navigation properties are not considered in view generation
|
|
return;
|
|
}
|
|
|
|
protected override void Visit(EdmMember edmMember)
|
|
{
|
|
int index;
|
|
if (!this.AddObjectToSeenListAndHashBuilder(edmMember, out index))
|
|
{
|
|
return;
|
|
}
|
|
|
|
this.AddObjectStartDumpToHashBuilder(edmMember, index);
|
|
|
|
#region Inner data visit
|
|
this.AddObjectContentToHashBuilder(edmMember.Identity);
|
|
// Name is covered by Identity
|
|
this.AddObjectContentToHashBuilder(edmMember.IsStoreGeneratedComputed);
|
|
this.AddObjectContentToHashBuilder(edmMember.IsStoreGeneratedIdentity);
|
|
|
|
base.Visit(edmMember);
|
|
|
|
#endregion
|
|
|
|
this.AddObjectEndDumpToHashBuilder();
|
|
}
|
|
|
|
protected override void Visit(AssociationEndMember associationEndMember)
|
|
{
|
|
int index;
|
|
if (!this.AddObjectToSeenListAndHashBuilder(associationEndMember, out index))
|
|
{
|
|
return;
|
|
}
|
|
|
|
this.AddObjectStartDumpToHashBuilder(associationEndMember, index);
|
|
|
|
#region Inner data visit
|
|
this.AddObjectContentToHashBuilder(associationEndMember.DeleteBehavior);
|
|
this.AddObjectContentToHashBuilder(associationEndMember.Identity);
|
|
// Name is covered by Identity
|
|
this.AddObjectContentToHashBuilder(associationEndMember.IsStoreGeneratedComputed);
|
|
this.AddObjectContentToHashBuilder(associationEndMember.IsStoreGeneratedIdentity);
|
|
this.AddObjectContentToHashBuilder(associationEndMember.RelationshipMultiplicity);
|
|
|
|
base.Visit(associationEndMember);
|
|
|
|
#endregion
|
|
|
|
this.AddObjectEndDumpToHashBuilder();
|
|
}
|
|
|
|
protected override void Visit(ReferentialConstraint referentialConstraint)
|
|
{
|
|
int index;
|
|
if (!this.AddObjectToSeenListAndHashBuilder(referentialConstraint, out index))
|
|
{
|
|
return;
|
|
}
|
|
|
|
this.AddObjectStartDumpToHashBuilder(referentialConstraint, index);
|
|
|
|
#region Inner data visit
|
|
this.AddObjectContentToHashBuilder(referentialConstraint.Identity);
|
|
|
|
base.Visit(referentialConstraint);
|
|
|
|
#endregion
|
|
|
|
this.AddObjectEndDumpToHashBuilder();
|
|
}
|
|
|
|
protected override void Visit(RelationshipEndMember relationshipEndMember)
|
|
{
|
|
int index;
|
|
if (!this.AddObjectToSeenListAndHashBuilder(relationshipEndMember, out index))
|
|
{
|
|
return;
|
|
}
|
|
|
|
this.AddObjectStartDumpToHashBuilder(relationshipEndMember, index);
|
|
|
|
#region Inner data visit
|
|
this.AddObjectContentToHashBuilder(relationshipEndMember.DeleteBehavior);
|
|
this.AddObjectContentToHashBuilder(relationshipEndMember.Identity);
|
|
// Name is covered by Identity
|
|
this.AddObjectContentToHashBuilder(relationshipEndMember.IsStoreGeneratedComputed);
|
|
this.AddObjectContentToHashBuilder(relationshipEndMember.IsStoreGeneratedIdentity);
|
|
this.AddObjectContentToHashBuilder(relationshipEndMember.RelationshipMultiplicity);
|
|
|
|
base.Visit(relationshipEndMember);
|
|
|
|
#endregion
|
|
|
|
this.AddObjectEndDumpToHashBuilder();
|
|
}
|
|
|
|
protected override void Visit(TypeUsage typeUsage)
|
|
{
|
|
int index;
|
|
if (!this.AddObjectToSeenListAndHashBuilder(typeUsage, out index))
|
|
{
|
|
return;
|
|
}
|
|
|
|
this.AddObjectStartDumpToHashBuilder(typeUsage, index);
|
|
|
|
#region Inner data visit
|
|
//No need to add identity of TypeUsage to the hash since it would take into account
|
|
//facets that viewgen would not care and we visit the important facets anyway.
|
|
|
|
base.Visit(typeUsage);
|
|
|
|
#endregion
|
|
|
|
this.AddObjectEndDumpToHashBuilder();
|
|
}
|
|
|
|
protected override void Visit(RelationshipType relationshipType)
|
|
{
|
|
base.Visit(relationshipType);
|
|
}
|
|
|
|
protected override void Visit(EdmType edmType)
|
|
{
|
|
base.Visit(edmType);
|
|
}
|
|
|
|
protected override void Visit(EnumType enumType)
|
|
{
|
|
int index;
|
|
if (!this.AddObjectToSeenListAndHashBuilder(enumType, out index))
|
|
{
|
|
return;
|
|
}
|
|
|
|
this.AddObjectStartDumpToHashBuilder(enumType, index);
|
|
|
|
this.AddObjectContentToHashBuilder(enumType.Identity);
|
|
this.Visit(enumType.UnderlyingType);
|
|
|
|
base.Visit(enumType);
|
|
|
|
this.AddObjectEndDumpToHashBuilder();
|
|
}
|
|
|
|
protected override void Visit(EnumMember enumMember)
|
|
{
|
|
int index;
|
|
if (!this.AddObjectToSeenListAndHashBuilder(enumMember, out index))
|
|
{
|
|
return;
|
|
}
|
|
|
|
this.AddObjectStartDumpToHashBuilder(enumMember, index);
|
|
|
|
this.AddObjectContentToHashBuilder(enumMember.Name);
|
|
this.AddObjectContentToHashBuilder(enumMember.Value);
|
|
|
|
base.Visit(enumMember);
|
|
|
|
this.AddObjectEndDumpToHashBuilder();
|
|
}
|
|
|
|
protected override void Visit(CollectionType collectionType)
|
|
{
|
|
int index;
|
|
if (!this.AddObjectToSeenListAndHashBuilder(collectionType, out index))
|
|
{
|
|
return;
|
|
}
|
|
|
|
this.AddObjectStartDumpToHashBuilder(collectionType, index);
|
|
|
|
#region Inner data visit
|
|
this.AddObjectContentToHashBuilder(collectionType.Identity);
|
|
// Identity contains Name, NamespaceName and FullName
|
|
|
|
base.Visit(collectionType);
|
|
|
|
#endregion
|
|
|
|
this.AddObjectEndDumpToHashBuilder();
|
|
}
|
|
|
|
protected override void Visit(RefType refType)
|
|
{
|
|
int index;
|
|
if (!this.AddObjectToSeenListAndHashBuilder(refType, out index))
|
|
{
|
|
return;
|
|
}
|
|
|
|
this.AddObjectStartDumpToHashBuilder(refType, index);
|
|
|
|
#region Inner data visit
|
|
this.AddObjectContentToHashBuilder(refType.Identity);
|
|
// Identity contains Name, NamespaceName and FullName
|
|
|
|
base.Visit(refType);
|
|
|
|
#endregion
|
|
|
|
this.AddObjectEndDumpToHashBuilder();
|
|
}
|
|
|
|
protected override void Visit(EntityTypeBase entityTypeBase)
|
|
{
|
|
base.Visit(entityTypeBase);
|
|
}
|
|
|
|
protected override void Visit(Facet facet)
|
|
{
|
|
int index;
|
|
if (facet.Name != DbProviderManifest.NullableFacetName)
|
|
{
|
|
// skip all the non interesting facets
|
|
return;
|
|
}
|
|
|
|
if (!this.AddObjectToSeenListAndHashBuilder(facet, out index))
|
|
{
|
|
return;
|
|
}
|
|
|
|
this.AddObjectStartDumpToHashBuilder(facet, index);
|
|
|
|
#region Inner data visit
|
|
this.AddObjectContentToHashBuilder(facet.Identity);
|
|
// Identity already contains Name
|
|
this.AddObjectContentToHashBuilder(facet.Value);
|
|
|
|
base.Visit(facet);
|
|
|
|
#endregion
|
|
|
|
this.AddObjectEndDumpToHashBuilder();
|
|
}
|
|
|
|
protected override void Visit(EdmFunction edmFunction)
|
|
{
|
|
// View Generation doesn't deal with functions
|
|
// so just return;
|
|
}
|
|
|
|
protected override void Visit(ComplexType complexType)
|
|
{
|
|
int index;
|
|
if (!this.AddObjectToSeenListAndHashBuilder(complexType, out index))
|
|
{
|
|
return;
|
|
}
|
|
|
|
this.AddObjectStartDumpToHashBuilder(complexType, index);
|
|
|
|
#region Inner data visit
|
|
this.AddObjectContentToHashBuilder(complexType.Abstract);
|
|
this.AddObjectContentToHashBuilder(complexType.Identity);
|
|
// Identity covers, FullName, Name, and NamespaceName
|
|
|
|
base.Visit(complexType);
|
|
|
|
#endregion
|
|
|
|
this.AddObjectEndDumpToHashBuilder();
|
|
}
|
|
|
|
protected override void Visit(PrimitiveType primitiveType)
|
|
{
|
|
int index;
|
|
if (!this.AddObjectToSeenListAndHashBuilder(primitiveType, out index))
|
|
{
|
|
return;
|
|
}
|
|
|
|
this.AddObjectStartDumpToHashBuilder(primitiveType, index);
|
|
|
|
#region Inner data visit
|
|
this.AddObjectContentToHashBuilder(primitiveType.Name);
|
|
this.AddObjectContentToHashBuilder(primitiveType.NamespaceName);
|
|
|
|
base.Visit(primitiveType);
|
|
|
|
#endregion
|
|
|
|
this.AddObjectEndDumpToHashBuilder();
|
|
}
|
|
|
|
protected override void Visit(FunctionParameter functionParameter)
|
|
{
|
|
int index;
|
|
if (!this.AddObjectToSeenListAndHashBuilder(functionParameter, out index))
|
|
{
|
|
return;
|
|
}
|
|
|
|
this.AddObjectStartDumpToHashBuilder(functionParameter, index);
|
|
|
|
#region Inner data visit
|
|
this.AddObjectContentToHashBuilder(functionParameter.Identity);
|
|
// Identity already has Name
|
|
this.AddObjectContentToHashBuilder(functionParameter.Mode);
|
|
|
|
base.Visit(functionParameter);
|
|
|
|
#endregion
|
|
|
|
this.AddObjectEndDumpToHashBuilder();
|
|
}
|
|
|
|
protected override void Visit(DbProviderManifest providerManifest)
|
|
{
|
|
// the provider manifest will be checked by all the other types lining up.
|
|
// no need to store more info.
|
|
}
|
|
#endregion
|
|
|
|
#region hasher helper method
|
|
|
|
internal string HashValue
|
|
{
|
|
get
|
|
{
|
|
return m_hashSourceBuilder.ComputeHash();
|
|
}
|
|
}
|
|
|
|
private void Clean()
|
|
{
|
|
this.m_hashSourceBuilder = new CompressingHashBuilder(MetadataHelper.CreateMetadataHashAlgorithm(m_MappingVersion));
|
|
this.m_instanceNumber = 0;
|
|
this.m_itemsAlreadySeen = new Dictionary<object, int>();
|
|
}
|
|
|
|
/// <summary>
|
|
/// if already seen, then out the object instance index, return false;
|
|
/// if haven't seen, then add it to the m_itemAlreadySeen, out the current index, return true
|
|
/// </summary>
|
|
/// <param name="o"></param>
|
|
/// <param name="indexSeen"></param>
|
|
/// <returns></returns>
|
|
private bool TryAddSeenItem(Object o, out int indexSeen)
|
|
{
|
|
if (!this.m_itemsAlreadySeen.TryGetValue(o, out indexSeen))
|
|
{
|
|
this.m_itemsAlreadySeen.Add(o, this.m_instanceNumber);
|
|
|
|
indexSeen = this.m_instanceNumber;
|
|
this.m_instanceNumber++;
|
|
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
/// <summary>
|
|
/// if the object has seen, then add the seen object style to the hash source, return false;
|
|
/// if not, then add it to the seen list, and append the object start dump to the hash source, return true
|
|
/// </summary>
|
|
/// <param name="o"></param>
|
|
/// <returns></returns>
|
|
private bool AddObjectToSeenListAndHashBuilder(object o, out int instanceIndex)
|
|
{
|
|
if (o == null)
|
|
{
|
|
instanceIndex = -1;
|
|
return false;
|
|
}
|
|
if (!TryAddSeenItem(o, out instanceIndex))
|
|
{
|
|
this.AddObjectStartDumpToHashBuilder(o, instanceIndex);
|
|
this.AddSeenObjectToHashBuilder(o, instanceIndex);
|
|
this.AddObjectEndDumpToHashBuilder();
|
|
return false;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
private void AddSeenObjectToHashBuilder(object o, int instanceIndex)
|
|
{
|
|
Debug.Assert(instanceIndex >= 0, "referencing index should not be less than 0");
|
|
this.m_hashSourceBuilder.AppendLine("Instance Reference: " + instanceIndex);
|
|
}
|
|
|
|
private void AddObjectStartDumpToHashBuilder(object o, int objectIndex)
|
|
{
|
|
this.m_hashSourceBuilder.AppendObjectStartDump(o, objectIndex);
|
|
}
|
|
|
|
private void AddObjectEndDumpToHashBuilder()
|
|
{
|
|
this.m_hashSourceBuilder.AppendObjectEndDump();
|
|
}
|
|
|
|
private void AddObjectContentToHashBuilder(object content)
|
|
{
|
|
if (content != null)
|
|
{
|
|
IFormattable formatContent = content as IFormattable;
|
|
if (formatContent != null)
|
|
{
|
|
// if the content is formattable, the following code made it culture invariant,
|
|
// for instance, the int, "30,000" can be formatted to "30-000" if the user
|
|
// has a different language and region setting
|
|
this.m_hashSourceBuilder.AppendLine(formatContent.ToString(null, CultureInfo.InvariantCulture));
|
|
}
|
|
else
|
|
{
|
|
this.m_hashSourceBuilder.AppendLine(content.ToString());
|
|
}
|
|
}
|
|
else
|
|
{
|
|
this.m_hashSourceBuilder.AppendLine("NULL");
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Add V2 schema properties and attributes to the hash builder
|
|
/// </summary>
|
|
/// <param name="content"></param>
|
|
/// <param name="defaultValue"></param>
|
|
private void AddV2ObjectContentToHashBuilder(object content, double version)
|
|
{
|
|
// if the version number is greater than or equal to V2, then we add the value
|
|
if (version >= XmlConstants.EdmVersionForV2)
|
|
{
|
|
this.AddObjectContentToHashBuilder(content);
|
|
}
|
|
}
|
|
|
|
internal static string GetMappingClosureHash(double mappingVersion, StorageEntityContainerMapping storageEntityContainerMapping)
|
|
{
|
|
Debug.Assert(storageEntityContainerMapping != null, "storageEntityContainerMapping is null!");
|
|
|
|
MetadataMappingHasherVisitor visitor = new MetadataMappingHasherVisitor(mappingVersion);
|
|
visitor.Visit(storageEntityContainerMapping);
|
|
return visitor.HashValue;
|
|
}
|
|
#endregion
|
|
|
|
}
|
|
}
|