Code:
/ Dotnetfx_Vista_SP2 / Dotnetfx_Vista_SP2 / 8.0.50727.4016 / DEVDIV / depot / DevDiv / releases / Orcas / QFE / 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

This book is available now!
Buy at Amazon US or
Buy at Amazon UK
- MessageQueueAccessControlEntry.cs
- TabControlEvent.cs
- XslNumber.cs
- SubtreeProcessor.cs
- DataGridViewImageColumn.cs
- PartialCachingControl.cs
- WindowVisualStateTracker.cs
- OpCopier.cs
- DataDocumentXPathNavigator.cs
- ButtonBaseAutomationPeer.cs
- EventDescriptorCollection.cs
- DefaultMergeHelper.cs
- ValidatorAttribute.cs
- ObjectItemNoOpAssemblyLoader.cs
- NativeMethodsOther.cs
- _ConnectStream.cs
- MemberRestriction.cs
- ColorMap.cs
- XmlSchemaObjectCollection.cs
- ListViewUpdateEventArgs.cs
- FileSecurity.cs
- ObjectContextServiceProvider.cs
- Hashtable.cs
- Win32Native.cs
- SqlStream.cs
- FrameworkTextComposition.cs
- InfoCardRSAPKCS1KeyExchangeFormatter.cs
- DataGridHeaderBorder.cs
- ScriptComponentDescriptor.cs
- WebPartCloseVerb.cs
- AutomationElement.cs
- MetadataArtifactLoaderComposite.cs
- TransformerInfoCollection.cs
- NamedObject.cs
- EntityDataSourceContainerNameItem.cs
- StrokeNodeOperations.cs
- StretchValidation.cs
- SecurityContext.cs
- PageThemeCodeDomTreeGenerator.cs
- ColorBuilder.cs
- BufferedStream.cs
- CopyCodeAction.cs
- DateTimeOffset.cs
- X509Certificate2.cs
- SqlNodeAnnotation.cs
- Msec.cs
- WindowsListViewGroupHelper.cs
- FigureParagraph.cs
- TracedNativeMethods.cs
- SelectionHighlightInfo.cs
- TaskbarItemInfo.cs
- Tablet.cs
- HitTestFilterBehavior.cs
- PersonalizationStateInfo.cs
- AQNBuilder.cs
- Msmq4PoisonHandler.cs
- TemplatedAdorner.cs
- MoveSizeWinEventHandler.cs
- CodeStatementCollection.cs
- ArraySegment.cs
- WebPartsPersonalization.cs
- GeometryDrawing.cs
- DataError.cs
- ConnectionManagementElement.cs
- _AuthenticationState.cs
- NativeWindow.cs
- WebPartEditorApplyVerb.cs
- ComponentEvent.cs
- PersistChildrenAttribute.cs
- PackUriHelper.cs
- RowBinding.cs
- ServiceContractAttribute.cs
- PageThemeParser.cs
- Win32.cs
- HttpException.cs
- RtfToXamlLexer.cs
- Exceptions.cs
- StorageEntityContainerMapping.cs
- HttpConfigurationSystem.cs
- StringFormat.cs
- ErrorFormatterPage.cs
- XmlUtil.cs
- FlowDocumentPaginator.cs
- CollectionConverter.cs
- ImageListStreamer.cs
- StylusButton.cs
- CalendarDateRange.cs
- FormsAuthenticationModule.cs
- PropertyNames.cs
- recordstate.cs
- FilteredXmlReader.cs
- SourceFilter.cs
- StateItem.cs
- ReadOnlyObservableCollection.cs
- OleDbDataReader.cs
- CryptoConfig.cs
- ValidationRuleCollection.cs
- NegatedConstant.cs
- DiffuseMaterial.cs
- SchemaCollectionCompiler.cs