1 //------------------------------------------------------------------------------
2 // <copyright file="SqlTypesAssembly.cs" company="Microsoft">
3 // Copyright (c) Microsoft Corporation. All rights reserved.
7 // @backupOwner Microsoft
8 //------------------------------------------------------------------------------
10 using System
.Collections
.Generic
;
11 using System
.Data
.Common
.Utils
;
12 using System
.Data
.Spatial
;
13 using System
.Data
.SqlClient
.Internal
;
14 using System
.Diagnostics
;
16 using System
.Linq
.Expressions
;
17 using System
.Reflection
;
19 namespace System
.Data
.SqlClient
21 internal static class Expressions
23 internal static Expression Null
<TNullType
>()
25 return Expression
.Constant(null, typeof(TNullType
));
28 internal static Expression
Null(Type nullType
)
30 return Expression
.Constant(null, nullType
);
33 internal static Expression
<Func
<TArg
, TResult
>> Lambda
<TArg
, TResult
>(string argumentName
, Func
<ParameterExpression
, Expression
> createLambdaBodyGivenParameter
)
35 ParameterExpression argParam
= Expression
.Parameter(typeof(TArg
), argumentName
);
36 Expression lambdaBody
= createLambdaBodyGivenParameter(argParam
);
37 return Expression
.Lambda
<Func
<TArg
, TResult
>>(lambdaBody
, argParam
);
40 internal static Expression
Call(this Expression exp
, string methodName
)
42 return Expression
.Call(exp
, methodName
, Type
.EmptyTypes
);
45 internal static Expression
ConvertTo(this Expression exp
, Type convertToType
)
47 return Expression
.Convert(exp
, convertToType
);
50 internal static Expression ConvertTo
<TConvertToType
>(this Expression exp
)
52 return Expression
.Convert(exp
, typeof(TConvertToType
));
55 internal sealed class ConditionalExpressionBuilder
57 private readonly Expression condition
;
58 private readonly Expression ifTrueThen
;
60 internal ConditionalExpressionBuilder(Expression conditionExpression
, Expression ifTrueExpression
)
62 this.condition
= conditionExpression
;
63 this.ifTrueThen
= ifTrueExpression
;
66 internal Expression
Else(Expression resultIfFalse
)
68 return Expression
.Condition(this.condition
, ifTrueThen
, resultIfFalse
);
72 internal static ConditionalExpressionBuilder
IfTrueThen(this Expression conditionExp
, Expression resultIfTrue
)
74 return new ConditionalExpressionBuilder(conditionExp
, resultIfTrue
);
77 internal static Expression Property
<TPropertyType
>(this Expression exp
, string propertyName
)
79 PropertyInfo prop
= exp
.Type
.GetProperty(propertyName
, BindingFlags
.Instance
| BindingFlags
.Public
);
80 Debug
.Assert(prop
!= null, "Type '" + exp
.Type
.FullName
+ "' does not declare a public instance property with the name '" + propertyName
+ "'");
82 return Expression
.Property(exp
, prop
);
87 /// SqlTypesAssembly allows for late binding to the capabilities of a specific version of the Microsoft.SqlServer.Types assembly
89 internal sealed class SqlTypesAssembly
91 private static readonly System
.Collections
.ObjectModel
.ReadOnlyCollection
<string> preferredSqlTypesAssemblies
= new List
<string>()
93 "Microsoft.SqlServer.Types, Version=11.0.0.0, Culture=neutral, PublicKeyToken=89845dcd8080cc91",
94 "Microsoft.SqlServer.Types, Version=10.0.0.0, Culture=neutral, PublicKeyToken=89845dcd8080cc91",
97 private static SqlTypesAssembly
BindToLatest()
99 Assembly sqlTypesAssembly
= null;
100 foreach (string assemblyFullName
in preferredSqlTypesAssemblies
)
102 AssemblyName asmName
= new AssemblyName(assemblyFullName
);
105 sqlTypesAssembly
= Assembly
.Load(asmName
);
108 catch (FileNotFoundException
)
111 catch (FileLoadException
)
116 if (sqlTypesAssembly
!= null)
118 return new SqlTypesAssembly(sqlTypesAssembly
);
123 internal static bool TryGetSqlTypesAssembly(Assembly assembly
, out SqlTypesAssembly sqlAssembly
)
125 if (IsKnownAssembly(assembly
))
127 sqlAssembly
= new SqlTypesAssembly(assembly
);
134 private static bool IsKnownAssembly(Assembly assembly
)
136 foreach (string knownAssemblyFullName
in preferredSqlTypesAssemblies
)
138 if (EntityUtil
.AssemblyNamesMatch(assembly
.FullName
, new AssemblyName(knownAssemblyFullName
)))
146 private static Singleton
<SqlTypesAssembly
> latestVersion
= new Singleton
<SqlTypesAssembly
>(BindToLatest
);
149 /// Returns the highest available version of the Microsoft.SqlServer.Types assembly that could be located using Assembly.Load; may return <c>null</c> if no version of the assembly could be found.
151 internal static SqlTypesAssembly Latest { get { return latestVersion.Value; }
}
153 private SqlTypesAssembly(Assembly sqlSpatialAssembly
)
155 // Retrieve SQL Server spatial types and static constructor methods
156 Type sqlGeog
= sqlSpatialAssembly
.GetType("Microsoft.SqlServer.Types.SqlGeography", throwOnError
: true);
157 Type sqlGeom
= sqlSpatialAssembly
.GetType("Microsoft.SqlServer.Types.SqlGeometry", throwOnError
: true);
159 Debug
.Assert(sqlGeog
!= null, "SqlGeography type was not properly retrieved?");
160 Debug
.Assert(sqlGeom
!= null, "SqlGeometry type was not properly retrieved?");
162 this.SqlGeographyType
= sqlGeog
;
163 this.sqlGeographyFromWKTString
= CreateStaticConstructorDelegate
<string>(sqlGeog
, "STGeomFromText");
164 this.sqlGeographyFromWKBByteArray
= CreateStaticConstructorDelegate
<byte[]>(sqlGeog
, "STGeomFromWKB");
165 this.sqlGeographyFromGMLReader
= CreateStaticConstructorDelegate
<System
.Xml
.XmlReader
>(sqlGeog
, "GeomFromGml");
167 this.SqlGeometryType
= sqlGeom
;
168 this.sqlGeometryFromWKTString
= CreateStaticConstructorDelegate
<string>(sqlGeom
, "STGeomFromText");
169 this.sqlGeometryFromWKBByteArray
= CreateStaticConstructorDelegate
<byte[]>(sqlGeom
, "STGeomFromWKB");
170 this.sqlGeometryFromGMLReader
= CreateStaticConstructorDelegate
<System
.Xml
.XmlReader
>(sqlGeom
, "GeomFromGml");
172 // Retrieve SQL Server specific primitive types
173 MethodInfo asTextMethod
= this.SqlGeometryType
.GetMethod("STAsText", BindingFlags
.Public
| BindingFlags
.Instance
, null, Type
.EmptyTypes
, null);
174 this.SqlCharsType
= asTextMethod
.ReturnType
;
175 this.SqlStringType
= this.SqlCharsType
.Assembly
.GetType("System.Data.SqlTypes.SqlString", throwOnError
: true);
176 this.SqlBooleanType
= this.SqlCharsType
.Assembly
.GetType("System.Data.SqlTypes.SqlBoolean", throwOnError
: true);
177 this.SqlBytesType
= this.SqlCharsType
.Assembly
.GetType("System.Data.SqlTypes.SqlBytes", throwOnError
: true);
178 this.SqlDoubleType
= this.SqlCharsType
.Assembly
.GetType("System.Data.SqlTypes.SqlDouble", throwOnError
: true);
179 this.SqlInt32Type
= this.SqlCharsType
.Assembly
.GetType("System.Data.SqlTypes.SqlInt32", throwOnError
: true);
180 this.SqlXmlType
= this.SqlCharsType
.Assembly
.GetType("System.Data.SqlTypes.SqlXml", throwOnError
: true);
182 // Create type conversion delegates to SQL Server types
183 this.sqlBytesFromByteArray
= Expressions
.Lambda
<byte[], object>("binaryValue", bytesVal
=> BuildConvertToSqlBytes(bytesVal
, this.SqlBytesType
)).Compile();
184 this.sqlStringFromString
= Expressions
.Lambda
<string, object>("stringValue", stringVal
=> BuildConvertToSqlString(stringVal
, this.SqlStringType
)).Compile();
185 this.sqlCharsFromString
= Expressions
.Lambda
<string, object>("stringValue", stringVal
=> BuildConvertToSqlChars(stringVal
, this.SqlCharsType
)).Compile();
186 this.sqlXmlFromXmlReader
= Expressions
.Lambda
<System
.Xml
.XmlReader
, object>("readerVaue", readerVal
=> BuildConvertToSqlXml(readerVal
, this.SqlXmlType
)).Compile();
188 // Create type conversion delegates from SQL Server types; all arguments are typed as 'object' and require Expression.Convert before use of members of the SQL Server type.
190 // Explicit cast from SqlBoolean to bool
191 this.sqlBooleanToBoolean
= Expressions
.Lambda
<object, bool>("sqlBooleanValue", sqlBoolVal
=> sqlBoolVal
.ConvertTo(this.SqlBooleanType
).ConvertTo
<bool>()).Compile();
193 // Explicit cast from SqlBoolean to bool? for non-Null values; otherwise null
194 this.sqlBooleanToNullableBoolean
= Expressions
.Lambda
<object, bool?>("sqlBooleanValue", sqlBoolVal
=>
195 sqlBoolVal
.ConvertTo(this.SqlBooleanType
).Property
<bool>("IsNull")
196 .IfTrueThen(Expressions
.Null
<bool?>())
197 .Else(sqlBoolVal
.ConvertTo(this.SqlBooleanType
).ConvertTo
<bool>().ConvertTo
<bool?>())).Compile();
199 // SqlBytes has instance byte[] property 'Value'
200 this.sqlBytesToByteArray
= Expressions
.Lambda
<object, byte[]>("sqlBytesValue", sqlBytesVal
=> sqlBytesVal
.ConvertTo(this.SqlBytesType
).Property
<byte[]>("Value")).Compile();
202 // SqlChars -> SqlString, SqlString has instance string property 'Value'
203 this.sqlCharsToString
= Expressions
.Lambda
<object, string>("sqlCharsValue", sqlCharsVal
=> sqlCharsVal
.ConvertTo(this.SqlCharsType
).Call("ToSqlString").Property
<string>("Value")).Compile();
205 // Explicit cast from SqlString to string
206 this.sqlStringToString
= Expressions
.Lambda
<object, string>("sqlStringValue", sqlStringVal
=> sqlStringVal
.ConvertTo(this.SqlStringType
).Property
<string>("Value")).Compile();
208 // Explicit cast from SqlDouble to double
209 this.sqlDoubleToDouble
= Expressions
.Lambda
<object, double>("sqlDoubleValue", sqlDoubleVal
=> sqlDoubleVal
.ConvertTo(this.SqlDoubleType
).ConvertTo
<double>()).Compile();
211 // Explicit cast from SqlDouble to double? for non-Null values; otherwise null
212 this.sqlDoubleToNullableDouble
= Expressions
.Lambda
<object, double?>("sqlDoubleValue", sqlDoubleVal
=>
213 sqlDoubleVal
.ConvertTo(this.SqlDoubleType
).Property
<bool>("IsNull")
214 .IfTrueThen(Expressions
.Null
<double?>())
215 .Else(sqlDoubleVal
.ConvertTo(this.SqlDoubleType
).ConvertTo
<double>().ConvertTo
<double?>())).Compile();
217 // Explicit cast from SqlInt32 to int
218 this.sqlInt32ToInt
= Expressions
.Lambda
<object, int>("sqlInt32Value", sqlInt32Val
=> sqlInt32Val
.ConvertTo(this.SqlInt32Type
).ConvertTo
<int>()).Compile();
220 // Explicit cast from SqlInt32 to int? for non-Null values; otherwise null
221 this.sqlInt32ToNullableInt
= Expressions
.Lambda
<object, int?>("sqlInt32Value", sqlInt32Val
=>
222 sqlInt32Val
.ConvertTo(this.SqlInt32Type
).Property
<bool>("IsNull")
223 .IfTrueThen(Expressions
.Null
<int?>())
224 .Else(sqlInt32Val
.ConvertTo(this.SqlInt32Type
).ConvertTo
<int>().ConvertTo
<int?>())).Compile();
226 // SqlXml has instance string property 'Value'
227 this.sqlXmlToString
= Expressions
.Lambda
<object, string>("sqlXmlValue", sqlXmlVal
=> sqlXmlVal
.ConvertTo(this.SqlXmlType
).Property
<string>("Value")).Compile();
229 this.isSqlGeographyNull
= Expressions
.Lambda
<object, bool>("sqlGeographyValue", sqlGeographyValue
=> sqlGeographyValue
.ConvertTo(this.SqlGeographyType
).Property
<bool>("IsNull")).Compile();
230 this.isSqlGeometryNull
= Expressions
.Lambda
<object, bool>("sqlGeometryValue", sqlGeometryValue
=> sqlGeometryValue
.ConvertTo(this.SqlGeometryType
).Property
<bool>("IsNull")).Compile();
232 this.geographyAsTextZMAsSqlChars
= Expressions
.Lambda
<object, object>("sqlGeographyValue", sqlGeographyValue
=> sqlGeographyValue
.ConvertTo(this.SqlGeographyType
).Call("AsTextZM")).Compile();
233 this.geometryAsTextZMAsSqlChars
= Expressions
.Lambda
<object, object>("sqlGeometryValue", sqlGeometryValue
=> sqlGeometryValue
.ConvertTo(this.SqlGeometryType
).Call("AsTextZM")).Compile();
238 #region Primitive Types and Type Conversions
240 internal Type SqlBooleanType { get; private set; }
241 internal Type SqlBytesType { get; private set; }
242 internal Type SqlCharsType { get; private set; }
243 internal Type SqlStringType { get; private set; }
244 internal Type SqlDoubleType { get; private set; }
245 internal Type SqlInt32Type { get; private set; }
246 internal Type SqlXmlType { get; private set; }
248 private readonly Func
<object, bool> sqlBooleanToBoolean
;
249 internal bool SqlBooleanToBoolean(object sqlBooleanValue
)
251 return this.sqlBooleanToBoolean(sqlBooleanValue
);
254 private readonly Func
<object, bool?> sqlBooleanToNullableBoolean
;
255 internal bool? SqlBooleanToNullableBoolean(object sqlBooleanValue
)
257 if (sqlBooleanToBoolean
== null)
262 return this.sqlBooleanToNullableBoolean(sqlBooleanValue
);
265 private readonly Func
<byte[], object> sqlBytesFromByteArray
;
266 internal object SqlBytesFromByteArray(byte[] binaryValue
)
268 return sqlBytesFromByteArray(binaryValue
);
271 private readonly Func
<object, byte[]> sqlBytesToByteArray
;
272 internal byte[] SqlBytesToByteArray(object sqlBytesValue
)
274 if (sqlBytesValue
== null)
279 return this.sqlBytesToByteArray(sqlBytesValue
);
282 private readonly Func
<string, object> sqlStringFromString
;
283 internal object SqlStringFromString(string stringValue
)
285 return sqlStringFromString(stringValue
);
288 private readonly Func
<string, object> sqlCharsFromString
;
289 internal object SqlCharsFromString(string stringValue
)
291 return sqlCharsFromString(stringValue
);
294 private readonly Func
<object, string> sqlCharsToString
;
295 internal string SqlCharsToString(object sqlCharsValue
)
297 if (sqlCharsValue
== null)
301 return this.sqlCharsToString(sqlCharsValue
);
304 private readonly Func
<object, string> sqlStringToString
;
305 internal string SqlStringToString(object sqlStringValue
)
307 if (sqlStringValue
== null)
311 return this.sqlStringToString(sqlStringValue
);
314 private readonly Func
<object, double> sqlDoubleToDouble
;
315 internal double SqlDoubleToDouble(object sqlDoubleValue
)
317 return this.sqlDoubleToDouble(sqlDoubleValue
);
320 private readonly Func
<object, double?> sqlDoubleToNullableDouble
;
321 internal double? SqlDoubleToNullableDouble(object sqlDoubleValue
)
323 if (sqlDoubleValue
== null)
327 return this.sqlDoubleToNullableDouble(sqlDoubleValue
);
330 private readonly Func
<object, int> sqlInt32ToInt
;
331 internal int SqlInt32ToInt(object sqlInt32Value
)
333 return this.sqlInt32ToInt(sqlInt32Value
);
336 private readonly Func
<object, int?> sqlInt32ToNullableInt
;
337 internal int? SqlInt32ToNullableInt(object sqlInt32Value
)
339 if (sqlInt32Value
== null)
343 return this.sqlInt32ToNullableInt(sqlInt32Value
);
346 private readonly Func
<System
.Xml
.XmlReader
, object> sqlXmlFromXmlReader
;
347 internal object SqlXmlFromString(string stringValue
)
349 System
.Xml
.XmlReader xmlReader
= XmlReaderFromString(stringValue
);
350 return sqlXmlFromXmlReader(xmlReader
);
353 private readonly Func
<object, string> sqlXmlToString
;
354 internal string SqlXmlToString(object sqlXmlValue
)
356 if (sqlXmlValue
== null)
361 return sqlXmlToString(sqlXmlValue
);
364 private readonly Func
<object, bool> isSqlGeographyNull
;
365 internal bool IsSqlGeographyNull(object sqlGeographyValue
)
367 if (sqlGeographyValue
== null)
372 return isSqlGeographyNull(sqlGeographyValue
);
375 private readonly Func
<object, bool> isSqlGeometryNull
;
376 internal bool IsSqlGeometryNull(object sqlGeometryValue
)
378 if (sqlGeometryValue
== null)
383 return isSqlGeometryNull(sqlGeometryValue
);
386 private readonly Func
<object, object> geographyAsTextZMAsSqlChars
;
387 internal string GeographyAsTextZM(DbGeography geographyValue
)
389 if (geographyValue
== null)
394 object sqlGeographyValue
= ConvertToSqlTypesGeography(geographyValue
);
395 object chars
= this.geographyAsTextZMAsSqlChars(sqlGeographyValue
);
396 return this.SqlCharsToString(chars
);
399 private readonly Func
<object, object> geometryAsTextZMAsSqlChars
;
400 internal string GeometryAsTextZM(DbGeometry geometryValue
)
402 if (geometryValue
== null)
407 object sqlGeometryValue
= ConvertToSqlTypesGeometry(geometryValue
);
408 object chars
= this.geometryAsTextZMAsSqlChars(sqlGeometryValue
);
409 return this.SqlCharsToString(chars
);
413 #region Spatial Types and Spatial Factory Methods
415 internal Type SqlGeographyType { get; private set; }
416 internal Type SqlGeometryType { get; private set; }
418 internal object ConvertToSqlTypesGeography(DbGeography geographyValue
)
420 geographyValue
.CheckNull("geographyValue");
421 object result
= GetSqlTypesSpatialValue(geographyValue
.AsSpatialValue(), SqlGeographyType
);
425 internal object SqlTypesGeographyFromBinary(byte[] wellKnownBinary
, int srid
)
427 Debug
.Assert(wellKnownBinary
!= null, "Validate WKB before calling SqlTypesGeographyFromBinary");
428 return sqlGeographyFromWKBByteArray(wellKnownBinary
, srid
);
431 internal object SqlTypesGeographyFromText(string wellKnownText
, int srid
)
433 Debug
.Assert(wellKnownText
!= null, "Validate WKT before calling SqlTypesGeographyFromText");
434 return sqlGeographyFromWKTString(wellKnownText
, srid
);
437 internal object ConvertToSqlTypesGeometry(DbGeometry geometryValue
)
439 geometryValue
.CheckNull("geometryValue");
440 object result
= GetSqlTypesSpatialValue(geometryValue
.AsSpatialValue(), SqlGeometryType
);
444 internal object SqlTypesGeometryFromBinary(byte[] wellKnownBinary
, int srid
)
446 Debug
.Assert(wellKnownBinary
!= null, "Validate WKB before calling SqlTypesGeometryFromBinary");
447 return sqlGeometryFromWKBByteArray(wellKnownBinary
, srid
);
450 internal object SqlTypesGeometryFromText(string wellKnownText
, int srid
)
452 Debug
.Assert(wellKnownText
!= null, "Validate WKT before calling SqlTypesGeometryFromText");
453 return sqlGeometryFromWKTString(wellKnownText
, srid
);
460 private object GetSqlTypesSpatialValue(IDbSpatialValue spatialValue
, Type requiredProviderValueType
)
462 Debug
.Assert(spatialValue
!= null, "Ensure spatial value is non-null before calling GetSqlTypesSpatialValue");
464 // If the specified value was created by this spatial services implementation, its underlying Microsoft.SqlServer.Types.SqlGeography value is available via the ProviderValue property.
465 object providerValue
= spatialValue
.ProviderValue
;
466 if (providerValue
!= null && providerValue
.GetType() == requiredProviderValueType
)
468 return providerValue
;
471 // Otherwise, attempt to retrieve a Well Known Binary, Well Known Text or GML (in descending order of preference) representation of the value that can be used to create an appropriate Microsoft.SqlServer.Types.SqlGeography/SqlGeometry value
473 int? srid
= spatialValue
.CoordinateSystemId
;
476 // Well Known Binary (WKB)
477 byte[] binaryValue
= spatialValue
.WellKnownBinary
;
478 if (binaryValue
!= null)
480 return (spatialValue
.IsGeography
? sqlGeographyFromWKBByteArray(binaryValue
, srid
.Value
) : sqlGeometryFromWKBByteArray(binaryValue
, srid
.Value
));
483 // Well Known Text (WKT)
484 string textValue
= spatialValue
.WellKnownText
;
485 if (textValue
!= null)
487 return (spatialValue
.IsGeography
? sqlGeographyFromWKTString(textValue
, srid
.Value
) : sqlGeometryFromWKTString(textValue
, srid
.Value
));
490 // Geography Markup Language (GML), as a string
491 string gmlValue
= spatialValue
.GmlString
;
492 if (gmlValue
!= null)
494 var xmlReader
= XmlReaderFromString(gmlValue
);
495 return (spatialValue
.IsGeography
? sqlGeographyFromGMLReader(xmlReader
, srid
.Value
) : sqlGeometryFromGMLReader(xmlReader
, srid
.Value
));
499 throw spatialValue
.NotSqlCompatible();
502 private static System
.Xml
.XmlReader
XmlReaderFromString(string stringValue
)
504 return System
.Xml
.XmlReader
.Create(new System
.IO
.StringReader(stringValue
));
507 private readonly Func
<string, int, object> sqlGeographyFromWKTString
;
508 private readonly Func
<byte[], int, object> sqlGeographyFromWKBByteArray
;
509 private readonly Func
<System
.Xml
.XmlReader
, int, object> sqlGeographyFromGMLReader
;
511 private readonly Func
<string, int, object> sqlGeometryFromWKTString
;
512 private readonly Func
<byte[], int, object> sqlGeometryFromWKBByteArray
;
513 private readonly Func
<System
.Xml
.XmlReader
, int, object> sqlGeometryFromGMLReader
;
515 #region Expression Compilation Helpers
517 private static Func
<TArg
, int, object> CreateStaticConstructorDelegate
<TArg
>(Type spatialType
, string methodName
)
519 Debug
.Assert(spatialType
!= null, "Ensure spatialType is non-null before calling CreateStaticConstructorDelegate");
520 var dataParam
= Expression
.Parameter(typeof(TArg
));
521 var sridParam
= Expression
.Parameter(typeof(int));
522 var staticCtorMethod
= spatialType
.GetMethod(methodName
, BindingFlags
.Public
| BindingFlags
.Static
);
523 Debug
.Assert(staticCtorMethod
!= null, "Could not find method '" + methodName
+ "' on type '" + spatialType
.FullName
+ "'");
524 Debug
.Assert(staticCtorMethod
.GetParameters().Length
== 2 && staticCtorMethod
.GetParameters()[1].ParameterType
== typeof(int), "Static constructor method on '" + spatialType
.FullName
+ "' does not match static constructor pattern?");
526 Expression sqlData
= BuildConvertToSqlType(dataParam
, staticCtorMethod
.GetParameters()[0].ParameterType
);
528 var ex
= Expression
.Lambda
<Func
<TArg
, int, object>>(Expression
.Call(null, staticCtorMethod
, sqlData
, sridParam
), dataParam
, sridParam
);
529 var result
= ex
.Compile();
533 private static Expression
BuildConvertToSqlType(Expression toConvert
, Type convertTo
)
535 if (toConvert
.Type
== typeof(byte[]))
537 return BuildConvertToSqlBytes(toConvert
, convertTo
);
539 else if (toConvert
.Type
== typeof(string))
541 if (convertTo
.Name
== "SqlString")
543 return BuildConvertToSqlString(toConvert
, convertTo
);
547 return BuildConvertToSqlChars(toConvert
, convertTo
);
552 Debug
.Assert(toConvert
.Type
== typeof(System
.Xml
.XmlReader
), "Argument to static constructor method was not byte[], string or XmlReader?");
553 if (toConvert
.Type
== typeof(System
.Xml
.XmlReader
))
555 return BuildConvertToSqlXml(toConvert
, convertTo
);
562 private static Expression
BuildConvertToSqlBytes(Expression toConvert
, Type sqlBytesType
)
564 // dataParam:byte[] => new SqlBytes(dataParam)
565 Debug
.Assert(sqlBytesType
.Name
== "SqlBytes", "byte[] argument used with non-SqlBytes static constructor method?");
566 ConstructorInfo byteArrayCtor
= sqlBytesType
.GetConstructor(BindingFlags
.Instance
| BindingFlags
.Public
, null, new Type
[] { toConvert.Type }
, null);
567 Debug
.Assert(byteArrayCtor
!= null, "SqlXml(System.IO.Stream) constructor not found?");
568 Expression result
= Expression
.New(byteArrayCtor
, toConvert
);
572 private static Expression
BuildConvertToSqlChars(Expression toConvert
, Type sqlCharsType
)
574 // dataParam:String => new SqlChars(new SqlString(dataParam))
575 Debug
.Assert(sqlCharsType
.Name
== "SqlChars", "String argument used with non-SqlChars static constructor method?");
576 Type sqlString
= sqlCharsType
.Assembly
.GetType("System.Data.SqlTypes.SqlString", throwOnError
: true);
577 ConstructorInfo sqlCharsFromSqlStringCtor
= sqlCharsType
.GetConstructor(BindingFlags
.Instance
| BindingFlags
.Public
, null, new Type
[] { sqlString }
, null);
578 Debug
.Assert(sqlCharsFromSqlStringCtor
!= null, "SqlXml(System.IO.Stream) constructor not found?");
579 ConstructorInfo sqlStringFromStringCtor
= sqlString
.GetConstructor(BindingFlags
.Instance
| BindingFlags
.Public
, null, new Type
[] { typeof(string) }
, null);
580 Expression result
= Expression
.New(sqlCharsFromSqlStringCtor
, Expression
.New(sqlStringFromStringCtor
, toConvert
));
584 private static Expression
BuildConvertToSqlString(Expression toConvert
, Type sqlStringType
)
586 // dataParam:String => new SqlString(dataParam)
587 Debug
.Assert(sqlStringType
.Name
== "SqlString", "String argument used with non-SqlString static constructor method?");
588 ConstructorInfo sqlStringFromStringCtor
= sqlStringType
.GetConstructor(BindingFlags
.Instance
| BindingFlags
.Public
, null, new Type
[] { typeof(string) }
, null);
589 Debug
.Assert(sqlStringFromStringCtor
!= null);
590 Expression result
= Expression
.Convert(Expression
.New(sqlStringFromStringCtor
, toConvert
), typeof(object));
594 private static Expression
BuildConvertToSqlXml(Expression toConvert
, Type sqlXmlType
)
596 // dataParam:Stream => new SqlXml(dataParam)
597 Debug
.Assert(sqlXmlType
.Name
== "SqlXml", "Stream argument used with non-SqlXml static constructor method?");
598 ConstructorInfo readerCtor
= sqlXmlType
.GetConstructor(BindingFlags
.Instance
| BindingFlags
.Public
, null, new Type
[] { toConvert.Type }
, null);
599 Debug
.Assert(readerCtor
!= null, "SqlXml(System.Xml.XmlReader) constructor not found?");
600 Expression result
= Expression
.New(readerCtor
, toConvert
);