tags:

views:

205

answers:

5

When I need to grab more than one record from table(database), my method populates List of particular class (all of my data access layer methods use List for set based select statements. I Don't use datatable/dataset or xmlDocument approach). So lets suppose next simplified scenario; I have two classes – customer and order with these fields/properties:

Class Customer{
   int IDCustomer
   string CustomerName
   string CustomerAddress
   string CustomerCity
}

Class Order{
   int IDOrder
   int IDCustomer
   string SalePersonName
   decimal OrderSubTotal
   datetime OrderDateCreated
}

So, lets say that we need a method which deliver to the UI (ObjectDataSource) all data from Order Class properties + CustomerName and CustomerCity from Customer class. I want my method from Order class looks like:

public List<Order> SelectAll(){ 
}

so which approach should I use to accomplish this? How to setup Order Class so it contain that two extra properties (CustomerName and CustomerCity) concerning best practices, object oriented paradigm, performance etc. :

APROACH A:


Class Order{
   int IDOrder
   int IDCustomer
   string SalePersonName
   decimal OrderSubTotal
   datetime OrderDateCreated
   //--- plus two extra properties of type string
   string CustomerName
   string CustomerCity
}

APROACH B:


Class Order{
   int IDOrder
   int IDCustomer
   string SalePersonName
   decimal OrderSubTotal
   datetime OrderDateCreated
   //--- plus extra property of type Customer
   Customer _Customer
}

APROACH C:


???

I am on .NET 2.0.

Thank you people for your time.

A: 

No question, B. There is a one-to-many relationship between customers and orders - a customer has many orders (list of orders) and an order has one customer (scalar property of type customer).

public class Customer
{
   public Int32 Id { get; private set; }
   public String Name { get; private set; }
   public String Address { get; private set; }
   public String City { get; private set; }

   public IList<Order> Orders { get { return this.orders; } }
   private readonly IList<Orders> orders = new List<Orders>();
}

Class Order
{
   public Int32 Id { get; private set; }
   public String SalesPersonName { get; private set; }
   public Decimal SubTotal { get; private set; }

   public Customer Customer { get; private set; }
}

For the user interface you can then create a separate class that wraps an order like the following.

public class OrderView
{
    private readonly Order order;

    public OrderView(Order order)
    {
        this.order = order;
    }

    public Decimal SubTotal { get { return this.order.SubTotal; } }
    public String CustomerCity { get { return this.order.Customer.City; } }
    // ...
}
Daniel Brückner
violates the Law of Demeter, if you care about that sort of thing.
Robert
I don't like the Law of Demeter that much ... would the following realy be better? Realy be different?Customer customer = this.order.Customer;return (customer != null) ? customer.City : String.Empty;And cluttering the Order class with GetCustomerFoo() methods is nothing I like to do, too.
Daniel Brückner
I am confused... you say option B but then you make up a different option to answer the question. In his approach B, he has order containing a customer. You have it the other way around and you create a third class. Not saying that this is a bad solution, but it is not approach B his as you describe it.
Brian ONeil
You are right - might be a bit confusing. Option B refers to the business entities (the first two classes) and I added both ends of the relationship - a customer to the order and a list of orders to the customer. The third class is what is required for some views if databinding to nested properties is not possible. It's option C and wrapps a business entity.
Daniel Brückner
+1  A: 

I have no problem creating another class that flattens the query whichs acts as a viewmodel.

almog.ori
A: 

This sounds like a job for an ORM.

Joel Coehoorn
A: 

If you allow that a one-to-many customer to order relationship exists, a customer class that has-a list of orders follows. While this slightly deviates from your original request, you'll probably have an easier time of manipulating a customer and the orders it contains rather than duplicating members from the parent.

Class Customer{
   int IDCustomer
   string CustomerName
   string CustomerAddress
   string CustomerCity
   List<Order> orders;

   public List<Order> SelectAll(){ return orders; }
}

Class Order{
   int IDOrder
   //int IDCustomer -not necessary as parent contains this info
   string SalePersonName
   decimal OrderSubTotal
   datetime OrderDateCreated
}
Eric H
A: 

Because this is a design question I think that there is more information needed to give a complete answer because I think that it depends on the circumstances.

If you already have the Order objects and the Customer objects loaded and use them for different things in the presentation layer then creating a specialized class to flatten the display data is a good solution.

If you are loading the information to display a list of orders and need the customer information on each order, then I would have to ask why you don't just create a CustomerOrder class that has the relevant fields on it and just load that to begin with because you are not going to use the extra data of Customer anyway.

All these design decisions depend on external factors. In the end, I would say that the right design decision is usually the simplest one that meets your needs.

Brian ONeil