338 lines
11 KiB
C#
338 lines
11 KiB
C#
|
//---------------------------------------------------------------------
|
||
|
// <copyright file="ObjectParameter.cs" company="Microsoft">
|
||
|
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||
|
// </copyright>
|
||
|
//
|
||
|
// @owner [....]
|
||
|
// @backupowner [....]
|
||
|
//---------------------------------------------------------------------
|
||
|
|
||
|
namespace System.Data.Objects
|
||
|
{
|
||
|
using System;
|
||
|
using System.Data;
|
||
|
using System.Data.Common.CommandTrees;
|
||
|
using System.Data.Metadata.Edm;
|
||
|
using System.Diagnostics;
|
||
|
|
||
|
/// <summary>
|
||
|
/// This class represents a query parameter at the object layer, which consists
|
||
|
/// of a Name, a Type and a Value.
|
||
|
/// </summary>
|
||
|
public sealed class ObjectParameter
|
||
|
{
|
||
|
#region Static Methods
|
||
|
|
||
|
// --------------
|
||
|
// Static Methods
|
||
|
// --------------
|
||
|
|
||
|
#region ValidateParameterName
|
||
|
|
||
|
/// <summary>
|
||
|
/// This internal method uses regular expression matching to ensure that the
|
||
|
/// specified parameter name is valid. Parameter names must start with a letter,
|
||
|
/// and may only contain letters (A-Z, a-z), numbers (0-9) and underscores (_).
|
||
|
/// </summary>
|
||
|
internal static bool ValidateParameterName (string name)
|
||
|
{
|
||
|
// Note: Parameter names must begin with a letter, and may contain only
|
||
|
// letters, numbers and underscores.
|
||
|
return DbCommandTree.IsValidParameterName(name);
|
||
|
}
|
||
|
|
||
|
#endregion
|
||
|
|
||
|
#endregion
|
||
|
|
||
|
#region Public Constructors
|
||
|
|
||
|
// -------------------
|
||
|
// Public Constructors
|
||
|
// -------------------
|
||
|
|
||
|
#region ObjectParameter (string, Type)
|
||
|
|
||
|
/// <summary>
|
||
|
/// This constructor creates an unbound (i.e., value-less) parameter from the
|
||
|
/// specified name and type. The value can be set at any time through the
|
||
|
/// public 'Value' property.
|
||
|
/// </summary>
|
||
|
/// <param name="name">
|
||
|
/// The parameter name.
|
||
|
/// </param>
|
||
|
/// <param name="type">
|
||
|
/// The CLR type of the parameter.
|
||
|
/// </param>
|
||
|
/// <returns>
|
||
|
/// A new unbound ObjectParameter instance.
|
||
|
/// </returns>
|
||
|
/// <exception cref="ArgumentNullException">
|
||
|
/// If the value of either argument is null.
|
||
|
/// </exception>
|
||
|
/// <exception cref="ArgumentOutOfRangeException">
|
||
|
/// If the value of the name argument is invalid. Parameter names must start
|
||
|
/// with a letter and may only contain letters (A-Z, a-z), numbers (0-9) and
|
||
|
/// underscores (_).
|
||
|
/// </exception>
|
||
|
public ObjectParameter (string name, Type type)
|
||
|
{
|
||
|
EntityUtil.CheckArgumentNull(name, "name");
|
||
|
EntityUtil.CheckArgumentNull(type, "type");
|
||
|
|
||
|
if (!ObjectParameter.ValidateParameterName(name))
|
||
|
{
|
||
|
throw EntityUtil.Argument(System.Data.Entity.Strings.ObjectParameter_InvalidParameterName(name), "name");
|
||
|
}
|
||
|
|
||
|
this._name = name;
|
||
|
this._type = type;
|
||
|
|
||
|
// If the parameter type is Nullable<>, we need to extract out the underlying
|
||
|
// Nullable<> type argument.
|
||
|
this._mappableType = System.Data.Objects.ELinq.TypeSystem.GetNonNullableType(this._type);
|
||
|
}
|
||
|
|
||
|
#endregion
|
||
|
|
||
|
#region ObjectParameter (string, object)
|
||
|
|
||
|
/// <summary>
|
||
|
/// This constructor creates a fully-bound (i.e., valued) parameter from the
|
||
|
/// specified name and value. The type is inferred from the initial value, but
|
||
|
/// the value can be changed at any time through the public 'Value' property.
|
||
|
/// </summary>
|
||
|
/// <param name="name">
|
||
|
/// The parameter name.
|
||
|
/// </param>
|
||
|
/// <param name="value">
|
||
|
/// The initial value (and inherently, type) of the parameter.
|
||
|
/// </param>
|
||
|
/// <returns>
|
||
|
/// A new fully-bound ObjectParameter instance.
|
||
|
/// </returns>
|
||
|
/// <exception cref="ArgumentNullException">
|
||
|
/// If the value of either argument is null.
|
||
|
/// </exception>
|
||
|
/// <exception cref="ArgumentOutOfRangeException">
|
||
|
/// If the value of the name argument is invalid. Parameter names must start
|
||
|
/// with a letter and may only contain letters (A-Z, a-z), numbers (0-9) and
|
||
|
/// underscores (_).
|
||
|
/// </exception>
|
||
|
public ObjectParameter (string name, object value)
|
||
|
{
|
||
|
EntityUtil.CheckArgumentNull(name, "name");
|
||
|
EntityUtil.CheckArgumentNull(value, "value");
|
||
|
|
||
|
if (!ObjectParameter.ValidateParameterName(name))
|
||
|
{
|
||
|
throw EntityUtil.Argument(System.Data.Entity.Strings.ObjectParameter_InvalidParameterName(name), "name");
|
||
|
}
|
||
|
|
||
|
this._name = name;
|
||
|
this._type = value.GetType();
|
||
|
this._value = value;
|
||
|
|
||
|
// If the parameter type is Nullable<>, we need to extract out the underlying
|
||
|
// Nullable<> type argument.
|
||
|
this._mappableType = System.Data.Objects.ELinq.TypeSystem.GetNonNullableType(this._type);
|
||
|
}
|
||
|
|
||
|
#endregion
|
||
|
|
||
|
#endregion
|
||
|
|
||
|
#region Private Constructors
|
||
|
|
||
|
// -------------------
|
||
|
// Copy Constructor
|
||
|
// -------------------
|
||
|
|
||
|
/// <summary>
|
||
|
/// This constructor is used by <see cref="ShallowCopy"/> to create a new ObjectParameter
|
||
|
/// with field values taken from the field values of an existing ObjectParameter.
|
||
|
/// </summary>
|
||
|
/// <param name="template">
|
||
|
/// The existing ObjectParameter instance from which field values should be taken.
|
||
|
/// </param>
|
||
|
/// <returns>
|
||
|
/// A new ObjectParameter instance with the same field values as the specified ObjectParameter
|
||
|
/// </returns>
|
||
|
private ObjectParameter(ObjectParameter template)
|
||
|
{
|
||
|
Debug.Assert(template != null, "Template ObjectParameter cannot be null");
|
||
|
|
||
|
this._name = template._name;
|
||
|
this._type = template._type;
|
||
|
this._mappableType = template._mappableType;
|
||
|
this._effectiveType = template._effectiveType;
|
||
|
this._value = template._value;
|
||
|
}
|
||
|
|
||
|
#endregion
|
||
|
|
||
|
#region Private Fields
|
||
|
|
||
|
// --------------
|
||
|
// Private Fields
|
||
|
// --------------
|
||
|
|
||
|
/// <summary>
|
||
|
/// The name of the parameter. Cannot be null and is immutable.
|
||
|
/// </summary>
|
||
|
private string _name;
|
||
|
|
||
|
/// <summary>
|
||
|
/// The CLR type of the parameter. Cannot be null and is immutable.
|
||
|
/// </summary>
|
||
|
private Type _type;
|
||
|
|
||
|
/// <summary>
|
||
|
/// The mappable CLR type of the parameter. Unless the parameter type is
|
||
|
/// Nullable, this type is equal to the parameter type. In the case of
|
||
|
/// Nullable parameters, this type is the underlying Nullable argument
|
||
|
/// type. Cannot be null and is immutable.
|
||
|
/// </summary>
|
||
|
private Type _mappableType;
|
||
|
|
||
|
/// <summary>
|
||
|
/// Used to specify the exact metadata type of this parameter.
|
||
|
/// Typically null, can only be set using the internal <see cref="TypeUsage"/> property.
|
||
|
/// </summary>
|
||
|
private TypeUsage _effectiveType;
|
||
|
|
||
|
/// <summary>
|
||
|
/// The value of the parameter. Does not need to be bound until execution
|
||
|
/// time and can be modified at any time.
|
||
|
/// </summary>
|
||
|
private object _value;
|
||
|
|
||
|
#endregion
|
||
|
|
||
|
#region Public Properties
|
||
|
|
||
|
// -----------------
|
||
|
// Public Properties
|
||
|
// -----------------
|
||
|
|
||
|
/// <summary>
|
||
|
/// The parameter name, which can only be set through a constructor.
|
||
|
/// </summary>
|
||
|
public string Name
|
||
|
{
|
||
|
get
|
||
|
{
|
||
|
return this._name;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/// <summary>
|
||
|
/// The parameter type, which can only be set through a constructor.
|
||
|
/// </summary>
|
||
|
public Type ParameterType
|
||
|
{
|
||
|
get
|
||
|
{
|
||
|
return this._type;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/// <summary>
|
||
|
/// The parameter value, which can be set at any time (and subsequently
|
||
|
/// changed) before query execution. Note that type-checking is not
|
||
|
/// enforced between the declared parameter type and the type of the
|
||
|
/// specified value; such validation is left up to the underlying
|
||
|
/// provider(s) at execution time.
|
||
|
/// </summary>
|
||
|
public object Value
|
||
|
{
|
||
|
get
|
||
|
{
|
||
|
return this._value;
|
||
|
}
|
||
|
|
||
|
set
|
||
|
{
|
||
|
this._value = value;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
#endregion
|
||
|
|
||
|
#region Internal Properties
|
||
|
|
||
|
// -------------------
|
||
|
// Internal Properties
|
||
|
// -------------------
|
||
|
|
||
|
/// <summary>
|
||
|
/// Gets or sets a <see cref="TypeUsage"/> that specifies the exact
|
||
|
/// type of which the parameter value is considered an instance.
|
||
|
/// </summary>
|
||
|
internal TypeUsage TypeUsage
|
||
|
{
|
||
|
get
|
||
|
{
|
||
|
return _effectiveType;
|
||
|
}
|
||
|
|
||
|
set
|
||
|
{
|
||
|
Debug.Assert(null == _effectiveType, "Effective type should only be set once");
|
||
|
_effectiveType = value;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/// <summary>
|
||
|
/// The mappable parameter type; this is primarily used to handle the case of
|
||
|
/// Nullable parameter types. For example, metadata knows nothing about 'int?',
|
||
|
/// only 'Int32'. For internal use only.
|
||
|
/// </summary>
|
||
|
internal Type MappableType
|
||
|
{
|
||
|
get
|
||
|
{
|
||
|
return this._mappableType;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
#endregion
|
||
|
|
||
|
#region Internal Methods
|
||
|
|
||
|
// ----------------
|
||
|
// Internal Methods
|
||
|
// ----------------
|
||
|
|
||
|
/// <summary>
|
||
|
/// Creates a new ObjectParameter instance with identical field values to this instance.
|
||
|
/// </summary>
|
||
|
/// <returns>The new ObjectParameter instance</returns>
|
||
|
internal ObjectParameter ShallowCopy()
|
||
|
{
|
||
|
return new ObjectParameter(this);
|
||
|
}
|
||
|
|
||
|
/// <summary>
|
||
|
/// This internal method ensures that the specified type is a scalar
|
||
|
/// type supported by the underlying provider by ensuring that scalar
|
||
|
/// metadata for this type is retrievable.
|
||
|
/// </summary>
|
||
|
internal bool ValidateParameterType (ClrPerspective perspective)
|
||
|
{
|
||
|
TypeUsage type = null;
|
||
|
|
||
|
// The parameter type metadata is only valid if it's scalar or enumeration type metadata.
|
||
|
if ((perspective.TryGetType(this._mappableType, out type)) &&
|
||
|
(TypeSemantics.IsScalarType(type)))
|
||
|
{
|
||
|
return true;
|
||
|
}
|
||
|
|
||
|
return false;
|
||
|
}
|
||
|
|
||
|
#endregion
|
||
|
}
|
||
|
}
|