1 //---------------------------------------------------------------------
2 // <copyright file="MetadataMappingHasherVisitor.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;
11 using System.Collections.Generic;
12 using System.Linq;
13 using System.Text;
14 using System.Data.Metadata.Edm;
15 using System.Data.Common;
16 using System.Data.Common.Utils;
17 using System.Data.Mapping;
18 using System.Diagnostics;
19 using System.Globalization;
20 
21 
22 namespace System.Data.Mapping
23 {
24     internal partial class MetadataMappingHasherVisitor : BaseMetadataMappingVisitor
25     {
26         private CompressingHashBuilder m_hashSourceBuilder;
27         private Dictionary<Object, int> m_itemsAlreadySeen = new Dictionary<Object, int>();
28         private int m_instanceNumber = 0;
29         private EdmItemCollection m_EdmItemCollection;
30         private double m_EdmVersion;
31         private double m_MappingVersion;
32 
MetadataMappingHasherVisitor(double mappingVersion)33         private MetadataMappingHasherVisitor(double mappingVersion)
34         {
35             m_MappingVersion = mappingVersion;
36             this.m_hashSourceBuilder = new CompressingHashBuilder(MetadataHelper.CreateMetadataHashAlgorithm(m_MappingVersion));
37         }
38 
39         #region visitor method
Visit(StorageEntityContainerMapping storageEntityContainerMapping)40         protected override void Visit(StorageEntityContainerMapping storageEntityContainerMapping)
41         {
42             Debug.Assert(storageEntityContainerMapping != null, "storageEntityContainerMapping cannot be null!");
43 
44             // at the entry point of visitor, we setup the versions
45             Debug.Assert(m_MappingVersion == storageEntityContainerMapping.StorageMappingItemCollection.MappingVersion, "the original version and the mapping collection version are not the same");
46             this.m_MappingVersion = storageEntityContainerMapping.StorageMappingItemCollection.MappingVersion;
47             this.m_EdmVersion = storageEntityContainerMapping.StorageMappingItemCollection.EdmItemCollection.EdmVersion;
48 
49             this.m_EdmItemCollection = storageEntityContainerMapping.StorageMappingItemCollection.EdmItemCollection;
50 
51             int index;
52             if (!this.AddObjectToSeenListAndHashBuilder(storageEntityContainerMapping, out index))
53             {
54                 // if this has been add to the seen list, then just
55                 return;
56             }
57             if (this.m_itemsAlreadySeen.Count > 1)
58             {
59 
60                 // this means user try another visit over SECM, this is allowed but all the previous visit all lost due to clean
61                 // user can visit different SECM objects by using the same visitor to load the SECM object
62                 this.Clean();
63                 Visit(storageEntityContainerMapping);
64                 return;
65             }
66 
67             this.AddObjectStartDumpToHashBuilder(storageEntityContainerMapping, index);
68 
69             #region Inner data visit
70 
71             this.AddObjectContentToHashBuilder(storageEntityContainerMapping.Identity);
72 
73             this.AddV2ObjectContentToHashBuilder(storageEntityContainerMapping.GenerateUpdateViews, this.m_MappingVersion);
74 
75             base.Visit(storageEntityContainerMapping);
76 
77             #endregion
78 
79             this.AddObjectEndDumpToHashBuilder();
80         }
81 
Visit(EntityContainer entityContainer)82         protected override void Visit(EntityContainer entityContainer)
83         {
84             int index;
85             if (!this.AddObjectToSeenListAndHashBuilder(entityContainer, out index))
86             {
87                 return;
88             }
89 
90             this.AddObjectStartDumpToHashBuilder(entityContainer, index);
91 
92             #region Inner data visit
93 
94             this.AddObjectContentToHashBuilder(entityContainer.Identity);
95             // Name is covered by Identity
96 
97             base.Visit(entityContainer);
98 
99             #endregion
100 
101             this.AddObjectEndDumpToHashBuilder();
102         }
103 
Visit(StorageSetMapping storageSetMapping)104         protected override void Visit(StorageSetMapping storageSetMapping)
105         {
106             int index;
107             if (!this.AddObjectToSeenListAndHashBuilder(storageSetMapping, out index))
108             {
109                 return;
110             }
111 
112             this.AddObjectStartDumpToHashBuilder(storageSetMapping, index);
113 
114             #region Inner data visit
115             base.Visit(storageSetMapping);
116             #endregion
117 
118             this.AddObjectEndDumpToHashBuilder();
119         }
120 
Visit(StorageTypeMapping storageTypeMapping)121         protected override void Visit(StorageTypeMapping storageTypeMapping)
122         {
123             int index;
124             if (!this.AddObjectToSeenListAndHashBuilder(storageTypeMapping, out index))
125             {
126                 return;
127             }
128 
129             this.AddObjectStartDumpToHashBuilder(storageTypeMapping, index);
130 
131             #region Inner data visit
132 
133             base.Visit(storageTypeMapping);
134 
135             #endregion
136 
137             this.AddObjectEndDumpToHashBuilder();
138         }
139 
Visit(StorageMappingFragment storageMappingFragment)140         protected override void Visit(StorageMappingFragment storageMappingFragment)
141         {
142             int index;
143             if (!this.AddObjectToSeenListAndHashBuilder(storageMappingFragment, out index))
144             {
145                 return;
146             }
147 
148             this.AddObjectStartDumpToHashBuilder(storageMappingFragment, index);
149 
150             #region Inner data visit
151 
152             this.AddV2ObjectContentToHashBuilder(storageMappingFragment.IsSQueryDistinct, this.m_MappingVersion);
153 
154             base.Visit(storageMappingFragment);
155 
156             #endregion
157 
158             this.AddObjectEndDumpToHashBuilder();
159         }
160 
Visit(StoragePropertyMapping storagePropertyMapping)161         protected override void Visit(StoragePropertyMapping storagePropertyMapping)
162         {
163             base.Visit(storagePropertyMapping);
164         }
165 
Visit(StorageComplexPropertyMapping storageComplexPropertyMapping)166         protected override void Visit(StorageComplexPropertyMapping storageComplexPropertyMapping)
167         {
168             int index;
169             if (!this.AddObjectToSeenListAndHashBuilder(storageComplexPropertyMapping, out index))
170             {
171                 return;
172             }
173 
174             this.AddObjectStartDumpToHashBuilder(storageComplexPropertyMapping, index);
175 
176             #region Inner data visit
177 
178             base.Visit(storageComplexPropertyMapping);
179 
180             #endregion
181 
182             this.AddObjectEndDumpToHashBuilder();
183         }
Visit(StorageComplexTypeMapping storageComplexTypeMapping)184         protected override void Visit(StorageComplexTypeMapping storageComplexTypeMapping)
185         {
186             int index;
187             if (!this.AddObjectToSeenListAndHashBuilder(storageComplexTypeMapping, out index))
188             {
189                 return;
190             }
191 
192             this.AddObjectStartDumpToHashBuilder(storageComplexTypeMapping, index);
193 
194             #region Inner data visit
195 
196             base.Visit(storageComplexTypeMapping);
197 
198             #endregion
199 
200             this.AddObjectEndDumpToHashBuilder();
201         }
202 
Visit(StorageConditionPropertyMapping storageConditionPropertyMapping)203         protected override void Visit(StorageConditionPropertyMapping storageConditionPropertyMapping)
204         {
205             int index;
206             if (!this.AddObjectToSeenListAndHashBuilder(storageConditionPropertyMapping, out index))
207             {
208                 return;
209             }
210 
211             this.AddObjectStartDumpToHashBuilder(storageConditionPropertyMapping, index);
212 
213             #region Inner data visit
214             this.AddObjectContentToHashBuilder(storageConditionPropertyMapping.IsNull);
215             this.AddObjectContentToHashBuilder(storageConditionPropertyMapping.Value);
216 
217             base.Visit(storageConditionPropertyMapping);
218 
219             #endregion
220 
221             this.AddObjectEndDumpToHashBuilder();
222         }
223 
Visit(StorageScalarPropertyMapping storageScalarPropertyMapping)224         protected override void Visit(StorageScalarPropertyMapping storageScalarPropertyMapping)
225         {
226             int index;
227             if (!this.AddObjectToSeenListAndHashBuilder(storageScalarPropertyMapping, out index))
228             {
229                 return;
230             }
231 
232             this.AddObjectStartDumpToHashBuilder(storageScalarPropertyMapping, index);
233 
234             #region Inner data visit
235 
236             base.Visit(storageScalarPropertyMapping);
237 
238             #endregion
239 
240             this.AddObjectEndDumpToHashBuilder();
241         }
242 
Visit(EntitySetBase entitySetBase)243         protected override void Visit(EntitySetBase entitySetBase)
244         {
245             base.Visit(entitySetBase);
246         }
247 
Visit(EntitySet entitySet)248         protected override void Visit(EntitySet entitySet)
249         {
250             int index;
251             if (!this.AddObjectToSeenListAndHashBuilder(entitySet, out index))
252             {
253                 return;
254             }
255             #region Inner data visit
256 
257             this.AddObjectStartDumpToHashBuilder(entitySet, index);
258             this.AddObjectContentToHashBuilder(entitySet.Name);
259             this.AddObjectContentToHashBuilder(entitySet.Schema);
260             this.AddObjectContentToHashBuilder(entitySet.Table);
261 
262             base.Visit(entitySet);
263 
264             foreach (var entityType in MetadataHelper.GetTypeAndSubtypesOf(entitySet.ElementType, this.m_EdmItemCollection, false).Where(type => type != entitySet.ElementType))
265             {
266                 this.Visit(entityType);
267             }
268 
269             #endregion
270 
271             this.AddObjectEndDumpToHashBuilder();
272         }
273 
Visit(AssociationSet associationSet)274         protected override void Visit(AssociationSet associationSet)
275         {
276             int index;
277             if (!this.AddObjectToSeenListAndHashBuilder(associationSet, out index))
278             {
279                 return;
280             }
281 
282             this.AddObjectStartDumpToHashBuilder(associationSet, index);
283 
284             #region Inner data visit
285             this.AddObjectContentToHashBuilder(associationSet.CachedProviderSql);
286             // Name is coverd by Identity
287             this.AddObjectContentToHashBuilder(associationSet.Identity);
288             this.AddObjectContentToHashBuilder(associationSet.Schema);
289             this.AddObjectContentToHashBuilder(associationSet.Table);
290 
291             base.Visit(associationSet);
292 
293             #endregion
294 
295             this.AddObjectEndDumpToHashBuilder();
296         }
297 
Visit(EntityType entityType)298         protected override void Visit(EntityType entityType)
299         {
300             int index;
301             if (!this.AddObjectToSeenListAndHashBuilder(entityType, out index))
302             {
303                 return;
304             }
305 
306             this.AddObjectStartDumpToHashBuilder(entityType, index);
307 
308             #region Inner data visit
309             this.AddObjectContentToHashBuilder(entityType.Abstract);
310             this.AddObjectContentToHashBuilder(entityType.Identity);
311             // FullName, Namespace and Name are all covered by Identity
312 
313             base.Visit(entityType);
314 
315             #endregion
316 
317             this.AddObjectEndDumpToHashBuilder();
318         }
319 
Visit(AssociationSetEnd associationSetEnd)320         protected override void Visit(AssociationSetEnd associationSetEnd)
321         {
322             int index;
323             if (!this.AddObjectToSeenListAndHashBuilder(associationSetEnd, out index))
324             {
325                 return;
326             }
327 
328             this.AddObjectStartDumpToHashBuilder(associationSetEnd, index);
329 
330             #region Inner data visit
331             this.AddObjectContentToHashBuilder(associationSetEnd.Identity);
332             // Name is covered by Identity
333 
334             base.Visit(associationSetEnd);
335 
336             #endregion
337 
338             this.AddObjectEndDumpToHashBuilder();
339         }
340 
Visit(AssociationType associationType)341         protected override void Visit(AssociationType associationType)
342         {
343             int index;
344             if (!this.AddObjectToSeenListAndHashBuilder(associationType, out index))
345             {
346                 return;
347             }
348 
349             this.AddObjectStartDumpToHashBuilder(associationType, index);
350 
351             #region Inner data visit
352             this.AddObjectContentToHashBuilder(associationType.Abstract);
353             this.AddObjectContentToHashBuilder(associationType.Identity);
354             // FullName, Namespace, and Name are all covered by Identity
355 
356             base.Visit(associationType);
357 
358             #endregion
359 
360             this.AddObjectEndDumpToHashBuilder();
361         }
362 
Visit(EdmProperty edmProperty)363         protected override void Visit(EdmProperty edmProperty)
364         {
365             int index;
366             if (!this.AddObjectToSeenListAndHashBuilder(edmProperty, out index))
367             {
368                 return;
369             }
370 
371             this.AddObjectStartDumpToHashBuilder(edmProperty, index);
372 
373             #region Inner data visit
374             // since the delaring type is fixed and referenced to the upper type,
375             // there is no need to hash this
376             //this.AddObjectContentToHashBuilder(edmProperty.DeclaringType);
377             this.AddObjectContentToHashBuilder(edmProperty.DefaultValue);
378             this.AddObjectContentToHashBuilder(edmProperty.Identity);
379             // Name is covered by Identity
380             this.AddObjectContentToHashBuilder(edmProperty.IsStoreGeneratedComputed);
381             this.AddObjectContentToHashBuilder(edmProperty.IsStoreGeneratedIdentity);
382             this.AddObjectContentToHashBuilder(edmProperty.Nullable);
383 
384             base.Visit(edmProperty);
385 
386             #endregion
387 
388             this.AddObjectEndDumpToHashBuilder();
389         }
390 
Visit(NavigationProperty navigationProperty)391         protected override void Visit(NavigationProperty navigationProperty)
392         {
393             // navigation properties are not considered in view generation
394             return;
395         }
396 
Visit(EdmMember edmMember)397         protected override void Visit(EdmMember edmMember)
398         {
399             int index;
400             if (!this.AddObjectToSeenListAndHashBuilder(edmMember, out index))
401             {
402                 return;
403             }
404 
405             this.AddObjectStartDumpToHashBuilder(edmMember, index);
406 
407             #region Inner data visit
408             this.AddObjectContentToHashBuilder(edmMember.Identity);
409             // Name is covered by Identity
410             this.AddObjectContentToHashBuilder(edmMember.IsStoreGeneratedComputed);
411             this.AddObjectContentToHashBuilder(edmMember.IsStoreGeneratedIdentity);
412 
413             base.Visit(edmMember);
414 
415             #endregion
416 
417             this.AddObjectEndDumpToHashBuilder();
418         }
419 
Visit(AssociationEndMember associationEndMember)420         protected override void Visit(AssociationEndMember associationEndMember)
421         {
422             int index;
423             if (!this.AddObjectToSeenListAndHashBuilder(associationEndMember, out index))
424             {
425                 return;
426             }
427 
428             this.AddObjectStartDumpToHashBuilder(associationEndMember, index);
429 
430             #region Inner data visit
431             this.AddObjectContentToHashBuilder(associationEndMember.DeleteBehavior);
432             this.AddObjectContentToHashBuilder(associationEndMember.Identity);
433             // Name is covered by Identity
434             this.AddObjectContentToHashBuilder(associationEndMember.IsStoreGeneratedComputed);
435             this.AddObjectContentToHashBuilder(associationEndMember.IsStoreGeneratedIdentity);
436             this.AddObjectContentToHashBuilder(associationEndMember.RelationshipMultiplicity);
437 
438             base.Visit(associationEndMember);
439 
440             #endregion
441 
442             this.AddObjectEndDumpToHashBuilder();
443         }
444 
Visit(ReferentialConstraint referentialConstraint)445         protected override void Visit(ReferentialConstraint referentialConstraint)
446         {
447             int index;
448             if (!this.AddObjectToSeenListAndHashBuilder(referentialConstraint, out index))
449             {
450                 return;
451             }
452 
453             this.AddObjectStartDumpToHashBuilder(referentialConstraint, index);
454 
455             #region Inner data visit
456             this.AddObjectContentToHashBuilder(referentialConstraint.Identity);
457 
458             base.Visit(referentialConstraint);
459 
460             #endregion
461 
462             this.AddObjectEndDumpToHashBuilder();
463         }
464 
Visit(RelationshipEndMember relationshipEndMember)465         protected override void Visit(RelationshipEndMember relationshipEndMember)
466         {
467             int index;
468             if (!this.AddObjectToSeenListAndHashBuilder(relationshipEndMember, out index))
469             {
470                 return;
471             }
472 
473             this.AddObjectStartDumpToHashBuilder(relationshipEndMember, index);
474 
475             #region Inner data visit
476             this.AddObjectContentToHashBuilder(relationshipEndMember.DeleteBehavior);
477             this.AddObjectContentToHashBuilder(relationshipEndMember.Identity);
478             // Name is covered by Identity
479             this.AddObjectContentToHashBuilder(relationshipEndMember.IsStoreGeneratedComputed);
480             this.AddObjectContentToHashBuilder(relationshipEndMember.IsStoreGeneratedIdentity);
481             this.AddObjectContentToHashBuilder(relationshipEndMember.RelationshipMultiplicity);
482 
483             base.Visit(relationshipEndMember);
484 
485             #endregion
486 
487             this.AddObjectEndDumpToHashBuilder();
488         }
489 
Visit(TypeUsage typeUsage)490         protected override void Visit(TypeUsage typeUsage)
491         {
492             int index;
493             if (!this.AddObjectToSeenListAndHashBuilder(typeUsage, out index))
494             {
495                 return;
496             }
497 
498             this.AddObjectStartDumpToHashBuilder(typeUsage, index);
499 
500             #region Inner data visit
501             //No need to add identity of TypeUsage to the hash since it would take into account
502             //facets that viewgen would not care and we visit the important facets anyway.
503 
504             base.Visit(typeUsage);
505 
506             #endregion
507 
508             this.AddObjectEndDumpToHashBuilder();
509         }
510 
Visit(RelationshipType relationshipType)511         protected override void Visit(RelationshipType relationshipType)
512         {
513             base.Visit(relationshipType);
514         }
515 
Visit(EdmType edmType)516         protected override void Visit(EdmType edmType)
517         {
518             base.Visit(edmType);
519         }
520 
Visit(EnumType enumType)521         protected override void Visit(EnumType enumType)
522         {
523             int index;
524             if (!this.AddObjectToSeenListAndHashBuilder(enumType, out index))
525             {
526                 return;
527             }
528 
529             this.AddObjectStartDumpToHashBuilder(enumType, index);
530 
531             this.AddObjectContentToHashBuilder(enumType.Identity);
532             this.Visit(enumType.UnderlyingType);
533 
534             base.Visit(enumType);
535 
536             this.AddObjectEndDumpToHashBuilder();
537         }
538 
Visit(EnumMember enumMember)539         protected override void Visit(EnumMember enumMember)
540         {
541             int index;
542             if (!this.AddObjectToSeenListAndHashBuilder(enumMember, out index))
543             {
544                 return;
545             }
546 
547             this.AddObjectStartDumpToHashBuilder(enumMember, index);
548 
549             this.AddObjectContentToHashBuilder(enumMember.Name);
550             this.AddObjectContentToHashBuilder(enumMember.Value);
551 
552             base.Visit(enumMember);
553 
554             this.AddObjectEndDumpToHashBuilder();
555         }
556 
Visit(CollectionType collectionType)557         protected override void Visit(CollectionType collectionType)
558         {
559             int index;
560             if (!this.AddObjectToSeenListAndHashBuilder(collectionType, out index))
561             {
562                 return;
563             }
564 
565             this.AddObjectStartDumpToHashBuilder(collectionType, index);
566 
567             #region Inner data visit
568             this.AddObjectContentToHashBuilder(collectionType.Identity);
569             // Identity contains Name, NamespaceName and FullName
570 
571             base.Visit(collectionType);
572 
573             #endregion
574 
575             this.AddObjectEndDumpToHashBuilder();
576         }
577 
Visit(RefType refType)578         protected override void Visit(RefType refType)
579         {
580             int index;
581             if (!this.AddObjectToSeenListAndHashBuilder(refType, out index))
582             {
583                 return;
584             }
585 
586             this.AddObjectStartDumpToHashBuilder(refType, index);
587 
588             #region Inner data visit
589             this.AddObjectContentToHashBuilder(refType.Identity);
590             // Identity contains Name, NamespaceName and FullName
591 
592             base.Visit(refType);
593 
594             #endregion
595 
596             this.AddObjectEndDumpToHashBuilder();
597         }
598 
Visit(EntityTypeBase entityTypeBase)599         protected override void Visit(EntityTypeBase entityTypeBase)
600         {
601             base.Visit(entityTypeBase);
602         }
603 
Visit(Facet facet)604         protected override void Visit(Facet facet)
605         {
606             int index;
607             if (facet.Name != DbProviderManifest.NullableFacetName)
608             {
609                 // skip all the non interesting facets
610                 return;
611             }
612 
613             if (!this.AddObjectToSeenListAndHashBuilder(facet, out index))
614             {
615                 return;
616             }
617 
618             this.AddObjectStartDumpToHashBuilder(facet, index);
619 
620             #region Inner data visit
621             this.AddObjectContentToHashBuilder(facet.Identity);
622             // Identity already contains Name
623             this.AddObjectContentToHashBuilder(facet.Value);
624 
625             base.Visit(facet);
626 
627             #endregion
628 
629             this.AddObjectEndDumpToHashBuilder();
630         }
631 
Visit(EdmFunction edmFunction)632         protected override void Visit(EdmFunction edmFunction)
633         {
634             // View Generation doesn't deal with functions
635             // so just return;
636         }
637 
Visit(ComplexType complexType)638         protected override void Visit(ComplexType complexType)
639         {
640             int index;
641             if (!this.AddObjectToSeenListAndHashBuilder(complexType, out index))
642             {
643                 return;
644             }
645 
646             this.AddObjectStartDumpToHashBuilder(complexType, index);
647 
648             #region Inner data visit
649             this.AddObjectContentToHashBuilder(complexType.Abstract);
650             this.AddObjectContentToHashBuilder(complexType.Identity);
651             // Identity covers, FullName, Name, and NamespaceName
652 
653             base.Visit(complexType);
654 
655             #endregion
656 
657             this.AddObjectEndDumpToHashBuilder();
658         }
659 
Visit(PrimitiveType primitiveType)660         protected override void Visit(PrimitiveType primitiveType)
661         {
662             int index;
663             if (!this.AddObjectToSeenListAndHashBuilder(primitiveType, out index))
664             {
665                 return;
666             }
667 
668             this.AddObjectStartDumpToHashBuilder(primitiveType, index);
669 
670             #region Inner data visit
671             this.AddObjectContentToHashBuilder(primitiveType.Name);
672             this.AddObjectContentToHashBuilder(primitiveType.NamespaceName);
673 
674             base.Visit(primitiveType);
675 
676             #endregion
677 
678             this.AddObjectEndDumpToHashBuilder();
679         }
680 
Visit(FunctionParameter functionParameter)681         protected override void Visit(FunctionParameter functionParameter)
682         {
683             int index;
684             if (!this.AddObjectToSeenListAndHashBuilder(functionParameter, out index))
685             {
686                 return;
687             }
688 
689             this.AddObjectStartDumpToHashBuilder(functionParameter, index);
690 
691             #region Inner data visit
692             this.AddObjectContentToHashBuilder(functionParameter.Identity);
693             // Identity already has Name
694             this.AddObjectContentToHashBuilder(functionParameter.Mode);
695 
696             base.Visit(functionParameter);
697 
698             #endregion
699 
700             this.AddObjectEndDumpToHashBuilder();
701         }
702 
Visit(DbProviderManifest providerManifest)703         protected override void Visit(DbProviderManifest providerManifest)
704         {
705             // the provider manifest will be checked by all the other types lining up.
706             // no need to store more info.
707         }
708         #endregion
709 
710         #region hasher helper method
711 
712         internal string HashValue
713         {
714             get
715             {
716                 return m_hashSourceBuilder.ComputeHash();
717             }
718         }
719 
Clean()720         private void Clean()
721         {
722             this.m_hashSourceBuilder = new CompressingHashBuilder(MetadataHelper.CreateMetadataHashAlgorithm(m_MappingVersion));
723             this.m_instanceNumber = 0;
724             this.m_itemsAlreadySeen = new Dictionary<object, int>();
725         }
726 
727         /// <summary>
728         /// if already seen, then out the object instance index, return false;
729         /// if haven't seen, then add it to the m_itemAlreadySeen, out the current index, return true
730         /// </summary>
731         /// <param name="o"></param>
732         /// <param name="indexSeen"></param>
733         /// <returns></returns>
TryAddSeenItem(Object o, out int indexSeen)734         private bool TryAddSeenItem(Object o, out int indexSeen)
735         {
736             if (!this.m_itemsAlreadySeen.TryGetValue(o, out indexSeen))
737             {
738                 this.m_itemsAlreadySeen.Add(o, this.m_instanceNumber);
739 
740                 indexSeen = this.m_instanceNumber;
741                 this.m_instanceNumber++;
742 
743                 return true;
744             }
745             return false;
746         }
747 
748         /// <summary>
749         /// if the object has seen, then add the seen object style to the hash source, return false;
750         /// if not, then add it to the seen list, and append the object start dump to the hash source, return true
751         /// </summary>
752         /// <param name="o"></param>
753         /// <returns></returns>
AddObjectToSeenListAndHashBuilder(object o, out int instanceIndex)754         private bool AddObjectToSeenListAndHashBuilder(object o, out int instanceIndex)
755         {
756             if (o == null)
757             {
758                 instanceIndex = -1;
759                 return false;
760             }
761             if (!TryAddSeenItem(o, out instanceIndex))
762             {
763                 this.AddObjectStartDumpToHashBuilder(o, instanceIndex);
764                 this.AddSeenObjectToHashBuilder(o, instanceIndex);
765                 this.AddObjectEndDumpToHashBuilder();
766                 return false;
767             }
768             return true;
769         }
770 
AddSeenObjectToHashBuilder(object o, int instanceIndex)771         private void AddSeenObjectToHashBuilder(object o, int instanceIndex)
772         {
773             Debug.Assert(instanceIndex >= 0, "referencing index should not be less than 0");
774             this.m_hashSourceBuilder.AppendLine("Instance Reference: " + instanceIndex);
775         }
776 
AddObjectStartDumpToHashBuilder(object o, int objectIndex)777         private void AddObjectStartDumpToHashBuilder(object o, int objectIndex)
778         {
779             this.m_hashSourceBuilder.AppendObjectStartDump(o, objectIndex);
780         }
781 
AddObjectEndDumpToHashBuilder()782         private void AddObjectEndDumpToHashBuilder()
783         {
784             this.m_hashSourceBuilder.AppendObjectEndDump();
785         }
786 
AddObjectContentToHashBuilder(object content)787         private void AddObjectContentToHashBuilder(object content)
788         {
789             if (content != null)
790             {
791                 IFormattable formatContent = content as IFormattable;
792                 if (formatContent != null)
793                 {
794                     // if the content is formattable, the following code made it culture invariant,
795                     // for instance, the int, "30,000" can be formatted to "30-000" if the user
796                     // has a different language and region setting
797                     this.m_hashSourceBuilder.AppendLine(formatContent.ToString(null, CultureInfo.InvariantCulture));
798                 }
799                 else
800                 {
801                     this.m_hashSourceBuilder.AppendLine(content.ToString());
802                 }
803             }
804             else
805             {
806                 this.m_hashSourceBuilder.AppendLine("NULL");
807             }
808         }
809 
810         /// <summary>
811         /// Add V2 schema properties and attributes to the hash builder
812         /// </summary>
813         /// <param name="content"></param>
814         /// <param name="defaultValue"></param>
AddV2ObjectContentToHashBuilder(object content, double version)815         private void AddV2ObjectContentToHashBuilder(object content, double version)
816         {
817             // if the version number is greater than or equal to V2, then we add the value
818             if (version >= XmlConstants.EdmVersionForV2)
819             {
820                 this.AddObjectContentToHashBuilder(content);
821             }
822         }
823 
GetMappingClosureHash(double mappingVersion, StorageEntityContainerMapping storageEntityContainerMapping)824         internal static string GetMappingClosureHash(double mappingVersion, StorageEntityContainerMapping storageEntityContainerMapping)
825         {
826             Debug.Assert(storageEntityContainerMapping != null, "storageEntityContainerMapping is null!");
827 
828             MetadataMappingHasherVisitor visitor = new MetadataMappingHasherVisitor(mappingVersion);
829             visitor.Visit(storageEntityContainerMapping);
830             return visitor.HashValue;
831         }
832         #endregion
833 
834     }
835 }
836