0

I have 2 tables _customerRepository.GetAllQueryable() and _customerSettlementRepository.GetAllQueryable().

In table _customerSettlementRepository.GetAllQueryable(), I have column ApplyD (date), after joining these two together, I want to find out max ApplyD in the where clause. This is my code:

var settlements = from c in _customerRepository.GetAllQueryable()
    join cs in _customerSettlementRepository.GetAllQueryable() on new {c.CustomerMainC, c.CustomerSubC}
    equals new {cs.CustomerMainC, cs.CustomerSubC} into c1
    where cs.ApplyD == (c1.Select(b=>b.ApplyD).Max())
    select new CustomerSettlementViewModel()
    {
            TaxRate = cs.TaxRate
    };
waka
  • 3,362
  • 9
  • 35
  • 54
Triet Pham
  • 88
  • 1
  • 14
  • 1
    add example input and output – Backs Oct 11 '17 at 04:09
  • Question is not very clear, waht do you want exactly ? – GGO Oct 11 '17 at 07:26
  • Simplify your query. If the LINQ query looks ugly, the generated SQL and performance will *also* be ugly. You won't be able to maintain this code in the future either – Panagiotis Kanavos Oct 11 '17 at 07:51
  • Furthermore, you are using an ORM, not writing SQL. If you have to use joins, you have a serious design bug. Your customer and customer *entities* should have navigation properties that point to each other. That's what LINQ and EF offer. If you end up using joins, what's the point of using LINQ at all? – Panagiotis Kanavos Oct 11 '17 at 07:52
  • Yes, I understand, thank you very much – Triet Pham Oct 11 '17 at 07:56

2 Answers2

2

It's remarkable that quite often in these questions people come up with an SQL(-like) statement without specification of the goal they want to reach. Hence it is impossible to see whether the provided statement fulfills the requirements.

Anyway, it seems you have something like Customers (in CustomerRepository) and CustomerSettlements in CustomerSettlementRepository.

both Customers and CustomerSettlements have a CustomerMainC and a CustomerSubC. You want to join Customers and CustomerSettlements on these two properties.

A CustomerSettlement also has an ApplyD and a TaxRate.

You only want to keep the join results where ApplyD has the maximum value of ApplyD

Finally, from every remaining join result you want to create one CustomerSettlementViewModel object with the value of the TaxRate in the join result that was taken from the CustomerSettlement.

Now that I wrote this, it baffles me why you need to join in the first place, because you only use values from the CustomerSettlements, not from the Customer.

Besides, if two Customers are joined with the same CustomerSettlements. this will result in two equal CustomerSettlementViewModel objects.

But let's assume this is really what you want.

In baby steps:

IQueryable<Customer> customers = ...
IQueryable<CustomerSettlement> customerSettlements = ...

var joinResults = customers.Join(customerSettlements
   customer => new {customer.CustomerMainC, customer.CustomerSubC},
   settlement => new {settlement.CustomerMainC, settlement.CustomerSubC}
   (customer, settlement) => new
   {
      settlement.ApplyD,
      settlement.TaxRate,
      // add other properties from customers and settlements you want in the end result
   });

In words: take all Customers and all CustomerSettlements. From every Customer create an object having the values of the customer's CustomerMainC and CustomerSubC. Do the same from every CustomerSettlement. When these two objects are equal, create a new object, having the values of the CustomerSettlement's ApplyD and TaxRate (and other properties you need in the end result)

Note that this is still an IQueryable. No query is performed yet.

From this joinResult you only want to keep those objects that have the value of ApplyD that equals the maximum value of ApplyD.

This question on StackOverflow is about selecting the records with the max value. The idea is to group the records into groups with the same value for ApplyD. Then order the groups in descending Key order and take the first group.

var groupsWithSameApplyD = joinResults.GroupBy(
    joinedItem => joinedItem.ApplyD,
    joinedItem => new CustomerSettlementViewModel()
    {
        TaxRate = orderedItem.TaxRate,
        // add other values from joinedItems as needed
    });

Every group in groupsWithSameApplyD has a key equal to ApplyD. The group consists of CustomerSettlementViewModel objects created frome the joinedItems that all have the same ApplyD that is in the Key of the group.

Now order by descending:

var orderedGroups = groupsWithSameApplyD.OrderByDescending(group => group.Key);

The first group contains all elements that had the largest ApplyD. Your desired result is the sequence of elements in the group.

If there is no group at all, return an empty sequence. Note if a sequence is requested as result, it is always better to return an empty sequence instead of null, so callers can use the returned value in a foreach without having to check for null return

var result = orderedGroups.FirstOrDefault() ??
    // if no groups at all, return empty sequence:
    Enumerable.Empty<CustomerSettlementViewModel>();

Note: the FirstOrDefault is the first step where the query is actually performed. If desired you could put everything in one big query. Not sure if this would improve readability and maintainability.

Harald Coppoolse
  • 28,834
  • 7
  • 67
  • 116
0

enter image description here

This is my syntet error, I need to write this since the first

var settlements = from c in _customerRepository.GetAllQueryable()
                    join cs in _customerSettlementRepository.GetAllQueryable() on new {c.CustomerMainC, c.CustomerSubC}
                        equals new {cs.CustomerMainC, cs.CustomerSubC} 
                    select new CustomerSettlementViewModel()
                    {
                        TaxRate = cs.TaxRate
                    };
                settlements = settlements.Where(p => p.ApplyD == settlements.Max(b => b.ApplyD));
Jaydip Jadhav
  • 12,179
  • 6
  • 24
  • 40
Triet Pham
  • 88
  • 1
  • 14