1 //---------------------------------------------------------------------
2 // <copyright file="CacheForPrimitiveTypes.cs" company="Microsoft">
3 // Copyright (c) Microsoft Corporation. All rights reserved.
7 // @backupOwner Microsoft
8 //---------------------------------------------------------------------
11 using System.Collections.Generic;
12 using System.Collections.ObjectModel;
13 using System.Data.EntityModel;
14 using System.Diagnostics;
16 using System.Xml.Serialization;
18 using System.Xml.Schema;
20 using System.Data.Common;
21 using System.Globalization;
23 namespace System.Data.Metadata.Edm
25 internal class CacheForPrimitiveTypes
28 // The primitive type kind is a list of enum which the EDM model
29 // Every specific instantiation of the model should map their
30 // primitive types to the edm primitive types.
32 // In this class, primitive type is to be cached
34 // Key for the cache: primitive type kind
35 // Value for the cache: List<PrimitiveType>. A list is used because there an be multiple types mapping to the
36 // same primitive type kind. For example, sqlserver has multiple string types.
38 private List<PrimitiveType>[] _primitiveTypeMap = new List<PrimitiveType>[EdmConstants.NumPrimitiveTypes];
43 /// Add the given primitive type to the primitive type cache
45 /// <param name="type">The primitive type to add</param>
46 internal void Add(PrimitiveType type)
49 List<PrimitiveType> primitiveTypes = EntityUtil.CheckArgumentOutOfRange(_primitiveTypeMap, (int)type.PrimitiveTypeKind, "primitiveTypeKind");
51 // If there isn't a list for the given model type, create one and add it
52 if (primitiveTypes == null)
54 primitiveTypes = new List<PrimitiveType>();
55 primitiveTypes.Add(type);
56 _primitiveTypeMap[(int)type.PrimitiveTypeKind] = primitiveTypes;
60 primitiveTypes.Add(type);
65 /// Try and get the mapped type for the given primitiveTypeKind in the given dataspace
67 /// <param name="primitiveTypeKind">The primitive type kind of the primitive type to retrieve</param>
68 /// <param name="facets">The facets to use in picking the primitive type</param>
69 /// <param name="type">The resulting type</param>
70 /// <returns>Whether a type was retrieved or not</returns>
71 internal bool TryGetType(PrimitiveTypeKind primitiveTypeKind, IEnumerable<Facet> facets, out PrimitiveType type)
75 // Now, see if we have any types for this model type, if so, loop through to find the best matching one
76 List<PrimitiveType> primitiveTypes = EntityUtil.CheckArgumentOutOfRange(_primitiveTypeMap, (int)primitiveTypeKind, "primitiveTypeKind");
77 if ((null != primitiveTypes) && (0 < primitiveTypes.Count))
79 if (primitiveTypes.Count == 1)
81 type = primitiveTypes[0];
87 FacetDescription[] facetDescriptions = EdmProviderManifest.GetInitialFacetDescriptions(primitiveTypeKind);
88 if (facetDescriptions == null)
90 type = primitiveTypes[0];
94 Debug.Assert(facetDescriptions.Length > 0);
95 facets = CacheForPrimitiveTypes.CreateInitialFacets(facetDescriptions);
98 Debug.Assert(type == null, "type must be null here");
99 bool isMaxLengthSentinel = false;
101 // Create a dictionary of facets for easy lookup
102 foreach (Facet facet in facets)
104 if ((primitiveTypeKind == PrimitiveTypeKind.String ||
105 primitiveTypeKind == PrimitiveTypeKind.Binary) &&
106 facet.Value != null &&
107 facet.Name == EdmProviderManifest.MaxLengthFacetName &&
108 Helper.IsUnboundedFacetValue(facet))
110 // MaxLength has the sentinel value. So this facet need not be added.
111 isMaxLengthSentinel = true;
117 // Find a primitive type with the matching constraint
118 foreach (PrimitiveType primitiveType in primitiveTypes)
120 if (isMaxLengthSentinel)
124 type = primitiveType;
125 maxLength = Helper.GetFacet(primitiveType.FacetDescriptions, EdmProviderManifest.MaxLengthFacetName).MaxValue.Value;
129 int newMaxLength = Helper.GetFacet(primitiveType.FacetDescriptions, EdmProviderManifest.MaxLengthFacetName).MaxValue.Value;
130 if (newMaxLength > maxLength)
132 type = primitiveType;
133 maxLength = newMaxLength;
139 type = primitiveType;
144 Debug.Assert(type != null);
151 private static Facet[] CreateInitialFacets(FacetDescription[] facetDescriptions)
153 Debug.Assert(facetDescriptions != null && facetDescriptions.Length > 0);
155 Facet[] facets = new Facet[facetDescriptions.Length];
157 for (int i = 0; i < facetDescriptions.Length; ++i)
159 switch (facetDescriptions[i].FacetName)
161 case DbProviderManifest.MaxLengthFacetName:
162 facets[i] = Facet.Create(facetDescriptions[i], TypeUsage.DefaultMaxLengthFacetValue);
165 case DbProviderManifest.UnicodeFacetName:
166 facets[i] = Facet.Create(facetDescriptions[i], TypeUsage.DefaultUnicodeFacetValue);
169 case DbProviderManifest.FixedLengthFacetName:
170 facets[i] = Facet.Create(facetDescriptions[i], TypeUsage.DefaultFixedLengthFacetValue);
173 case DbProviderManifest.PrecisionFacetName:
174 facets[i] = Facet.Create(facetDescriptions[i], TypeUsage.DefaultPrecisionFacetValue);
177 case DbProviderManifest.ScaleFacetName:
178 facets[i] = Facet.Create(facetDescriptions[i], TypeUsage.DefaultScaleFacetValue);
182 Debug.Assert(false, "Unexpected facet");
191 /// Get the list of the primitive types for the given dataspace
193 /// <returns></returns>
194 internal System.Collections.ObjectModel.ReadOnlyCollection<PrimitiveType> GetTypes()
196 List<PrimitiveType> primitiveTypes = new List<PrimitiveType>();
197 foreach (List<PrimitiveType> types in _primitiveTypeMap)
201 primitiveTypes.AddRange(types);
204 return primitiveTypes.AsReadOnly();