Итак, у вас есть последовательность 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,
});
См? При использовании виртуальных свойств классов вашей структуры сущностей запросы будут выглядеть намного проще и интуитивно понятнее, чем когда вы выполняете присоединение (группы) самостоятельно.