1 //---------------------------------------------------------------------
2 // <copyright file="Parameter.cs" company="Microsoft">
3 // Copyright (c) Microsoft Corporation. All rights reserved.
8 //---------------------------------------------------------------------
10 namespace System.Data.EntityModel.SchemaObjectModel
13 using System.Collections.Generic;
15 using System.Data.Entity;
16 using System.Data.Metadata.Edm;
17 using System.Diagnostics;
18 using System.Globalization;
21 using Som = System.Data.EntityModel.SchemaObjectModel;
24 /// Summary description for StructuredProperty.
26 internal class Parameter : FacetEnabledSchemaElement
28 #region Instance Fields
29 private ParameterDirection _parameterDirection = ParameterDirection.Input;
30 private CollectionKind _collectionKind = CollectionKind.None;
31 private ModelFunctionTypeElement _typeSubElement = null;
32 private bool _isRefType = false;
39 /// <param name="parentElement"></param>
40 internal Parameter(Function parentElement)
43 _typeUsageBuilder = new TypeUsageBuilder(this);
48 #region Public Properties
50 internal ParameterDirection ParameterDirection
54 return _parameterDirection;
58 internal CollectionKind CollectionKind
62 return _collectionKind;
66 _collectionKind = value;
70 internal bool IsRefType
72 get { return _isRefType; }
75 internal override TypeUsage TypeUsage
79 if (_typeSubElement != null)
81 return _typeSubElement.GetTypeUsage();
83 else if (base.TypeUsage == null)
87 else if (CollectionKind != CollectionKind.None)
89 return TypeUsage.Create(new CollectionType(base.TypeUsage));
93 return base.TypeUsage;
100 new internal SchemaType Type
109 internal void WriteIdentity(StringBuilder builder)
111 builder.Append("Parameter(");
112 if (UnresolvedType != null && !UnresolvedType.Trim().Equals(String.Empty))
114 if (_collectionKind != CollectionKind.None)
116 builder.Append("Collection(" + UnresolvedType + ")");
120 builder.Append("Ref(" + UnresolvedType + ")");
124 builder.Append(UnresolvedType);
127 else if (_typeSubElement!=null)
129 _typeSubElement.WriteIdentity(builder);
134 internal override SchemaElement Clone(SchemaElement parentElement)
136 Parameter parameter = new Parameter((Function)parentElement);
137 parameter._collectionKind = _collectionKind;
138 parameter._parameterDirection = _parameterDirection;
139 parameter._type = _type;
140 parameter.Name = this.Name;
141 parameter._typeUsageBuilder = this._typeUsageBuilder;
145 internal bool ResolveNestedTypeNames(Converter.ConversionCache convertedItemCache, Dictionary<Som.SchemaElement, GlobalItem> newGlobalItems)
147 if (_typeSubElement == null)
151 return _typeSubElement.ResolveNameAndSetTypeUsage(convertedItemCache, newGlobalItems);
155 protected override bool HandleAttribute(XmlReader reader)
157 if (base.HandleAttribute(reader))
161 else if (CanHandleAttribute(reader, XmlConstants.TypeElement))
163 HandleTypeAttribute(reader);
166 else if (CanHandleAttribute(reader, XmlConstants.Mode))
168 HandleModeAttribute(reader);
171 else if (_typeUsageBuilder.HandleAttribute(reader))
179 #region Private Methods
181 private void HandleTypeAttribute(XmlReader reader)
183 Debug.Assert(reader != null);
184 Debug.Assert(UnresolvedType == null);
187 if (!Utils.GetString(Schema, reader, out type))
190 TypeModifier typeModifier;
192 Function.RemoveTypeModifier(ref type, out typeModifier, out _isRefType);
194 switch (typeModifier)
196 case TypeModifier.Array:
197 CollectionKind = CollectionKind.Bag;
200 Debug.Assert(typeModifier == TypeModifier.None, string.Format(CultureInfo.CurrentCulture, "Type is not valid for property {0}: {1}. The modifier for the type cannot be used in this context.", FQName, reader.Value));
204 if (!Utils.ValidateDottedName(Schema, reader, type))
207 UnresolvedType = type;
210 private void HandleModeAttribute(XmlReader reader)
212 Debug.Assert(reader != null);
214 string value = reader.Value;
216 if (String.IsNullOrEmpty(value))
221 value = value.Trim();
223 if (!String.IsNullOrEmpty(value))
227 case XmlConstants.In:
228 _parameterDirection = ParameterDirection.Input;
230 case XmlConstants.Out:
231 _parameterDirection = ParameterDirection.Output;
232 if (this.ParentElement.IsComposable && this.ParentElement.IsFunctionImport)
234 AddErrorBadParameterDirection(value, reader, System.Data.Entity.Strings.BadParameterDirectionForComposableFunctions);
237 case XmlConstants.InOut:
238 _parameterDirection = ParameterDirection.InputOutput;
239 if (this.ParentElement.IsComposable && this.ParentElement.IsFunctionImport)
241 AddErrorBadParameterDirection(value, reader, System.Data.Entity.Strings.BadParameterDirectionForComposableFunctions);
246 AddErrorBadParameterDirection(value, reader, System.Data.Entity.Strings.BadParameterDirection);
253 private void AddErrorBadParameterDirection(string value, XmlReader reader, Func<object, object, object, object, string> errorFunc)
255 // don't try to identify the parameter by any of the attributes
256 // because we are still parsing attributes, and we don't know which ones
257 // have been parsed yet.
258 AddError(ErrorCode.BadParameterDirection, EdmSchemaErrorSeverity.Error, reader,
260 this.ParentElement.Parameters.Count, // indexed at 0 to be similar to the old exception
261 this.ParentElement.Name,
262 this.ParentElement.ParentElement.FQName,
266 protected override bool HandleElement(XmlReader reader)
268 if (base.HandleElement(reader))
272 else if (CanHandleElement(reader, XmlConstants.CollectionType))
274 HandleCollectionTypeElement(reader);
277 else if (CanHandleElement(reader, XmlConstants.ReferenceType))
279 HandleReferenceTypeElement(reader);
282 else if (CanHandleElement(reader, XmlConstants.TypeRef))
284 HandleTypeRefElement(reader);
287 else if (CanHandleElement(reader, XmlConstants.RowType))
289 HandleRowTypeElement(reader);
292 else if (Schema.DataModel == SchemaDataModelOption.EntityDataModel)
294 if (CanHandleElement(reader, XmlConstants.ValueAnnotation))
296 // EF does not support this EDM 3.0 element, so ignore it.
300 else if (CanHandleElement(reader, XmlConstants.TypeAnnotation))
302 // EF does not support this EDM 3.0 element, so ignore it.
312 protected void HandleCollectionTypeElement(XmlReader reader)
314 Debug.Assert(reader != null);
316 var subElement = new CollectionTypeElement(this);
317 subElement.Parse(reader);
318 _typeSubElement = subElement;
321 protected void HandleReferenceTypeElement(XmlReader reader)
323 Debug.Assert(reader != null);
325 var subElement = new ReferenceTypeElement(this);
326 subElement.Parse(reader);
327 _typeSubElement = subElement;
330 protected void HandleTypeRefElement(XmlReader reader)
332 Debug.Assert(reader != null);
334 var subElement = new TypeRefElement(this);
335 subElement.Parse(reader);
336 _typeSubElement = subElement;
339 protected void HandleRowTypeElement(XmlReader reader)
341 Debug.Assert(reader != null);
343 var subElement = new RowTypeElement(this);
344 subElement.Parse(reader);
345 _typeSubElement = subElement;
350 internal override void ResolveTopLevelNames()
352 // If type was defined as an attribute: <ReturnType Type="int"/>
353 if (_unresolvedType != null)
355 base.ResolveTopLevelNames();
358 // If type was defined as a subelement: <ReturnType><CollectionType>...</CollectionType></ReturnType>
359 if (_typeSubElement != null)
361 _typeSubElement.ResolveTopLevelNames();
365 internal override void Validate()
369 ValidationHelper.ValidateTypeDeclaration(this, _type, _typeSubElement);
371 if (Schema.DataModel != SchemaDataModelOption.EntityDataModel)
373 Debug.Assert(Schema.DataModel == SchemaDataModelOption.ProviderDataModel ||
374 Schema.DataModel == SchemaDataModelOption.ProviderManifestModel, "Unexpected data model");
376 bool collectionAllowed = this.ParentElement.IsAggregate;
378 // Only scalar parameters are allowed for functions in s-space.
379 Debug.Assert(_typeSubElement == null, "Unexpected type subelement inside <Parameter> element.");
380 if (_type != null && (_type is ScalarType == false || (!collectionAllowed && _collectionKind != CollectionKind.None)))
382 string typeName = "";
385 typeName = Function.GetTypeNameForErrorMessage(_type, _collectionKind, _isRefType);
387 else if (_typeSubElement != null)
389 typeName = _typeSubElement.FQName;
391 if (Schema.DataModel == SchemaDataModelOption.ProviderManifestModel)
393 AddError(ErrorCode.FunctionWithNonEdmTypeNotSupported,
394 EdmSchemaErrorSeverity.Error,
396 System.Data.Entity.Strings.FunctionWithNonEdmPrimitiveTypeNotSupported(typeName, this.ParentElement.FQName));
400 AddError(ErrorCode.FunctionWithNonPrimitiveTypeNotSupported,
401 EdmSchemaErrorSeverity.Error,
403 System.Data.Entity.Strings.FunctionWithNonPrimitiveTypeNotSupported(typeName, this.ParentElement.FQName));
409 ValidationHelper.ValidateFacets(this, _type, _typeUsageBuilder);
413 ValidationHelper.ValidateRefType(this, _type);
417 if (_typeSubElement != null)
419 _typeSubElement.Validate();