views:

1476

answers:

8

Hi,

I have a method in my DAL returning a list of Customers:

Collection<Customer> FindAllCustomers();

The Customer has these columns: ID, Name, Address, Bio

I need to show them in a paged grid in my ASPX form (show-customers.aspx) where I'll be showing only these columns: ID, Name

Now, in my DAL FindAllCustomers(), do I return the Bio field too from the SP (I am filling in the collection using a reader)? The Bio field can be large (nvarchar(max)). I was thinking of lazy loading or loading only the required fields. But then in that case I would need to create another method which returns a "full" list of customers including the bio so that 3rd party apps can use it through a service layer. So is it ok to create a method like this:

Collection<Customer> FindAllCustomers(bool loadPartial);

If loadPartial = true, then do not load Bio, else load it. In this case since I do not want to return the Bio from the SP, I would need to create 2 select statements in my SP based on the bool value.

I think using lazy loading here will not work, because then the DAL method can be accessed by a 3rd party app, which might want to load the bio too.

Any suggestions on the best pattern to implement in such cases?

thanks,

Vikas

+1  A: 

If your list of customers never shows the bio, then having a streamlined version would be fine.

A few questions...

  • Does that parameter only determine whether the Bio is loaded? In the future, will you have other fields that don't load when it's set to true?
  • What happens if I try to access Bio if loadPartial was set to true?

The key will be to ensure that whatever mechanism you choose is resilient to change. Put yourself in the perspective of a 3rd party and try to make your methods do what you'd expect. You don't want the developers who use your classes to have to understand the mechanisms deeply. So maybe instead of a "loadPartial" parameter, you simply have a different method which resolves the fast, minimal data needed to bind to a list and lazy loads the other fields as needed.

Larsenal
1. the bool parameter passed in the DAL determines whether if we need to load other "non-essential large" fields or not. There can be other fields in future which might not be required.2. if loadPartial=true, bio will not be accessible at all. I understand the alternative way: lazily loading Bio as soon as that property is accessed.
But then again, IMO there are two methods for this type of lazy loading:1. in DAL, let the reader read the Bio column, but dont load it in the Customer property. In this case since the reader reads the entire row (and not column-wise), we will anyways waste precious DB bandwidth sending by letting the SP return the whole Bio column for each record.2. Load bio column through parametrized SP, as soon as the Bio property is accessed. In this case I would be making 2 DAL calls. Not sure how good is that?
+1  A: 

I think that is acceptable... It is your program. You'd just want to ensure the API is documented and makes sense to others.

As a side note, you don't necessarily need two stored procedures or a classic if statement in your stored procedure.

You can use a case statement to NULL out the field when loadPartial == true.

Case WHEN @loadPartial = 1 THEN NULL ELSE [bio] END
Frank V
+1  A: 

I think it's fine to have two methods optimised for specific cases so long as you make it clear in your method names. Personally I don't think:

Collection<Customer> FindAllCustomers(bool loadPartial);

Is very clear. How would a developer know what that boolean param actually meant in practise? See boolean parameters — do they smell? question.

Make it clear and all is well.

Dan Diplo
+3  A: 

The 3rd party thing is a bind.

At first blush I would normally suggest that you load only the minimal data normally and then load complete or further detail on an as-requested (i.e. touching a property could trigger a DB call - mild abuse of property there perhaps) or background process basis, depending on the nature of what you're doing.

Lazy property code by way of clarification:

class Customer
{
  private string _lazydata = null;

  public string LazyData
  {
    get
    {
      if (this._lazydata==null)
      {
        LazyPopulate();
      }
      return this._lazydata;
    }
  }

  private void LazyPopulate()
  {
    /* fetch data and set lazy fields */
  }
}

Be careful with this, you don't want to make lots of DB calls but nor do you want to be creating a bottleneck whenever you look at something lazy. Only the nature of your app can decide if this is suitable.

I think you have a valid case for creating the boolean flag method (though I would default to lightweight version) on the grounds that it's very likely a 3rd party would want the lightweight version for the same reasons you do.

I'd go with:

Collection<Customer> FindAllCustomers()
{
  return this.FindAllCustomers(false);
}

Collection<Customer> FindAllCustomers(bool alldata)
{
  /* do work */
}
annakata
+1  A: 

Why not use lazy loading in the properties of the Customer Class itself? Give each property (Id, Name,Bio), a private variable. In the getter of each property, if the private variable is not null then return it, otherwise read it in from your DAL.

When it comes to Bio, if you have to lazy load it, then in your getter you call another method in the Customer Class called LazyLoadAdditionalDetails() and call the appropriate sprocs there, then return your private variable.

This way you can keep your code as normal, and your paging view will only call the getters of the ID and Name, and your Bio will be populated from a sproc only when needed without you having to remember to call a lazy loading method.

One has to pay attention with this approach in the web environment. Using a LazyLoad approach on the single properties of the Customer object itself has the drawback that in case of a list, this would result in a bunch of DB requests which may be fired in sequence. In such a case LazyLoading would have to be enabled for the list as a whole, say for the amount of objects displayed on one page (if the list uses paging) which would then result in a single DB access.
Juri
it could be one request not a bunch, but it definitely requires care
annakata
@annakata: I agree. Some of my workmates tried this out on a former project where they said it didn't work fine for this reason. I guess they didn't try to implement the lazy-loading on the whole list as this would be more performant I guess (or implement some kind of caching).
Juri
Ah yes, very good point. I suppose it's nicer from a code perspective, but DB performance wise you are right, why do in multiple calls what you can do in one.I suppose it boils down to how many items will be in the List. Even so, I'd say most of the times the method I just described would not be ideal when DB performance is concerned.
A: 
class CustomerDAO
{
   private bool _LoadPartial = true;
   public bool LoadPartial
   {
      get
      {
         return _LoadPartial;
      }

      set
      {
         _LoadPartial = value;
      }
   }


   public Collection<Customer> FindAllCustomers()
   {
      ...
   }
}

Would be another option, although I also like annakata's one.

Juri
A: 

Instead of

Collection<Customer> FindAllCustomers(bool loadPartial);

I'd make it

Collection<Customer> FindAllCustomers(bool includeBio);

"loadPartial" doesn't tell the consumer what constitutes a "partial" customer. I also agree with annakata's points.

Chuck
+1  A: 

In that case I would use an enum to be even more clear about the meaning of the parameter...

public enum RetriveCustomerInfo
{
   WithBio,
   WithoutBio
}

And when you call the method:

dao.FindAllCustomers(RetriveCustomerInfo.WithBio);

I don't know if it's better but I think it's more clear.

What do you think?

pabloide86