Binding a grid to a grand child

Binding a grid to a grand child

Old forum URL: forums.lhotka.net/forums/t/4404.aspx


triplea posted on Monday, February 25, 2008

Hi

I have (roughly) the following model:

InvoiceList : BusinessBaseList<InvoiceList, Invoice>
   Invoice : BusinessBase<Invoice>
      Customer: BusinessBase<Customer>

So a list of invoices where each invoice has (only and always) one customer. I need to display in a grid all the customers.
It appears that only 1 Customer is displayed in the list if I do something like:

InvoiceList list = InvoiceList.GetList();
myBindingSource.DataSource = list;

Of ourse the above is wrong, just not sure what the correct way of phrasing this would be. If this is at all possible... Has anyone got any suggestions?

cliffordru replied on Friday, February 29, 2008

It sounds like you have the need to create another set of objects.  If your use case calls for displaying a list of customers, then you will probably want to create a CustomerList class and a CustomerListItem child class whose reposnsibility will be to display a list of customers.

Regards,

Cliff

triplea replied on Monday, March 03, 2008

Thanks for all the replies

cliffordru:

It sounds like you have the need to create another set of objects.  If your use case calls for displaying a list of customers, then you will probably want to create a CustomerList class and a CustomerListItem child class whose reposnsibility will be to display a list of customers.

That is partly true. The problem is that this is more than just a view, the functionality is to create a "bulk" list of invoices (based on some previous criteria) which is normally done on a 1 by one basis on a normal form. I just wanted to reuse the invoice object by wrapping it in a list.

rsbaker0:

Do you have more than one invoice?

It depends on what the grid will support, but the invoice could always expose properties of the customer that you need to show in the grid.

Of course, this would be a list of invoice + customer -- not sure if this is what you want.

If you just want a list of all customers (and customers can appear on more than one invoice so you don't want duplicates), then you need a separate list for your customers as the data source for the grid.

Yes there are many invoices. And yes each invoice has a public Customer property. List of Invoice + Customer is fine, just not sure how to bind a Customer property to a column. I tried stuff like "Customer.Name" but all I get is a blank column.

And finally thanks for sharing the code vdhant. I will need to look into the code a bit more though I think you are trying to achieve a more complex scenario than mine.

Just for the record, as a temporary solution I created a master/detail grid combo which seems to be working alright at the moment but still would like to solve the previous challenge for future reference!

 

vdhant replied on Monday, March 03, 2008

That's cool...
Hope it works out for you and if you are after more on what i am trying to get to have a look here http://code.msdn.microsoft.com/UOM i have added this to code gallery so others can have a look as well.
ant

rsbaker0 replied on Saturday, March 01, 2008

Do you have more than one invoice?

It depends on what the grid will support, but the invoice could always expose properties of the customer that you need to show in the grid.

Of course, this would be a list of invoice + customer -- not sure if this is what you want.

If you just want a list of all customers (and customers can appear on more than one invoice so you don't want duplicates), then you need a separate list for your customers as the data source for the grid.

vdhant replied on Saturday, March 01, 2008

I had a similar issue that i am trying to work through. I haven't completely come up with a solution that i am 100% happy with yet but this is the basic principle of how i want to deal with binding to child and grandchild lists in a normal object tree.

Please note it is not complete or 100% the way i want it to be in the end (ideally I want the object tree to be more complete), but it is more a proof of concept.

Also in this situation the Companies is the root node which has Customers which have Orders. Also this sample has been put together from the point of view that from a database and SQL point of view it is easier and far more efficient to return 1 row per entity that is at the end of the object tree (i.e. bottom up) (and in this case one row per Order) than come from the other direction (top down).

Let me know if this helps.
Anthony

P.s. I am calling this concept UOM (Utopian Object Model) because someone said that you couldn't do it and it was a fantasy...


     class Program
    {
        static void Main(string[] args)
        {
            Orders orders = new Orders();
            orders.PopulateList();

            Orders newOrders;
            byte[] temp;
            using (MemoryStream buffer = new MemoryStream())
            {
                BinaryFormatter formatter = new BinaryFormatter();
                formatter.Serialize(buffer, orders);
                temp = buffer.ToArray();
            }
            using (MemoryStream buffer = new MemoryStream(temp))
            {
                buffer.Position = 0;
                BinaryFormatter formatter = new BinaryFormatter();
                newOrders = (Orders)formatter.Deserialize(buffer);
            }

            newOrders[0].Customer.Desc = "TEST";

            //You will note that how ever you want to get/use the data you can
            foreach (Company company in orders.Companies)
            {
                foreach (Customer customer in company.Customers)
                {
                    Company companyAlter = customer.Company;

                    foreach (Order order in customer.Orders)
                    {
                        Customer customerAlt = order.Customer;
                        Company companyAlt = order.Company;
                    }
                }
            }

            foreach (Customer customer in orders.Customers)
            {
                Company company = customer.Company;

                foreach (Order order in customer.Orders)
                {
                    Customer customerAlt = order.Customer;
                    Company companyAlt = order.Company;
                }
            }

            foreach (Order order in orders)
            {
                Customer customer = order.Customer;
                Company customer = order.Company;
            }
        }
    }

    [Serializable()]
    public class Company : ItemBase
    {
        public string Desc = "";
        public Customers Customers = new Customers();
    }

    [Serializable()]
    public class Companies : ListBase<Company>
    {
    }

    [Serializable()]
    public class Customer : ItemBase
    {
        public string Desc = "";
        public Orders Orders = new Orders();
        public Company Company;
    }

    [Serializable()]
    public class Customers : ListBase<Customer>
    {
    }

    [Serializable()]
    public class Order : ItemBase
    {
        public string Desc = "";
        public Customer Customer;
        public Company Company;
    }

    [Serializable()]
    public class Orders : ListBase<Order>
    {
        public Companies Companies = new Companies();
        public Customers Customers = new Customers();

        public void PopulateList()
        {
            for (int i = 0; i < 5; i++)
            {
                Order order = new Order();
                order.Id = i;
                order.Desc = "Order " + order.Id;

                int customerRef = i % 2;
                Customer customer = this.Customers.ReturnItem(customerRef);
                if (customer == null)
                {
                    customer = new Customer();
                    customer.Id = customerRef;
                    customer.Desc = "Customer " + customer.Id;
                    this.Customers.Add(customer);
                }
                order.Customer = customer;
 
                int companyRef = 1;
                Company company = this.Companies.ReturnItem(companyRef);
                if (company == null)
                {
                    company = new Company();
                    company.Id = companyRef;
                    company.Desc = "Company " + company.Id;
                    this.Companies.Add(company);
                }
                order.Company = company;

                customer.Company = company;

                order.Customer.Orders.Add(order);

                order.Company.Customers.Add(order.Customer);

                this.Add(order);
            }
        }
    }


    [Serializable()]
    public abstract class ListBase<T> : BindingList<T>
        where T : ItemBase
    {
        public T ReturnItem(int itemId)
        { 
            foreach (T item in this)
            {
                if (item.Id == itemId)
                    return item;
            }
            return null;
        }
    }

    [Serializable()]
    public abstract class ItemBase
    {
        private int _Id = -1;

        public int Id
        {
            get { return this._Id; }
            set { this._Id = value; }
        }
    }

Note this is the original spec that i laid down for the problem that i was trying to solve..
"
I have a number of custom business objects and am running into a little bit of a problem with coming up with an architecture in regards to the populate the various objects in different scenarios.

Now let’s say that I have a simple example where i have a customer object can have multiple orders and the customer can also have a street property which is an address object.

If i want to populate a list of orders which meets a set of critiria, normally what i would do is create the stored proc which returns the orders and I would initiate this call this from the orders class. Thus once called, the orders object which I made the call from will contain a list of order objects. The problem comes when, I also need to have the associated customer order data returned as well.

Technically the structure that I should have is not a single orders object but a single customers object each which contains a single orders object which contains the orders. But to do this I would have to shift the method call from the orders class into customer class which means I am putting the logic around how to populate orders and any criteria into the customer’s class instead of where I think it should be in the orders class. There is maybe an argument that it should go in the customers class but in reality what happens when I decide that I also when other associated data brought back as well, this might mean that I have to shift the method call again from the customer class into another class.

Now SQL can return the data really easily and efficiently since I can just do something like "SELECT * FROM Order LEFT JOIN Customer WHERE ...". But as I have said the problem comes when I am trying to map this flat structure to the object.

One thing i could do is have a customer object in the order as well so that when I am looping through and creating the order items I can populate customer object off the order item. But then i have multiple customer objects which should be the same thing... I guess I could keep a collection of customer separately and only create each customer once when i find them and then add just the reference to each of the order items. But i don’t know if this is the best way to go.

It seems to me that the problem comes when i have a collection of items as I want to have data which is back up the object tree. Going down is not a problem (like having a collection of customers and then creating the address item for each one as i go), just up. "

Copyright (c) Marimer LLC