Jun 2, 2010

poco fix-up during relation change

I have a poco entity like following. At first I do not have Items navigation property, but it turns out, this property is important. Bascially it makes the following code work.



var countBeforeInsert = _db.Entities.Count();
            //
            Entity parent = new Entity();
            parent.Id = Guid.NewGuid();
            parent.Name = "parent";
            parent.Created = DateTime.Now;
            parent.LastUpdated = DateTime.Now;

            Entity child = new Entity();
            child.Id = Guid.NewGuid();
            child.Name = "child";
            child.Created = DateTime.Now;
            child.LastUpdated = DateTime.Now;
            child.Container = parent;

            _db.Entities.AddObject(parent);
            _db.SaveChanges();
            //
            var countAfterInsert = _db.Entities.Count();
            //
            Assert.Equal(countBeforeInsert + 2, countAfterInsert);
            //
            _db.DeleteObject(parent);
            _db.SaveChanges();
            //
            var countAfterDelete = _db.Entities.Count();
            //
            Assert.Equal(countAfterDelete, countBeforeInsert);


What happen, if we remove the Items property. The above code doesn't work. To make it work again, we need to add a line like the following.


_db.Entities.AddObject(parent);
_db.Entities.AddObject(child);

What happen? When saving changes to database, entity framework will use ObjectStateManager to check ObjectStateEntries. When "Items" is defined, the we don't need to add the child to the cache pool. When "Items" is not defined, we need to do that. Please note that regardless whether we define "Items" property, the association between parent and child always exists. The when the Items is accessed, entity framework will intercept the request and add the children into cache pool.


#region Navigation Properties
    
        //public virtual ICollection<Entity> Items
        //{
        //    get
        //    {
        //        if (_items == null)
        //       {
        //            var newCollection = new FixupCollection<Entity>();
        //            newCollection.CollectionChanged += FixupItems;
        //            _items = newCollection;
         //       }
        //        return _items;
        //    }
        //    set
        //    {
        //        if (!ReferenceEquals(_items, value))
        //        {
        //            var previousValue = _items as FixupCollection<Entity>;
        //            if (previousValue != null)
        //            {
        //                previousValue.CollectionChanged -= FixupItems;
        //           }
        //            _items = value;
        //            var newValue = value as FixupCollection<Entity>;
        //            if (newValue != null)
        //            {
        //                newValue.CollectionChanged += FixupItems;
        //            }
        //        }
        //    }
        //}
        //private ICollection<Entity> _items;
    
        public virtual Entity Container
        {
            get { return _container; }
            set
            {
                if (!ReferenceEquals(_container, value))
                {
                    var previousValue = _container;
                    _container = value;
                    FixupContainer(previousValue);
                }
            }
        }
        private Entity _container;

        #endregion
        #region Association Fixup
    
        private bool _settingFK = false;
    
        private void FixupContainer(Entity previousValue)
        {
        //    if (previousValue != null && previousValue.Items.Contains(this))
        //    {
        //        previousValue.Items.Remove(this);
        / /   }
    
            if (Container != null)
            {
        //        if (!Container.Items.Contains(this))
        //        {
        //            Container.Items.Add(this);
        //        }
                if (ContainerId != Container.Id)
                {
                    ContainerId = Container.Id;
                }
            }
            else if (!_settingFK)
            {
                ContainerId = null;
            }
        }
    /*
        private void FixupItems(object sender, NotifyCollectionChangedEventArgs e)
        {
            if (e.NewItems != null)
            {
                foreach (Entity item in e.NewItems)
                {
                    item.Container = this;
                }
            }
    
            if (e.OldItems != null)
            {
                foreach (Entity item in e.OldItems)
                {
                    if (ReferenceEquals(item.Container, this))
                    {
                        item.Container = null;
                    }
                }
            }
        }
*/
        #endregion