|
//---------------------------------------------------------------------
// <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
}
}
|