private void ProcessFlattenedJoin(GroupJoinClause nonAggregatingJoin, QuerySourceUsageLocator locator) { var nhJoin = locator.LeftJoin ? new NhOuterJoinClause(nonAggregatingJoin.JoinClause) : (IQuerySource)nonAggregatingJoin.JoinClause; // Need to: // 1. Remove the group join and replace it with a join // 2. Remove the corresponding "from" clause (the thing that was doing the flattening) // 3. Rewrite the query model to reference the "join" rather than the "from" clause SwapClause(nonAggregatingJoin, (IBodyClause)nhJoin); _model.BodyClauses.Remove((IBodyClause)locator.Usages[0]); SwapQuerySourceVisitor querySourceSwapper; if (locator.LeftJoin) { // As we wrapped the join clause we have to update all references to the wrapped clause querySourceSwapper = new SwapQuerySourceVisitor(nonAggregatingJoin.JoinClause, nhJoin); _model.TransformExpressions(querySourceSwapper.Swap); } querySourceSwapper = new SwapQuerySourceVisitor(locator.Usages[0], nhJoin); _model.TransformExpressions(querySourceSwapper.Swap); }
private void ReWrite() { var aggregateDetectorResults = GetGroupJoinInformation(_groupJoinClauses); foreach (var nonAggregatingJoin in aggregateDetectorResults.NonAggregatingClauses) { // Group joins get processed (currently) in one of three ways. // Option 1: results of group join are not further referenced outside of the final projection. // In this case, replace the group join with a join, and add a client-side grouping operator // to build the correct hierarchy // // Option 2: Results of group join are only used in a plain "from" expression, such as: // from o in db.Orders // from p in db.Products // join d in db.OrderLines // on new {o.OrderId, p.ProductId} equals new {d.Order.OrderId, d.Product.ProductId} // into details // from d in details // select new {o.OrderId, p.ProductId, d.UnitPrice}; // In this case, simply change the group join to a join; the results of the grouping are being // removed by the subsequent "from" // // Option 3: Results of group join are only used in a "from ... DefaultIfEmpty()" construction, such as: // from o in dc.Orders // join v in dc.Vendors on o.VendorId equals v.Id into ov // from x in ov.DefaultIfEmpty() // join s in dc.Status on o.StatusId equals s.Id into os // from y in os.DefaultIfEmpty() // select new { o.OrderNumber, x.VendorName, y.StatusName } // This is used to repesent an outer join, and again the "from" is removing the hierarchy. So // simply change the group join to an outer join _locator = new QuerySourceUsageLocator(nonAggregatingJoin); foreach (var bodyClause in _model.BodyClauses) { _locator.Search(bodyClause); } if (IsHierarchicalJoin(nonAggregatingJoin)) { } else if (IsFlattenedJoin(nonAggregatingJoin)) { ProcessFlattenedJoin(nonAggregatingJoin); } else if (IsOuterJoin(nonAggregatingJoin)) { } else { // Wonder what this is? throw new NotSupportedException(); } } }
private bool IsFlattenedJoin(GroupJoinClause nonAggregatingJoin, QuerySourceUsageLocator locator) { if (locator.Usages.Count == 1) { var from = locator.Usages[0] as AdditionalFromClause; if (from != null) { return(true); } } return(false); }
private bool IsHierarchicalJoin(GroupJoinClause nonAggregatingJoin, QuerySourceUsageLocator locator) { return(locator.Usages.Count == 0); }
private static bool IsHierarchicalJoin(QuerySourceUsageLocator locator) { return(locator.Usages.Count == 0); }
private static bool IsFlattenedJoin(QuerySourceUsageLocator locator) { return(locator.Usages.Count == 1 && locator.Usages[0] is AdditionalFromClause); }
private static bool IsOuterJoin(QuerySourceUsageLocator locator) { return(false); }