1 //------------------------------------------------------------------------------
2 // <copyright file="DbCommandDefinition.cs" company="Microsoft">
3 // Copyright (c) Microsoft Corporation. All rights reserved.
8 //------------------------------------------------------------------------------
10 using System.Diagnostics;
11 using System.Data.Metadata.Edm;
13 namespace System.Data.Common {
16 /// A prepared command definition, can be cached and reused to avoid
17 /// repreparing a command.
19 [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Naming", "CA1709:IdentifiersShouldBeCasedCorrectly", MessageId = "Db")]
20 public class DbCommandDefinition {
22 private readonly ICloneable _prototype;
25 /// Internal factory method to create the default Command Definition object
26 /// based on a prototype command. The prototype command is cloned
27 /// before the protected constructor is invoked
29 /// <param name="prototype">prototype DbCommand</param>
30 /// <returns>the DbCommandDefinition</returns>
31 internal static DbCommandDefinition CreateCommandDefinition(DbCommand prototype) {
32 EntityUtil.CheckArgumentNull(prototype, "prototype");
33 ICloneable cloneablePrototype = prototype as ICloneable;
34 if (null == cloneablePrototype) {
35 throw EntityUtil.CannotCloneStoreProvider();
37 DbCommand clonedPrototype = (DbCommand)(cloneablePrototype.Clone());
38 return new DbCommandDefinition(clonedPrototype);
42 /// Protected constructor; the command is assumed to be a prototype
43 /// that will be cloned on CreateCommand, and the cloned command will be executed.
45 protected DbCommandDefinition(DbCommand prototype) {
46 EntityUtil.CheckArgumentNull(prototype, "prototype");
47 _prototype = prototype as ICloneable;
48 if (null == _prototype) {
49 throw EntityUtil.CannotCloneStoreProvider();
54 /// Constructor overload for subclasses to use
56 protected DbCommandDefinition() {
60 /// Create a DbCommand object from the definition, that can be executed.
62 /// <returns></returns>
63 public virtual DbCommand CreateCommand() {
64 return (DbCommand)(_prototype.Clone());
67 internal static void PopulateParameterFromTypeUsage(DbParameter parameter, TypeUsage type, bool isOutParam)
69 EntityUtil.CheckArgumentNull(parameter, "parameter");
70 EntityUtil.CheckArgumentNull(type, "type");
72 // parameter.IsNullable - from the NullableConstraintAttribute value
73 parameter.IsNullable = TypeSemantics.IsNullable(type);
75 // parameter.ParameterName - set by the caller;
76 // parameter.SourceColumn - not applicable until we have a data adapter;
77 // parameter.SourceColumnNullMapping - not applicable until we have a data adapter;
78 // parameter.SourceVersion - not applicable until we have a data adapter;
79 // parameter.Value - left unset;
80 // parameter.DbType - determined by the TypeMapping;
81 // parameter.Precision - from the TypeMapping;
82 // parameter.Scale - from the TypeMapping;
83 // parameter.Size - from the TypeMapping;
86 // type.EdmType may not be a primitive type here - e.g. the user specified
87 // a complex or entity type when creating an ObjectParameter instance. To keep
88 // the same behavior we had in previous versions we let it through here. We will
89 // throw an exception later when actually invoking the stored procedure where we
90 // don't allow parameters that are non-primitive.
91 if(Helper.IsPrimitiveType(type.EdmType))
94 if (TryGetDbTypeFromPrimitiveType((PrimitiveType)type.EdmType, out dbType))
99 PopulateBinaryParameter(parameter, type, dbType, isOutParam);
101 case DbType.DateTime:
103 case DbType.DateTimeOffset:
104 PopulateDateTimeParameter(parameter, type, dbType);
107 PopulateDecimalParameter(parameter, type, dbType);
110 PopulateStringParameter(parameter, type, isOutParam);
113 parameter.DbType = dbType;
120 internal static bool TryGetDbTypeFromPrimitiveType(PrimitiveType type, out DbType dbType)
122 switch (type.PrimitiveTypeKind)
124 case PrimitiveTypeKind.Binary:
125 dbType = DbType.Binary;
127 case PrimitiveTypeKind.Boolean:
128 dbType = DbType.Boolean;
130 case PrimitiveTypeKind.Byte:
131 dbType = DbType.Byte;
133 case PrimitiveTypeKind.DateTime:
134 dbType = DbType.DateTime;
136 case PrimitiveTypeKind.Time:
137 dbType = DbType.Time;
139 case PrimitiveTypeKind.DateTimeOffset:
140 dbType = DbType.DateTimeOffset;
142 case PrimitiveTypeKind.Decimal:
143 dbType = DbType.Decimal;
145 case PrimitiveTypeKind.Double:
146 dbType = DbType.Double;
148 case PrimitiveTypeKind.Guid:
149 dbType = DbType.Guid;
151 case PrimitiveTypeKind.Single:
152 dbType = DbType.Single;
154 case PrimitiveTypeKind.SByte:
155 dbType = DbType.SByte;
157 case PrimitiveTypeKind.Int16:
158 dbType = DbType.Int16;
160 case PrimitiveTypeKind.Int32:
161 dbType = DbType.Int32;
163 case PrimitiveTypeKind.Int64:
164 dbType = DbType.Int64;
166 case PrimitiveTypeKind.String:
167 dbType = DbType.String;
170 dbType = default(DbType);
175 private static void PopulateBinaryParameter(DbParameter parameter, TypeUsage type, DbType dbType, bool isOutParam)
177 parameter.DbType = dbType;
179 // For each facet, set the facet value only if we have it, note that it's possible to not have
180 // it in the case the facet value is null
181 SetParameterSize(parameter, type, isOutParam);
184 private static void PopulateDecimalParameter (DbParameter parameter, TypeUsage type, DbType dbType)
186 parameter.DbType = dbType;
187 IDbDataParameter dataParameter = (IDbDataParameter)parameter;
189 // For each facet, set the facet value only if we have it, note that it's possible to not have
190 // it in the case the facet value is null
193 if (TypeHelpers.TryGetPrecision(type, out precision))
195 dataParameter.Precision = precision;
198 if (TypeHelpers.TryGetScale(type, out scale))
200 dataParameter.Scale = scale;
204 private static void PopulateDateTimeParameter(DbParameter parameter, TypeUsage type, DbType dbType)
206 parameter.DbType = dbType;
207 IDbDataParameter dataParameter = (IDbDataParameter)parameter;
209 // For each facet, set the facet value only if we have it, note that it's possible to not have
210 // it in the case the facet value is null
212 if (TypeHelpers.TryGetPrecision(type, out precision))
214 dataParameter.Precision = precision;
219 private static void PopulateStringParameter(DbParameter parameter, TypeUsage type, bool isOutParam)
221 // For each facet, set the facet value only if we have it, note that it's possible to not have
222 // it in the case the facet value is null
224 bool fixedLength = false;
226 if (!TypeHelpers.TryGetIsFixedLength(type, out fixedLength))
228 // If we can't get the fixed length facet value, then default to fixed length = false
232 if (!TypeHelpers.TryGetIsUnicode(type, out unicode))
234 // If we can't get the unicode facet value, then default to unicode = true
240 parameter.DbType = (unicode ? DbType.StringFixedLength : DbType.AnsiStringFixedLength);
244 parameter.DbType = (unicode ? DbType.String : DbType.AnsiString);
247 SetParameterSize(parameter, type, isOutParam);
250 private static void SetParameterSize(DbParameter parameter, TypeUsage type, bool isOutParam)
252 // only set the size if the parameter has a specific size value.
253 Facet maxLengthFacet;
254 if (type.Facets.TryGetValue(DbProviderManifest.MaxLengthFacetName, true, out maxLengthFacet) && maxLengthFacet.Value != null)
256 // only set size if there is a specific size
257 if (!Helper.IsUnboundedFacetValue(maxLengthFacet))
259 parameter.Size = (int)maxLengthFacet.Value;
263 // if it is store procedure parameter and it is unbounded set the size to max
264 parameter.Size = Int32.MaxValue;