как согласовать SQL-запрос с LINQ с помощью count, group by и isnull - PullRequest
0 голосов
/ 20 ноября 2018

У меня есть следующий SQL-запрос, который я пытаюсь перевести на LINQ Query

SELECT C.NAME,C.MOBILEPHONE,ISNULL (SUM(P.PAYMENTAMOUNT),0)  AS 
PAYAMOUNT,BILLAMOUNT ,B.ID,BILLNO , BILLDATE FROM CUSTOMERS C
JOIN BILLS B ON B.CUSTOMERID=C.ID
LEFT JOIN BILLPAYMENTS P ON P.BILLID=B.ID
GROUP BY C.NAME ,B.BILLAMOUNT,B.ID,BILLNO,BILLDATE,C.MOBILEPHONE
HAVING B.BILLAMOUNT> ( ISNULL(SUM(P.PAYMENTAMOUNT),0)) 

Как вы представляете это в LINQ?

Я видел типичную реализацию этого

var query = from c in db.Customers
                    join b in db.Bills on c.Id equals b.CustomerId
                     join p in db.BillPayments on b.Id equals p.BillId into cs
                     from xx in cs.DefaultIfEmpty()

                    group xx by new { c.Name, c.MobilePhone, b.BillAmount, b.BillNo, b.Id, b.BillDate } into g
                    where g.Sum(p => p.PaymentAmount) < g.Key.BillAmount
                    select new
                    {
                        Received = g.Key,
                        ReceivedTotal =   g.Sum(p => p.PaymentAmount) 

                    };

но не уверен, как реализовать следующее:

 HAVING B.BILLAMOUNT> ( ISNULL(SUM(P.PAYMENTAMOUNT),0)) 

1 Ответ

0 голосов
/ 20 ноября 2018

Итак, у вас есть последовательность Customers, где каждый Customer имеет ноль или более Bills, а каждый Bill принадлежит ровно одному Customer: прямое отношение один-ко-многим.

Кроме того, каждый Bill имеет ноль или более BillPayments, где каждый BillPayment принадлежит ровно одному Bill, также отношение один ко многим.

Увы, вы забыли рассказать нам свои занятия. Если вы следовали первым соглашениям кода структуры сущности , у вас будет что-то похожее на:

class Customer
{
     public int Id {get; set;}
     public string Name {get; set;}
     ...

     // every Customer has zero or more Bills (one-to-many)
     public virtual ICollection<Bill> Bills {get; set;}
}
class Bill
{
     public int Id {get; set;}
     public int BillNo {get; set;}
     public decimal BillAmount {get; set;}
     ...

     // every Bill belongs to exactly one Customer, using foreign key
     public int CustomerId {get; set;}
     public virtual Customer Customer {get; set;}

     // every Bill has zero or more BillPayments (one-to-many)
     public virtual ICollection<BillPayment> BillPayments {get; set;}
}
class BillPayment
{
     public int Id {get; set;}
     ...

     // every BillPayment belongs to exactly one Bill, using foreign key
     public int BillId {get; set;}
     public virtual Bill Bill{get; set;}

     // every Bill has zero or more BillPayments (one-to-many)
     public virtual ICollection<BillPayment> BillPayments {get; set;}
}

В структуре сущностей столбцы вашей таблицы представлены не виртуальными свойствами, виртуальные свойства представляют отношения между таблицами.

Вы также забыли требования вашего запроса. Мне кажется, что вы хотите следующее:

Дайте мне определенные свойства Счетов (Id, BillNo, BillDate, BillAmount), с определенными свойствами Клиента этого Счета (Имя и Мобильный телефон), из всех Счетов, которые еще не полностью оплачены. Или, другими словами, из всех счетов, где сумма всех платежей меньше, чем сумма счета.

Одна из приятных сторон структуры сущностей заключается в том, что вам не нужно выполнять объединения самостоятельно, вы можете использовать виртуальные свойства. Entity Framework знает отношения между таблицами и выполняет для вас правильные объединения.

Просто для удовольствия мы добавим оригинал BillAmount, AmountPaid и RemainingAmount, чтобы вы могли сообщить своему клиенту, сколько ему еще нужно заплатить, когда вы звоните ему по мобильному телефону

В требовании вы видите центральную роль Bills, поэтому давайте использовать ее в качестве отправной точки:

// (1) from all bills, calculate the AmountPaid; remember the original bill data:
var notFullyPaidBills = myDbContext.Bills
    .Select(bill => new
    {
        BillData = bill,
        AmountPaid = bill.BillPayments
          .Select(billPayment => billPayment.PaymentAmount)
          .Sum(),
    })
    // (2) Keep only those bills that are not fully paid yet
    .Where(bill => bill.Bil.BillAmount > bill.AmountPaid)

    // (3) from the remaining bills select the required properties:
    .Select(bill => new
    {
        // Customer properties:
        CustomerName = bill.BillData.Customer.Name,
        MobilePhone = bill.BillData.Customer.MobilePhone,

        // bill properties:
        BillId = bill.BillData.Id,
        BillNo = bill.BillData.BillNo,
        BillDate = bill.BillData.Date,

        // Amounts:
        BillAmount = bill.BillData.BillAmount,
        AmountPaid = bill.AmountPaid,
        RemainingAmount = bill.BillData.BillAmount - bill.AmountPaid,
    });

См? При использовании виртуальных свойств классов вашей структуры сущностей запросы будут выглядеть намного проще и интуитивно понятнее, чем когда вы выполняете присоединение (группы) самостоятельно.

...