1 //---------------------------------------------------------------------
2 // <copyright file="ObjectParameter.cs" company="Microsoft">
3 // Copyright (c) Microsoft Corporation. All rights reserved.
8 //---------------------------------------------------------------------
10 namespace System.Data.Objects
14 using System.Data.Common.CommandTrees;
15 using System.Data.Metadata.Edm;
16 using System.Diagnostics;
19 /// This class represents a query parameter at the object layer, which consists
20 /// of a Name, a Type and a Value.
22 public sealed class ObjectParameter
24 #region Static Methods
30 #region ValidateParameterName
33 /// This internal method uses regular expression matching to ensure that the
34 /// specified parameter name is valid. Parameter names must start with a letter,
35 /// and may only contain letters (A-Z, a-z), numbers (0-9) and underscores (_).
37 internal static bool ValidateParameterName (string name)
39 // Note: Parameter names must begin with a letter, and may contain only
40 // letters, numbers and underscores.
41 return DbCommandTree.IsValidParameterName(name);
48 #region Public Constructors
50 // -------------------
51 // Public Constructors
52 // -------------------
54 #region ObjectParameter (string, Type)
57 /// This constructor creates an unbound (i.e., value-less) parameter from the
58 /// specified name and type. The value can be set at any time through the
59 /// public 'Value' property.
61 /// <param name="name">
62 /// The parameter name.
64 /// <param name="type">
65 /// The CLR type of the parameter.
68 /// A new unbound ObjectParameter instance.
70 /// <exception cref="ArgumentNullException">
71 /// If the value of either argument is null.
73 /// <exception cref="ArgumentOutOfRangeException">
74 /// If the value of the name argument is invalid. Parameter names must start
75 /// with a letter and may only contain letters (A-Z, a-z), numbers (0-9) and
78 public ObjectParameter (string name, Type type)
80 EntityUtil.CheckArgumentNull(name, "name");
81 EntityUtil.CheckArgumentNull(type, "type");
83 if (!ObjectParameter.ValidateParameterName(name))
85 throw EntityUtil.Argument(System.Data.Entity.Strings.ObjectParameter_InvalidParameterName(name), "name");
91 // If the parameter type is Nullable<>, we need to extract out the underlying
92 // Nullable<> type argument.
93 this._mappableType = System.Data.Objects.ELinq.TypeSystem.GetNonNullableType(this._type);
98 #region ObjectParameter (string, object)
101 /// This constructor creates a fully-bound (i.e., valued) parameter from the
102 /// specified name and value. The type is inferred from the initial value, but
103 /// the value can be changed at any time through the public 'Value' property.
105 /// <param name="name">
106 /// The parameter name.
108 /// <param name="value">
109 /// The initial value (and inherently, type) of the parameter.
112 /// A new fully-bound ObjectParameter instance.
114 /// <exception cref="ArgumentNullException">
115 /// If the value of either argument is null.
117 /// <exception cref="ArgumentOutOfRangeException">
118 /// If the value of the name argument is invalid. Parameter names must start
119 /// with a letter and may only contain letters (A-Z, a-z), numbers (0-9) and
122 public ObjectParameter (string name, object value)
124 EntityUtil.CheckArgumentNull(name, "name");
125 EntityUtil.CheckArgumentNull(value, "value");
127 if (!ObjectParameter.ValidateParameterName(name))
129 throw EntityUtil.Argument(System.Data.Entity.Strings.ObjectParameter_InvalidParameterName(name), "name");
133 this._type = value.GetType();
136 // If the parameter type is Nullable<>, we need to extract out the underlying
137 // Nullable<> type argument.
138 this._mappableType = System.Data.Objects.ELinq.TypeSystem.GetNonNullableType(this._type);
145 #region Private Constructors
147 // -------------------
149 // -------------------
152 /// This constructor is used by <see cref="ShallowCopy"/> to create a new ObjectParameter
153 /// with field values taken from the field values of an existing ObjectParameter.
155 /// <param name="template">
156 /// The existing ObjectParameter instance from which field values should be taken.
159 /// A new ObjectParameter instance with the same field values as the specified ObjectParameter
161 private ObjectParameter(ObjectParameter template)
163 Debug.Assert(template != null, "Template ObjectParameter cannot be null");
165 this._name = template._name;
166 this._type = template._type;
167 this._mappableType = template._mappableType;
168 this._effectiveType = template._effectiveType;
169 this._value = template._value;
174 #region Private Fields
181 /// The name of the parameter. Cannot be null and is immutable.
183 private string _name;
186 /// The CLR type of the parameter. Cannot be null and is immutable.
191 /// The mappable CLR type of the parameter. Unless the parameter type is
192 /// Nullable, this type is equal to the parameter type. In the case of
193 /// Nullable parameters, this type is the underlying Nullable argument
194 /// type. Cannot be null and is immutable.
196 private Type _mappableType;
199 /// Used to specify the exact metadata type of this parameter.
200 /// Typically null, can only be set using the internal <see cref="TypeUsage"/> property.
202 private TypeUsage _effectiveType;
205 /// The value of the parameter. Does not need to be bound until execution
206 /// time and can be modified at any time.
208 private object _value;
212 #region Public Properties
219 /// The parameter name, which can only be set through a constructor.
230 /// The parameter type, which can only be set through a constructor.
232 public Type ParameterType
241 /// The parameter value, which can be set at any time (and subsequently
242 /// changed) before query execution. Note that type-checking is not
243 /// enforced between the declared parameter type and the type of the
244 /// specified value; such validation is left up to the underlying
245 /// provider(s) at execution time.
262 #region Internal Properties
264 // -------------------
265 // Internal Properties
266 // -------------------
269 /// Gets or sets a <see cref="TypeUsage"/> that specifies the exact
270 /// type of which the parameter value is considered an instance.
272 internal TypeUsage TypeUsage
276 return _effectiveType;
281 Debug.Assert(null == _effectiveType, "Effective type should only be set once");
282 _effectiveType = value;
287 /// The mappable parameter type; this is primarily used to handle the case of
288 /// Nullable parameter types. For example, metadata knows nothing about 'int?',
289 /// only 'Int32'. For internal use only.
291 internal Type MappableType
295 return this._mappableType;
301 #region Internal Methods
308 /// Creates a new ObjectParameter instance with identical field values to this instance.
310 /// <returns>The new ObjectParameter instance</returns>
311 internal ObjectParameter ShallowCopy()
313 return new ObjectParameter(this);
317 /// This internal method ensures that the specified type is a scalar
318 /// type supported by the underlying provider by ensuring that scalar
319 /// metadata for this type is retrievable.
321 internal bool ValidateParameterType (ClrPerspective perspective)
323 TypeUsage type = null;
325 // The parameter type metadata is only valid if it's scalar or enumeration type metadata.
326 if ((perspective.TryGetType(this._mappableType, out type)) &&
327 (TypeSemantics.IsScalarType(type)))