How did I get to this?

DL

First try

public static Invoice Insert(Invoice newInvoice)
{
  using (TestDC dc = new TestDC())
  {
    long? customerId = newInvoice.Customer == null ? null : (long?)newInvoice.Customer.CustomerID;
    Invoice inserted = (from i in dc.csTtaInvoice_I1(customerId, newInvoice.Amount, newInvoice.Date)
                        select i).Single();
    return inserted;
  }
}

public static Invoice Update(Invoice changed)
{
  using (TestDC dc = new TestDC())
  {
    long? customerId = changed.Customer == null ? null : (long?)changed.Customer.CustomerID;
    Invoice updated = (from i in dc.csTtaInvoice_U1(changed.InvoiceID, customerId, changed.Amount, changed.Date, changed.Tms)
                       select i).Single();
    return updated;
  }
}

Using

If you use 'using', it's not possible anymore to get entitysets (eg. the invoice details) of the returned object.
Because here we insert a new object, there are no entitysets, but for an update this could be an issue.
Probably you want to compare the updated entitysets with the ones in the database to decide which ones to update, to delete and to insert.
Also if there are calculated fields into the database, you won't have the results.
For this reasons, we'll remove the usings.

Second try

public static Invoice Insert(Invoice newInvoice)
{
  TestDC dc = new TestDC();
  long? customerId = newInvoice.Customer == null ? null : (long?)newInvoice.Customer.CustomerID;
  Invoice inserted = (from i in dc.csTtaInvoice_I1(customerId, newInvoice.Amount, newInvoice.Date)
                      select i).Single();
  return inserted;
}

public static Invoice Update(Invoice changed)
{
  TestDC dc = new TestDC();
  long? customerId = changed.Customer == null ? null : (long?)changed.Customer.CustomerID;
  Invoice updated = (from i in dc.csTtaInvoice_U1(changed.InvoiceID, customerId, changed.Amount, changed.Date, changed.Tms)
                     select i).Single();
  return updated;
}

public static InvoiceDetail Insert(InvoiceDetail newDetail)
{
  TestDC dc = new TestDC();
  InvoiceDetail inserted = (from d in dc.csTtaInvoiceDetail_I1(newDetail.Invoice.InvoiceID, newDetail.ProductID, 
                              newDetail.Number, newDetail.Amount)
                            select d).Single();
  return inserted;
}

public static InvoiceDetail Update(InvoiceDetail changed)
{
  TestDC dc = new TestDC();
  InvoiceDetail updated = (from d in dc.csTtaInvoiceDetail_U1(changed.InvoiceDetailID, changed.Invoice.InvoiceID, 
                             changed.ProductID, changed.Number, changed.Amount, changed.Tms)
                           select d).Single();
  return updated;
}

Invoice: long? customerId

If there is no customer linked to the invoice, newInvoice.Customer will be null. So in this case, null will be inserted.
If there is a customer linked to the invoice, it is not sure that newInvoice.CustomerID will contain the right CustomerID. This will only be the case if it has been loaded from Linq.
If you manually do newInvoice.Customer = someCustomer, newInvoice.Customer.CustomerID will be correct. But newInvoice.CustomerID will be 0.

InvoiceDetail: newDetail.Invoice.InvoiceID

The same as with the customer, except that newDetail.Invoice should not be null, so the null check is not really necessary.

BL

InvoiceDetail

public static void Insert(InvoiceDetail newDetail)
{
  InvoiceDetail insertedDetail = InvoiceDetailDL.Insert(newDetail);
  newDetail.InvoiceDetailID = insertedDetail.InvoiceDetailID;
  newDetail.Tms = insertedDetail.Tms;
}

public static void Update(InvoiceDetail changed)
{
  InvoiceDetail updated = InvoiceDetailDL.Update(changed);
  changed.Tms = updated.Tms;
}

The object that is passed from the GUI to the BL is updated.
This has the advantage that you have only one object in the GUI.
It has the disadvantage that the original object doesn't exist anymore.
But why would we still need this? It would only make the code more complicated.
If really necessary, the code can easily be rewritten to support returning the inserted/updated instance.

Invoice

public static void Insert(Invoice newInvoice)
{
  Invoice inserted = InvoiceDL.Insert(newInvoice);
  newInvoice.InvoiceID = inserted.InvoiceID;
  newInvoice.Tms = inserted.Tms;

  foreach (InvoiceDetail detail in newInvoice.InvoiceDetails)
  {
    InvoiceDetailBL.Insert(detail);
  }
}

public static void Update(Invoice changed)
{
  Invoice updated = InvoiceDL.Update(changed);
  changed.Tms = updated.Tms;

  SaveChangedDetails(changed, updated);

  DeleteRemovedDetails(changed, updated);
}

private static void SaveChangedDetails(Invoice changed, Invoice updated)
{
  foreach (InvoiceDetail changedDetail in changed.InvoiceDetails)
  {
    if (changedDetail.InvoiceDetailID == 0)
    {
      InvoiceDetailBL.Insert(changedDetail);
    }
    else
    {
      foreach (InvoiceDetail databaseDetail in updated.InvoiceDetails)
      {
        if (changedDetail.InvoiceDetailID == databaseDetail.InvoiceDetailID)
        {
          InvoiceDetailBL.Update(changedDetail);
        }
      }
    }
  }
}

private static void DeleteRemovedDetails(Invoice changed, Invoice updated)
{
  foreach (InvoiceDetail databaseDetail in updated.InvoiceDetails)
  {
    bool found = false;
    foreach (InvoiceDetail changedDetail in changed.InvoiceDetails)
    {
      if (databaseDetail.InvoiceDetailID == changedDetail.InvoiceDetailID)
      {
        found = true;
      }
    }
    if (!found)
    {
      InvoiceDetailDL.Delete(databaseDetail);
    }
  }
}
Unless otherwise stated, the content of this page is licensed under Creative Commons Attribution-ShareAlike 3.0 License