Deserialized: Is this a problem?

Deserialized: Is this a problem?

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


vdhant posted on Sunday, January 13, 2008

Hi guys
I know that the below doesn't have any CSLA stuff in it yet but I am working on a prototype to implement within CSLA. If i wanted to have the below, can anyone see any problems. The reason why I ask is that I noticed that the parent reference in the businessbase is set to NonSerialized and after any Deserializion occurs it sets up the parent references again. I can see that in essence I am wanting to do the same thing, but my tests haven't shown any problems as of yet. 

The only thing that I could think of is that it might be is due to an event problem. If this is done due to events can anyone let me know? As it is a lot harder to work with the model I am experimenting with it I have to rebuild the relationships all the time. The basic idea is that I am wanting to be able to reference parent items (not just the parent list) from within my objects. This means that I can a stored proc that returns a list of all current orders that contains both Order and Customer data (where a customer can have many orders), where I want to have a list of orders not a list of customers each of which have different sub lists of orders.  
Thanks
Anthony

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].RelationshipItem.Customer.Desc = "TEST";
    }
}

[Serializable()]
public class Customer
{
    public int Id = -1;
    public string Desc = "";
}

[Serializable()]
public class Order
{
    public int Id = -1;
    public string Desc = "";
    public Relationship RelationshipItem = new Relationship();

    [Serializable()]
    public class Relationship
    {
        public Customer Customer;
    }
}

[Serializable()]
public class Orders : BindingList<Order>
{
    Relationship RelationshipItem = new Relationship();

    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.RelationshipItem.ReturnCustomer(customerRef);
            if (customer == null)
            {
                customer = new Customer();
                customer.Id = customerRef;
                customer.Desc = "Customer " + customer.Id;
                this.RelationshipItem.AddCustomer(customer);
            }

            order.RelationshipItem.Customer = customer;
            this.Add(order);
        }
    }

    [Serializable()]
    public class Relationship
    {
        private List<Customer> Customers = new List<Customer>();

        public Customer ReturnCustomer(int custmerRef)
        {
            foreach (Customer customer in this.Customers)
            {
                if (customer.Id == custmerRef)
                    return customer;
            }
            return null;
        }

        public void AddCustomer(Customer customer)
        {
            this.Customers.Add(customer);
        }
    }
}

JoeFallon1 replied on Sunday, January 13, 2008

Rocky is building in Parent support to the framework in the version he is currently working on. It will support collections and also root BOs with contained child objects. It will also re-hook them after passing through the Data Portal.

Joe

 

vdhant replied on Sunday, January 13, 2008

Sounds interesting. Have any details come out about this yet???
Thanks
Anthony

vdhant replied on Sunday, January 13, 2008

Also here is a revised model for what I was working on:

    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";
        }
    }

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

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

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

    [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;

                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; }
        }
    }

RockfordLhotka replied on Monday, January 14, 2008

vdhant:

Sounds interesting. Have any details come out about this yet???

 

What details do you want? Smile [:)]

 

It works as described: child objects (whether single or list) now all have a protected Parent property that is always set to the immediate parent object reference. This value is loaded when the child becomes a child of a parent, and is reset automatically on deserialization.

 

Additionally, the PropertyChanged or ListChanged event of a child object is automatically hooked by the parent (and rehooked on deserialization) so the event cascades up through the parent's property. So if the parent exposes the child as a MyChild property, then when the child changes, the parent raises a PropertyChanged event for its MyChild property.

 

This is all combined with the new managed property/field syntax discussed in this huge thread.

 

A child property is now declared like this in CSLA 3.5:

 

private static PropertyInfo<Child> MyChildProperty =

  new PropertyInfo<Child>("MyChild");

public Child MyChild

{

  get

  {

    if (!FieldManager.FieldExists(MyChildProperty))

      LoadProperty<Child>(MyChildProperty, Child.GetChild(this.Id));

    return GetProperty<Child>(MyChildProperty);

  }

}

 

A number of things happen here, at the LoadProperty() step:

  1. The child is associated with the parent
  2. The child's Parent property is set
  3. The child's PropertyChanged/ListChanged event is hooked
  4. The child's edit level is set to match the parent (or one lower if the parent is currently data bound)
  5. The child's IsValid/IsDirty state automatically becomes part of the parent's state

The result is that you have no plumbing code to write around child objects. It is all automatic.

 

Better yet, this is the model for lazy loading or not. The same coding model here works regardless of lazy loading or immediate loading. That decision is made in the parent's DataPortal_Fetch() method (and the implementation of the child itself, since it needs a factory method and a DataPortal_Fetch() method of its own to support lazy loading).

Copyright (c) Marimer LLC