5a4f283f1fbf48294f684596d6a01ace847839bc
[mono.git] / mcs / class / referencesource / System.Data.Entity / System / Data / Objects / ELinq / Translator.cs
1 //---------------------------------------------------------------------
2 // <copyright file="Translator.cs" company="Microsoft">
3 //      Copyright (c) Microsoft Corporation.  All rights reserved.
4 // </copyright>
5 //
6 // @owner  Microsoft, Microsoft
7 //---------------------------------------------------------------------
8
9 namespace System.Data.Objects.ELinq
10 {
11     using System.Collections.Generic;
12     using System.Data.Common;
13     using System.Data.Common.CommandTrees;
14     using System.Data.Common.CommandTrees.ExpressionBuilder;
15     using System.Data.Entity;
16     using System.Data.Metadata.Edm;
17     using System.Data.Objects.DataClasses;
18     using System.Diagnostics;
19     using System.Globalization;
20     using System.Linq;
21     using System.Linq.Expressions;
22     using System.Reflection;
23
24     internal sealed partial class ExpressionConverter
25     {
26         // Base class supporting the translation of LINQ node type(s) given a LINQ expression
27         // of that type, and the "parent" translation context (the ExpressionConverter processor)
28         private abstract class Translator
29         {
30             private readonly ExpressionType[] _nodeTypes;
31             protected Translator(params ExpressionType[] nodeTypes)
32             {
33                 _nodeTypes = nodeTypes;
34             }
35             // Gets LINQ node types this translator should be registed to process.
36             internal IEnumerable<ExpressionType> NodeTypes { get { return _nodeTypes; } }
37             internal abstract DbExpression Translate(ExpressionConverter parent, Expression linq);
38             public override string ToString()
39             {
40                 return this.GetType().Name;
41             }
42         }
43
44         #region Misc
45         // Typed version of Translator
46         private abstract class TypedTranslator<T_Linq> : Translator
47             where T_Linq : Expression
48         {
49             protected TypedTranslator(params ExpressionType[] nodeTypes)
50                 : base(nodeTypes) { }
51             internal override DbExpression Translate(ExpressionConverter parent, Expression linq)
52             {
53                 return TypedTranslate(parent, (T_Linq)linq);
54             }
55             protected abstract DbExpression TypedTranslate(ExpressionConverter parent, T_Linq linq);
56         }
57         private sealed class ConstantTranslator
58             : TypedTranslator<System.Linq.Expressions.ConstantExpression>
59         {
60             internal ConstantTranslator()
61                 : base(ExpressionType.Constant) { }
62             protected override DbExpression TypedTranslate(ExpressionConverter parent, ConstantExpression linq)
63             {
64                 // Check to see if this constant corresponds to the compiled query context parameter (it
65                 // gets turned into a constant during funcletization and has special error handling).
66                 if (linq == parent._funcletizer.RootContextExpression)
67                 {
68                     throw EntityUtil.InvalidOperation(System.Data.Entity.Strings.ELinq_UnsupportedUseOfContextParameter(
69                         parent._funcletizer.RootContextParameter.Name));
70                 }
71
72                 ObjectQuery queryOfT = linq.Value as ObjectQuery;
73                 if (null != queryOfT)
74                 {
75                     return parent.TranslateInlineQueryOfT(queryOfT);
76                 }
77
78                 // If it is something we can enumerate then we can evaluate locally and send to the server
79                 var values = linq.Value as System.Collections.IEnumerable;
80                 if (values != null)
81                 {
82                     Type elementType = TypeSystem.GetElementType(linq.Type);
83                     if ((elementType != null) && (elementType != linq.Type))
84                     {
85                         var expressions = new List<Expression>();
86                         foreach (object o in values)
87                         {
88                             expressions.Add(Expression.Constant(o, elementType));
89                         }
90
91                         // Invalidate the query plan every time the query is executed since it is possible
92                         // to modify an element of a collection without changing the reference.
93                         parent._recompileRequired = () => true;
94
95                         return parent.TranslateExpression(Expression.NewArrayInit(elementType, expressions));
96                     }
97                 }
98
99                 bool isNullValue = null == linq.Value;
100
101                 // Remove facet information: null instances do not constrain type facets (e.g. a null string does not restrict
102                 // "length" in compatibility checks)
103                 TypeUsage type;
104                 bool typeSupported = false;
105                 if (parent.TryGetValueLayerType(linq.Type, out type))
106                 {
107                     // For constant values, support only primitive and enum type (this is all that is supported by CQTs)
108                     // For null types, also allow EntityType. Although other types claim to be supported, they
109                     // don't work (e.g. complex type, see SQL BU 543956)
110                     if (Helper.IsScalarType(type.EdmType) ||
111                         (isNullValue && Helper.IsEntityType(type.EdmType)))
112                     {
113                         typeSupported = true;
114                     }
115                 }
116
117                 if (!typeSupported)
118                 {
119                     if (isNullValue)
120                     {
121                         throw EntityUtil.NotSupported(Strings.ELinq_UnsupportedNullConstant(DescribeClrType(linq.Type)));
122                     }
123                     else
124                     {
125                         throw EntityUtil.NotSupported(Strings.ELinq_UnsupportedConstant(DescribeClrType(linq.Type)));
126                     }
127                 }
128
129                 // create a constant or null expression depending on value
130                 if (isNullValue)
131                 {
132                     return DbExpressionBuilder.Null(type);
133                 }
134                 else
135                 {
136                     // By default use the value specified in the ConstantExpression.Value property. However,
137                     // if the value was of an enum type that is not in the model its type was converted
138                     // to the EdmType type corresponding to the underlying type of the enum type. In this case
139                     // we also need to cast the value to the same type to avoid mismatches.
140                     var value = linq.Value;
141                     if (Helper.IsPrimitiveType(type.EdmType))
142                     {
143                         var nonNullableLinqType = TypeSystem.GetNonNullableType(linq.Type);
144                         if (nonNullableLinqType.IsEnum)
145                         {
146                             value = System.Convert.ChangeType(linq.Value, nonNullableLinqType.GetEnumUnderlyingType(), CultureInfo.InvariantCulture);
147                         }
148                     }
149
150                     return DbExpressionBuilder.Constant(type, value);
151                 }
152             }
153         }
154         private sealed partial class MemberAccessTranslator
155             : TypedTranslator<MemberExpression>
156         {
157             internal MemberAccessTranslator()
158                 : base(ExpressionType.MemberAccess) { }
159             // attempt to translate the member access to a "regular" property, a navigation property, or a calculated
160             // property
161             protected override DbExpression TypedTranslate(ExpressionConverter parent, MemberExpression linq)
162             {
163                 DbExpression propertyExpression;
164                 string memberName;
165                 Type memberType;
166                 MemberInfo memberInfo = TypeSystem.PropertyOrField(linq.Member, out memberName, out memberType);
167
168                 // note: we check for "regular" properties last, since the other two flavors derive
169                 // from this one
170                 if (linq.Expression != null)
171                 {
172                     DbExpression instance = parent.TranslateExpression(linq.Expression);
173                     if (TryResolveAsProperty(parent, memberInfo,
174                         instance.ResultType, instance, out propertyExpression))
175                     {
176                         return propertyExpression;
177                     }
178                 }
179
180                 if (memberInfo.MemberType == MemberTypes.Property)
181                 {
182                     // Check whether it is one of the special properties that we know how to translate
183                     PropertyTranslator propertyTranslator;
184                     if (TryGetTranslator((PropertyInfo)memberInfo, out propertyTranslator))
185                     {
186                         return propertyTranslator.Translate(parent, linq);
187                     }
188                 }
189
190                 // no other property types are supported by LINQ over entities
191                 throw EntityUtil.NotSupported(System.Data.Entity.Strings.ELinq_UnrecognizedMember(linq.Member.Name));
192             }
193
194             #region Static members and initializers
195             private static readonly Dictionary<PropertyInfo, PropertyTranslator> s_propertyTranslators;
196             private static bool s_vbPropertiesInitialized;
197             private static readonly object s_vbInitializerLock = new object();
198
199             static MemberAccessTranslator()
200             {
201                 // initialize translators for specific properties
202                 s_propertyTranslators = new Dictionary<PropertyInfo, PropertyTranslator>();
203                 foreach (PropertyTranslator translator in GetPropertyTranslators())
204                 {
205                     foreach (PropertyInfo property in translator.Properties)
206                     {
207                         s_propertyTranslators.Add(property, translator);
208                     }
209                 }
210             }
211
212             /// <summary>
213             /// Tries to get a translator for the given property info.  
214             /// If the given property info corresponds to a Visual Basic property, 
215             /// it also initializes the Visual Basic translators if they have not been initialized
216             /// </summary>
217             /// <param name="propertyInfo"></param>
218             /// <param name="propertyTranslator"></param>
219             /// <returns></returns>
220             private static bool TryGetTranslator(PropertyInfo propertyInfo, out PropertyTranslator propertyTranslator)
221             {
222                 //If the type is generic, we try to match the generic property
223                 PropertyInfo nonGenericPropertyInfo = propertyInfo;
224                 if (propertyInfo.DeclaringType.IsGenericType)
225                 {
226                     try
227                     {
228                         propertyInfo = propertyInfo.DeclaringType.GetGenericTypeDefinition().GetProperty(propertyInfo.Name, BindingFlags.DeclaredOnly | BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public);
229                     }
230                     catch (AmbiguousMatchException)
231                     {
232                         propertyTranslator = null;
233                         return false;
234                     }                   
235                     if (propertyInfo == null)
236                     {
237                         propertyTranslator = null;
238                         return false;
239                     }
240                 }
241
242                 PropertyTranslator translatorInstance;
243                 if (s_propertyTranslators.TryGetValue(propertyInfo, out translatorInstance))
244                 {
245                     propertyTranslator = translatorInstance;
246                     return true;
247                 }
248
249                 // check if this is the visual basic assembly
250                 if (s_visualBasicAssemblyFullName == propertyInfo.DeclaringType.Assembly.FullName)
251                 {
252                     lock (s_vbInitializerLock)
253                     {
254                         if (!s_vbPropertiesInitialized)
255                         {
256                             InitializeVBProperties(propertyInfo.DeclaringType.Assembly);
257                             s_vbPropertiesInitialized = true;
258                         }
259                         // try again
260                         if (s_propertyTranslators.TryGetValue(propertyInfo, out translatorInstance))
261                         {
262                             propertyTranslator = translatorInstance;
263                             return true;
264                         }
265                         else
266                         {
267                             propertyTranslator = null;
268                             return false;
269                         }
270                     }
271                 }
272
273                 if (GenericICollectionTranslator.TryGetPropertyTranslator(nonGenericPropertyInfo, out propertyTranslator))
274                 {
275                     return true;
276                 }
277
278                 propertyTranslator = null;
279                 return false;
280             }
281
282             // Determines if the given property can be resolved as a standard or navigation property.
283             private static bool TryResolveAsProperty(ExpressionConverter parent,
284                 MemberInfo clrMember, TypeUsage definingType, DbExpression instance, out DbExpression propertyExpression)
285             {
286                 // retrieve members directly from row types, which are not mapped between O and C
287                 RowType rowType = definingType.EdmType as RowType;
288                 string name = clrMember.Name;
289
290                 if (null != rowType)
291                 {
292                     EdmMember member;
293                     if (rowType.Members.TryGetValue(name, false, out member))
294                     {
295                         propertyExpression = instance.Property(name);
296                         return true;
297                     }
298
299                     propertyExpression = null;
300                     return false;
301                 }
302
303                 // for non-row structural types, map from the O to the C layer using the perspective
304                 StructuralType structuralType = definingType.EdmType as StructuralType;
305                 if (null != structuralType)
306                 {
307                     EdmMember member = null;
308                     if (parent._perspective.TryGetMember(structuralType, name, false, out member))
309                     {
310                         if (null != member)
311                         {
312                             if (member.BuiltInTypeKind == BuiltInTypeKind.NavigationProperty)
313                             {
314                                 NavigationProperty navProp = (NavigationProperty)member;
315                                 propertyExpression = TranslateNavigationProperty(parent, clrMember, instance, navProp);
316                                 return true;
317                             }
318                             else
319                             {
320                                 propertyExpression = instance.Property(name);
321                                 return true;
322                             }
323
324                         }
325                     }
326                 }
327
328                 // try to unwrap GroupBy "Key" member
329                 if (name == ExpressionConverter.KeyColumnName)
330                 {
331                     // see if we can "unwrap" the current instance
332                     if (DbExpressionKind.Property == instance.ExpressionKind)
333                     {
334                         DbPropertyExpression property = (DbPropertyExpression)instance;
335                         InitializerMetadata initializerMetadata;
336
337                         // if we're dealing with the "Group" property of a GroupBy projection, we know how to unwrap
338                         // it
339                         if (property.Property.Name == ExpressionConverter.GroupColumnName && // only know how to unwrap the group
340                             InitializerMetadata.TryGetInitializerMetadata(property.Instance.ResultType, out initializerMetadata) &&
341                             initializerMetadata.Kind == InitializerMetadataKind.Grouping)
342                         {
343                             propertyExpression = property.Instance.Property(ExpressionConverter.KeyColumnName);
344                             return true;
345                         }
346                     }
347                 }
348
349                 propertyExpression = null;
350                 return false;
351             }
352                         
353             private static DbExpression TranslateNavigationProperty(ExpressionConverter parent, MemberInfo clrMember, DbExpression instance, NavigationProperty navProp)
354             {
355                 DbExpression propertyExpression;
356                 propertyExpression = instance.Property(navProp);
357
358                 // for EntityCollection navigations, wrap in "grouping" where the key is the parent
359                 // entity and the group contains the child entities
360                 // For non-EntityCollection navigations (e.g. from POCO entities), we just need the
361                 // enumeration, not the grouping
362                 if (BuiltInTypeKind.CollectionType == propertyExpression.ResultType.EdmType.BuiltInTypeKind)
363                 {
364                     Debug.Assert(clrMember is PropertyInfo, "Navigation property was not a property; should not be allowed by metadata.");
365                     Type propertyType = ((PropertyInfo)clrMember).PropertyType;
366                     if (propertyType.IsGenericType && propertyType.GetGenericTypeDefinition() == typeof(EntityCollection<>))
367                     {
368                         List<KeyValuePair<string, DbExpression>> collectionColumns =
369                             new List<KeyValuePair<string, DbExpression>>(2);
370                         collectionColumns.Add(new KeyValuePair<string, DbExpression>(
371                             ExpressionConverter.EntityCollectionOwnerColumnName, instance));
372                         collectionColumns.Add(new KeyValuePair<string, DbExpression>(
373                             ExpressionConverter.EntityCollectionElementsColumnName, propertyExpression));
374                         propertyExpression = parent.CreateNewRowExpression(collectionColumns,
375                             InitializerMetadata.CreateEntityCollectionInitializer(parent.EdmItemCollection, ((PropertyInfo)clrMember).PropertyType, navProp));
376                     }
377                 }
378                 return propertyExpression;
379             }
380
381             private static DbExpression TranslateCount(ExpressionConverter parent, Type sequenceElementType, Expression sequence)
382             {
383                 // retranslate as a Count() aggregate, since the name collision prevents us
384                 // from calling the method directly in VB and C#
385                 MethodInfo countMethod;
386                 ReflectionUtil.TryLookupMethod(SequenceMethod.Count, out countMethod);
387                 Debug.Assert(null != countMethod, "Count() must exist");
388                 countMethod = countMethod.MakeGenericMethod(sequenceElementType);
389                 Expression countCall = Expression.Call(countMethod, sequence);
390                 return parent.TranslateExpression(countCall);
391             }
392
393             private static void InitializeVBProperties(Assembly vbAssembly)
394             {
395                 Debug.Assert(!s_vbPropertiesInitialized);
396                 foreach (PropertyTranslator translator in GetVisualBasicPropertyTranslators(vbAssembly))
397                 {
398                     foreach (PropertyInfo property in translator.Properties)
399                     {
400                         s_propertyTranslators.Add(property, translator);
401                     }
402                 }
403             }
404
405             private static IEnumerable<PropertyTranslator> GetVisualBasicPropertyTranslators(Assembly vbAssembly)
406             {
407                 yield return new VBDateAndTimeNowTranslator(vbAssembly);
408             }
409
410             private static IEnumerable<PropertyTranslator> GetPropertyTranslators()
411             {
412                 yield return new DefaultCanonicalFunctionPropertyTranslator();
413                 yield return new RenameCanonicalFunctionPropertyTranslator();
414                 yield return new EntityCollectionCountTranslator();
415                 yield return new NullableHasValueTranslator();
416                 yield return new NullableValueTranslator();
417                 yield return new SpatialPropertyTranslator();
418             }
419
420             /// <summary>
421             /// This method is used to determine whether client side evaluation should be done, 
422             /// if the property can be evaluated in the store, it is not being evaluated on the client
423             /// </summary>
424             internal static bool CanFuncletizePropertyInfo(PropertyInfo propertyInfo)
425             {
426                 PropertyTranslator propertyTranslator;
427                 // In most cases, we only allow funcletization of properties that could not otherwise be
428                 // handled by the query pipeline. ICollection<>.Count is the one exception to the rule
429                 // (avoiding a breaking change)
430                 return GenericICollectionTranslator.TryGetPropertyTranslator(propertyInfo, out propertyTranslator) ||
431                     !TryGetTranslator(propertyInfo, out propertyTranslator);
432             }
433             #endregion
434
435             #region Dynamic Property Translators
436
437             private sealed class GenericICollectionTranslator : PropertyTranslator
438             {
439                 private readonly Type _elementType;
440
441                 private GenericICollectionTranslator(Type elementType) : base(Enumerable.Empty<PropertyInfo>())
442                 {
443                     _elementType = elementType;
444                 }
445
446                 internal override DbExpression Translate(ExpressionConverter parent, MemberExpression call)
447                 {
448                     return TranslateCount(parent, _elementType, call.Expression);
449                 }
450
451                 internal static bool TryGetPropertyTranslator(PropertyInfo propertyInfo, out PropertyTranslator propertyTranslator)
452                 {
453                     // Implementation note: When adding support for additional properties, use less expensive checks
454                     // such as property name and return type to test for a property defined by ICollection<T> first
455                     // before calling the more expensive TypeSystem.FindICollection to test whether the declaring type
456                     // of the property implements ICollection<T>.
457
458                     //
459                     // Int32 Count
460                     //
461                     if (propertyInfo.Name == "Count" &&
462                         propertyInfo.PropertyType.Equals(typeof(int)))
463                     {
464                         foreach (KeyValuePair<Type, Type> implementedCollectionInfo in GetImplementedICollections(propertyInfo.DeclaringType))
465                         {
466                             Type implementedCollection = implementedCollectionInfo.Key;
467                             Type elementType = implementedCollectionInfo.Value;
468
469                             if (propertyInfo.IsImplementationOf(implementedCollection))
470                             {
471                                 propertyTranslator = new GenericICollectionTranslator(elementType);
472                                 return true;
473                             }
474                         }
475                     }
476
477                     // Not a supported ICollection<T> property
478                     propertyTranslator = null;
479                     return false;
480                 }
481
482                 private static bool IsICollection(Type candidateType, out Type elementType)
483                 {
484                     if (candidateType.IsGenericType &&
485                         candidateType.GetGenericTypeDefinition().Equals(typeof(System.Collections.Generic.ICollection<>)))
486                     {
487                         elementType = candidateType.GetGenericArguments()[0];
488                         return true;
489                     }
490                     elementType = null;
491                     return false;
492                 }
493
494                 private static IEnumerable<KeyValuePair<Type, Type>> GetImplementedICollections(Type type)
495                 {
496                     Type collectionElementType;
497                     if (IsICollection(type, out collectionElementType))
498                     {
499                         yield return new KeyValuePair<Type, Type>(type, collectionElementType);
500                     }
501                     else
502                     {
503                         foreach (Type interfaceType in type.GetInterfaces())
504                         {
505                             if (IsICollection(interfaceType, out collectionElementType))
506                             {
507                                 yield return new KeyValuePair<Type, Type>(interfaceType, collectionElementType);
508                             }
509                         }
510                     }
511                 }
512             }
513
514             #endregion
515
516             #region Signature-based Property Translators
517             private abstract class PropertyTranslator
518             {
519                 private readonly IEnumerable<PropertyInfo> _properties;
520                 protected PropertyTranslator(params PropertyInfo[] properties) { _properties = properties; }
521                 protected PropertyTranslator(IEnumerable<PropertyInfo> properties) { _properties = properties; }
522                 internal IEnumerable<PropertyInfo> Properties { get { return _properties; } }
523                 internal abstract DbExpression Translate(ExpressionConverter parent, MemberExpression call);
524                 public override string ToString()
525                 {
526                     return GetType().Name;
527                 }
528             }
529
530             private sealed class DefaultCanonicalFunctionPropertyTranslator : PropertyTranslator
531             {
532                 internal DefaultCanonicalFunctionPropertyTranslator()
533                     : base(GetProperties()) { }
534
535                 private static IEnumerable<PropertyInfo> GetProperties()
536                 {
537                     yield return typeof(String).GetProperty("Length", BindingFlags.Public | BindingFlags.Instance);
538                     yield return typeof(DateTime).GetProperty("Year", BindingFlags.Public | BindingFlags.Instance);
539                     yield return typeof(DateTime).GetProperty("Month", BindingFlags.Public | BindingFlags.Instance);
540                     yield return typeof(DateTime).GetProperty("Day", BindingFlags.Public | BindingFlags.Instance);
541                     yield return typeof(DateTime).GetProperty("Hour", BindingFlags.Public | BindingFlags.Instance);
542                     yield return typeof(DateTime).GetProperty("Minute", BindingFlags.Public | BindingFlags.Instance);
543                     yield return typeof(DateTime).GetProperty("Second", BindingFlags.Public | BindingFlags.Instance);
544                     yield return typeof(DateTime).GetProperty("Millisecond", BindingFlags.Public | BindingFlags.Instance);
545
546                     yield return typeof(DateTimeOffset).GetProperty("Year", BindingFlags.Public | BindingFlags.Instance);
547                     yield return typeof(DateTimeOffset).GetProperty("Month", BindingFlags.Public | BindingFlags.Instance);
548                     yield return typeof(DateTimeOffset).GetProperty("Day", BindingFlags.Public | BindingFlags.Instance);
549                     yield return typeof(DateTimeOffset).GetProperty("Hour", BindingFlags.Public | BindingFlags.Instance);
550                     yield return typeof(DateTimeOffset).GetProperty("Minute", BindingFlags.Public | BindingFlags.Instance);
551                     yield return typeof(DateTimeOffset).GetProperty("Second", BindingFlags.Public | BindingFlags.Instance);
552                     yield return typeof(DateTimeOffset).GetProperty("Millisecond", BindingFlags.Public | BindingFlags.Instance);
553                 }
554
555                 // Default translator for method calls into canonical functions.
556                 // Translation:
557                 //      object.PropertyName  -> PropertyName(object)
558                 internal override DbExpression Translate(ExpressionConverter parent, MemberExpression call)
559                 {
560                     return parent.TranslateIntoCanonicalFunction(call.Member.Name, call, call.Expression);
561                 }
562             }
563
564             private sealed class RenameCanonicalFunctionPropertyTranslator : PropertyTranslator
565             {
566                 private static readonly Dictionary<PropertyInfo, string> s_propertyRenameMap = new Dictionary<PropertyInfo, string>(2);
567
568                 internal RenameCanonicalFunctionPropertyTranslator()
569                     : base(GetProperties()) { }
570
571                 private static IEnumerable<PropertyInfo> GetProperties()
572                 {
573                     yield return GetProperty(typeof(DateTime), "Now", BindingFlags.Public | BindingFlags.Static, ExpressionConverter.CurrentDateTime);
574                     yield return GetProperty(typeof(DateTime), "UtcNow", BindingFlags.Public | BindingFlags.Static, ExpressionConverter.CurrentUtcDateTime);
575                     yield return GetProperty(typeof(DateTimeOffset), "Now", BindingFlags.Public | BindingFlags.Static, ExpressionConverter.CurrentDateTimeOffset);
576
577                     yield return GetProperty(typeof(TimeSpan), "Hours", BindingFlags.Public | BindingFlags.Instance, ExpressionConverter.Hour);
578                     yield return GetProperty(typeof(TimeSpan), "Minutes", BindingFlags.Public | BindingFlags.Instance, ExpressionConverter.Minute);
579                     yield return GetProperty(typeof(TimeSpan), "Seconds", BindingFlags.Public | BindingFlags.Instance, ExpressionConverter.Second);
580                     yield return GetProperty(typeof(TimeSpan), "Milliseconds", BindingFlags.Public | BindingFlags.Instance, ExpressionConverter.Millisecond);
581                 }
582
583                 private static PropertyInfo GetProperty(Type declaringType, string propertyName, BindingFlags bindingFlages, string canonicalFunctionName)
584                 {
585                     PropertyInfo propertyInfo = declaringType.GetProperty(propertyName, bindingFlages);
586                     s_propertyRenameMap.Add(propertyInfo, canonicalFunctionName);
587                     return propertyInfo;
588                 }
589
590                 // Translator for static properties into canonical functions when there is a corresponding 
591                 // canonical function but with a differnet name
592                 // Translation:
593                 //      object.PropertyName  -> CanonicalFunctionName(object)
594                 //      Type.PropertyName  -> CanonicalFunctionName()
595                 internal override DbExpression Translate(ExpressionConverter parent, MemberExpression call)
596                 {
597                     PropertyInfo property = (PropertyInfo)call.Member;
598                     String canonicalFunctionName = s_propertyRenameMap[property];
599                     DbExpression result;
600                     if (call.Expression == null)
601                     {
602                         result = parent.TranslateIntoCanonicalFunction(canonicalFunctionName, call);
603                     }
604                     else
605                     {
606                         result = parent.TranslateIntoCanonicalFunction(canonicalFunctionName, call, call.Expression);
607                     }
608                     return result;
609                 }
610             }
611
612             private sealed class VBDateAndTimeNowTranslator : PropertyTranslator
613             {
614                 private const string s_dateAndTimeTypeFullName = "Microsoft.VisualBasic.DateAndTime";
615
616                 internal VBDateAndTimeNowTranslator(Assembly vbAssembly)
617                     : base(GetProperty(vbAssembly)) { }
618
619                 private static PropertyInfo GetProperty(Assembly vbAssembly)
620                 {
621                     return vbAssembly.GetType(s_dateAndTimeTypeFullName).GetProperty("Now", BindingFlags.Public | BindingFlags.Static);
622                 }
623
624                 // Translation:
625                 //      Now -> GetDate()
626                 internal override DbExpression Translate(ExpressionConverter parent, MemberExpression call)
627                 {
628                     return parent.TranslateIntoCanonicalFunction(ExpressionConverter.CurrentDateTime, call);
629                 }
630             }
631
632             private sealed class EntityCollectionCountTranslator : PropertyTranslator
633             {
634                 internal EntityCollectionCountTranslator()
635                     : base(GetProperty()) { }
636
637                 private static PropertyInfo GetProperty()
638                 {
639                     return typeof(EntityCollection<>).GetProperty(ExpressionConverter.s_entityCollectionCountPropertyName, BindingFlags.Public | BindingFlags.Instance);
640                 }
641
642                 // Translation:
643                 //      EntityCollection<T>.Count -> Count()
644                 internal override DbExpression Translate(ExpressionConverter parent, MemberExpression call)
645                 {
646                     // retranslate as a Count() aggregate, since the name collision prevents us
647                     // from calling the method directly in VB and C#
648                     return MemberAccessTranslator.TranslateCount(parent, call.Member.DeclaringType.GetGenericArguments()[0], call.Expression);
649                 }
650             }
651
652             private sealed class NullableHasValueTranslator : PropertyTranslator
653             {
654                 internal NullableHasValueTranslator()
655                     : base(GetProperty()) { }
656
657                 private static PropertyInfo GetProperty()
658                 {
659                     return typeof(Nullable<>).GetProperty(ExpressionConverter.s_nullableHasValuePropertyName, BindingFlags.Public | BindingFlags.Instance);
660                 }
661
662                 // Translation:
663                 //      Nullable<T>.HasValue -> Not(IsNull(arg))
664                 internal override DbExpression Translate(ExpressionConverter parent, MemberExpression call)
665                 {
666                     DbExpression argument = parent.TranslateExpression(call.Expression);
667                     Debug.Assert(!TypeSemantics.IsCollectionType(argument.ResultType), "Did not expect collection type");
668                     return parent.CreateIsNullExpression(argument, call.Expression.Type).Not();
669                 }
670             }
671
672             private sealed class NullableValueTranslator : PropertyTranslator
673             {
674                 internal NullableValueTranslator()
675                     : base(GetProperty()) { }
676
677                 private static PropertyInfo GetProperty()
678                 {
679                     return typeof(Nullable<>).GetProperty(ExpressionConverter.s_nullableValuePropertyName, BindingFlags.Public | BindingFlags.Instance);
680                 }
681
682                 // Translation:
683                 //      Nullable<T>.Value -> arg
684                 internal override DbExpression Translate(ExpressionConverter parent, MemberExpression call)
685                 {
686                     DbExpression argument = parent.TranslateExpression(call.Expression);
687                     Debug.Assert(!TypeSemantics.IsCollectionType(argument.ResultType), "Did not expect collection type");
688                     return argument;
689                 }
690             }
691             #endregion
692         }
693         private sealed class ParameterTranslator
694             : TypedTranslator<ParameterExpression>
695         {
696             internal ParameterTranslator()
697                 : base(ExpressionType.Parameter) { }
698             protected override DbExpression TypedTranslate(ExpressionConverter parent, ParameterExpression linq)
699             {
700                 // Bindings should be intercepted before we get to this point (in ExpressionConverter.TranslateExpression)
701                 throw EntityUtil.InvalidOperation(System.Data.Entity.Strings.ELinq_UnboundParameterExpression(linq.Name));
702             }
703         }
704         private sealed class NewTranslator
705             : TypedTranslator<NewExpression>
706         {
707             internal NewTranslator()
708                 : base(ExpressionType.New) { }
709             protected override DbExpression TypedTranslate(ExpressionConverter parent, NewExpression linq)
710             {
711                 int memberCount = null == linq.Members ? 0 : linq.Members.Count;
712
713                 if (null == linq.Constructor ||
714                     linq.Arguments.Count != memberCount)
715                 {
716                     throw EntityUtil.NotSupported(System.Data.Entity.Strings.ELinq_UnsupportedConstructor);
717                 }
718
719                 parent.CheckInitializerType(linq.Type);
720
721                 List<KeyValuePair<String, DbExpression>> recordColumns =
722                     new List<KeyValuePair<string, DbExpression>>(memberCount + 1);
723
724                 HashSet<string> memberNames = new HashSet<string>(StringComparer.Ordinal);
725                 for (int i = 0; i < memberCount; i++)
726                 {
727                     string memberName;
728                     Type memberType;
729                     MemberInfo memberInfo = TypeSystem.PropertyOrField(linq.Members[i], out memberName, out memberType);
730                     DbExpression memberValue = parent.TranslateExpression(linq.Arguments[i]);
731                     memberNames.Add(memberName);
732                     recordColumns.Add(new KeyValuePair<string, DbExpression>(memberName, memberValue));
733                 }
734
735                 InitializerMetadata initializerMetadata;
736                 if (0 == memberCount)
737                 {
738                     // add a sentinel column because CQTs do not accept empty row types
739                     recordColumns.Add(DbExpressionBuilder.True.As(KeyColumnName));
740                     initializerMetadata = InitializerMetadata.CreateEmptyProjectionInitializer(parent.EdmItemCollection, linq);
741                 }
742                 else
743                 {
744                     // Construct a new initializer type in metadata for this projection (provides the
745                     // necessary context for the object materializer)
746                     initializerMetadata = InitializerMetadata.CreateProjectionInitializer(parent.EdmItemCollection, linq);
747                 }
748                 parent.ValidateInitializerMetadata(initializerMetadata);
749
750                 DbNewInstanceExpression projection = parent.CreateNewRowExpression(recordColumns, initializerMetadata);
751
752                 return projection;
753             }
754         }
755         private sealed class NewArrayInitTranslator
756             : TypedTranslator<NewArrayExpression>
757         {
758             internal NewArrayInitTranslator()
759                 : base(ExpressionType.NewArrayInit) { }
760             protected override DbExpression TypedTranslate(ExpressionConverter parent, NewArrayExpression linq)
761             {
762                 if (linq.Expressions.Count > 0)
763                 {
764                     return DbExpressionBuilder.NewCollection(linq.Expressions.Select(e => parent.TranslateExpression(e)));
765                 }
766
767                 TypeUsage typeUsage;
768                 if (typeof(byte[]) == linq.Type)
769                 {
770                     TypeUsage type;
771                     if (parent.TryGetValueLayerType(typeof(byte), out type))
772                     {
773                         typeUsage = TypeHelpers.CreateCollectionTypeUsage(type);
774                         return DbExpressionBuilder.NewEmptyCollection(typeUsage);
775                     }
776                 }
777                 else
778                 {
779                     if (parent.TryGetValueLayerType(linq.Type, out typeUsage))
780                     {
781                         return DbExpressionBuilder.NewEmptyCollection(typeUsage);
782                     }
783                 }
784
785                 throw EntityUtil.NotSupported(Strings.ELinq_UnsupportedType(DescribeClrType(linq.Type)));
786             }
787         }
788         private sealed class ListInitTranslator
789             : TypedTranslator<ListInitExpression>
790         {
791             internal ListInitTranslator()
792                 : base(ExpressionType.ListInit ) { }
793             protected override DbExpression TypedTranslate(ExpressionConverter parent, ListInitExpression linq)
794             {
795                 // Ensure requirements: one list initializer argument and a default constructor.
796                 if ((linq.NewExpression.Constructor != null) && (linq.NewExpression.Constructor.GetParameters().Length != 0))
797                 {
798                     throw EntityUtil.NotSupported(System.Data.Entity.Strings.ELinq_UnsupportedConstructor);
799                 }
800
801                 if (linq.Initializers.Any(i => i.Arguments.Count != 1))
802                 {
803                     throw EntityUtil.NotSupported(System.Data.Entity.Strings.ELinq_UnsupportedInitializers);
804                 }
805
806                 return DbExpressionBuilder.NewCollection(linq.Initializers.Select(i => parent.TranslateExpression(i.Arguments[0])));
807             }
808         }
809         private sealed class MemberInitTranslator
810             : TypedTranslator<MemberInitExpression>
811         {
812             internal MemberInitTranslator()
813                 : base(ExpressionType.MemberInit) { }
814             protected override DbExpression TypedTranslate(ExpressionConverter parent, MemberInitExpression linq)
815             {
816                 if (null == linq.NewExpression.Constructor ||
817                     0 != linq.NewExpression.Constructor.GetParameters().Length)
818                 {
819                     throw EntityUtil.NotSupported(System.Data.Entity.Strings.ELinq_UnsupportedConstructor);
820                 }
821
822                 parent.CheckInitializerType(linq.Type);
823
824                 List<KeyValuePair<String, DbExpression>> recordColumns =
825                     new List<KeyValuePair<string, DbExpression>>(linq.Bindings.Count + 1);
826                 MemberInfo[] members = new MemberInfo[linq.Bindings.Count];
827
828                 HashSet<string> memberNames = new HashSet<string>(StringComparer.Ordinal);
829                 for (int i = 0; i < linq.Bindings.Count; i++)
830                 {
831                     MemberAssignment binding = linq.Bindings[i] as MemberAssignment;
832                     if (null == binding)
833                     {
834                         throw EntityUtil.NotSupported(System.Data.Entity.Strings.ELinq_UnsupportedBinding);
835                     }
836                     string memberName;
837                     Type memberType;
838                     MemberInfo memberInfo = TypeSystem.PropertyOrField(binding.Member, out memberName, out memberType);
839
840                     DbExpression memberValue = parent.TranslateExpression(binding.Expression);
841                     memberNames.Add(memberName);
842                     members[i] = memberInfo;
843                     recordColumns.Add(new KeyValuePair<string, DbExpression>(memberName, memberValue));
844                 }
845
846                 InitializerMetadata initializerMetadata;
847
848                 if (0 == recordColumns.Count)
849                 {
850                     // add a sentinel column because CQTs do not accept empty row types
851                     recordColumns.Add(DbExpressionBuilder.Constant(true).As(KeyColumnName));
852                     initializerMetadata = InitializerMetadata.CreateEmptyProjectionInitializer(parent.EdmItemCollection, linq.NewExpression);
853                 }
854                 else
855                 {
856                     // Construct a new initializer type in metadata for this projection (provides the
857                     // necessary context for the object materializer)
858                     initializerMetadata = InitializerMetadata.CreateProjectionInitializer(parent.EdmItemCollection, linq, members);
859                 }
860                 parent.ValidateInitializerMetadata(initializerMetadata);
861                 DbNewInstanceExpression projection = parent.CreateNewRowExpression(recordColumns, initializerMetadata);
862
863                 return projection;
864             }
865         }
866         private sealed class ConditionalTranslator : TypedTranslator<ConditionalExpression>
867         {
868             internal ConditionalTranslator()
869                 : base(ExpressionType.Conditional) { }
870             protected override DbExpression TypedTranslate(ExpressionConverter parent, ConditionalExpression linq)
871             {
872                 // translate Test ? IfTrue : IfFalse --> CASE WHEN Test THEN IfTrue ELSE IfFalse
873                 List<DbExpression> whenExpressions = new List<DbExpression>(1);
874                 whenExpressions.Add(parent.TranslateExpression(linq.Test));
875                 List<DbExpression> thenExpressions = new List<DbExpression>(1);
876                 thenExpressions.Add(parent.TranslateExpression(linq.IfTrue));
877                 DbExpression elseExpression = parent.TranslateExpression(linq.IfFalse);
878                 return DbExpressionBuilder.Case(whenExpressions, thenExpressions, elseExpression);
879             }
880         }
881         private sealed class NotSupportedTranslator : Translator
882         {
883             internal NotSupportedTranslator(params ExpressionType[] nodeTypes)
884                 : base(nodeTypes)
885             {
886             }
887             internal override DbExpression Translate(ExpressionConverter parent, Expression linq)
888             {
889                 throw EntityUtil.NotSupported(System.Data.Entity.Strings.ELinq_UnsupportedExpressionType(linq.NodeType));
890             }
891         }
892         private sealed class ExtensionTranslator : Translator
893         {
894             internal ExtensionTranslator()
895                 : base(EntityExpressionVisitor.CustomExpression)
896             {
897             }
898             internal override DbExpression Translate(ExpressionConverter parent, Expression linq)
899             {
900                 QueryParameterExpression queryParameter = linq as QueryParameterExpression;
901                 if (null == queryParameter)
902                 {
903                     throw EntityUtil.NotSupported(System.Data.Entity.Strings.ELinq_UnsupportedExpressionType(linq.NodeType));
904                 }
905                 // otherwise add a new query parameter...
906                 parent.AddParameter(queryParameter);
907                 return queryParameter.ParameterReference;
908             }
909         }
910         #endregion
911
912         #region Binary expression translators
913         private abstract class BinaryTranslator
914             : TypedTranslator<System.Linq.Expressions.BinaryExpression>
915         {
916             protected BinaryTranslator(params ExpressionType[] nodeTypes)
917                 : base(nodeTypes) { }
918             protected override DbExpression TypedTranslate(ExpressionConverter parent, System.Linq.Expressions.BinaryExpression linq)
919             {
920                 return TranslateBinary(parent, parent.TranslateExpression(linq.Left), parent.TranslateExpression(linq.Right), linq);
921             }
922             protected abstract DbExpression TranslateBinary(ExpressionConverter parent, DbExpression left, DbExpression right, BinaryExpression linq);
923         }
924         private sealed class CoalesceTranslator : BinaryTranslator
925         {
926             internal CoalesceTranslator()
927                 : base(ExpressionType.Coalesce) { }
928             protected override DbExpression TranslateBinary(ExpressionConverter parent, DbExpression left, DbExpression right, BinaryExpression linq)
929             {
930                 // left ?? right gets translated to:
931                 // CASE WHEN IsNull(left) THEN right ELSE left
932
933                 // construct IsNull
934                 DbExpression isNull = parent.CreateIsNullExpression(left, linq.Left.Type);
935
936                 // construct case expression
937                 List<DbExpression> whenExpressions = new List<DbExpression>(1);
938                 whenExpressions.Add(isNull);
939                 List<DbExpression> thenExpressions = new List<DbExpression>(1);
940                 thenExpressions.Add(right);
941                 DbExpression caseExpression = DbExpressionBuilder.Case(whenExpressions,
942                     thenExpressions, left);
943
944                 return caseExpression;
945             }
946         }
947         private sealed class AndAlsoTranslator : BinaryTranslator
948         {
949             internal AndAlsoTranslator()
950                 : base(ExpressionType.AndAlso) { }
951             protected override DbExpression TranslateBinary(ExpressionConverter parent, DbExpression left, DbExpression right, BinaryExpression linq)
952             {
953                 return left.And(right);
954             }
955         }
956         private sealed class OrElseTranslator : BinaryTranslator
957         {
958             internal OrElseTranslator()
959                 : base(ExpressionType.OrElse) { }
960             protected override DbExpression TranslateBinary(ExpressionConverter parent, DbExpression left, DbExpression right, BinaryExpression linq)
961             {
962                 return left.Or(right);
963             }
964         }
965         private sealed class LessThanTranslator : BinaryTranslator
966         {
967             internal LessThanTranslator()
968                 : base(ExpressionType.LessThan) { }
969             protected override DbExpression TranslateBinary(ExpressionConverter parent, DbExpression left, DbExpression right, BinaryExpression linq)
970             {
971                 return left.LessThan(right);
972             }
973         }
974         private sealed class LessThanOrEqualsTranslator : BinaryTranslator
975         {
976             internal LessThanOrEqualsTranslator()
977                 : base(ExpressionType.LessThanOrEqual) { }
978             protected override DbExpression TranslateBinary(ExpressionConverter parent, DbExpression left, DbExpression right, BinaryExpression linq)
979             {
980                 return left.LessThanOrEqual(right);
981             }
982         }
983         private sealed class GreaterThanTranslator : BinaryTranslator
984         {
985             internal GreaterThanTranslator()
986                 : base(ExpressionType.GreaterThan) { }
987             protected override DbExpression TranslateBinary(ExpressionConverter parent, DbExpression left, DbExpression right, BinaryExpression linq)
988             {
989                 return left.GreaterThan(right);
990             }
991         }
992         private sealed class GreaterThanOrEqualsTranslator : BinaryTranslator
993         {
994             internal GreaterThanOrEqualsTranslator()
995                 : base(ExpressionType.GreaterThanOrEqual) { }
996             protected override DbExpression TranslateBinary(ExpressionConverter parent, DbExpression left, DbExpression right, BinaryExpression linq)
997             {
998                 return left.GreaterThanOrEqual(right);
999             }
1000         }
1001         private sealed class EqualsTranslator : TypedTranslator<System.Linq.Expressions.BinaryExpression>
1002         {
1003             internal EqualsTranslator()
1004                 : base(ExpressionType.Equal) { }
1005             protected override DbExpression TypedTranslate(ExpressionConverter parent, System.Linq.Expressions.BinaryExpression linq)
1006             {
1007                 Expression linqLeft = linq.Left;
1008                 Expression linqRight = linq.Right;
1009
1010                 bool leftIsNull = ExpressionIsNullConstant(linqLeft);
1011                 bool rightIsNull = ExpressionIsNullConstant(linqRight);
1012
1013                 // if both values are null, short-circuit
1014                 if (leftIsNull && rightIsNull) { return DbExpressionBuilder.True; }
1015
1016                 // if only one side is null, produce an IsNull statement
1017                 if (leftIsNull) { return CreateIsNullExpression(parent, linqRight); }
1018                 if (rightIsNull) { return CreateIsNullExpression(parent, linqLeft); }
1019
1020                 // create a standard equals expression, calling utility method to compensate for null equality
1021                 DbExpression cqtLeft = parent.TranslateExpression(linqLeft);
1022                 DbExpression cqtRight = parent.TranslateExpression(linqRight);
1023                 EqualsPattern pattern = EqualsPattern.Store;
1024                 if (parent._funcletizer.RootContext.ContextOptions.UseCSharpNullComparisonBehavior)
1025                 {
1026                     pattern = EqualsPattern.PositiveNullEqualityComposable;
1027                 }
1028                 return parent.CreateEqualsExpression(cqtLeft, cqtRight, pattern, linqLeft.Type, linqRight.Type);
1029             }
1030             private static DbExpression CreateIsNullExpression(ExpressionConverter parent, Expression input)
1031             {
1032                 input = UnwrapConvert(input);
1033
1034                 // translate input
1035                 DbExpression inputCqt = parent.TranslateExpression(input);
1036
1037                 // create IsNull expression
1038                 return parent.CreateIsNullExpression(inputCqt, input.Type);
1039             }
1040             private static bool ExpressionIsNullConstant(Expression expression)
1041             {
1042                 // convert statements introduced by compiler should not affect nullness
1043                 expression = UnwrapConvert(expression);
1044
1045                 // check if the unwrapped expression is a null constant
1046                 if (ExpressionType.Constant != expression.NodeType) { return false; }
1047                 System.Linq.Expressions.ConstantExpression constant = (System.Linq.Expressions.ConstantExpression)expression;
1048                 return null == constant.Value;
1049             }
1050             private static Expression UnwrapConvert(Expression input)
1051             {
1052                 // unwrap all converts
1053                 while (ExpressionType.Convert == input.NodeType)
1054                 {
1055                     input = ((UnaryExpression)input).Operand;
1056                 }
1057                 return input;
1058             }
1059         }
1060         private sealed class NotEqualsTranslator : TypedTranslator<System.Linq.Expressions.BinaryExpression>
1061         {
1062             internal NotEqualsTranslator()
1063                 : base(ExpressionType.NotEqual) { }
1064             protected override DbExpression TypedTranslate(ExpressionConverter parent, System.Linq.Expressions.BinaryExpression linq)
1065             {
1066                 // rewrite as a not equals expression
1067                 Expression notLinq = Expression.Not(
1068                     Expression.Equal(linq.Left, linq.Right));
1069                 return parent.TranslateExpression(notLinq);
1070             }
1071         }
1072         #endregion
1073
1074         #region Type binary expression translator
1075         private sealed class IsTranslator : TypedTranslator<TypeBinaryExpression>
1076         {
1077             internal IsTranslator()
1078                 : base(ExpressionType.TypeIs) { }
1079             protected override DbExpression TypedTranslate(ExpressionConverter parent, TypeBinaryExpression linq)
1080             {
1081                 DbExpression operand = parent.TranslateExpression(linq.Expression);
1082                 TypeUsage fromType = operand.ResultType;
1083                 TypeUsage toType = parent.GetIsOrAsTargetType(fromType, ExpressionType.TypeIs, linq.TypeOperand, linq.Expression.Type);
1084                 return operand.IsOf(toType);
1085             }
1086         }
1087         #endregion
1088
1089         #region Arithmetic expressions
1090         private sealed class AddTranslator : BinaryTranslator
1091         {
1092             internal AddTranslator()
1093                 : base(ExpressionType.Add, ExpressionType.AddChecked) { }
1094             protected override DbExpression TranslateBinary(ExpressionConverter parent, DbExpression left, DbExpression right, BinaryExpression linq)
1095             {
1096                 if (TypeSemantics.IsPrimitiveType(left.ResultType, PrimitiveTypeKind.String) &&
1097                    TypeSemantics.IsPrimitiveType(right.ResultType, PrimitiveTypeKind.String))
1098                 {
1099                     // Add(string, string) => Concat(string, string)
1100                     return parent.CreateCanonicalFunction(ExpressionConverter.Concat, linq, left, right);
1101                 }
1102                 else
1103                 {
1104                     return left.Plus(right);
1105                 }
1106             }
1107         }
1108         private sealed class DivideTranslator : BinaryTranslator
1109         {
1110             internal DivideTranslator()
1111                 : base(ExpressionType.Divide) { }
1112             protected override DbExpression TranslateBinary(ExpressionConverter parent, DbExpression left, DbExpression right, BinaryExpression linq)
1113             {
1114                 return left.Divide(right);
1115             }
1116         }
1117         private sealed class ModuloTranslator : BinaryTranslator
1118         {
1119             internal ModuloTranslator()
1120                 : base(ExpressionType.Modulo) { }
1121             protected override DbExpression TranslateBinary(ExpressionConverter parent, DbExpression left, DbExpression right, BinaryExpression linq)
1122             {
1123                 return left.Modulo(right);
1124             }
1125         }
1126         private sealed class MultiplyTranslator : BinaryTranslator
1127         {
1128             internal MultiplyTranslator()
1129                 : base(ExpressionType.Multiply, ExpressionType.MultiplyChecked) { }
1130             protected override DbExpression TranslateBinary(ExpressionConverter parent, DbExpression left, DbExpression right, BinaryExpression linq)
1131             {
1132                 return left.Multiply(right);
1133             }
1134         }
1135         private sealed class SubtractTranslator : BinaryTranslator
1136         {
1137             internal SubtractTranslator()
1138                 : base(ExpressionType.Subtract, ExpressionType.SubtractChecked) { }
1139             protected override DbExpression TranslateBinary(ExpressionConverter parent, DbExpression left, DbExpression right, BinaryExpression linq)
1140             {
1141                 return left.Minus(right);
1142             }
1143         }
1144         private sealed class NegateTranslator : UnaryTranslator
1145         {
1146             internal NegateTranslator()
1147                 : base(ExpressionType.Negate, ExpressionType.NegateChecked) { }
1148             protected override DbExpression TranslateUnary(ExpressionConverter parent, System.Linq.Expressions.UnaryExpression unary, DbExpression operand)
1149             {
1150                 return operand.UnaryMinus();
1151             }
1152         }
1153         private sealed class UnaryPlusTranslator : UnaryTranslator
1154         {
1155             internal UnaryPlusTranslator()
1156                 : base(ExpressionType.UnaryPlus) { }
1157             protected override DbExpression TranslateUnary(ExpressionConverter parent, UnaryExpression unary, DbExpression operand)
1158             {
1159                 // +x = x
1160                 return operand;
1161             }
1162         }
1163         #endregion
1164
1165         #region Bitwise expressions
1166         private abstract class BitwiseBinaryTranslator : TypedTranslator<System.Linq.Expressions.BinaryExpression>
1167         {
1168             private readonly string _canonicalFunctionName;
1169
1170             protected BitwiseBinaryTranslator(ExpressionType nodeType, string canonicalFunctionName)
1171                 : base(nodeType)
1172             {
1173                 _canonicalFunctionName = canonicalFunctionName;
1174             }
1175
1176             protected override DbExpression TypedTranslate(ExpressionConverter parent, System.Linq.Expressions.BinaryExpression linq)
1177             {
1178                 DbExpression left = parent.TranslateExpression(linq.Left);
1179                 DbExpression right = parent.TranslateExpression(linq.Right);
1180
1181                 //If the arguments are binary we translate into logic expressions
1182                 if (TypeSemantics.IsBooleanType(left.ResultType))
1183                 {
1184                     return TranslateIntoLogicExpression(parent, linq, left, right);
1185                 }
1186
1187                 //Otherwise we translate into bitwise canonical functions
1188                 return parent.CreateCanonicalFunction(_canonicalFunctionName, linq, left, right);
1189             }
1190             protected abstract DbExpression TranslateIntoLogicExpression(ExpressionConverter parent, System.Linq.Expressions.BinaryExpression linq, DbExpression left, DbExpression right);
1191         }
1192         private sealed class AndTranslator : BitwiseBinaryTranslator
1193         {
1194             internal AndTranslator()
1195                 : base(ExpressionType.And, ExpressionConverter.BitwiseAnd) { }
1196             protected override DbExpression TranslateIntoLogicExpression(ExpressionConverter parent, System.Linq.Expressions.BinaryExpression linq, DbExpression left, DbExpression right)
1197             {
1198                 return left.And(right);
1199             }
1200         }
1201         private sealed class OrTranslator : BitwiseBinaryTranslator
1202         {
1203             internal OrTranslator()
1204                 : base(ExpressionType.Or, ExpressionConverter.BitwiseOr) { }
1205             protected override DbExpression TranslateIntoLogicExpression(ExpressionConverter parent, System.Linq.Expressions.BinaryExpression linq, DbExpression left, DbExpression right)
1206             {
1207                 return left.Or(right);
1208             }
1209         }
1210         private sealed class ExclusiveOrTranslator : BitwiseBinaryTranslator
1211         {
1212             internal ExclusiveOrTranslator()
1213                 : base(ExpressionType.ExclusiveOr, ExpressionConverter.BitwiseXor) { }
1214             protected override DbExpression TranslateIntoLogicExpression(ExpressionConverter parent, System.Linq.Expressions.BinaryExpression linq, DbExpression left, DbExpression right)
1215             {
1216                 //No direct translation, we translate into ((left && !right) || (!left && right))
1217                 DbExpression firstExpression = left.And(right.Not());
1218                 DbExpression secondExpression = left.Not().And(right);
1219                 DbExpression result = firstExpression.Or(secondExpression);
1220                 return result;
1221             }
1222         }
1223         private sealed class NotTranslator : TypedTranslator<UnaryExpression>
1224         {
1225             internal NotTranslator()
1226                 : base(ExpressionType.Not) { }
1227             protected override DbExpression TypedTranslate(ExpressionConverter parent, System.Linq.Expressions.UnaryExpression linq)
1228             {
1229                 DbExpression operand = parent.TranslateExpression(linq.Operand);
1230                 if (TypeSemantics.IsBooleanType(operand.ResultType))
1231                 {
1232                     return operand.Not();
1233                 }
1234                 return parent.CreateCanonicalFunction(ExpressionConverter.BitwiseNot, linq, operand);
1235             }
1236         }
1237         #endregion
1238
1239         #region Unary expression translators
1240         private abstract class UnaryTranslator
1241             : TypedTranslator<System.Linq.Expressions.UnaryExpression>
1242         {
1243             protected UnaryTranslator(params ExpressionType[] nodeTypes)
1244                 : base(nodeTypes) { }
1245             protected override DbExpression TypedTranslate(ExpressionConverter parent, System.Linq.Expressions.UnaryExpression linq)
1246             {
1247                 return TranslateUnary(parent, linq, parent.TranslateExpression(linq.Operand));
1248             }
1249             protected abstract DbExpression TranslateUnary(ExpressionConverter parent, System.Linq.Expressions.UnaryExpression unary, DbExpression operand);
1250         }
1251         private sealed class QuoteTranslator : UnaryTranslator
1252         {
1253             internal QuoteTranslator()
1254                 : base(ExpressionType.Quote) { }
1255             protected override DbExpression TranslateUnary(ExpressionConverter parent, System.Linq.Expressions.UnaryExpression unary, DbExpression operand)
1256             {
1257                 // simply return the operand: expressions compilations not cached for LINQ, so
1258                 // parameters are always bound properly
1259                 return operand;
1260             }
1261         }
1262         private sealed class ConvertTranslator : UnaryTranslator
1263         {
1264             internal ConvertTranslator()
1265                 : base(ExpressionType.Convert, ExpressionType.ConvertChecked) { }
1266             protected override DbExpression TranslateUnary(ExpressionConverter parent, System.Linq.Expressions.UnaryExpression unary, DbExpression operand)
1267             {
1268                 Type toClrType = unary.Type;
1269                 Type fromClrType = unary.Operand.Type;
1270                 DbExpression cast = parent.CreateCastExpression(operand, toClrType, fromClrType);
1271                 return cast;
1272             }
1273         }
1274         private sealed class AsTranslator : UnaryTranslator
1275         {
1276             internal AsTranslator()
1277                 : base(ExpressionType.TypeAs) { }
1278             protected override DbExpression TranslateUnary(ExpressionConverter parent, System.Linq.Expressions.UnaryExpression unary, DbExpression operand)
1279             {
1280                 TypeUsage fromType = operand.ResultType;
1281                 TypeUsage toType = parent.GetIsOrAsTargetType(fromType, ExpressionType.TypeAs, unary.Type, unary.Operand.Type);
1282                 return operand.TreatAs(toType);
1283             }
1284         }
1285         #endregion
1286     }
1287 }