Updates referencesource to .NET 4.7
[mono.git] / mcs / class / referencesource / System.Data.Entity / System / Data / Metadata / Edm / TypeUsage.cs
1 //---------------------------------------------------------------------
2 // <copyright file="TypeUsage.cs" company="Microsoft">
3 //      Copyright (c) Microsoft Corporation.  All rights reserved.
4 // </copyright>
5 //
6 // @owner       Microsoft
7 // @backupOwner Microsoft
8 //---------------------------------------------------------------------
9
10 namespace System.Data.Metadata.Edm
11 {
12     using System;
13     using System.Collections.Generic;
14     using System.Data.Common;
15     using System.Diagnostics;
16     using System.Text;
17
18     /// <summary>
19     /// Class representing a type information for an item
20     /// </summary>
21     [DebuggerDisplay("EdmType={EdmType}, Facets.Count={Facets.Count}")]
22     public sealed class TypeUsage : MetadataItem
23     {
24         #region Constructors
25
26         /// <summary>
27         /// The constructor for TypeUsage taking in a type
28         /// </summary>
29         /// <param name="edmType">The type which the TypeUsage object describes</param>
30         /// <exception cref="System.ArgumentNullException">Thrown if edmType argument is null</exception>
31         private TypeUsage(EdmType edmType)
32         :base(MetadataFlags.Readonly)
33         {
34             EntityUtil.GenericCheckArgumentNull(edmType, "edmType");
35
36             _edmType = edmType;
37
38             // I would like to be able to assert that the edmType is ReadOnly, but
39             // because some types are still in loading while the TypeUsage is being created
40             // that won't work. We should consider a way to change this
41         }
42
43         /// <summary>
44         /// The constructor for TypeUsage taking in a type and a collection of facets
45         /// </summary>
46         /// <param name="edmType">The type which the TypeUsage object describes</param>
47         /// <param name="facets">The replacement collection of facets</param>
48         /// <exception cref="System.ArgumentNullException">Thrown if edmType argument is null</exception>
49         private TypeUsage(EdmType edmType, IEnumerable<Facet> facets)
50             : this(edmType)
51         {
52             MetadataCollection<Facet> facetCollection = new MetadataCollection<Facet>(facets);
53             facetCollection.SetReadOnly();
54             _facets = facetCollection.AsReadOnlyMetadataCollection();
55         }
56         #endregion
57
58         #region Factory Methods
59         /// <summary>
60         /// Factory method for creating a TypeUsage with specified EdmType
61         /// </summary>
62         /// <param name="edmType">EdmType for which to create a type usage</param>
63         /// <returns>new TypeUsage instance with default facet values</returns>
64         internal static TypeUsage Create(EdmType edmType)
65         {
66             return new TypeUsage(edmType);
67         }
68
69         /// <summary>
70         /// Factory method for creating a TypeUsage with specified EdmType
71         /// </summary>
72         /// <param name="edmType">EdmType for which to create a type usage</param>
73         /// <returns>new TypeUsage instance with default facet values</returns>
74         internal static TypeUsage Create(EdmType edmType, FacetValues values)
75         {
76             return new TypeUsage(edmType,
77                 GetDefaultFacetDescriptionsAndOverrideFacetValues(edmType, values));
78         }
79
80         /// <summary>
81         /// Factory method for creating a TypeUsage with specified EdmType and facets
82         /// </summary>
83         /// <param name="edmType">EdmType for which to create a type usage</param>
84         /// <param name="facets">facets to be copied into the new TypeUsage</param>
85         /// <returns>new TypeUsage instance</returns>
86         internal static TypeUsage Create(EdmType edmType, IEnumerable<Facet> facets)
87         {
88             return new TypeUsage(edmType, facets);
89         }
90
91         internal TypeUsage ShallowCopy(FacetValues facetValues)
92         {
93             return TypeUsage.Create(_edmType, OverrideFacetValues(Facets, facetValues));
94         }
95
96         /// <summary>
97         /// Factory method for creating a "readonly" TypeUsage with specified EdmType
98         /// </summary>
99         /// <param name="edmType">An EdmType for which to create a TypeUsage</param>
100         /// <returns>A TypeUsage instance with default facet values for the specified EdmType</returns>
101         [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Naming", "CA1704:IdentifiersShouldBeSpelledCorrectly", MessageId = "0#edm")]
102         [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Naming", "CA1704:IdentifiersShouldBeSpelledCorrectly", MessageId = "edm")]
103         public static TypeUsage CreateDefaultTypeUsage(EdmType edmType)
104         {
105             EntityUtil.CheckArgumentNull<EdmType>(edmType, "edmType");
106             
107             TypeUsage type = TypeUsage.Create(edmType);
108             return type;
109         }
110
111         /// <summary>
112         /// Factory method for creating a string TypeUsage object with the specified facets
113         /// </summary>
114         /// <param name="primitiveType">A PrimitiveType for which to construct the TypeUsage</param>
115         /// <param name="isUnicode">Whether the string type is unicode or not</param>
116         /// <param name="isFixedLength">Whether the string type is fixed length or not</param>
117         /// <param name="maxLength">The max length of the string type</param>
118         /// <returns>A TypeUsage object describing a string type with the given facet values</returns>
119         public static TypeUsage CreateStringTypeUsage(PrimitiveType primitiveType,
120                                                       bool isUnicode,
121                                                       bool isFixedLength,
122                                                       int maxLength)
123         {
124             EntityUtil.CheckArgumentNull<PrimitiveType>(primitiveType, "primitiveType");
125
126             if (primitiveType.PrimitiveTypeKind != PrimitiveTypeKind.String)
127             {
128                 throw EntityUtil.NotStringTypeForTypeUsage();
129             }
130
131             ValidateMaxLength(maxLength);
132
133             TypeUsage typeUsage = TypeUsage.Create(primitiveType,
134                 new FacetValues{ MaxLength = maxLength, Unicode = isUnicode, FixedLength = isFixedLength});
135
136             return typeUsage;
137         }
138
139         /// <summary>
140         /// Factory method for creating a string TypeUsage object with the specified facets and 
141         /// unbounded MaxLength
142         /// </summary>
143         /// <param name="primitiveType">A PrimitiveType for which to construct the TypeUsage</param>
144         /// <param name="isUnicode">Whether the string type is unicode or not</param>
145         /// <param name="isFixedLength">Whether the string type is fixed length or not</param>
146         /// <returns>A TypeUsage object describing a string type with the given facet values
147         /// and unbounded MaxLength</returns>
148         public static TypeUsage CreateStringTypeUsage(PrimitiveType primitiveType,
149                                                       bool isUnicode,
150                                                       bool isFixedLength)
151         {
152             EntityUtil.CheckArgumentNull<PrimitiveType>(primitiveType, "primitiveType");
153
154             if (primitiveType.PrimitiveTypeKind != PrimitiveTypeKind.String)
155             {
156                 throw EntityUtil.NotStringTypeForTypeUsage();
157             }
158             TypeUsage typeUsage = TypeUsage.Create(primitiveType,
159                 new FacetValues{ MaxLength = TypeUsage.DefaultMaxLengthFacetValue,
160                                   Unicode = isUnicode, FixedLength = isFixedLength});
161
162             return typeUsage;
163         }
164
165
166         /// <summary>
167         /// Factory method for creating a Binary TypeUsage object with the specified facets
168         /// </summary>
169         /// <param name="primitiveType">A PrimitiveType for which to construct TypeUsage</param>
170         /// <param name="isFixedLength">Whether the binary type is fixed length or not</param>
171         /// <param name="maxLength">The max length of the binary type</param>
172         /// <returns>A TypeUsage object describing a binary type with the given facet values</returns>
173         public static TypeUsage CreateBinaryTypeUsage(PrimitiveType primitiveType,
174                                                       bool isFixedLength,
175                                                       int maxLength)
176         {
177             EntityUtil.CheckArgumentNull<PrimitiveType>(primitiveType, "primitiveType");
178
179             if (primitiveType.PrimitiveTypeKind != PrimitiveTypeKind.Binary)
180             {
181                 throw EntityUtil.NotBinaryTypeForTypeUsage();
182             }
183
184             ValidateMaxLength(maxLength);
185
186             TypeUsage typeUsage = TypeUsage.Create(primitiveType,
187                 new FacetValues{MaxLength = maxLength, FixedLength = isFixedLength});
188
189             return typeUsage;
190         }
191
192         /// <summary>
193         /// Factory method for creating a Binary TypeUsage object with the specified facets and 
194         /// unbounded MaxLength
195         /// </summary>
196         /// <param name="primitiveType">A PrimitiveType for which to construct the TypeUsage</param>
197         /// <param name="isFixedLength">Whether the binary type is fixed length or not</param>
198         /// <returns>A TypeUsage object describing a binary type with the given facet values</returns>
199         public static TypeUsage CreateBinaryTypeUsage(PrimitiveType primitiveType, bool isFixedLength)
200         {
201             EntityUtil.CheckArgumentNull<PrimitiveType>(primitiveType, "primitiveType");
202
203             if (primitiveType.PrimitiveTypeKind != PrimitiveTypeKind.Binary)
204             {
205                 throw EntityUtil.NotBinaryTypeForTypeUsage();
206             }
207             TypeUsage typeUsage = TypeUsage.Create(primitiveType,
208                 new FacetValues{MaxLength = TypeUsage.DefaultMaxLengthFacetValue,
209                                  FixedLength = isFixedLength});
210
211             return typeUsage;
212         }
213
214         /// <summary>
215         /// Factory method for creating a DateTime TypeUsage object with the specified facets
216         /// </summary>
217         /// <param name="primitiveType">A PrimitiveType for which to construct the TypeUsage</param>
218         /// <param name="precision">Precision for seconds</param>
219         /// <returns>A TypeUsage object describing a DateTime type with the given facet values</returns>
220         public static TypeUsage CreateDateTimeTypeUsage(PrimitiveType primitiveType,
221                                                         byte? precision)
222         {
223             EntityUtil.CheckArgumentNull<PrimitiveType>(primitiveType, "primitiveType");
224
225             if (primitiveType.PrimitiveTypeKind != PrimitiveTypeKind.DateTime)
226             {
227                 throw EntityUtil.NotDateTimeTypeForTypeUsage();
228             }
229             TypeUsage typeUsage = TypeUsage.Create(primitiveType,
230                 new FacetValues{Precision = precision});
231
232             return typeUsage;
233         }
234
235         /// <summary>
236         /// Factory method for creating a DateTimeOffset TypeUsage object with the specified facets
237         /// </summary>
238         /// <param name="primitiveType">A PrimitiveType for which to construct the TypeUsage</param>
239         /// <param name="precision">Precision for seconds</param>
240         /// <returns>A TypeUsage object describing a DateTime type with the given facet values</returns>
241         public static TypeUsage CreateDateTimeOffsetTypeUsage(PrimitiveType primitiveType,
242                                                         byte? precision)
243         {
244             EntityUtil.CheckArgumentNull<PrimitiveType>(primitiveType, "primitiveType");
245
246             if (primitiveType.PrimitiveTypeKind != PrimitiveTypeKind.DateTimeOffset)
247             {
248                 throw EntityUtil.NotDateTimeOffsetTypeForTypeUsage();
249             }
250
251             TypeUsage typeUsage = TypeUsage.Create(primitiveType,
252                 new FacetValues{ Precision = precision });
253
254             return typeUsage;
255         }
256
257         /// <summary>
258         /// Factory method for creating a Time TypeUsage object with the specified facets
259         /// </summary>
260         /// <param name="primitiveType">A PrimitiveType for which to construct the TypeUsage</param>
261         /// <param name="precision">Precision for seconds</param>
262         /// <returns>A TypeUsage object describing a Time type with the given facet values</returns>
263         public static TypeUsage CreateTimeTypeUsage(PrimitiveType primitiveType,
264                                                         byte? precision)
265         {
266             EntityUtil.CheckArgumentNull<PrimitiveType>(primitiveType, "primitiveType");
267
268             if (primitiveType.PrimitiveTypeKind != PrimitiveTypeKind.Time)
269             {
270                 throw EntityUtil.NotTimeTypeForTypeUsage();
271             }
272             TypeUsage typeUsage = TypeUsage.Create(primitiveType,
273                 new FacetValues{ Precision = precision });
274
275             return typeUsage;
276         }
277
278
279
280         /// <summary>
281         /// Factory method for creating a Decimal TypeUsage object with the specified facets
282         /// </summary>
283         /// <param name="primitiveType">A PrimitiveType for which to construct type usage</param>
284         /// <param name="precision">The precision of the decimal type</param>
285         /// <param name="scale">The scale of the decimal type</param>
286         /// <returns>A TypeUsage object describing a decimal type with the given facet values</returns>
287         public static TypeUsage CreateDecimalTypeUsage(PrimitiveType primitiveType,
288                                                        byte precision,
289                                                        byte scale)
290         {
291             EntityUtil.CheckArgumentNull<PrimitiveType>(primitiveType, "primitiveType");
292
293             if (primitiveType.PrimitiveTypeKind != PrimitiveTypeKind.Decimal)
294             {
295                 throw EntityUtil.NotDecimalTypeForTypeUsage();
296             }
297
298             TypeUsage typeUsage = TypeUsage.Create(primitiveType,
299                 new FacetValues{Precision = precision, Scale = scale });
300
301             return typeUsage;
302         }
303
304         /// <summary>
305         /// Factory method for creating a Decimal TypeUsage object with unbounded precision and scale
306         /// </summary>
307         /// <param name="primitiveType">The PrimitiveType for which to construct type usage</param>
308         /// <returns>A TypeUsage object describing a decimal type with unbounded precision and scale</returns>
309         public static TypeUsage CreateDecimalTypeUsage(PrimitiveType primitiveType)
310         {
311             EntityUtil.CheckArgumentNull<PrimitiveType>(primitiveType, "primitiveType");
312
313             if (primitiveType.PrimitiveTypeKind != PrimitiveTypeKind.Decimal)
314             {
315                 throw EntityUtil.NotDecimalTypeForTypeUsage();
316             }
317             TypeUsage typeUsage = TypeUsage.Create(primitiveType,
318                 new FacetValues{ Precision = TypeUsage.DefaultPrecisionFacetValue, Scale = TypeUsage.DefaultScaleFacetValue });
319
320             return typeUsage;
321         }
322         #endregion
323
324         #region Fields
325         private TypeUsage _modelTypeUsage;
326         private readonly EdmType _edmType;
327         private ReadOnlyMetadataCollection<Facet> _facets;
328         private string _identity;
329
330         /// <summary>
331         /// Set of facets that should be included in identity for TypeUsage
332         /// </summary>
333         /// <remarks>keep this sorted for binary searching</remarks>
334         private static readonly string[] s_identityFacets = new string[] { 
335             DbProviderManifest.DefaultValueFacetName,
336             DbProviderManifest.FixedLengthFacetName,
337             DbProviderManifest.MaxLengthFacetName,
338             DbProviderManifest.NullableFacetName,
339             DbProviderManifest.PrecisionFacetName,
340             DbProviderManifest.ScaleFacetName,
341             DbProviderManifest.UnicodeFacetName,
342             DbProviderManifest.SridFacetName,
343         };
344
345         internal static readonly EdmConstants.Unbounded DefaultMaxLengthFacetValue       = EdmConstants.UnboundedValue;
346         internal static readonly EdmConstants.Unbounded DefaultPrecisionFacetValue       = EdmConstants.UnboundedValue;
347         internal static readonly EdmConstants.Unbounded DefaultScaleFacetValue           = EdmConstants.UnboundedValue;
348         internal static readonly bool                   DefaultUnicodeFacetValue         = true;
349         internal static readonly bool                   DefaultFixedLengthFacetValue     = false;
350         internal static readonly byte?                  DefaultDateTimePrecisionFacetValue = null;
351
352         #endregion
353
354         #region Properties
355         /// <summary>
356         /// Returns the kind of the type
357         /// </summary>
358         public override BuiltInTypeKind BuiltInTypeKind { get { return BuiltInTypeKind.TypeUsage; } }
359
360         /// <summary>
361         /// Gets the type that this TypeUsage describes
362         /// </summary>
363         [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Naming", "CA1704:IdentifiersShouldBeSpelledCorrectly", MessageId = "Edm")]
364         [MetadataProperty(BuiltInTypeKind.EdmType, false)]
365         public EdmType EdmType
366         {
367             get
368             {
369                 return _edmType;
370             }
371         }
372
373         /// <summary>
374         /// Gets the list of facets for the type in this TypeUsage
375         /// </summary>
376         [MetadataProperty(BuiltInTypeKind.Facet, true)]
377         public ReadOnlyMetadataCollection<Facet> Facets
378         {
379             get
380             {
381                 if (null == _facets)
382                 {
383                     MetadataCollection<Facet> facets = new MetadataCollection<Facet>(GetFacets());
384                     // we never modify the collection so we can set it readonly from the start
385                     facets.SetReadOnly();
386                     System.Threading.Interlocked.CompareExchange(ref _facets, facets.AsReadOnlyMetadataCollection(), null);
387                 }
388                 return _facets;
389             }
390         }
391         #endregion
392
393         #region Methods
394         /// <summary>
395         /// Returns a Model type usage for a provider type
396         /// </summary>
397         /// <returns>model (CSpace) type usage</returns>
398         internal TypeUsage GetModelTypeUsage()
399         {
400             if (_modelTypeUsage == null)
401             {
402                 EdmType edmType = this.EdmType;
403
404                 // If the edm type is already a cspace type, return the same type
405                 if (edmType.DataSpace == DataSpace.CSpace || edmType.DataSpace == DataSpace.OSpace)
406                 {
407                     return this;
408                 }
409
410                 TypeUsage result;
411                 if (Helper.IsRowType(edmType))
412                 {
413                     RowType sspaceRowType = (RowType)edmType;
414                     EdmProperty[] properties = new EdmProperty[sspaceRowType.Properties.Count];
415                     for (int i = 0; i < properties.Length; i++)
416                     {
417                         EdmProperty sspaceProperty = sspaceRowType.Properties[i];
418                         TypeUsage newTypeUsage = sspaceProperty.TypeUsage.GetModelTypeUsage();
419                         properties[i] = new EdmProperty(sspaceProperty.Name, newTypeUsage);
420                     }
421                     RowType edmRowType = new RowType(properties, sspaceRowType.InitializerMetadata);
422                     result = TypeUsage.Create(edmRowType, this.Facets);
423                 }
424                 else if (Helper.IsCollectionType(edmType))
425                 {
426                     CollectionType sspaceCollectionType = ((CollectionType)edmType);
427                     TypeUsage newTypeUsage = sspaceCollectionType.TypeUsage.GetModelTypeUsage();
428                     result = TypeUsage.Create(new CollectionType(newTypeUsage), this.Facets);
429                 }
430                 else if (Helper.IsRefType(edmType))
431                 {
432                     System.Diagnostics.Debug.Assert(((RefType)edmType).ElementType.DataSpace == DataSpace.CSpace);
433                     result = this;
434                 }
435                 else if (Helper.IsPrimitiveType(edmType))
436                 {
437                     result = ((PrimitiveType)edmType).ProviderManifest.GetEdmType(this);
438
439                     if (result == null)
440                     {
441                         throw EntityUtil.ProviderIncompatible(System.Data.Entity.Strings.Mapping_ProviderReturnsNullType(this.ToString()));
442                     }
443
444                     if (!TypeSemantics.IsNullable(this))
445                     {
446                         result = TypeUsage.Create(result.EdmType,
447                             OverrideFacetValues(result.Facets,
448                                 new FacetValues{ Nullable = false }));        
449                     }
450                 }
451                 else if (Helper.IsEntityTypeBase(edmType) || Helper.IsComplexType(edmType))
452                 {
453                     result = this;
454                 }
455                 else
456                 {
457                     System.Diagnostics.Debug.Assert(false, "Unexpected type found in entity data reader");
458                     return null;
459                 }
460                 System.Threading.Interlocked.CompareExchange(ref _modelTypeUsage, result, null);
461             }
462             return _modelTypeUsage;
463         }
464
465         /// <summary>
466         /// check if "this" is a subtype of the specified TypeUsage
467         /// </summary>
468         /// <param name="typeUsage">The typeUsage to be checked</param>
469         /// <returns>true if this typeUsage is a subtype of the specified typeUsage</returns>
470         public bool IsSubtypeOf(TypeUsage typeUsage)
471         {
472             if (EdmType == null || typeUsage == null)
473             {
474                 return false;
475             }
476
477             return EdmType.IsSubtypeOf(typeUsage.EdmType);
478         }
479
480         private IEnumerable<Facet> GetFacets()
481         {
482             foreach (FacetDescription facetDescription in _edmType.GetAssociatedFacetDescriptions())
483             {
484                 yield return facetDescription.DefaultValueFacet;
485             }
486         }
487
488         internal override void SetReadOnly()
489         {
490             Debug.Fail("TypeUsage.SetReadOnly should not need to ever be called");
491             base.SetReadOnly();
492         }
493
494         /// <summary>
495         /// returns the identity of the type usage
496         /// </summary>
497         internal override String Identity
498         {
499             get
500             {
501                 if (this.Facets.Count == 0)
502                 {
503                     return this.EdmType.Identity;
504                 }
505
506                 if (this._identity == null)
507                 {
508                     StringBuilder builder = new StringBuilder(128);
509                     BuildIdentity(builder);
510                     string identity = builder.ToString();
511                     System.Threading.Interlocked.CompareExchange(ref _identity, identity, null);
512                 }
513                 return this._identity;
514             }
515         }
516         
517         private static IEnumerable<Facet> GetDefaultFacetDescriptionsAndOverrideFacetValues(EdmType type, FacetValues values)
518         {
519             return OverrideFacetValues(type.GetAssociatedFacetDescriptions(),
520                 fd => fd,
521                 fd => fd.DefaultValueFacet,
522                 values);
523         }
524
525
526         private static IEnumerable<Facet> OverrideFacetValues(IEnumerable<Facet> facets, FacetValues values)
527         {
528             return OverrideFacetValues(facets,
529                 f => f.Description,
530                 f => f,
531                 values);
532         }
533
534      
535         private static IEnumerable<Facet> OverrideFacetValues<T>(IEnumerable<T> facetThings,
536                 Func<T, FacetDescription> getDescription,
537                 Func<T, Facet> getFacet,
538                 FacetValues values)
539         {
540             // yield all the non custom values
541             foreach (var thing in facetThings)
542             {
543                 FacetDescription description = getDescription(thing);
544                 Facet facet;    
545                 if (!description.IsConstant && values.TryGetFacet(description, out facet))
546                 {
547                     yield return facet;
548                 }
549                 else
550                 {
551                     yield return getFacet(thing);
552                 }
553             }
554
555         }
556
557         internal override void BuildIdentity(StringBuilder builder)
558         {
559             // if we've already cached the identity, simply append it
560             if (null != _identity)
561             {
562                 builder.Append(_identity);
563                 return;
564             }
565
566             builder.Append(this.EdmType.Identity);
567
568             builder.Append("(");
569             bool first = true;
570             for (int j = 0; j < this.Facets.Count; j++)
571             {
572                 Facet facet = this.Facets[j];
573                 
574                 if (0 <= Array.BinarySearch(s_identityFacets, facet.Name, StringComparer.Ordinal))
575                 {
576                     if (first) { first = false; }
577                     else { builder.Append(","); }
578
579                     builder.Append(facet.Name);
580                     builder.Append("=");
581                     // If the facet is present, add its value to the identity
582                     // We only include built-in system facets for the identity
583                     builder.Append(facet.Value ?? String.Empty);
584                 }                
585             }
586             builder.Append(")");
587         }
588
589         /// <summary>
590         /// </summary>
591         public override string ToString()
592         {
593             return EdmType.ToString();
594         }
595
596         /// <summary>
597         /// EdmEquals override verifying the equivalence of all facets. Two facets are considered
598         /// equal if they have the same name and the same value (Object.Equals)
599         /// </summary>
600         /// <param name="item"></param>
601         /// <returns></returns>
602         internal override bool EdmEquals(MetadataItem item)
603         {
604             // short-circuit if this and other are reference equivalent
605             if (Object.ReferenceEquals(this, item)) { return true; }
606
607             // check type of item
608             if (null == item || BuiltInTypeKind.TypeUsage != item.BuiltInTypeKind) { return false; }
609             TypeUsage other = (TypeUsage)item;
610
611             // verify edm types are equivalent
612             if (!this.EdmType.EdmEquals(other.EdmType)) { return false; }
613
614             // if both usages have default facets, no need to compare
615             if (null == this._facets && null == other._facets) { return true; }
616
617             // initialize facets and compare
618             if (this.Facets.Count != other.Facets.Count) { return false; }
619
620             foreach (Facet thisFacet in this.Facets)
621             {
622                 Facet otherFacet;
623                 if (!other.Facets.TryGetValue(thisFacet.Name, false, out otherFacet))
624                 {
625                     // other type usage doesn't have the same facets as this type usage
626                     return false;
627                 }
628
629                 // check that the facet values are the same
630                 if (!Object.Equals(thisFacet.Value, otherFacet.Value))
631                 {
632                     return false;
633                 }
634             }
635
636             return true;
637         }
638
639         private static void ValidateMaxLength(int maxLength)
640         {
641             if (maxLength <= 0)
642             {
643                 throw EntityUtil.ArgumentOutOfRange(System.Data.Entity.Strings.InvalidMaxLengthSize, "maxLength");
644             }
645         }
646
647         #endregion
648
649     }
650 }