public void SubstitutionsReplaceReferencedKeys() { //Arrange var refGuids = GuidArray(3); var table1 = _om.Make <SnapshotObjectMother.GuidKeyTable>(GuidArray(4)); var refTable1 = _om.Make <SnapshotObjectMother.GuidRefTable>((refGuids[0], table1[0].GuidKeyId), (refGuids[1], table1[1].GuidKeyId)); void TakeSnapshot(string name) { var builder = _om.NewSnapshot(name); table1.ToSnapshotTable(builder); refTable1.ToSnapshotTable(builder); } TakeSnapshot("Before"); table1[0].Variable = "edited"; table1[1].Variable = "edited"; refTable1[0].GuidKeyParentId = table1[1].GuidKeyId; refTable1[1].GuidKeyParentId = table1[2].GuidKeyId; TakeSnapshot("After"); var before = _om.GetSnapshot("Before"); var after = _om.GetSnapshot("After"); var diffs = DifferenceRegulator.ExpandDifferences(_om.Collection, SnapshotDifferenceCalculator.GetDifferences(_om.Collection, before, after), before); var tables = diffs.Select(d => d.TableDefinition).ToList(); var unpredictableCols = UnpredictableColumnLocator.Locate(tables); var columnValueSets = unpredictableCols.Select(u => UnpredictableValueScanner.Scan(u, diffs)).ToList(); //Act var result = diffs; foreach (var columnValueSet in columnValueSets) { result = ValueSubstituter.Substitute(columnValueSet, result, _om.Collection); } //Assert var output = new Output(); result.Report(output); output.Report.Verify(); }
public void SubstitutionsReplaceDifferences() { //Arrange var refGuids = GuidArray(3); var table1 = _om.Make <SnapshotObjectMother.GuidKeyTable>(GuidArray(4)); void TakeSnapshot(string name) { var builder = _om.NewSnapshot(name); table1.ToSnapshotTable(builder); } TakeSnapshot("Before"); table1[0].Variable = "edited"; table1[1].Variable = "edited"; TakeSnapshot("After"); var before = _om.GetSnapshot("Before"); var after = _om.GetSnapshot("After"); var allDiffs = SnapshotDifferenceCalculator.GetDifferences(_om.Collection, before, after); var diffs = DifferenceRegulator.ExpandDifferences(_om.Collection, allDiffs, before); var tables = diffs.Select(d => d.TableDefinition).ToList(); var unpredictableCols = UnpredictableColumnLocator.Locate(tables).Single(t => t.Table.TableName == nameof(SnapshotObjectMother.GuidKeyTable)); var columnValueSets = UnpredictableValueScanner.Scan(unpredictableCols, diffs); //Act var result = ValueSubstituter.Substitute(columnValueSets, diffs, _om.Collection); //Assert var output = new Output(); result.Report(output); output.Report.Verify(); }
private static DbExpression SimplifyNestedTphDiscriminator(DbExpression expression) { var entityProjection = (DbProjectExpression)expression; var booleanColumnFilter = (DbFilterExpression)entityProjection.Input.Expression; var rowProjection = (DbProjectExpression)booleanColumnFilter.Input.Expression; var discriminatorFilter = (DbFilterExpression)rowProjection.Input.Expression; var predicates = FlattenOr(booleanColumnFilter.Predicate).ToList(); var propertyPredicates = predicates.OfType <DbPropertyExpression>() .Where( px => px.Instance.ExpressionKind == DbExpressionKind.VariableReference && ((DbVariableReferenceExpression)px.Instance).VariableName == booleanColumnFilter.Input.VariableName) .ToList(); if (predicates.Count != propertyPredicates.Count) { return(null); } var predicateColumnNames = propertyPredicates.Select(px => px.Property.Name).ToList(); var discriminatorPredicates = new Dictionary <object, DbComparisonExpression>(); if (!TypeSemantics.IsEntityType(discriminatorFilter.Input.VariableType) || !TryMatchDiscriminatorPredicate(discriminatorFilter, (compEx, discValue) => discriminatorPredicates.Add(discValue, compEx))) { return(null); } var discriminatorProp = (EdmProperty)((DbPropertyExpression)(discriminatorPredicates.First().Value).Left).Property; var rowConstructor = (DbNewInstanceExpression)rowProjection.Projection; var resultRow = TypeHelpers.GetEdmType <RowType>(rowConstructor.ResultType); var inputPredicateMap = new Dictionary <string, DbComparisonExpression>(); var selectorPredicateMap = new Dictionary <string, DbComparisonExpression>(); var columnValues = new Dictionary <string, DbExpression>(rowConstructor.Arguments.Count); for (var idx = 0; idx < rowConstructor.Arguments.Count; idx++) { var propName = resultRow.Properties[idx].Name; var columnVal = rowConstructor.Arguments[idx]; if (predicateColumnNames.Contains(propName)) { if (columnVal.ExpressionKind != DbExpressionKind.Case) { return(null); } var casePredicate = (DbCaseExpression)columnVal; if (casePredicate.When.Count != 1 || !TypeSemantics.IsBooleanType(casePredicate.Then[0].ResultType) || !TypeSemantics.IsBooleanType(casePredicate.Else.ResultType) || casePredicate.Then[0].ExpressionKind != DbExpressionKind.Constant || casePredicate.Else.ExpressionKind != DbExpressionKind.Constant || (bool)((DbConstantExpression)casePredicate.Then[0]).Value != true || (bool)((DbConstantExpression)casePredicate.Else).Value) { return(null); } DbPropertyExpression comparedProp; object constValue; if ( !TryMatchPropertyEqualsValue( casePredicate.When[0], rowProjection.Input.VariableName, out comparedProp, out constValue) || comparedProp.Property != discriminatorProp || !discriminatorPredicates.ContainsKey(constValue)) { return(null); } inputPredicateMap.Add(propName, discriminatorPredicates[constValue]); selectorPredicateMap.Add(propName, (DbComparisonExpression)casePredicate.When[0]); } else { columnValues.Add(propName, columnVal); } } // Build a new discriminator-based filter that only includes the same rows allowed by the higher '_from0' column-based filter var newDiscriminatorPredicate = Helpers.BuildBalancedTreeInPlace( new List <DbExpression>(inputPredicateMap.Values), (left, right) => left.Or(right)); discriminatorFilter = discriminatorFilter.Input.Filter(newDiscriminatorPredicate); var entitySelector = (DbCaseExpression)entityProjection.Projection; var newWhens = new List <DbExpression>(entitySelector.When.Count); var newThens = new List <DbExpression>(entitySelector.Then.Count); for (var idx = 0; idx < entitySelector.When.Count; idx++) { var propWhen = (DbPropertyExpression)entitySelector.When[idx]; var entityThen = (DbNewInstanceExpression)entitySelector.Then[idx]; DbComparisonExpression discriminatorWhen; if (!selectorPredicateMap.TryGetValue(propWhen.Property.Name, out discriminatorWhen)) { return(null); } newWhens.Add(discriminatorWhen); var inputBoundEntityConstructor = ValueSubstituter.Substitute(entityThen, entityProjection.Input.VariableName, columnValues); newThens.Add(inputBoundEntityConstructor); } var newElse = ValueSubstituter.Substitute(entitySelector.Else, entityProjection.Input.VariableName, columnValues); var newEntitySelector = DbExpressionBuilder.Case(newWhens, newThens, newElse); DbExpression result = discriminatorFilter.BindAs(rowProjection.Input.VariableName).Project(newEntitySelector); return(result); }