errorpatternmatcher.cs source code in C# .NET

Source code for the .NET framework in C#

                        

Code:

/ Dotnetfx_Win7_3.5.1 / Dotnetfx_Win7_3.5.1 / 3.5.1 / DEVDIV / depot / DevDiv / releases / Orcas / NetFXw7 / ndp / fx / src / DataEntity / System / Data / Map / ViewGeneration / Validation / errorpatternmatcher.cs / 1 / errorpatternmatcher.cs

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

using System.Data.Common.Utils; 
using System.Collections.Generic;
using System.Data.Mapping.ViewGeneration.Validation;
using System.Data.Mapping.ViewGeneration.Structures;
using System.Text; 
using System.Diagnostics;
using System.Collections.ObjectModel; 
using System.Data.Mapping.ViewGeneration.Utils; 
using System.Data.Metadata.Edm;
using System.Data.Entity; 
using System.Data.Common.Utils.Boolean;
using System.Linq;
using System.Data.Mapping.ViewGeneration.QueryRewriting;
 
namespace System.Data.Mapping.ViewGeneration.Validation {
 
    using CompositeCondition = Dictionary>; 
    using System.Globalization;
    delegate bool LCWComparer(FragmentQuery query1, FragmentQuery query2); 

    internal class ErrorPatternMatcher {

        private CellNormalizer m_normalizer; 
        private MemberDomainMap m_domainMap;
        private IEnumerable m_keyAttributes; 
        private ErrorLog m_errorLog; 
        private int m_originalErrorCount;
        private const int NUM_PARTITION_ERR_TO_FIND = 5; 


        #region Constructor
        private ErrorPatternMatcher(CellNormalizer normalizer, MemberDomainMap domainMap, ErrorLog errorLog) 
        {
            m_normalizer = normalizer; 
            m_domainMap = domainMap; 
            m_keyAttributes = MemberPath.GetKeyMembers(normalizer.Extent, domainMap, normalizer.Workspace);
            m_errorLog = errorLog; 
            m_originalErrorCount = m_errorLog.Count;
        }

        public static bool FindMappingErrors(CellNormalizer normalizer, MemberDomainMap domainMap, ErrorLog errorLog) 
        {
            ErrorPatternMatcher matcher = new ErrorPatternMatcher(normalizer, domainMap, errorLog); 
 
            matcher.MatchMissingMappingErrors();
            matcher.MatchConditionErrors(); 
            matcher.MatchSplitErrors();

            if (matcher.m_errorLog.Count == matcher.m_originalErrorCount)
            {   //this will generate redundant errors if one of the above routine finds an error 
                // so execute it only when we dont have any other errors
                matcher.MatchPartitionErrors(); 
            } 

            if (matcher.m_errorLog.Count > matcher.m_originalErrorCount) 
            {
                ExceptionHelpers.ThrowMappingException(matcher.m_errorLog, matcher.m_normalizer.Config);
            }
 
            return false;
        } 
        #endregion 

        #region Error Matching Routines 


        /// 
        /// Finds Types (possibly without any members) that have no mapping specified 
        /// 
        private void MatchMissingMappingErrors() 
        { 
            if (m_normalizer.SchemaContext.ViewTarget == ViewTarget.QueryView)
            { 
                //Find all types for the given EntitySet
                Set unmapepdTypesInExtent = new Set(MetadataHelper.GetTypeAndSubtypesOf(m_normalizer.Extent.ElementType, m_normalizer.Workspace, false /*isAbstract*/));

                //Figure out which type has no Cell mapped to it 
                foreach (var fragment in m_normalizer.AllWrappersForExtent)
                { 
                    foreach (Cell cell in fragment.Cells) 
                    {
                        foreach( var oneOfConst in cell.CQuery.GetConjunctsFromOriginalWhereClause()) 
                        {
                            foreach (var cellConst in oneOfConst.Values.Values)
                            {
                                //if there is a mapping to this type... 
                                TypeConstant typeConst = cellConst as TypeConstant;
                                if (typeConst != null) 
                                { 
                                    unmapepdTypesInExtent.Remove(typeConst.CdmType);
                                } 
                            }
                        }
                    }
                } 

                //We are left with a type that has no mapping 
                if (unmapepdTypesInExtent.Count > 0) 
                {
                    //error unmapped type 
                    m_errorLog.AddEntry(new ErrorLog.Record(true, ViewGenErrorCode.ErrorPatternMissingMappingError,
                            Strings.ViewGen_Missing_Type_Mapping_0(BuildCommaSeparatedErrorString(unmapepdTypesInExtent)), m_normalizer.AllWrappersForExtent, ""));
                }
            } 
        }
 
 
        /// 
        /// Finds errors related to splitting Conditions 
        /// 1. Condition value is repeated across multiple types
        /// 2. A Column/attribute is mapped but also used as a condition
        /// 
        private void MatchConditionErrors() 
        {
            List leftCellWrappers = m_normalizer.AllWrappersForExtent; 
 
            //Stores violating Discriminator (condition member) so that we dont repeat the same error
            Set mappedConditionMembers = new Set(); 

            //Both of these data-structs help in finding duplicate conditions
            Set setOfconditions = new Set(new ConditionComparer());
            Dictionary firstLCWForCondition = new Dictionary(new ConditionComparer()); 

            foreach (var leftCellWrapper in leftCellWrappers) 
            { 
                CompositeCondition condMembersValues = new CompositeCondition();
 
                CellQuery cellQuery = leftCellWrapper.OnlyInputCell.GetLeftQuery(m_normalizer.SchemaContext.ViewTarget);

                foreach (OneOfConst condition in cellQuery.GetConjunctsFromWhereClause())
                { 
                    MemberPath memberPath = condition.Slot.MemberPath;
 
                    if (!m_domainMap.IsConditionMember(memberPath)) 
                    {
                        continue; 
                    }

                    OneOfScalarConst scalarCond = condition as OneOfScalarConst;
                    //Check for mapping of Scalar member condition, ignore type conditions 
                    if (scalarCond != null &&
                        !mappedConditionMembers.Contains(memberPath) && /* prevents duplicate errors */ 
                        !(scalarCond.Values.Contains(CellConstant.NotNull) || scalarCond.Values.Contains(CellConstant.Null)) && /*mapping is allowed for NOT_NULL condition. We loosen the check and allow Null condition because if there is a null condition here, another mapping fragment may have not_null, in which case there is no error */ 
                        !leftCellWrapper.OnlyInputCell.CQuery.WhereClause.Equals(leftCellWrapper.OnlyInputCell.SQuery.WhereClause) /*allowed when both conditiosn are equal*/)
                    { 
                        CheckConditionMemberIsNotMapped(memberPath, leftCellWrappers, mappedConditionMembers);
                    }

                    //CheckForDuplicateConditionValue 
                    //discover a composite condition of the form {path1=x, path2=y, ...}
                    foreach (var element in condition.Values.Values) 
                    { 
                        Set values;
                        //if not in the dict, add it 
                        if (!condMembersValues.TryGetValue(memberPath, out values))
                        {
                            values = new Set(CellConstant.EqualityComparer);
                            condMembersValues.Add(memberPath, values); 
                        }
                        values.Add(element); 
                    } 

                } //foreach condition 

                if (condMembersValues.Count > 0) //it is possible that there are no condition members
                {
                    //Check if the composite condition has been encountered before 
                    if (setOfconditions.Contains(condMembersValues))
                    { 
                        //Extents may be Equal on right side (e.g: by some form of Refconstraint) 
                        if (!RightSideEqual(firstLCWForCondition[condMembersValues], leftCellWrapper))
                        { 
                            //error duplicate conditions
                            m_errorLog.AddEntry(new ErrorLog.Record(true, ViewGenErrorCode.ErrorPatternConditionError,
                                    Strings.Viewgen_ErrorPattern_DuplicateConditionValue(
                                            BuildCommaSeparatedErrorString(condMembersValues.Keys) 
                                        ),
                                    ToIEnum(firstLCWForCondition[condMembersValues].OnlyInputCell, leftCellWrapper.OnlyInputCell), "")); 
                        } 
                    }
                    else 
                    {
                        setOfconditions.Add(condMembersValues);

                        //Remember which cell the condition came from.. used for error reporting 
                        firstLCWForCondition.Add(condMembersValues, leftCellWrapper);
                    } 
                } 
            } //foreach fragment related to the Extent we are working on
 
        }


        ///  
        /// When we are dealing with an update view, this method
        /// finds out if the given Table is mapped to different EntitySets 
        ///  
        private void MatchSplitErrors()
        { 
            List leftCellWrappers = m_normalizer.AllWrappersForExtent;

            //Check that the given Table is mapped to only one EntitySet (avoid AssociationSets)
            var nonAssociationWrappers = leftCellWrappers.Where(r => !(r.LeftExtent is AssociationSet) && !(r.RightCellQuery.Extent is AssociationSet)); 

            if (m_normalizer.SchemaContext.ViewTarget == ViewTarget.UpdateView && nonAssociationWrappers.Any()) 
            { 
                LeftCellWrapper firstLeftCWrapper = nonAssociationWrappers.First();
                EntitySetBase rightExtent = firstLeftCWrapper.RightCellQuery.Extent; 

                foreach (var leftCellWrapper in nonAssociationWrappers)
                {
                    //!(leftCellWrapper.RightCellQuery.Extent is AssociationSet) && 
                    if (!leftCellWrapper.RightCellQuery.Extent.EdmEquals(rightExtent))
                    { 
                        //A Table may be mapped to two extents but the extents may be Equal (by some form of Refconstraint) 
                        if(!RightSideEqual(leftCellWrapper, firstLeftCWrapper))
                        { 
                            //Report Error
                            m_errorLog.AddEntry(new ErrorLog.Record(true, ViewGenErrorCode.ErrorPatternSplittingError,
                                Strings.Viewgen_ErrorPattern_TableMappedToMultipleES(leftCellWrapper.LeftExtent.ToString(), leftCellWrapper.RightCellQuery.Extent.ToString(), rightExtent.ToString()),
                                leftCellWrapper.Cells.First(), "")); 
                        }
                    } 
                } 
            }
        } 

        /// 
        /// Finds out whether fragments (partitions) violate constraints that would produce an invalid mapping.
        /// We compare equality/disjointness/containment for all 2-combinations of fragments. 
        /// Error is reported if given relationship on S side is not maintained on the C side.
        /// If we know nothing about S-side then any relationship on C side is valid. 
        ///  
        private void MatchPartitionErrors()
        { 
            List mappingFragments = m_normalizer.AllWrappersForExtent;

            //for every 2-combination nC2  (n choose 2)
            int i = 0; 
            foreach (var fragment1 in mappingFragments)
            { 
                foreach (var fragment2 in mappingFragments.Skip(++i)) 
                {
                    FragmentQuery rightFragmentQuery1 = CreateRightFragmentQuery(fragment1); 
                    FragmentQuery rightFragmentQuery2 = CreateRightFragmentQuery(fragment2);

                    bool isSDisjoint = CompareS(ComparisonOP.IsDisjointFrom, m_normalizer, fragment1, fragment2, rightFragmentQuery1, rightFragmentQuery2);
                    bool isCDisjoint = CompareC(ComparisonOP.IsDisjointFrom, m_normalizer, fragment1, fragment2, rightFragmentQuery1, rightFragmentQuery2); 

                    bool is1SubsetOf2_C; 
                    bool is2SubsetOf1_C; 
                    bool is1SubsetOf2_S;
                    bool is2SubsetOf1_S; 
                    bool isSEqual;
                    bool isCEqual;

                    if (isSDisjoint) 
                    {
                        if (isCDisjoint) 
                        { 
                            continue;
                        } 
                        else
                        {
                            //Figure out more info for accurate message
                            is1SubsetOf2_C = CompareC(ComparisonOP.IsContainedIn, m_normalizer, fragment1, fragment2, rightFragmentQuery1, rightFragmentQuery2); 
                            is2SubsetOf1_C = CompareC(ComparisonOP.IsContainedIn, m_normalizer, fragment2, fragment1, rightFragmentQuery2, rightFragmentQuery1);
                            isCEqual = is1SubsetOf2_C && is2SubsetOf1_C; 
 
                            StringBuilder errorString = new StringBuilder();
                            //error 
                            if (isCEqual) //equal
                            {
                                //MSG:  These two fragments are disjoint on the S-side but equal on the C-side.
                                //      Ensure disjointness on C-side by mapping them to different types within the same EntitySet 
                                //      or by mapping them to the same type but with a C-side discriminator.
                                //TestCase (1) 
                                errorString.Append(Strings.Viewgen_ErrorPattern_Partition_Disj_Eq); 
                            }
                            else if (is1SubsetOf2_C || is2SubsetOf1_C) 
                            {
                                //Really overlap is not accurate term (should be contianed in or subset of), but its easiest to read.

                                if (CSideHasDifferentEntitySets(fragment1, fragment2)) 
                                {
                                    //MSG:  These two fragments are disjoint on the S-side but overlap on the C-side via a Referential constraint. 
                                    //      Ensure disjointness on C-side by mapping them to different types within the same EntitySet 
                                    //      or by mapping them to the same type but with a C-side discriminator.
 
                                    //TestCase (Not possible because all PKs must be mapped)
                                    errorString.Append(Strings.Viewgen_ErrorPattern_Partition_Disj_Subs_Ref);
                                }
                                else 
                                {
                                    //MSG:  These two fragments are disjoint on the S-side but overlap on the C-side. 
                                    //      Ensure disjointness on C-side. You may be using IsTypeOf() quantifier to 
                                    //      map multiple types within one of these fragments.
                                    //TestCase (2) 
                                    errorString.Append(Strings.Viewgen_ErrorPattern_Partition_Disj_Subs);
                                }
                            }
                            else //relationship is unknown 
                            {
                                //MSG:  These two fragments are disjoint on the S-side but not so on the C-side. 
                                //      Ensure disjointness on C-side by mapping them to different types within the same EntitySet 
                                //      or by mapping them to the same type but with a C-side discriminator.
 
                                //TestCase (4)
                                errorString.Append(Strings.Viewgen_ErrorPattern_Partition_Disj_Unk);
                            }
 
                            m_errorLog.AddEntry(new ErrorLog.Record(true, ViewGenErrorCode.ErrorPatternInvalidPartitionError, errorString.ToString(), ToIEnum(fragment1.OnlyInputCell, fragment2.OnlyInputCell), ""));
 
                            if (FoundTooManyErrors()) 
                            {
                                return; 
                            }
                        }
                    }
                    else 
                    {
                        is1SubsetOf2_C = CompareC(ComparisonOP.IsContainedIn, m_normalizer, fragment1, fragment2, rightFragmentQuery1, rightFragmentQuery2); 
                        is2SubsetOf1_C = CompareC(ComparisonOP.IsContainedIn, m_normalizer, fragment2, fragment1, rightFragmentQuery2, rightFragmentQuery1); 
                    }
                    is1SubsetOf2_S = CompareS(ComparisonOP.IsContainedIn, m_normalizer, fragment1, fragment2, rightFragmentQuery1, rightFragmentQuery2); 
                    is2SubsetOf1_S = CompareS(ComparisonOP.IsContainedIn, m_normalizer, fragment2, fragment1, rightFragmentQuery2, rightFragmentQuery1);

                    isCEqual = is1SubsetOf2_C && is2SubsetOf1_C;
                    isSEqual = is1SubsetOf2_S && is2SubsetOf1_S; 

 
                    if (isSEqual) 
                    {
                        if (isCEqual) //c-side equal 
                        {
                            continue;
                        }
                        else 
                        {
                            //error 
                            StringBuilder errorString = new StringBuilder(); 

                            if (isCDisjoint) 
                            {
                                //MSG:  These two fragments are equal on the S-side but disjoint on the C-side.
                                //      Either partition the S-side by adding a condition or remove any C-side conditions along with resulting redundant mapping fragments.
                                //      You may also map these two disjoint C-side partitions to different tables. 
                                //TestCase (5)
                                errorString.Append(Strings.Viewgen_ErrorPattern_Partition_Eq_Disj); 
                            } 
                            else if (is1SubsetOf2_C || is2SubsetOf1_C)
                            { 
                                if (CSideHasDifferentEntitySets(fragment1, fragment2))
                                {
                                    //MSG:  These two fragments are equal on the S-side but overlap on the C-side.
                                    //      It is likely that you have not added Referential Integrity constriaint for all Key attributes of both EntitySets. 
                                    //      Doing so would ensure equality on the C-side.
                                    //TestCase (Not possible, right?) 
                                    errorString.Append(Strings.Viewgen_ErrorPattern_Partition_Eq_Subs_Ref); 
                                }
                                else 
                                {
                                    //MSG:  These two fragments are equal on the S-side but overlap on the C-side.
                                    //      If you are using IsTypeOf() quantifier ensure both mapping fragments capture same types on the C-side.
                                    //      Otherwise you may have intended to partition the S-side. 
                                    //TestCase (6)
                                    errorString.Append(Strings.Viewgen_ErrorPattern_Partition_Eq_Subs); 
                                } 
                            }
                            else //unknown 
                            {
                                //S-side equal, C-side Unknown
                                if (!IsQueryView() &&
                                    (fragment1.OnlyInputCell.CQuery.Extent is AssociationSet || 
                                     fragment2.OnlyInputCell.CQuery.Extent is AssociationSet))
                                { 
                                    //one side is an association set 
                                    errorString.Append(Strings.Viewgen_ErrorPattern_Partition_Eq_Unk_----);
                                } 
                                else
                                {

                                    //MSG:  These two fragments are equal on the S-side but not so on the C-side. 
                                    //      Try adding an Association with Referntial Integrity constraint if they are
                                    //      mapped to different EntitySets in order to make theme equal on the C-side. 
                                    //TestCase (no need, Table mapped to multiple ES tests cover this scenario) 
                                    errorString.Append(Strings.Viewgen_ErrorPattern_Partition_Eq_Unk);
                                } 
                            }

                            m_errorLog.AddEntry(new ErrorLog.Record(true, ViewGenErrorCode.ErrorPatternInvalidPartitionError, errorString.ToString(), ToIEnum(fragment1.OnlyInputCell, fragment2.OnlyInputCell), ""));
 
                            if (FoundTooManyErrors())
                            { 
                                return; 
                            }
                        } 
                    }
                    else if (is1SubsetOf2_S || is2SubsetOf1_S) //proper subset - note: else if ensures inverse need not be checked
                    {
                        //C-side proper subset (c side must not be equal) 
                        if ((is1SubsetOf2_S && is1SubsetOf2_C == true && !(is2SubsetOf1_C==true)) || (is2SubsetOf1_S && is2SubsetOf1_C==true && !(is1SubsetOf2_C==true)))
                        { 
                            continue; 
                        }
                        else 
                        {   //error

                            StringBuilder errorString = new StringBuilder();
 
                            if (isCDisjoint)
                            { 
                                //MSG:  One of the fragments is a subset of the other on the S-side but they are disjoint on the C-side. 
                                //      If you intended overlap on the S-side ensure they have similar relationship on teh C-side.
                                //      You may need to use IsTypeOf() quantifier or loosen conditions in one of the fragments. 
                                //TestCase (9, 10)
                                errorString.Append(Strings.Viewgen_ErrorPattern_Partition_Sub_Disj);
                            }
                            else if (isCEqual) //equal 
                            {
                                //MSG:  One of the fragments is a subset of the other on the S-side but they are equal on the C-side. 
                                //      If you intended overlap on the S-side ensure they have similar relationship on teh C-side. 
                                //TestCase (10)
 

                                if (CSideHasDifferentEntitySets(fragment1, fragment2))
                                {
                                    // If they are equal via a Referential integrity constraint try making one a subset of the other by 
                                    // not including all primary keys in the constraint.
                                    //TestCase (Not possible) 
                                    errorString.Append(" "+Strings.Viewgen_ErrorPattern_Partition_Sub_Eq_Ref); 
                                }
                                else 
                                {
                                    //      You may need to modify conditions in one of the fragments.
                                    //TestCase (10)
                                    errorString.Append(Strings.Viewgen_ErrorPattern_Partition_Sub_Eq); 
                                }
                            } 
                            else 
                            {   //unknown
                                //MSG:  One of the fragments is a subset of the other on the S-side but they are disjoint on the C-side. 
                                //      If you intended overlap on the S-side ensure they have similar relationship on teh C-side.
                                //TestCase (no need, Table mapped to multiple ES tests cover this scenario)
                                errorString.Append(Strings.Viewgen_ErrorPattern_Partition_Sub_Unk);
                            } 

                            m_errorLog.AddEntry(new ErrorLog.Record(true, ViewGenErrorCode.ErrorPatternInvalidPartitionError, errorString.ToString(), ToIEnum(fragment1.OnlyInputCell, fragment2.OnlyInputCell), "")); 
 
                            if (FoundTooManyErrors())
                            { 
                                return;
                            }
                        }
                    } 
                    //else unknown relationship on the S-side
                } 
            }   //end looping over every 2-combination of fragment 
        }
 
        private void CheckConditionMemberIsNotMapped(MemberPath conditionMember, List mappingFragments, Set mappedConditionMembers)
        {

            //Make sure memberPath is not mapped (in any other cells) 
            foreach (var anotherFragment in mappingFragments)
            { 
                foreach (var anotherCell in anotherFragment.Cells) 
                {
                    CellQuery anotherCellQuery = anotherCell.GetLeftQuery(m_normalizer.SchemaContext.ViewTarget); 
                    if (anotherCellQuery.GetProjectedMembers().Contains(conditionMember))
                    {
                        mappedConditionMembers.Add(conditionMember);
                        //error condition memer is projected somewhere 
                        m_errorLog.AddEntry(new ErrorLog.Record(true, ViewGenErrorCode.ErrorPatternConditionError, Strings.Viewgen_ErrorPattern_ConditionMemberIsMapped(conditionMember.ToString()), anotherCell, ""));
                    } 
                } 
            }
        } 

        #endregion

        private bool FoundTooManyErrors() 
        {
            return (m_errorLog.Count > m_originalErrorCount + NUM_PARTITION_ERR_TO_FIND); 
        } 

        #region Private Helpers 

        private string BuildCommaSeparatedErrorString(IEnumerable members)
        {
            StringBuilder builder = new StringBuilder(); 

            var firstMember = members.First(); 
            foreach (var member in members) 
            {
                if (!member.Equals(firstMember)) 
                {
                    builder.Append(", ");
                }
                builder.Append("'" + member.ToString() + "'"); 
            }
            return builder.ToString(); 
        } 

        private bool CSideHasDifferentEntitySets(LeftCellWrapper a, LeftCellWrapper b) 
        {
            if (IsQueryView())
            {
                return a.LeftExtent == b.LeftExtent; 
            }
            else 
            { 
                return a.RightCellQuery == b.RightCellQuery;
            } 
        }

        private bool CompareC(ComparisonOP op, CellNormalizer normalizer, LeftCellWrapper leftWrapper1, LeftCellWrapper leftWrapper2, FragmentQuery rightQuery1, FragmentQuery rightQuery2)
        { 
            return Compare(true /*lookingForCSide*/, op, normalizer, leftWrapper1, leftWrapper2, rightQuery1, rightQuery2);
        } 
 
        private bool CompareS(ComparisonOP op, CellNormalizer normalizer, LeftCellWrapper leftWrapper1, LeftCellWrapper leftWrapper2, FragmentQuery rightQuery1, FragmentQuery rightQuery2)
        { 
            return Compare(false/*lookingForCSide*/, op, normalizer, leftWrapper1, leftWrapper2, rightQuery1, rightQuery2);
        }

        private bool Compare(bool lookingForC, ComparisonOP op, CellNormalizer normalizer, LeftCellWrapper leftWrapper1, LeftCellWrapper leftWrapper2, FragmentQuery rightQuery1, FragmentQuery rightQuery2) 
        {
            LCWComparer comparer; 
 
            if ((lookingForC && IsQueryView()) || (!lookingForC && !IsQueryView()))
            { 
                if (op == ComparisonOP.IsContainedIn)
                {
                    comparer = normalizer.LeftFragmentQP.IsContainedIn;
                } 
                else if (op == ComparisonOP.IsDisjointFrom)
                { 
                    comparer = normalizer.LeftFragmentQP.IsDisjointFrom; 
                }
                else 
                {
                    Debug.Fail("Unexpected comparison operator, only IsDisjointFrom and IsContainedIn are expected");
                    return false;
                } 

                return comparer(leftWrapper1.FragmentQuery, leftWrapper2.FragmentQuery); 
            } 
            else
            { 
                if (op == ComparisonOP.IsContainedIn)
                {
                    comparer = normalizer.RightFragmentQP.IsContainedIn;
                } 
                else if (op == ComparisonOP.IsDisjointFrom)
                { 
                    comparer = normalizer.RightFragmentQP.IsDisjointFrom; 
                }
                else 
                {
                    Debug.Fail("Unexpected comparison operator, only IsDisjointFrom and IsContainedIn are expected");
                    return false;
                } 

                return comparer(rightQuery1, rightQuery2); 
            } 
        }
 
        private bool RightSideEqual(LeftCellWrapper wrapper1, LeftCellWrapper wrapper2)
        {
            FragmentQuery rightFragmentQuery1 = CreateRightFragmentQuery(wrapper1);
            FragmentQuery rightFragmentQuery2 = CreateRightFragmentQuery(wrapper2); 

            return m_normalizer.RightFragmentQP.IsEquivalentTo(rightFragmentQuery1, rightFragmentQuery2); 
        } 

        private FragmentQuery CreateRightFragmentQuery(LeftCellWrapper wrapper) 
        {
            return FragmentQuery.Create(wrapper.OnlyInputCell.CellLabel.ToString(), wrapper.CreateRoleBoolean(), wrapper.OnlyInputCell.GetRightQuery(m_normalizer.SchemaContext.ViewTarget));
        }
 
        private IEnumerable ToIEnum(Cell one, Cell two)
        { 
            List cells = new List(); 
            cells.Add(one);
            cells.Add(two); 
            return cells;
        }

        private bool IsQueryView() 
        {
            return (m_normalizer.SchemaContext.ViewTarget == ViewTarget.QueryView); 
        } 

        #endregion 

        enum ComparisonOP
        {
            IsContainedIn, 
            IsDisjointFrom
        } 
    } 

    class ConditionComparer : IEqualityComparer>> 
    {
        public bool Equals(Dictionary> one, Dictionary> two)
        {
            Set keysOfOne = new Set(one.Keys, MemberPath.EqualityComparer); 
            Set keysOfTwo = new Set(two.Keys, MemberPath.EqualityComparer);
 
            if (!keysOfOne.SetEquals(keysOfTwo)) 
            {
                return false; 
            }

            foreach (var member in keysOfOne)
            { 
                Set constantsOfOne = one[member];
                Set constantsOfTwo = two[member]; 
 
                if (!constantsOfOne.SetEquals(constantsOfTwo))
                { 
                    return false;
                }
            }
            return true; 
        }
 
        public int GetHashCode(Dictionary> obj) 
        {
            return obj.ToString().ToLower(CultureInfo.InvariantCulture).GetHashCode(); 
        }

    }
} 

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

using System.Data.Common.Utils; 
using System.Collections.Generic;
using System.Data.Mapping.ViewGeneration.Validation;
using System.Data.Mapping.ViewGeneration.Structures;
using System.Text; 
using System.Diagnostics;
using System.Collections.ObjectModel; 
using System.Data.Mapping.ViewGeneration.Utils; 
using System.Data.Metadata.Edm;
using System.Data.Entity; 
using System.Data.Common.Utils.Boolean;
using System.Linq;
using System.Data.Mapping.ViewGeneration.QueryRewriting;
 
namespace System.Data.Mapping.ViewGeneration.Validation {
 
    using CompositeCondition = Dictionary>; 
    using System.Globalization;
    delegate bool LCWComparer(FragmentQuery query1, FragmentQuery query2); 

    internal class ErrorPatternMatcher {

        private CellNormalizer m_normalizer; 
        private MemberDomainMap m_domainMap;
        private IEnumerable m_keyAttributes; 
        private ErrorLog m_errorLog; 
        private int m_originalErrorCount;
        private const int NUM_PARTITION_ERR_TO_FIND = 5; 


        #region Constructor
        private ErrorPatternMatcher(CellNormalizer normalizer, MemberDomainMap domainMap, ErrorLog errorLog) 
        {
            m_normalizer = normalizer; 
            m_domainMap = domainMap; 
            m_keyAttributes = MemberPath.GetKeyMembers(normalizer.Extent, domainMap, normalizer.Workspace);
            m_errorLog = errorLog; 
            m_originalErrorCount = m_errorLog.Count;
        }

        public static bool FindMappingErrors(CellNormalizer normalizer, MemberDomainMap domainMap, ErrorLog errorLog) 
        {
            ErrorPatternMatcher matcher = new ErrorPatternMatcher(normalizer, domainMap, errorLog); 
 
            matcher.MatchMissingMappingErrors();
            matcher.MatchConditionErrors(); 
            matcher.MatchSplitErrors();

            if (matcher.m_errorLog.Count == matcher.m_originalErrorCount)
            {   //this will generate redundant errors if one of the above routine finds an error 
                // so execute it only when we dont have any other errors
                matcher.MatchPartitionErrors(); 
            } 

            if (matcher.m_errorLog.Count > matcher.m_originalErrorCount) 
            {
                ExceptionHelpers.ThrowMappingException(matcher.m_errorLog, matcher.m_normalizer.Config);
            }
 
            return false;
        } 
        #endregion 

        #region Error Matching Routines 


        /// 
        /// Finds Types (possibly without any members) that have no mapping specified 
        /// 
        private void MatchMissingMappingErrors() 
        { 
            if (m_normalizer.SchemaContext.ViewTarget == ViewTarget.QueryView)
            { 
                //Find all types for the given EntitySet
                Set unmapepdTypesInExtent = new Set(MetadataHelper.GetTypeAndSubtypesOf(m_normalizer.Extent.ElementType, m_normalizer.Workspace, false /*isAbstract*/));

                //Figure out which type has no Cell mapped to it 
                foreach (var fragment in m_normalizer.AllWrappersForExtent)
                { 
                    foreach (Cell cell in fragment.Cells) 
                    {
                        foreach( var oneOfConst in cell.CQuery.GetConjunctsFromOriginalWhereClause()) 
                        {
                            foreach (var cellConst in oneOfConst.Values.Values)
                            {
                                //if there is a mapping to this type... 
                                TypeConstant typeConst = cellConst as TypeConstant;
                                if (typeConst != null) 
                                { 
                                    unmapepdTypesInExtent.Remove(typeConst.CdmType);
                                } 
                            }
                        }
                    }
                } 

                //We are left with a type that has no mapping 
                if (unmapepdTypesInExtent.Count > 0) 
                {
                    //error unmapped type 
                    m_errorLog.AddEntry(new ErrorLog.Record(true, ViewGenErrorCode.ErrorPatternMissingMappingError,
                            Strings.ViewGen_Missing_Type_Mapping_0(BuildCommaSeparatedErrorString(unmapepdTypesInExtent)), m_normalizer.AllWrappersForExtent, ""));
                }
            } 
        }
 
 
        /// 
        /// Finds errors related to splitting Conditions 
        /// 1. Condition value is repeated across multiple types
        /// 2. A Column/attribute is mapped but also used as a condition
        /// 
        private void MatchConditionErrors() 
        {
            List leftCellWrappers = m_normalizer.AllWrappersForExtent; 
 
            //Stores violating Discriminator (condition member) so that we dont repeat the same error
            Set mappedConditionMembers = new Set(); 

            //Both of these data-structs help in finding duplicate conditions
            Set setOfconditions = new Set(new ConditionComparer());
            Dictionary firstLCWForCondition = new Dictionary(new ConditionComparer()); 

            foreach (var leftCellWrapper in leftCellWrappers) 
            { 
                CompositeCondition condMembersValues = new CompositeCondition();
 
                CellQuery cellQuery = leftCellWrapper.OnlyInputCell.GetLeftQuery(m_normalizer.SchemaContext.ViewTarget);

                foreach (OneOfConst condition in cellQuery.GetConjunctsFromWhereClause())
                { 
                    MemberPath memberPath = condition.Slot.MemberPath;
 
                    if (!m_domainMap.IsConditionMember(memberPath)) 
                    {
                        continue; 
                    }

                    OneOfScalarConst scalarCond = condition as OneOfScalarConst;
                    //Check for mapping of Scalar member condition, ignore type conditions 
                    if (scalarCond != null &&
                        !mappedConditionMembers.Contains(memberPath) && /* prevents duplicate errors */ 
                        !(scalarCond.Values.Contains(CellConstant.NotNull) || scalarCond.Values.Contains(CellConstant.Null)) && /*mapping is allowed for NOT_NULL condition. We loosen the check and allow Null condition because if there is a null condition here, another mapping fragment may have not_null, in which case there is no error */ 
                        !leftCellWrapper.OnlyInputCell.CQuery.WhereClause.Equals(leftCellWrapper.OnlyInputCell.SQuery.WhereClause) /*allowed when both conditiosn are equal*/)
                    { 
                        CheckConditionMemberIsNotMapped(memberPath, leftCellWrappers, mappedConditionMembers);
                    }

                    //CheckForDuplicateConditionValue 
                    //discover a composite condition of the form {path1=x, path2=y, ...}
                    foreach (var element in condition.Values.Values) 
                    { 
                        Set values;
                        //if not in the dict, add it 
                        if (!condMembersValues.TryGetValue(memberPath, out values))
                        {
                            values = new Set(CellConstant.EqualityComparer);
                            condMembersValues.Add(memberPath, values); 
                        }
                        values.Add(element); 
                    } 

                } //foreach condition 

                if (condMembersValues.Count > 0) //it is possible that there are no condition members
                {
                    //Check if the composite condition has been encountered before 
                    if (setOfconditions.Contains(condMembersValues))
                    { 
                        //Extents may be Equal on right side (e.g: by some form of Refconstraint) 
                        if (!RightSideEqual(firstLCWForCondition[condMembersValues], leftCellWrapper))
                        { 
                            //error duplicate conditions
                            m_errorLog.AddEntry(new ErrorLog.Record(true, ViewGenErrorCode.ErrorPatternConditionError,
                                    Strings.Viewgen_ErrorPattern_DuplicateConditionValue(
                                            BuildCommaSeparatedErrorString(condMembersValues.Keys) 
                                        ),
                                    ToIEnum(firstLCWForCondition[condMembersValues].OnlyInputCell, leftCellWrapper.OnlyInputCell), "")); 
                        } 
                    }
                    else 
                    {
                        setOfconditions.Add(condMembersValues);

                        //Remember which cell the condition came from.. used for error reporting 
                        firstLCWForCondition.Add(condMembersValues, leftCellWrapper);
                    } 
                } 
            } //foreach fragment related to the Extent we are working on
 
        }


        ///  
        /// When we are dealing with an update view, this method
        /// finds out if the given Table is mapped to different EntitySets 
        ///  
        private void MatchSplitErrors()
        { 
            List leftCellWrappers = m_normalizer.AllWrappersForExtent;

            //Check that the given Table is mapped to only one EntitySet (avoid AssociationSets)
            var nonAssociationWrappers = leftCellWrappers.Where(r => !(r.LeftExtent is AssociationSet) && !(r.RightCellQuery.Extent is AssociationSet)); 

            if (m_normalizer.SchemaContext.ViewTarget == ViewTarget.UpdateView && nonAssociationWrappers.Any()) 
            { 
                LeftCellWrapper firstLeftCWrapper = nonAssociationWrappers.First();
                EntitySetBase rightExtent = firstLeftCWrapper.RightCellQuery.Extent; 

                foreach (var leftCellWrapper in nonAssociationWrappers)
                {
                    //!(leftCellWrapper.RightCellQuery.Extent is AssociationSet) && 
                    if (!leftCellWrapper.RightCellQuery.Extent.EdmEquals(rightExtent))
                    { 
                        //A Table may be mapped to two extents but the extents may be Equal (by some form of Refconstraint) 
                        if(!RightSideEqual(leftCellWrapper, firstLeftCWrapper))
                        { 
                            //Report Error
                            m_errorLog.AddEntry(new ErrorLog.Record(true, ViewGenErrorCode.ErrorPatternSplittingError,
                                Strings.Viewgen_ErrorPattern_TableMappedToMultipleES(leftCellWrapper.LeftExtent.ToString(), leftCellWrapper.RightCellQuery.Extent.ToString(), rightExtent.ToString()),
                                leftCellWrapper.Cells.First(), "")); 
                        }
                    } 
                } 
            }
        } 

        /// 
        /// Finds out whether fragments (partitions) violate constraints that would produce an invalid mapping.
        /// We compare equality/disjointness/containment for all 2-combinations of fragments. 
        /// Error is reported if given relationship on S side is not maintained on the C side.
        /// If we know nothing about S-side then any relationship on C side is valid. 
        ///  
        private void MatchPartitionErrors()
        { 
            List mappingFragments = m_normalizer.AllWrappersForExtent;

            //for every 2-combination nC2  (n choose 2)
            int i = 0; 
            foreach (var fragment1 in mappingFragments)
            { 
                foreach (var fragment2 in mappingFragments.Skip(++i)) 
                {
                    FragmentQuery rightFragmentQuery1 = CreateRightFragmentQuery(fragment1); 
                    FragmentQuery rightFragmentQuery2 = CreateRightFragmentQuery(fragment2);

                    bool isSDisjoint = CompareS(ComparisonOP.IsDisjointFrom, m_normalizer, fragment1, fragment2, rightFragmentQuery1, rightFragmentQuery2);
                    bool isCDisjoint = CompareC(ComparisonOP.IsDisjointFrom, m_normalizer, fragment1, fragment2, rightFragmentQuery1, rightFragmentQuery2); 

                    bool is1SubsetOf2_C; 
                    bool is2SubsetOf1_C; 
                    bool is1SubsetOf2_S;
                    bool is2SubsetOf1_S; 
                    bool isSEqual;
                    bool isCEqual;

                    if (isSDisjoint) 
                    {
                        if (isCDisjoint) 
                        { 
                            continue;
                        } 
                        else
                        {
                            //Figure out more info for accurate message
                            is1SubsetOf2_C = CompareC(ComparisonOP.IsContainedIn, m_normalizer, fragment1, fragment2, rightFragmentQuery1, rightFragmentQuery2); 
                            is2SubsetOf1_C = CompareC(ComparisonOP.IsContainedIn, m_normalizer, fragment2, fragment1, rightFragmentQuery2, rightFragmentQuery1);
                            isCEqual = is1SubsetOf2_C && is2SubsetOf1_C; 
 
                            StringBuilder errorString = new StringBuilder();
                            //error 
                            if (isCEqual) //equal
                            {
                                //MSG:  These two fragments are disjoint on the S-side but equal on the C-side.
                                //      Ensure disjointness on C-side by mapping them to different types within the same EntitySet 
                                //      or by mapping them to the same type but with a C-side discriminator.
                                //TestCase (1) 
                                errorString.Append(Strings.Viewgen_ErrorPattern_Partition_Disj_Eq); 
                            }
                            else if (is1SubsetOf2_C || is2SubsetOf1_C) 
                            {
                                //Really overlap is not accurate term (should be contianed in or subset of), but its easiest to read.

                                if (CSideHasDifferentEntitySets(fragment1, fragment2)) 
                                {
                                    //MSG:  These two fragments are disjoint on the S-side but overlap on the C-side via a Referential constraint. 
                                    //      Ensure disjointness on C-side by mapping them to different types within the same EntitySet 
                                    //      or by mapping them to the same type but with a C-side discriminator.
 
                                    //TestCase (Not possible because all PKs must be mapped)
                                    errorString.Append(Strings.Viewgen_ErrorPattern_Partition_Disj_Subs_Ref);
                                }
                                else 
                                {
                                    //MSG:  These two fragments are disjoint on the S-side but overlap on the C-side. 
                                    //      Ensure disjointness on C-side. You may be using IsTypeOf() quantifier to 
                                    //      map multiple types within one of these fragments.
                                    //TestCase (2) 
                                    errorString.Append(Strings.Viewgen_ErrorPattern_Partition_Disj_Subs);
                                }
                            }
                            else //relationship is unknown 
                            {
                                //MSG:  These two fragments are disjoint on the S-side but not so on the C-side. 
                                //      Ensure disjointness on C-side by mapping them to different types within the same EntitySet 
                                //      or by mapping them to the same type but with a C-side discriminator.
 
                                //TestCase (4)
                                errorString.Append(Strings.Viewgen_ErrorPattern_Partition_Disj_Unk);
                            }
 
                            m_errorLog.AddEntry(new ErrorLog.Record(true, ViewGenErrorCode.ErrorPatternInvalidPartitionError, errorString.ToString(), ToIEnum(fragment1.OnlyInputCell, fragment2.OnlyInputCell), ""));
 
                            if (FoundTooManyErrors()) 
                            {
                                return; 
                            }
                        }
                    }
                    else 
                    {
                        is1SubsetOf2_C = CompareC(ComparisonOP.IsContainedIn, m_normalizer, fragment1, fragment2, rightFragmentQuery1, rightFragmentQuery2); 
                        is2SubsetOf1_C = CompareC(ComparisonOP.IsContainedIn, m_normalizer, fragment2, fragment1, rightFragmentQuery2, rightFragmentQuery1); 
                    }
                    is1SubsetOf2_S = CompareS(ComparisonOP.IsContainedIn, m_normalizer, fragment1, fragment2, rightFragmentQuery1, rightFragmentQuery2); 
                    is2SubsetOf1_S = CompareS(ComparisonOP.IsContainedIn, m_normalizer, fragment2, fragment1, rightFragmentQuery2, rightFragmentQuery1);

                    isCEqual = is1SubsetOf2_C && is2SubsetOf1_C;
                    isSEqual = is1SubsetOf2_S && is2SubsetOf1_S; 

 
                    if (isSEqual) 
                    {
                        if (isCEqual) //c-side equal 
                        {
                            continue;
                        }
                        else 
                        {
                            //error 
                            StringBuilder errorString = new StringBuilder(); 

                            if (isCDisjoint) 
                            {
                                //MSG:  These two fragments are equal on the S-side but disjoint on the C-side.
                                //      Either partition the S-side by adding a condition or remove any C-side conditions along with resulting redundant mapping fragments.
                                //      You may also map these two disjoint C-side partitions to different tables. 
                                //TestCase (5)
                                errorString.Append(Strings.Viewgen_ErrorPattern_Partition_Eq_Disj); 
                            } 
                            else if (is1SubsetOf2_C || is2SubsetOf1_C)
                            { 
                                if (CSideHasDifferentEntitySets(fragment1, fragment2))
                                {
                                    //MSG:  These two fragments are equal on the S-side but overlap on the C-side.
                                    //      It is likely that you have not added Referential Integrity constriaint for all Key attributes of both EntitySets. 
                                    //      Doing so would ensure equality on the C-side.
                                    //TestCase (Not possible, right?) 
                                    errorString.Append(Strings.Viewgen_ErrorPattern_Partition_Eq_Subs_Ref); 
                                }
                                else 
                                {
                                    //MSG:  These two fragments are equal on the S-side but overlap on the C-side.
                                    //      If you are using IsTypeOf() quantifier ensure both mapping fragments capture same types on the C-side.
                                    //      Otherwise you may have intended to partition the S-side. 
                                    //TestCase (6)
                                    errorString.Append(Strings.Viewgen_ErrorPattern_Partition_Eq_Subs); 
                                } 
                            }
                            else //unknown 
                            {
                                //S-side equal, C-side Unknown
                                if (!IsQueryView() &&
                                    (fragment1.OnlyInputCell.CQuery.Extent is AssociationSet || 
                                     fragment2.OnlyInputCell.CQuery.Extent is AssociationSet))
                                { 
                                    //one side is an association set 
                                    errorString.Append(Strings.Viewgen_ErrorPattern_Partition_Eq_Unk_----);
                                } 
                                else
                                {

                                    //MSG:  These two fragments are equal on the S-side but not so on the C-side. 
                                    //      Try adding an Association with Referntial Integrity constraint if they are
                                    //      mapped to different EntitySets in order to make theme equal on the C-side. 
                                    //TestCase (no need, Table mapped to multiple ES tests cover this scenario) 
                                    errorString.Append(Strings.Viewgen_ErrorPattern_Partition_Eq_Unk);
                                } 
                            }

                            m_errorLog.AddEntry(new ErrorLog.Record(true, ViewGenErrorCode.ErrorPatternInvalidPartitionError, errorString.ToString(), ToIEnum(fragment1.OnlyInputCell, fragment2.OnlyInputCell), ""));
 
                            if (FoundTooManyErrors())
                            { 
                                return; 
                            }
                        } 
                    }
                    else if (is1SubsetOf2_S || is2SubsetOf1_S) //proper subset - note: else if ensures inverse need not be checked
                    {
                        //C-side proper subset (c side must not be equal) 
                        if ((is1SubsetOf2_S && is1SubsetOf2_C == true && !(is2SubsetOf1_C==true)) || (is2SubsetOf1_S && is2SubsetOf1_C==true && !(is1SubsetOf2_C==true)))
                        { 
                            continue; 
                        }
                        else 
                        {   //error

                            StringBuilder errorString = new StringBuilder();
 
                            if (isCDisjoint)
                            { 
                                //MSG:  One of the fragments is a subset of the other on the S-side but they are disjoint on the C-side. 
                                //      If you intended overlap on the S-side ensure they have similar relationship on teh C-side.
                                //      You may need to use IsTypeOf() quantifier or loosen conditions in one of the fragments. 
                                //TestCase (9, 10)
                                errorString.Append(Strings.Viewgen_ErrorPattern_Partition_Sub_Disj);
                            }
                            else if (isCEqual) //equal 
                            {
                                //MSG:  One of the fragments is a subset of the other on the S-side but they are equal on the C-side. 
                                //      If you intended overlap on the S-side ensure they have similar relationship on teh C-side. 
                                //TestCase (10)
 

                                if (CSideHasDifferentEntitySets(fragment1, fragment2))
                                {
                                    // If they are equal via a Referential integrity constraint try making one a subset of the other by 
                                    // not including all primary keys in the constraint.
                                    //TestCase (Not possible) 
                                    errorString.Append(" "+Strings.Viewgen_ErrorPattern_Partition_Sub_Eq_Ref); 
                                }
                                else 
                                {
                                    //      You may need to modify conditions in one of the fragments.
                                    //TestCase (10)
                                    errorString.Append(Strings.Viewgen_ErrorPattern_Partition_Sub_Eq); 
                                }
                            } 
                            else 
                            {   //unknown
                                //MSG:  One of the fragments is a subset of the other on the S-side but they are disjoint on the C-side. 
                                //      If you intended overlap on the S-side ensure they have similar relationship on teh C-side.
                                //TestCase (no need, Table mapped to multiple ES tests cover this scenario)
                                errorString.Append(Strings.Viewgen_ErrorPattern_Partition_Sub_Unk);
                            } 

                            m_errorLog.AddEntry(new ErrorLog.Record(true, ViewGenErrorCode.ErrorPatternInvalidPartitionError, errorString.ToString(), ToIEnum(fragment1.OnlyInputCell, fragment2.OnlyInputCell), "")); 
 
                            if (FoundTooManyErrors())
                            { 
                                return;
                            }
                        }
                    } 
                    //else unknown relationship on the S-side
                } 
            }   //end looping over every 2-combination of fragment 
        }
 
        private void CheckConditionMemberIsNotMapped(MemberPath conditionMember, List mappingFragments, Set mappedConditionMembers)
        {

            //Make sure memberPath is not mapped (in any other cells) 
            foreach (var anotherFragment in mappingFragments)
            { 
                foreach (var anotherCell in anotherFragment.Cells) 
                {
                    CellQuery anotherCellQuery = anotherCell.GetLeftQuery(m_normalizer.SchemaContext.ViewTarget); 
                    if (anotherCellQuery.GetProjectedMembers().Contains(conditionMember))
                    {
                        mappedConditionMembers.Add(conditionMember);
                        //error condition memer is projected somewhere 
                        m_errorLog.AddEntry(new ErrorLog.Record(true, ViewGenErrorCode.ErrorPatternConditionError, Strings.Viewgen_ErrorPattern_ConditionMemberIsMapped(conditionMember.ToString()), anotherCell, ""));
                    } 
                } 
            }
        } 

        #endregion

        private bool FoundTooManyErrors() 
        {
            return (m_errorLog.Count > m_originalErrorCount + NUM_PARTITION_ERR_TO_FIND); 
        } 

        #region Private Helpers 

        private string BuildCommaSeparatedErrorString(IEnumerable members)
        {
            StringBuilder builder = new StringBuilder(); 

            var firstMember = members.First(); 
            foreach (var member in members) 
            {
                if (!member.Equals(firstMember)) 
                {
                    builder.Append(", ");
                }
                builder.Append("'" + member.ToString() + "'"); 
            }
            return builder.ToString(); 
        } 

        private bool CSideHasDifferentEntitySets(LeftCellWrapper a, LeftCellWrapper b) 
        {
            if (IsQueryView())
            {
                return a.LeftExtent == b.LeftExtent; 
            }
            else 
            { 
                return a.RightCellQuery == b.RightCellQuery;
            } 
        }

        private bool CompareC(ComparisonOP op, CellNormalizer normalizer, LeftCellWrapper leftWrapper1, LeftCellWrapper leftWrapper2, FragmentQuery rightQuery1, FragmentQuery rightQuery2)
        { 
            return Compare(true /*lookingForCSide*/, op, normalizer, leftWrapper1, leftWrapper2, rightQuery1, rightQuery2);
        } 
 
        private bool CompareS(ComparisonOP op, CellNormalizer normalizer, LeftCellWrapper leftWrapper1, LeftCellWrapper leftWrapper2, FragmentQuery rightQuery1, FragmentQuery rightQuery2)
        { 
            return Compare(false/*lookingForCSide*/, op, normalizer, leftWrapper1, leftWrapper2, rightQuery1, rightQuery2);
        }

        private bool Compare(bool lookingForC, ComparisonOP op, CellNormalizer normalizer, LeftCellWrapper leftWrapper1, LeftCellWrapper leftWrapper2, FragmentQuery rightQuery1, FragmentQuery rightQuery2) 
        {
            LCWComparer comparer; 
 
            if ((lookingForC && IsQueryView()) || (!lookingForC && !IsQueryView()))
            { 
                if (op == ComparisonOP.IsContainedIn)
                {
                    comparer = normalizer.LeftFragmentQP.IsContainedIn;
                } 
                else if (op == ComparisonOP.IsDisjointFrom)
                { 
                    comparer = normalizer.LeftFragmentQP.IsDisjointFrom; 
                }
                else 
                {
                    Debug.Fail("Unexpected comparison operator, only IsDisjointFrom and IsContainedIn are expected");
                    return false;
                } 

                return comparer(leftWrapper1.FragmentQuery, leftWrapper2.FragmentQuery); 
            } 
            else
            { 
                if (op == ComparisonOP.IsContainedIn)
                {
                    comparer = normalizer.RightFragmentQP.IsContainedIn;
                } 
                else if (op == ComparisonOP.IsDisjointFrom)
                { 
                    comparer = normalizer.RightFragmentQP.IsDisjointFrom; 
                }
                else 
                {
                    Debug.Fail("Unexpected comparison operator, only IsDisjointFrom and IsContainedIn are expected");
                    return false;
                } 

                return comparer(rightQuery1, rightQuery2); 
            } 
        }
 
        private bool RightSideEqual(LeftCellWrapper wrapper1, LeftCellWrapper wrapper2)
        {
            FragmentQuery rightFragmentQuery1 = CreateRightFragmentQuery(wrapper1);
            FragmentQuery rightFragmentQuery2 = CreateRightFragmentQuery(wrapper2); 

            return m_normalizer.RightFragmentQP.IsEquivalentTo(rightFragmentQuery1, rightFragmentQuery2); 
        } 

        private FragmentQuery CreateRightFragmentQuery(LeftCellWrapper wrapper) 
        {
            return FragmentQuery.Create(wrapper.OnlyInputCell.CellLabel.ToString(), wrapper.CreateRoleBoolean(), wrapper.OnlyInputCell.GetRightQuery(m_normalizer.SchemaContext.ViewTarget));
        }
 
        private IEnumerable ToIEnum(Cell one, Cell two)
        { 
            List cells = new List(); 
            cells.Add(one);
            cells.Add(two); 
            return cells;
        }

        private bool IsQueryView() 
        {
            return (m_normalizer.SchemaContext.ViewTarget == ViewTarget.QueryView); 
        } 

        #endregion 

        enum ComparisonOP
        {
            IsContainedIn, 
            IsDisjointFrom
        } 
    } 

    class ConditionComparer : IEqualityComparer>> 
    {
        public bool Equals(Dictionary> one, Dictionary> two)
        {
            Set keysOfOne = new Set(one.Keys, MemberPath.EqualityComparer); 
            Set keysOfTwo = new Set(two.Keys, MemberPath.EqualityComparer);
 
            if (!keysOfOne.SetEquals(keysOfTwo)) 
            {
                return false; 
            }

            foreach (var member in keysOfOne)
            { 
                Set constantsOfOne = one[member];
                Set constantsOfTwo = two[member]; 
 
                if (!constantsOfOne.SetEquals(constantsOfTwo))
                { 
                    return false;
                }
            }
            return true; 
        }
 
        public int GetHashCode(Dictionary> obj) 
        {
            return obj.ToString().ToLower(CultureInfo.InvariantCulture).GetHashCode(); 
        }

    }
} 

// 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