//---------------------------------------------------------------------
//
// Copyright (c) Microsoft Corporation. All rights reserved.
//
//
// @owner [....]
// @backupOwner [....]
//---------------------------------------------------------------------
using System.Data.Common.CommandTrees;
using System.Data.Common.CommandTrees.Internal;
using System.Collections.Generic;
using System.Data.Metadata.Edm;
using System.Linq;
using System.Globalization;
using System.Diagnostics;
using System.Data.Common.Utils;
namespace System.Data.Mapping.ViewGeneration
{
///
/// Describes top-level query mapping view projection of the form:
///
/// SELECT VALUE CASE
/// WHEN Discriminator = DiscriminatorValue1 THEN EntityType1(...)
/// WHEN Discriminator = DiscriminatorValue2 THEN EntityType2(...)
/// ...
///
/// Supports optimizing queries to leverage user supplied discriminator values
/// in TPH mappings rather than introducing our own. This avoids the need
/// to introduce a CASE statement in the store.
///
internal class DiscriminatorMap
{
///
/// Expression retrieving discriminator value from projection input.
///
internal readonly DbPropertyExpression Discriminator;
///
/// Map from discriminator values to implied entity type.
///
internal readonly System.Collections.ObjectModel.ReadOnlyCollection> TypeMap;
///
/// Map from entity property to expression generating value for that property. Note that
/// the expression must be the same for all types in discriminator map.
///
internal readonly System.Collections.ObjectModel.ReadOnlyCollection> PropertyMap;
///
/// Map from entity relproperty to expression generating value for that property. Note that
/// the expression must be the same for all types in discriminator map.
///
internal readonly System.Collections.ObjectModel.ReadOnlyCollection> RelPropertyMap;
///
/// EntitySet to which the map applies.
///
internal readonly EntitySet EntitySet;
private DiscriminatorMap(DbPropertyExpression discriminator,
List> typeMap,
Dictionary propertyMap,
Dictionary relPropertyMap,
EntitySet entitySet)
{
this.Discriminator = discriminator;
this.TypeMap = typeMap.AsReadOnly();
this.PropertyMap = propertyMap.ToList().AsReadOnly();
this.RelPropertyMap = relPropertyMap.ToList().AsReadOnly();
this.EntitySet = entitySet;
}
///
/// Determines whether the given query view matches the discriminator map pattern.
///
internal static bool TryCreateDiscriminatorMap(EntitySet entitySet, DbExpression queryView, out DiscriminatorMap discriminatorMap)
{
discriminatorMap = null;
if (queryView.ExpressionKind != DbExpressionKind.Project) { return false; }
var project = (DbProjectExpression)queryView;
if (project.Projection.ExpressionKind != DbExpressionKind.Case) { return false; }
var caseExpression = (DbCaseExpression)project.Projection;
if (project.Projection.ResultType.EdmType.BuiltInTypeKind != BuiltInTypeKind.EntityType) { return false; }
// determine value domain by walking filter
if (project.Input.Expression.ExpressionKind != DbExpressionKind.Filter) { return false; }
var filterExpression = (DbFilterExpression)project.Input.Expression;
HashSet