Take the 2-minute tour ×
Programmers Stack Exchange is a question and answer site for professional programmers interested in conceptual questions about software development. It's 100% free, no registration required.

For example, I've got a root object exposed in a SOA service, say Invoice (Invoice has line items as children).

Sometimes, I need to retrieve its detail line items. I'm thinking to make it lazy loading, because it's a traffic overhead to transfer line items every time Invoice is required. But in SOA fashion, it seems unlikely. Because all it can expose are Invoice POCOs, with contain no logic. Thus I cannot attach my lazy loading logic to Invoice to instruct it to load lines items when needed.

share|improve this question
2  
Marvin, your brain is the size of a planet, how come you ask us lowly humans? :P –  Yannis Rizos Jan 7 '12 at 13:54
add comment

3 Answers

up vote 3 down vote accepted

There is nothing wrong in calling a service again to get the invoice items. On service level:

  1. ServiceInvoice LoadInvoice(Guid invoiceId) will get you the invoice without the details,
  2. List<InvoiceItem> LoadDetails(Guid invoiceId) will get you the lines.

After you've done that, you've lost the OOP part and the code becomes less intuitive on client side. To correct that, you may want to add an additional abstraction layer:

class Invoice : ServiceInvoice
{
    public List<InvoiceItem> Lines
    {
        get
        {
            return MyService.LoadDetails(this.Id);
        }
    }
}
share|improve this answer
add comment

What I would do is to implement a client library that interacts with that service and then use some proxy to provide lazy loading.

For example, your service could return Invoice POCOs and InvoiceLine POCOs in two separate calls. Now, as the user/caller/client of that service, you can have your own client library that facilitates interacting with the service from your application code. In that client library you could have an Invoice class with a proxy method get_lines() that would call again to the service, get the InvoiceLine POCOs and return those (or some more functional InvoiceLine objects)

Update: Obviously, you cannot guarantee that all systems calling your service will use that same client, so the Service should not rely or depend on having that specific client library doing the calls. But for your own application, for your own client purposes, you can have whatever client functionality you want (just like many existing classes wrapping Google Analytics APIs, etc)

share|improve this answer
add comment

Certainly you want to reduce the number of round trips. That's a realistic requirement of any SOA. That means you probably have many use cases you want to code for:

interface IInvoice
{
    Guid InvoiceId { get; }
    string InvoiceNumber { get; }
    string CustomerName { get; }
    decimal TotalPrice { get; }
}
public IEnumerable<IInvoiceSummary> FindInvoices(IInvoiceCriteria criteria);

interface IInvoiceSummary : IInvoice
{
    int NumberOfLineItems { get; }
}

public IDetailedInvoice GetInvoice(Guid invoiceId);

interface IDetailedInvoice : IInvoice
{
    ReadOnlyCollection<IInvoiceLineItem> LineItems { get; }
}

Of course if you have different use cases, you may want to change those. Perhaps you want to get unpaid invoices for a customer, but in detailed format, so maybe you have another service point that returns that special case.

So, I recommend not building lazy loading into your SOA architecture. Since lazy loading hides the number of round trips to the database, and round trips are something the programmer should always be paying attention to because they're expensive, then you shouldn't hide them.

share|improve this answer
add comment

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.