ViewValidator.cs source code in C# .NET

Source code for the .NET framework in C#

                        

Code:

/ 4.0 / 4.0 / DEVDIV_TFS / Dev10 / Releases / RTMRel / ndp / fx / src / DataEntity / System / Data / Mapping / ViewValidator.cs / 1305376 / ViewValidator.cs

                            //---------------------------------------------------------------------- 
// 
//      Copyright (c) Microsoft Corporation.  All rights reserved.
// 
// 
// @owner       [....]
// @backupOwner [....] 
//--------------------------------------------------------------------- 

using System.Data.Metadata.Edm; 
using System.Globalization;
using System.Data.Common.CommandTrees;
using System.Collections.Generic;
using System.Diagnostics; 
using System.Data.Entity;
using System.Linq; 
using System.Data.Common.Utils; 

namespace System.Data.Mapping 
{
    /// 
    /// Verifies that only legal expressions exist in a user-defined query mapping view.
    /// 
    /// -	ViewExpr = (see ViewExpressionValidator)
    ///         Project(Projection, ViewExpr) | 
    ///         Project(Value, ViewExpr) | 
    ///         Filter(ViewExpr, ViewExpr) |
    ///         Join(ViewExpr, ViewExpr, ViewExpr) | 
    ///         UnionAll(ViewExpr, ViewExpr) |
    ///         Scan(S-Space EntitySet)
    ///         Constant |
    ///         Property{StructuralProperty}(ViewExpr) | 
    ///         Null |
    ///         VariableReference | 
    ///         Cast(ViewExpr) | 
    ///         Case([Predicate, ViewExpr]*, ViewExpr) |
    ///         Comparison(ViewExpr, ViewExpr) | 
    ///         Not(ViewExpr) |
    ///         And(ViewExpr, ViewExpr) |
    ///         Or(ViewExpr, ViewExpr) |
    ///         IsNull(ViewExpr) 
    /// -	Projection = (see ViewExpressionValidator.Visit(DbProjectExpression)
    ///         NewInstance{TargetEntity}(ViewExpr*) | 
    ///         NewInstance{Row}(ViewExpr*) 
    /// 
    internal static class ViewValidator 
    {
        /// 
        /// Determines whether the given view is valid.
        ///  
        /// Query view to validate.
        /// Store item collection. 
        /// Mapping in which view is declared. 
        /// Errors in view definition.
        internal static IEnumerable ValidateQueryView(DbQueryCommandTree view, StorageSetMapping setMapping, EntityTypeBase elementType, bool includeSubtypes) 
        {
            ViewExpressionValidator validator = new ViewExpressionValidator(setMapping, elementType, includeSubtypes);
            validator.VisitExpression(view.Query);
            if (validator.Errors.Count() == 0) 
            {
                //For AssociationSet views, we have to check for a specific pattern of errors where 
                //the Ref expression passed into the construcor might use an EntitySet that is different from 
                //the EntitySet defined in the CSDL.
                if (setMapping.Set.BuiltInTypeKind == BuiltInTypeKind.AssociationSet) 
                {
                    AssociationSetViewValidator refValidator = new AssociationSetViewValidator(setMapping);
                    refValidator.VisitExpression(view.Query);
                    return refValidator.Errors; 
                }
            } 
            return validator.Errors; 
        }
 
        private sealed class ViewExpressionValidator : BasicExpressionVisitor
        {
            private readonly StorageSetMapping _setMapping;
            private readonly List _errors; 
            private readonly EntityTypeBase _elementType;
            private readonly bool _includeSubtypes; 
 
            private EdmItemCollection EdmItemCollection { get { return _setMapping.EntityContainerMapping.StorageMappingItemCollection.EdmItemCollection; } }
 
            internal ViewExpressionValidator(StorageSetMapping setMapping, EntityTypeBase elementType, bool includeSubtypes)
            {
                Debug.Assert(null != setMapping);
                Debug.Assert(null != elementType); 

                _setMapping = setMapping; 
                _elementType = elementType; 
                _includeSubtypes = includeSubtypes;
 
                _errors = new List();
            }

            internal IEnumerable Errors { get { return _errors; } } 

            public override void VisitExpression(DbExpression expression) 
            { 
                if (null != expression)
                { 
                    ValidateExpressionKind(expression.ExpressionKind);
                }
                base.VisitExpression(expression);
            } 

            private void ValidateExpressionKind(DbExpressionKind expressionKind) 
            { 
                switch (expressionKind)
                { 
                    // Supported expression kinds
                    case DbExpressionKind.Constant:
                    case DbExpressionKind.Property:
                    case DbExpressionKind.Null: 
                    case DbExpressionKind.VariableReference:
                    case DbExpressionKind.Cast: 
                    case DbExpressionKind.Case: 
                    case DbExpressionKind.Not:
                    case DbExpressionKind.Or: 
                    case DbExpressionKind.And:
                    case DbExpressionKind.IsNull:
                    case DbExpressionKind.Equals:
                    case DbExpressionKind.NotEquals: 
                    case DbExpressionKind.LessThan:
                    case DbExpressionKind.LessThanOrEquals: 
                    case DbExpressionKind.GreaterThan: 
                    case DbExpressionKind.GreaterThanOrEquals:
                    case DbExpressionKind.Project: 
                    case DbExpressionKind.NewInstance:
                    case DbExpressionKind.Filter:
                    case DbExpressionKind.Ref:
                    case DbExpressionKind.UnionAll: 
                    case DbExpressionKind.Scan:
                    case DbExpressionKind.FullOuterJoin: 
                    case DbExpressionKind.LeftOuterJoin: 
                    case DbExpressionKind.InnerJoin:
                    case DbExpressionKind.EntityRef: 
                        break;
                    default:
                        string elementString = (_includeSubtypes) ? "IsTypeOf(" + _elementType.ToString() + ")" : _elementType.ToString();
                        _errors.Add(new EdmSchemaError(System.Data.Entity.Strings.Mapping_UnsupportedExpressionKind_QueryView_2( 
                            _setMapping.Set.Name, elementString, expressionKind), (int)StorageMappingErrorCode.MappingUnsupportedExpressionKindQueryView,
                            EdmSchemaErrorSeverity.Error, _setMapping.EntityContainerMapping.SourceLocation, _setMapping.StartLineNumber, 
                            _setMapping.StartLinePosition)); 
                        break;
                } 
            }

            public override void Visit(DbPropertyExpression expression)
            { 
                base.Visit(expression);
                if (expression.Property.BuiltInTypeKind != BuiltInTypeKind.EdmProperty) 
                { 
                    _errors.Add(new EdmSchemaError(System.Data.Entity.Strings.Mapping_UnsupportedPropertyKind_QueryView_3(
                        _setMapping.Set.Name, expression.Property.Name, expression.Property.BuiltInTypeKind), (int)StorageMappingErrorCode.MappingUnsupportedPropertyKindQueryView, 
                        EdmSchemaErrorSeverity.Error, _setMapping.EntityContainerMapping.SourceLocation, _setMapping.StartLineNumber,
                        _setMapping.StartLinePosition));

                } 
            }
 
            public override void Visit(DbNewInstanceExpression expression) 
            {
                base.Visit(expression); 
                EdmType type = expression.ResultType.EdmType;
                if (type.BuiltInTypeKind != BuiltInTypeKind.RowType)
                {
                    // restrict initialization of non-row types to the target of the view or complex types 
                    // in the target
                    if (!(type == _elementType || (_includeSubtypes && _elementType.IsAssignableFrom(type))) && 
                        !(type.BuiltInTypeKind == BuiltInTypeKind.ComplexType && GetComplexTypes().Contains((ComplexType)type))) 
                    {
                        _errors.Add(new EdmSchemaError(System.Data.Entity.Strings.Mapping_UnsupportedInitialization_QueryView_2( 
                            _setMapping.Set.Name, type.FullName), (int)StorageMappingErrorCode.MappingUnsupportedInitializationQueryView,
                            EdmSchemaErrorSeverity.Error, _setMapping.EntityContainerMapping.SourceLocation, _setMapping.StartLineNumber,
                            _setMapping.StartLinePosition));
                    } 
                }
            } 
 
            /// 
            /// Retrieves all complex types that can be constructed as part of the view. 
            /// 
            private IEnumerable GetComplexTypes()
            {
                // Retrieve all top-level properties of entity types constructed in the view. 
                IEnumerable properties = GetEntityTypes().SelectMany(entityType => entityType.Properties).Distinct();
                return GetComplexTypes(properties); 
            } 

            ///  
            /// Recursively identify complex types.
            /// 
            private IEnumerable GetComplexTypes(IEnumerable properties)
            { 
                //
                foreach (ComplexType complexType in properties.Select(p => p.TypeUsage.EdmType).OfType()) 
                { 
                    yield return complexType;
                    foreach (ComplexType nestedComplexType in GetComplexTypes(complexType.Properties)) 
                    {
                        yield return nestedComplexType;
                    }
                } 
            }
 
            ///  
            /// Gets all entity types in scope for this view.
            ///  
            private IEnumerable GetEntityTypes()
            {
                if (_includeSubtypes)
                { 
                    // Return all entity types in the hierarchy for OfType or 'complete' views.
                    return MetadataHelper.GetTypeAndSubtypesOf(_elementType, this.EdmItemCollection, true).OfType(); 
                } 
                else if (_elementType.BuiltInTypeKind == BuiltInTypeKind.EntityType)
                { 
                    // Yield single entity type for OfType(only ) views.
                    return Enumerable.Repeat((EntityType)_elementType, 1);
                }
                else 
                {
                    // For association set views, there are no entity types involved. 
                    return Enumerable.Empty(); 
                }
            } 

            public override void Visit(DbScanExpression expression)
            {
                base.Visit(expression); 
                Debug.Assert(null != expression.Target);
 
                // verify scan target is in S-space 
                EntitySetBase target = expression.Target;
                EntityContainer targetContainer = target.EntityContainer; 
                Debug.Assert(null != target.EntityContainer);

                if ((targetContainer.DataSpace != DataSpace.SSpace))
                { 
                    _errors.Add(new EdmSchemaError(System.Data.Entity.Strings.Mapping_UnsupportedScanTarget_QueryView_2(
                        _setMapping.Set.Name, target.Name), (int)StorageMappingErrorCode.MappingUnsupportedScanTargetQueryView, 
                        EdmSchemaErrorSeverity.Error, _setMapping.EntityContainerMapping.SourceLocation, _setMapping.StartLineNumber, 
                        _setMapping.StartLinePosition));
                } 
            }
        }
        /// 
        /// The visitor validates that the QueryView for an AssociationSet uses the same EntitySets when 
        /// creating the ends that were used in CSDL. Since the Query View is already validated, we can expect to
        /// see only a very restricted set of expressions in the tree. 
        ///  
        private class AssociationSetViewValidator : DbExpressionVisitor
        { 
            private readonly Stack> variableScopes = new Stack>();
            private StorageSetMapping _setMapping;
            private List _errors = new List();
 
            internal AssociationSetViewValidator(StorageSetMapping setMapping)
                : base() 
            { 
                Debug.Assert(setMapping != null);
                _setMapping = setMapping; 
            }

            internal List Errors
            { 
                get { return _errors; }
            } 
 
            internal DbExpressionEntitySetInfo VisitExpression(DbExpression expression)
            { 
                return expression.Accept(this);
            }

            private DbExpressionEntitySetInfo VisitExpressionBinding(DbExpressionBinding binding) 
            {
                DbExpressionBinding result = binding; 
                if (binding != null) 
                {
                    return this.VisitExpression(binding.Expression); 
                }
                return null;
            }
 
            private void VisitExpressionBindingEnterScope(DbExpressionBinding binding)
            { 
                DbExpressionEntitySetInfo info = this.VisitExpressionBinding(binding); 
                this.variableScopes.Push(new KeyValuePair(binding.VariableName, info));
            } 

            private void VisitExpressionBindingExitScope()
            {
                this.variableScopes.Pop(); 
            }
 
            //Verifies that the Sets we got from visiting the tree( under AssociationType constructor) match the ones 
            //defined in CSDL
            private void ValidateEntitySetsMappedForAssociationSetMapping(DbExpressionStructuralTypeEntitySetInfo setInfos) 
            {
                AssociationSet associationSet = _setMapping.Set as AssociationSet;
                int i = 0;
                //While we should be able to find the EntitySets in all cases, since this is a user specified 
                //query view, it is better to be defensive since we might have missed some path up the tree
                //while computing the sets 
                if (setInfos.SetInfos.All(it => ((it.Value != null) && (it.Value is DbExpressionSimpleTypeEntitySetInfo))) 
                    && setInfos.SetInfos.Count() == 2)
                { 
                    foreach (DbExpressionSimpleTypeEntitySetInfo setInfo in setInfos.SetInfos.Select(it => it.Value))
                    {
                        AssociationSetEnd setEnd = associationSet.AssociationSetEnds[i];
                        EntitySet declaredSet = setEnd.EntitySet; 
                        if (!declaredSet.Equals(setInfo.EntitySet))
                        { 
                            _errors.Add(new EdmSchemaError(System.Data.Entity.Strings.Mapping_EntitySetMismatchOnAssociationSetEnd_QueryView_4( 
                            setInfo.EntitySet.Name, declaredSet.Name, setEnd.Name, _setMapping.Set.Name), (int)StorageMappingErrorCode.MappingUnsupportedInitializationQueryView,
                            EdmSchemaErrorSeverity.Error, _setMapping.EntityContainerMapping.SourceLocation, _setMapping.StartLineNumber, 
                            _setMapping.StartLinePosition));
                        }
                        i++;
                    } 
                }
            } 
 

            #region DbExpressionVisitor Members 
            public override DbExpressionEntitySetInfo Visit(DbExpression expression)
            {
                return null;
            } 

            public override DbExpressionEntitySetInfo Visit(DbVariableReferenceExpression expression) 
            { 
                return this.variableScopes.Where(it => (it.Key == expression.VariableName)).Select(it => it.Value).FirstOrDefault();
            } 

            public override DbExpressionEntitySetInfo Visit(DbPropertyExpression expression)
            {
                DbExpressionStructuralTypeEntitySetInfo setInfos = VisitExpression(expression.Instance) as DbExpressionStructuralTypeEntitySetInfo; 
                if (setInfos != null)
                { 
                    return setInfos.GetEntitySetInfoForMember(expression.Property.Name); 
                }
                return null; 
            }

            public override DbExpressionEntitySetInfo Visit(DbProjectExpression expression)
            { 
                this.VisitExpressionBindingEnterScope(expression.Input);
                DbExpressionEntitySetInfo setInfo = VisitExpression(expression.Projection); 
                this.VisitExpressionBindingExitScope(); 
                return setInfo;
            } 

            public override DbExpressionEntitySetInfo Visit(DbNewInstanceExpression expression)
            {
                DbExpressionMemberCollectionEntitySetInfo argumentSetInfos = VisitExpressionList(expression.Arguments); 
                StructuralType structuralType = (expression.ResultType.EdmType as StructuralType);
                if (argumentSetInfos != null && structuralType != null) 
                { 
                    DbExpressionStructuralTypeEntitySetInfo structuralTypeSetInfos = new DbExpressionStructuralTypeEntitySetInfo();
                    int i = 0; 
                    foreach (DbExpressionEntitySetInfo info in argumentSetInfos.entitySetInfos)
                    {
                        structuralTypeSetInfos.Add(structuralType.Members[i].Name, info);
                        i++; 
                    }
                    //Since we already validated the query view, the only association type that 
                    //can be constructed is the type for the set we are validating the mapping for. 
                    if (expression.ResultType.EdmType.BuiltInTypeKind == BuiltInTypeKind.AssociationType)
                    { 
                        ValidateEntitySetsMappedForAssociationSetMapping(structuralTypeSetInfos);
                    }
                    return structuralTypeSetInfos;
                } 
                return null;
            } 
 
            private DbExpressionMemberCollectionEntitySetInfo VisitExpressionList(IList list)
            { 
                return new DbExpressionMemberCollectionEntitySetInfo(list.Select(it => (VisitExpression(it))));
            }

 
            public override DbExpressionEntitySetInfo Visit(DbRefExpression expression)
            { 
                return new DbExpressionSimpleTypeEntitySetInfo(expression.EntitySet); 
            }
 

            public override DbExpressionEntitySetInfo Visit(DbComparisonExpression expression)
            {
                return null; 
            }
 
            public override DbExpressionEntitySetInfo Visit(DbLikeExpression expression) 
            {
                return null; 
            }

            public override DbExpressionEntitySetInfo Visit(DbLimitExpression expression)
            { 
                return null;
            } 
 
            public override DbExpressionEntitySetInfo Visit(DbIsNullExpression expression)
            { 
                return null;
            }

            public override DbExpressionEntitySetInfo Visit(DbArithmeticExpression expression) 
            {
                return null; 
            } 

            public override DbExpressionEntitySetInfo Visit(DbAndExpression expression) 
            {
                return null;
            }
 
            public override DbExpressionEntitySetInfo Visit(DbOrExpression expression)
            { 
                return null; 
            }
 
            public override DbExpressionEntitySetInfo Visit(DbNotExpression expression)
            {
                return null;
            } 

            public override DbExpressionEntitySetInfo Visit(DbDistinctExpression expression) 
            { 
                return null;
            } 

            public override DbExpressionEntitySetInfo Visit(DbElementExpression expression)
            {
                return null; 
            }
 
            public override DbExpressionEntitySetInfo Visit(DbIsEmptyExpression expression) 
            {
                return null; 
            }

            public override DbExpressionEntitySetInfo Visit(DbUnionAllExpression expression)
            { 
                return null;
            } 
 
            public override DbExpressionEntitySetInfo Visit(DbIntersectExpression expression)
            { 
                return null;
            }

            public override DbExpressionEntitySetInfo Visit(DbExceptExpression expression) 
            {
                return null; 
            } 

            public override DbExpressionEntitySetInfo Visit(DbTreatExpression expression) 
            {
                return null;
            }
 
            public override DbExpressionEntitySetInfo Visit(DbIsOfExpression expression)
            { 
                return null; 
            }
 
            public override DbExpressionEntitySetInfo Visit(DbCastExpression expression)
            {
                return null;
            } 

            public override DbExpressionEntitySetInfo Visit(DbCaseExpression expression) 
            { 
                return null;
            } 

            public override DbExpressionEntitySetInfo Visit(DbOfTypeExpression expression)
            {
                return null; 
            }
 
            public override DbExpressionEntitySetInfo Visit(DbRelationshipNavigationExpression expression) 
            {
                return null; 
            }

            public override DbExpressionEntitySetInfo Visit(DbDerefExpression expression)
            { 
                return null;
            } 
 
            public override DbExpressionEntitySetInfo Visit(DbRefKeyExpression expression)
            { 
                return null;
            }

            public override DbExpressionEntitySetInfo Visit(DbEntityRefExpression expression) 
            {
                return null; 
            } 

            public override DbExpressionEntitySetInfo Visit(DbScanExpression expression) 
            {
                return null;
            }
 
            public override DbExpressionEntitySetInfo Visit(DbFilterExpression expression)
            { 
                return null; 
            }
 
            public override DbExpressionEntitySetInfo Visit(DbConstantExpression expression)
            {
                return null;
            } 

            public override DbExpressionEntitySetInfo Visit(DbNullExpression expression) 
            { 
                return null;
            } 

            public override DbExpressionEntitySetInfo Visit(DbCrossJoinExpression expression)
            {
                return null; 
            }
 
            public override DbExpressionEntitySetInfo Visit(DbJoinExpression expression) 
            {
                return null; 
            }

            public override DbExpressionEntitySetInfo Visit(DbParameterReferenceExpression expression)
            { 
                return null;
            } 
 
            public override DbExpressionEntitySetInfo Visit(DbFunctionExpression expression)
            { 
                return null;
            }

            public override DbExpressionEntitySetInfo Visit(DbLambdaExpression expression) 
            {
                return null; 
            } 

 
            public override DbExpressionEntitySetInfo Visit(DbApplyExpression expression)
            {
                return null;
            } 

            public override DbExpressionEntitySetInfo Visit(DbGroupByExpression expression) 
            { 
                return null;
            } 

            public override DbExpressionEntitySetInfo Visit(DbSkipExpression expression)
            {
                return null; 
            }
 
            public override DbExpressionEntitySetInfo Visit(DbSortExpression expression) 
            {
                return null; 
            }

            public override DbExpressionEntitySetInfo Visit(DbQuantifierExpression expression)
            { 
                return null;
            } 
 
            #endregion
 
        }


        internal class DbExpressionEntitySetInfo 
        {
        } 
 

        private class DbExpressionSimpleTypeEntitySetInfo : DbExpressionEntitySetInfo 
        {
            private EntitySet m_entitySet;

            internal EntitySet EntitySet 
            {
                get { return m_entitySet; } 
            } 

            internal DbExpressionSimpleTypeEntitySetInfo(EntitySet entitySet) 
            {
                m_entitySet = entitySet;
            }
        } 

        private class DbExpressionStructuralTypeEntitySetInfo : DbExpressionEntitySetInfo 
        { 
            private Dictionary m_entitySetInfos;
 
            internal DbExpressionStructuralTypeEntitySetInfo()
            {
                m_entitySetInfos = new Dictionary();
            } 

            internal void Add(string key, DbExpressionEntitySetInfo value) 
            { 
                m_entitySetInfos.Add(key, value);
            } 

            internal IEnumerable> SetInfos
            {
                get 
                {
                    return m_entitySetInfos; 
                } 
            }
 
            internal DbExpressionEntitySetInfo GetEntitySetInfoForMember(string memberName)
            {
                return m_entitySetInfos[memberName];
            } 
        }
 
        private class DbExpressionMemberCollectionEntitySetInfo : DbExpressionEntitySetInfo 
        {
            private IEnumerable m_entitySets; 

            internal DbExpressionMemberCollectionEntitySetInfo(IEnumerable entitySetInfos)
            {
                m_entitySets = entitySetInfos; 
            }
 
            internal IEnumerable entitySetInfos 
            {
                get 
                {
                    return m_entitySets;
                }
            } 
        }
    } 
} 

// File provided for Reference Use Only by Microsoft Corporation (c) 2007.
//---------------------------------------------------------------------- 
// 
//      Copyright (c) Microsoft Corporation.  All rights reserved.
// 
// 
// @owner       [....]
// @backupOwner [....] 
//--------------------------------------------------------------------- 

using System.Data.Metadata.Edm; 
using System.Globalization;
using System.Data.Common.CommandTrees;
using System.Collections.Generic;
using System.Diagnostics; 
using System.Data.Entity;
using System.Linq; 
using System.Data.Common.Utils; 

namespace System.Data.Mapping 
{
    /// 
    /// Verifies that only legal expressions exist in a user-defined query mapping view.
    /// 
    /// -	ViewExpr = (see ViewExpressionValidator)
    ///         Project(Projection, ViewExpr) | 
    ///         Project(Value, ViewExpr) | 
    ///         Filter(ViewExpr, ViewExpr) |
    ///         Join(ViewExpr, ViewExpr, ViewExpr) | 
    ///         UnionAll(ViewExpr, ViewExpr) |
    ///         Scan(S-Space EntitySet)
    ///         Constant |
    ///         Property{StructuralProperty}(ViewExpr) | 
    ///         Null |
    ///         VariableReference | 
    ///         Cast(ViewExpr) | 
    ///         Case([Predicate, ViewExpr]*, ViewExpr) |
    ///         Comparison(ViewExpr, ViewExpr) | 
    ///         Not(ViewExpr) |
    ///         And(ViewExpr, ViewExpr) |
    ///         Or(ViewExpr, ViewExpr) |
    ///         IsNull(ViewExpr) 
    /// -	Projection = (see ViewExpressionValidator.Visit(DbProjectExpression)
    ///         NewInstance{TargetEntity}(ViewExpr*) | 
    ///         NewInstance{Row}(ViewExpr*) 
    /// 
    internal static class ViewValidator 
    {
        /// 
        /// Determines whether the given view is valid.
        ///  
        /// Query view to validate.
        /// Store item collection. 
        /// Mapping in which view is declared. 
        /// Errors in view definition.
        internal static IEnumerable ValidateQueryView(DbQueryCommandTree view, StorageSetMapping setMapping, EntityTypeBase elementType, bool includeSubtypes) 
        {
            ViewExpressionValidator validator = new ViewExpressionValidator(setMapping, elementType, includeSubtypes);
            validator.VisitExpression(view.Query);
            if (validator.Errors.Count() == 0) 
            {
                //For AssociationSet views, we have to check for a specific pattern of errors where 
                //the Ref expression passed into the construcor might use an EntitySet that is different from 
                //the EntitySet defined in the CSDL.
                if (setMapping.Set.BuiltInTypeKind == BuiltInTypeKind.AssociationSet) 
                {
                    AssociationSetViewValidator refValidator = new AssociationSetViewValidator(setMapping);
                    refValidator.VisitExpression(view.Query);
                    return refValidator.Errors; 
                }
            } 
            return validator.Errors; 
        }
 
        private sealed class ViewExpressionValidator : BasicExpressionVisitor
        {
            private readonly StorageSetMapping _setMapping;
            private readonly List _errors; 
            private readonly EntityTypeBase _elementType;
            private readonly bool _includeSubtypes; 
 
            private EdmItemCollection EdmItemCollection { get { return _setMapping.EntityContainerMapping.StorageMappingItemCollection.EdmItemCollection; } }
 
            internal ViewExpressionValidator(StorageSetMapping setMapping, EntityTypeBase elementType, bool includeSubtypes)
            {
                Debug.Assert(null != setMapping);
                Debug.Assert(null != elementType); 

                _setMapping = setMapping; 
                _elementType = elementType; 
                _includeSubtypes = includeSubtypes;
 
                _errors = new List();
            }

            internal IEnumerable Errors { get { return _errors; } } 

            public override void VisitExpression(DbExpression expression) 
            { 
                if (null != expression)
                { 
                    ValidateExpressionKind(expression.ExpressionKind);
                }
                base.VisitExpression(expression);
            } 

            private void ValidateExpressionKind(DbExpressionKind expressionKind) 
            { 
                switch (expressionKind)
                { 
                    // Supported expression kinds
                    case DbExpressionKind.Constant:
                    case DbExpressionKind.Property:
                    case DbExpressionKind.Null: 
                    case DbExpressionKind.VariableReference:
                    case DbExpressionKind.Cast: 
                    case DbExpressionKind.Case: 
                    case DbExpressionKind.Not:
                    case DbExpressionKind.Or: 
                    case DbExpressionKind.And:
                    case DbExpressionKind.IsNull:
                    case DbExpressionKind.Equals:
                    case DbExpressionKind.NotEquals: 
                    case DbExpressionKind.LessThan:
                    case DbExpressionKind.LessThanOrEquals: 
                    case DbExpressionKind.GreaterThan: 
                    case DbExpressionKind.GreaterThanOrEquals:
                    case DbExpressionKind.Project: 
                    case DbExpressionKind.NewInstance:
                    case DbExpressionKind.Filter:
                    case DbExpressionKind.Ref:
                    case DbExpressionKind.UnionAll: 
                    case DbExpressionKind.Scan:
                    case DbExpressionKind.FullOuterJoin: 
                    case DbExpressionKind.LeftOuterJoin: 
                    case DbExpressionKind.InnerJoin:
                    case DbExpressionKind.EntityRef: 
                        break;
                    default:
                        string elementString = (_includeSubtypes) ? "IsTypeOf(" + _elementType.ToString() + ")" : _elementType.ToString();
                        _errors.Add(new EdmSchemaError(System.Data.Entity.Strings.Mapping_UnsupportedExpressionKind_QueryView_2( 
                            _setMapping.Set.Name, elementString, expressionKind), (int)StorageMappingErrorCode.MappingUnsupportedExpressionKindQueryView,
                            EdmSchemaErrorSeverity.Error, _setMapping.EntityContainerMapping.SourceLocation, _setMapping.StartLineNumber, 
                            _setMapping.StartLinePosition)); 
                        break;
                } 
            }

            public override void Visit(DbPropertyExpression expression)
            { 
                base.Visit(expression);
                if (expression.Property.BuiltInTypeKind != BuiltInTypeKind.EdmProperty) 
                { 
                    _errors.Add(new EdmSchemaError(System.Data.Entity.Strings.Mapping_UnsupportedPropertyKind_QueryView_3(
                        _setMapping.Set.Name, expression.Property.Name, expression.Property.BuiltInTypeKind), (int)StorageMappingErrorCode.MappingUnsupportedPropertyKindQueryView, 
                        EdmSchemaErrorSeverity.Error, _setMapping.EntityContainerMapping.SourceLocation, _setMapping.StartLineNumber,
                        _setMapping.StartLinePosition));

                } 
            }
 
            public override void Visit(DbNewInstanceExpression expression) 
            {
                base.Visit(expression); 
                EdmType type = expression.ResultType.EdmType;
                if (type.BuiltInTypeKind != BuiltInTypeKind.RowType)
                {
                    // restrict initialization of non-row types to the target of the view or complex types 
                    // in the target
                    if (!(type == _elementType || (_includeSubtypes && _elementType.IsAssignableFrom(type))) && 
                        !(type.BuiltInTypeKind == BuiltInTypeKind.ComplexType && GetComplexTypes().Contains((ComplexType)type))) 
                    {
                        _errors.Add(new EdmSchemaError(System.Data.Entity.Strings.Mapping_UnsupportedInitialization_QueryView_2( 
                            _setMapping.Set.Name, type.FullName), (int)StorageMappingErrorCode.MappingUnsupportedInitializationQueryView,
                            EdmSchemaErrorSeverity.Error, _setMapping.EntityContainerMapping.SourceLocation, _setMapping.StartLineNumber,
                            _setMapping.StartLinePosition));
                    } 
                }
            } 
 
            /// 
            /// Retrieves all complex types that can be constructed as part of the view. 
            /// 
            private IEnumerable GetComplexTypes()
            {
                // Retrieve all top-level properties of entity types constructed in the view. 
                IEnumerable properties = GetEntityTypes().SelectMany(entityType => entityType.Properties).Distinct();
                return GetComplexTypes(properties); 
            } 

            ///  
            /// Recursively identify complex types.
            /// 
            private IEnumerable GetComplexTypes(IEnumerable properties)
            { 
                //
                foreach (ComplexType complexType in properties.Select(p => p.TypeUsage.EdmType).OfType()) 
                { 
                    yield return complexType;
                    foreach (ComplexType nestedComplexType in GetComplexTypes(complexType.Properties)) 
                    {
                        yield return nestedComplexType;
                    }
                } 
            }
 
            ///  
            /// Gets all entity types in scope for this view.
            ///  
            private IEnumerable GetEntityTypes()
            {
                if (_includeSubtypes)
                { 
                    // Return all entity types in the hierarchy for OfType or 'complete' views.
                    return MetadataHelper.GetTypeAndSubtypesOf(_elementType, this.EdmItemCollection, true).OfType(); 
                } 
                else if (_elementType.BuiltInTypeKind == BuiltInTypeKind.EntityType)
                { 
                    // Yield single entity type for OfType(only ) views.
                    return Enumerable.Repeat((EntityType)_elementType, 1);
                }
                else 
                {
                    // For association set views, there are no entity types involved. 
                    return Enumerable.Empty(); 
                }
            } 

            public override void Visit(DbScanExpression expression)
            {
                base.Visit(expression); 
                Debug.Assert(null != expression.Target);
 
                // verify scan target is in S-space 
                EntitySetBase target = expression.Target;
                EntityContainer targetContainer = target.EntityContainer; 
                Debug.Assert(null != target.EntityContainer);

                if ((targetContainer.DataSpace != DataSpace.SSpace))
                { 
                    _errors.Add(new EdmSchemaError(System.Data.Entity.Strings.Mapping_UnsupportedScanTarget_QueryView_2(
                        _setMapping.Set.Name, target.Name), (int)StorageMappingErrorCode.MappingUnsupportedScanTargetQueryView, 
                        EdmSchemaErrorSeverity.Error, _setMapping.EntityContainerMapping.SourceLocation, _setMapping.StartLineNumber, 
                        _setMapping.StartLinePosition));
                } 
            }
        }
        /// 
        /// The visitor validates that the QueryView for an AssociationSet uses the same EntitySets when 
        /// creating the ends that were used in CSDL. Since the Query View is already validated, we can expect to
        /// see only a very restricted set of expressions in the tree. 
        ///  
        private class AssociationSetViewValidator : DbExpressionVisitor
        { 
            private readonly Stack> variableScopes = new Stack>();
            private StorageSetMapping _setMapping;
            private List _errors = new List();
 
            internal AssociationSetViewValidator(StorageSetMapping setMapping)
                : base() 
            { 
                Debug.Assert(setMapping != null);
                _setMapping = setMapping; 
            }

            internal List Errors
            { 
                get { return _errors; }
            } 
 
            internal DbExpressionEntitySetInfo VisitExpression(DbExpression expression)
            { 
                return expression.Accept(this);
            }

            private DbExpressionEntitySetInfo VisitExpressionBinding(DbExpressionBinding binding) 
            {
                DbExpressionBinding result = binding; 
                if (binding != null) 
                {
                    return this.VisitExpression(binding.Expression); 
                }
                return null;
            }
 
            private void VisitExpressionBindingEnterScope(DbExpressionBinding binding)
            { 
                DbExpressionEntitySetInfo info = this.VisitExpressionBinding(binding); 
                this.variableScopes.Push(new KeyValuePair(binding.VariableName, info));
            } 

            private void VisitExpressionBindingExitScope()
            {
                this.variableScopes.Pop(); 
            }
 
            //Verifies that the Sets we got from visiting the tree( under AssociationType constructor) match the ones 
            //defined in CSDL
            private void ValidateEntitySetsMappedForAssociationSetMapping(DbExpressionStructuralTypeEntitySetInfo setInfos) 
            {
                AssociationSet associationSet = _setMapping.Set as AssociationSet;
                int i = 0;
                //While we should be able to find the EntitySets in all cases, since this is a user specified 
                //query view, it is better to be defensive since we might have missed some path up the tree
                //while computing the sets 
                if (setInfos.SetInfos.All(it => ((it.Value != null) && (it.Value is DbExpressionSimpleTypeEntitySetInfo))) 
                    && setInfos.SetInfos.Count() == 2)
                { 
                    foreach (DbExpressionSimpleTypeEntitySetInfo setInfo in setInfos.SetInfos.Select(it => it.Value))
                    {
                        AssociationSetEnd setEnd = associationSet.AssociationSetEnds[i];
                        EntitySet declaredSet = setEnd.EntitySet; 
                        if (!declaredSet.Equals(setInfo.EntitySet))
                        { 
                            _errors.Add(new EdmSchemaError(System.Data.Entity.Strings.Mapping_EntitySetMismatchOnAssociationSetEnd_QueryView_4( 
                            setInfo.EntitySet.Name, declaredSet.Name, setEnd.Name, _setMapping.Set.Name), (int)StorageMappingErrorCode.MappingUnsupportedInitializationQueryView,
                            EdmSchemaErrorSeverity.Error, _setMapping.EntityContainerMapping.SourceLocation, _setMapping.StartLineNumber, 
                            _setMapping.StartLinePosition));
                        }
                        i++;
                    } 
                }
            } 
 

            #region DbExpressionVisitor Members 
            public override DbExpressionEntitySetInfo Visit(DbExpression expression)
            {
                return null;
            } 

            public override DbExpressionEntitySetInfo Visit(DbVariableReferenceExpression expression) 
            { 
                return this.variableScopes.Where(it => (it.Key == expression.VariableName)).Select(it => it.Value).FirstOrDefault();
            } 

            public override DbExpressionEntitySetInfo Visit(DbPropertyExpression expression)
            {
                DbExpressionStructuralTypeEntitySetInfo setInfos = VisitExpression(expression.Instance) as DbExpressionStructuralTypeEntitySetInfo; 
                if (setInfos != null)
                { 
                    return setInfos.GetEntitySetInfoForMember(expression.Property.Name); 
                }
                return null; 
            }

            public override DbExpressionEntitySetInfo Visit(DbProjectExpression expression)
            { 
                this.VisitExpressionBindingEnterScope(expression.Input);
                DbExpressionEntitySetInfo setInfo = VisitExpression(expression.Projection); 
                this.VisitExpressionBindingExitScope(); 
                return setInfo;
            } 

            public override DbExpressionEntitySetInfo Visit(DbNewInstanceExpression expression)
            {
                DbExpressionMemberCollectionEntitySetInfo argumentSetInfos = VisitExpressionList(expression.Arguments); 
                StructuralType structuralType = (expression.ResultType.EdmType as StructuralType);
                if (argumentSetInfos != null && structuralType != null) 
                { 
                    DbExpressionStructuralTypeEntitySetInfo structuralTypeSetInfos = new DbExpressionStructuralTypeEntitySetInfo();
                    int i = 0; 
                    foreach (DbExpressionEntitySetInfo info in argumentSetInfos.entitySetInfos)
                    {
                        structuralTypeSetInfos.Add(structuralType.Members[i].Name, info);
                        i++; 
                    }
                    //Since we already validated the query view, the only association type that 
                    //can be constructed is the type for the set we are validating the mapping for. 
                    if (expression.ResultType.EdmType.BuiltInTypeKind == BuiltInTypeKind.AssociationType)
                    { 
                        ValidateEntitySetsMappedForAssociationSetMapping(structuralTypeSetInfos);
                    }
                    return structuralTypeSetInfos;
                } 
                return null;
            } 
 
            private DbExpressionMemberCollectionEntitySetInfo VisitExpressionList(IList list)
            { 
                return new DbExpressionMemberCollectionEntitySetInfo(list.Select(it => (VisitExpression(it))));
            }

 
            public override DbExpressionEntitySetInfo Visit(DbRefExpression expression)
            { 
                return new DbExpressionSimpleTypeEntitySetInfo(expression.EntitySet); 
            }
 

            public override DbExpressionEntitySetInfo Visit(DbComparisonExpression expression)
            {
                return null; 
            }
 
            public override DbExpressionEntitySetInfo Visit(DbLikeExpression expression) 
            {
                return null; 
            }

            public override DbExpressionEntitySetInfo Visit(DbLimitExpression expression)
            { 
                return null;
            } 
 
            public override DbExpressionEntitySetInfo Visit(DbIsNullExpression expression)
            { 
                return null;
            }

            public override DbExpressionEntitySetInfo Visit(DbArithmeticExpression expression) 
            {
                return null; 
            } 

            public override DbExpressionEntitySetInfo Visit(DbAndExpression expression) 
            {
                return null;
            }
 
            public override DbExpressionEntitySetInfo Visit(DbOrExpression expression)
            { 
                return null; 
            }
 
            public override DbExpressionEntitySetInfo Visit(DbNotExpression expression)
            {
                return null;
            } 

            public override DbExpressionEntitySetInfo Visit(DbDistinctExpression expression) 
            { 
                return null;
            } 

            public override DbExpressionEntitySetInfo Visit(DbElementExpression expression)
            {
                return null; 
            }
 
            public override DbExpressionEntitySetInfo Visit(DbIsEmptyExpression expression) 
            {
                return null; 
            }

            public override DbExpressionEntitySetInfo Visit(DbUnionAllExpression expression)
            { 
                return null;
            } 
 
            public override DbExpressionEntitySetInfo Visit(DbIntersectExpression expression)
            { 
                return null;
            }

            public override DbExpressionEntitySetInfo Visit(DbExceptExpression expression) 
            {
                return null; 
            } 

            public override DbExpressionEntitySetInfo Visit(DbTreatExpression expression) 
            {
                return null;
            }
 
            public override DbExpressionEntitySetInfo Visit(DbIsOfExpression expression)
            { 
                return null; 
            }
 
            public override DbExpressionEntitySetInfo Visit(DbCastExpression expression)
            {
                return null;
            } 

            public override DbExpressionEntitySetInfo Visit(DbCaseExpression expression) 
            { 
                return null;
            } 

            public override DbExpressionEntitySetInfo Visit(DbOfTypeExpression expression)
            {
                return null; 
            }
 
            public override DbExpressionEntitySetInfo Visit(DbRelationshipNavigationExpression expression) 
            {
                return null; 
            }

            public override DbExpressionEntitySetInfo Visit(DbDerefExpression expression)
            { 
                return null;
            } 
 
            public override DbExpressionEntitySetInfo Visit(DbRefKeyExpression expression)
            { 
                return null;
            }

            public override DbExpressionEntitySetInfo Visit(DbEntityRefExpression expression) 
            {
                return null; 
            } 

            public override DbExpressionEntitySetInfo Visit(DbScanExpression expression) 
            {
                return null;
            }
 
            public override DbExpressionEntitySetInfo Visit(DbFilterExpression expression)
            { 
                return null; 
            }
 
            public override DbExpressionEntitySetInfo Visit(DbConstantExpression expression)
            {
                return null;
            } 

            public override DbExpressionEntitySetInfo Visit(DbNullExpression expression) 
            { 
                return null;
            } 

            public override DbExpressionEntitySetInfo Visit(DbCrossJoinExpression expression)
            {
                return null; 
            }
 
            public override DbExpressionEntitySetInfo Visit(DbJoinExpression expression) 
            {
                return null; 
            }

            public override DbExpressionEntitySetInfo Visit(DbParameterReferenceExpression expression)
            { 
                return null;
            } 
 
            public override DbExpressionEntitySetInfo Visit(DbFunctionExpression expression)
            { 
                return null;
            }

            public override DbExpressionEntitySetInfo Visit(DbLambdaExpression expression) 
            {
                return null; 
            } 

 
            public override DbExpressionEntitySetInfo Visit(DbApplyExpression expression)
            {
                return null;
            } 

            public override DbExpressionEntitySetInfo Visit(DbGroupByExpression expression) 
            { 
                return null;
            } 

            public override DbExpressionEntitySetInfo Visit(DbSkipExpression expression)
            {
                return null; 
            }
 
            public override DbExpressionEntitySetInfo Visit(DbSortExpression expression) 
            {
                return null; 
            }

            public override DbExpressionEntitySetInfo Visit(DbQuantifierExpression expression)
            { 
                return null;
            } 
 
            #endregion
 
        }


        internal class DbExpressionEntitySetInfo 
        {
        } 
 

        private class DbExpressionSimpleTypeEntitySetInfo : DbExpressionEntitySetInfo 
        {
            private EntitySet m_entitySet;

            internal EntitySet EntitySet 
            {
                get { return m_entitySet; } 
            } 

            internal DbExpressionSimpleTypeEntitySetInfo(EntitySet entitySet) 
            {
                m_entitySet = entitySet;
            }
        } 

        private class DbExpressionStructuralTypeEntitySetInfo : DbExpressionEntitySetInfo 
        { 
            private Dictionary m_entitySetInfos;
 
            internal DbExpressionStructuralTypeEntitySetInfo()
            {
                m_entitySetInfos = new Dictionary();
            } 

            internal void Add(string key, DbExpressionEntitySetInfo value) 
            { 
                m_entitySetInfos.Add(key, value);
            } 

            internal IEnumerable> SetInfos
            {
                get 
                {
                    return m_entitySetInfos; 
                } 
            }
 
            internal DbExpressionEntitySetInfo GetEntitySetInfoForMember(string memberName)
            {
                return m_entitySetInfos[memberName];
            } 
        }
 
        private class DbExpressionMemberCollectionEntitySetInfo : DbExpressionEntitySetInfo 
        {
            private IEnumerable m_entitySets; 

            internal DbExpressionMemberCollectionEntitySetInfo(IEnumerable entitySetInfos)
            {
                m_entitySets = entitySetInfos; 
            }
 
            internal IEnumerable entitySetInfos 
            {
                get 
                {
                    return m_entitySets;
                }
            } 
        }
    } 
} 

// File provided for Reference Use Only by Microsoft Corporation (c) 2007.
                        

Link Menu

Network programming in C#, Network Programming in VB.NET, Network Programming in .NET
This book is available now!
Buy at Amazon US or
Buy at Amazon UK