如何使用count,group by和isull子句协调对LINQ的SQL查询

时间:2018-11-20 05:33:59

标签: entity-framework linq sql-to-linq-conversion

我尝试将以下SQL查询转换为LINQ查询

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 :(得分:0)

因此,您有一个Customers序列,其中每个Customer具有零个或多个Bills,而每个Bill恰好属于一个Customer:简单的一对多关系。

此外,每个Bill都有零个或多个BillPayments,其中每个BillPayment恰好属于一个Bill,也是一对多的关系。

A,您忘了告诉我们您的课程。如果您遵循entity framework code first conventions,将会得到类似的内容:

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),以及该账单的客户的某些属性(名称和移动电话),以及所有尚未支付的账单。换句话说,就是所有付款的总和小于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,
    });

看到了吗?使用实体框架类的虚拟属性时,查询将比您(组)加入自己时看起来更简单和直观。