Child object "IsNew" on update

Child object "IsNew" on update

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


jspurlin posted on Monday, December 11, 2006

I have a base Address class that I extend to an OfficeAddress which is contained in a collection of addresses called OfficeAddresses which is a child collection to Office. Although an office typically will only have one address, I am using the same pattern for Persons who may have seasonal (more than one) addresses.

When I extend a base class, do I "MarkOld()" in the Subclass?

Here is the base class :

[Serializable()]
    public abstract class BaseAddress<T> : BusinessBase<T> where T : BaseAddress<T>
    {
        #region Business Methods

        private int _addressId = 0;
        private string _addressLine1 = string.Empty;
        private string _addressLine2 = string.Empty;
        private string _addressLine3 = string.Empty;
        private int _cityId = 0;
        private int _stateProvidenceId = 0;
        private string _zipCode = String.Empty;
        private byte[] _timestamp = new byteMusic [8];

        [System.ComponentModel.DataObjectField(true, true)]
        public int AddressId
        {
            [System.Runtime.CompilerServices.MethodImpl(System.Runtime.CompilerServices.MethodImplOptions.NoInlining)]
            get
            {
                CanReadProperty(true);
                return _addressId;
            }
        }

       etc...

        protected override object GetIdValue()
        {
            return _addressId;
        }

        #endregion

        //No Factory Methods

        protected virtual void Fetch(SafeDataReader dr)
        {
            _addressId = dr.GetInt32("AddressId");
            _addressLine1 = dr.GetString("AddressLine1");
            _addressLine2 = dr.GetString("AddressLine2");
            _addressLine3 = dr.GetString("AddressLine3");
            _cityId = dr.GetInt32("CityId");
            _stateProvidenceId = dr.GetInt32("StateProvidenceId");
            _zipCode = dr.GetString("ZipCode");
            dr.GetBytes("LastChanged", 0, _timestamp, 0, 8);
        }


        protected virtual int InsertAddress(SqlCommand cm)
        {
           
if we make it this far, no problem
        }

        protected virtual int UpdateAddress(SqlCommand cm)
        {
           
if we make it this far, no problem
        }

        protected virtual int DeleteAddress(SqlCommand cm)
        {
            if we make it this far, no problem
        }
    }

Here is the OfficeAddress:

[System.Serializable()]
    public class OfficeAddress : BaseAddress<OfficeAddress>
    {
        protected override object GetIdValue()
        {
            return base.GetIdValue();
        }

        #region Factory Methods

        internal static OfficeAddress NewOfficeAddress()
        {
            return new OfficeAddress();
        }

        internal static OfficeAddress GetAddress(SafeDataReader dr)
        {
            return new OfficeAddress(dr);
        }

        private OfficeAddress()
        {
            MarkAsChild();
        }

        private OfficeAddress(SafeDataReader dr)
        {
            MarkAsChild();
            Fetch(dr);
        }

        #endregion

        #region Data Access

        protected override void Fetch(SafeDataReader dr)
        {
            MarkAsChild();
            base.Fetch(dr);
        }

        internal void Insert(SqlConnection cn, Office office)
        {
            // if we're not dirty then don't update the database
            if (!this.IsDirty) return;

            using (SqlCommand cm = cn.CreateCommand())
            {
                etc...
                MarkOld();
            }
        }

        internal void Update(SqlConnection cn, Office office)
        {
            // if we're not dirty then don't update the database
            if (!this.IsDirty) return;

            using (SqlCommand cm = cn.CreateCommand())
            {
                etc...
                MarkOld();
            }
        }

        internal void DeleteSelf(SqlConnection cn, Office office)
        {
            // if we're not dirty then don't update the database
            if (!this.IsDirty) return;

            // if we're new then don't update the database
            if (this.IsNew) return;

            using (SqlCommand cm = cn.CreateCommand())
            {
                etc...
            }
        }

        #endregion
    }

Here is the OfficeAddresses class, and where the updated object is showing up IsDirty "and" IsNew

[Serializable()]
    public class OfficeAddresses :
      BusinessListBase<OfficeAddresses, OfficeAddress>
    {
        #region Business Methods

        public OfficeAddress GetItem(int addressId)
        {
            foreach (OfficeAddress address in this)
                if (address.AddressId == addressId)
                    return address;
            return OfficeAddress.NewOfficeAddress();
        }

        public void Insert()
        {
            OfficeAddress address =
                  OfficeAddress.NewOfficeAddress();
            this.Add(address);
        }

        public void Remove(int addressId)
        {
            foreach (OfficeAddress address in this)
            {
                if (address.AddressId == addressId)
                {
                    Remove(address);
                    break;
                }
            }
        }

        public bool Contains(int addressId)
        {
            foreach (OfficeAddress address in this)
                if (address.AddressId == addressId)
                    return true;
            return false;
        }

        public bool ContainsDeleted(int addressId)
        {
            foreach (OfficeAddress address in DeletedList)
                if (address.AddressId == addressId)
                    return true;
            return false;
        }

        #endregion

        #region Factory Methods

        internal static OfficeAddresses NewOfficeAddresses()
        {
            return new OfficeAddresses();
        }

        internal static OfficeAddresses GetOfficeAddresses(SafeDataReader dr)
        {
            return new OfficeAddresses(dr);
        }

        private OfficeAddresses()
        {
            MarkAsChild();
        }

        private OfficeAddresses(SafeDataReader dr)
        {
            MarkAsChild();
            Fetch(dr);
        }

        #endregion

        #region Data Access

        // called to load data from the database
        private void Fetch(SafeDataReader dr)
        {
            this.RaiseListChangedEvents = false;
            while (dr.Read())
                this.Add(OfficeAddress.GetAddress(dr));
            this.RaiseListChangedEvents = true;
        }

        internal void Update(SqlConnection cn, Office person)
        {
            this.RaiseListChangedEvents = false;
            // update (thus deleting) any deleted child objects
            foreach (OfficeAddress obj in DeletedList)
                obj.DeleteSelf(cn, person);
            // now that they are deleted, remove them from memory too
            DeletedList.Clear();

            // add/update any current child objects
            foreach (OfficeAddress obj in this)
            {
                if (obj.IsNew)
                    obj.Insert(cn, person);
                else
                    obj.Update(cn, person);
            }
            this.RaiseListChangedEvents = true;
        }

        #endregion

    }

Finally, int the office class itself, during the DataPortal_Fetch(Criteria criteria) I have this after the datareader returns the office:

// load child objects (Address, Phone)
dr.NextResult();
_addresses = OfficeAddresses.GetOfficeAddresses(dr);

I had this pattern working fine without creating a base Address class. Any advice on why the OfficeAddress.IsNew on update would be greatly appreciated.

Thank you.

xal replied on Monday, December 11, 2006

You should always call MarkOld inside your fetch methods for child objects.
The DP will do this automatically for root objects, but not for children. I think the candidate for this is your Fetch() method in your base class.

Andrés

jspurlin replied on Monday, December 11, 2006

That was it. Bless you for helping this neophyte.  I don't know what the "points" are for, but I'll trade you some of mine!~

Copyright (c) Marimer LLC